pwn demo
首先,pwn大概是pwn to own的意思,就是通过二进制/系统调用等方式获得目标主机的shell;
我直接以一个非常简单的栈溢出例子(基于Linux)来讲解pwn所要用到的一些常用的工具及命令;
所需要的工具安装等,可以先看这个链接(https://blog.csdn.net/qq_40827990/article/details/83217716)
例子下载地址:https://download.csdn.net/download/qq_40827990/10740077
https://pan.baidu.com/s/1feWmSgR2c9mStjR6uzEO8Q
前言:栈溢出就是缓冲区溢出的一种。 由于缓冲区溢出而使得有用的存储单元被改写,往往会引发不可预料的后果。程序在运行过程中,为了临时存取数据的需要,一般都要分配一些内存空间,通常称这些空间为缓冲区。如果向缓冲区中写入超过其本身长度的数据,以致于缓冲区无法容纳,就会造成缓冲区以外的存储单元被改写,这种现象就称为缓冲区溢出。缓冲区长度一般与用户自己定义的缓冲变量的类型有关。
从汇编语言的方面来讲直白但是不是特别准确的来讲就是,当我们call一个函数的时候,我们会把返回地址push到栈中,但程序没有检查机制的时候,如果用户输入的字符串太长了,就会覆盖到返回地址,这时候程序就会出错;但如果我们别有用心的构造一段字符串来覆盖返回地址的话,就可以让程序运行我们想做的事情,为所欲为;
好了,直接开始讲吧;
1.我们先用file命令查看一下文件的基本信息:
可以看到这是一个32位的ELF文件(这个影响后面我们shell code的书写);
2.然后我们用checksec命令查看一下文件的安全性:
【1】RELRO:RELRO会有Partial RELRO和FULL RELRO,如果开启FULL RELRO,意味着我们无法修改got表,设置符号重定向表格为只读或在程序启动时就解析并绑定所有动态符号,从而减少对GOT(Global Offset Table)攻击。RELRO为”Partial RELRO”,说明我们对GOT表具有写权限
【2】Stack:如果栈中开启Canary found,那么就不能用直接用溢出的方法覆盖栈中返回地址,而且要通过改写指针与局部变量、leak canary、overwrite canary的方法来绕过
【3】NX:NX enabled如果这个保护开启就是意味着栈中数据没有执行权限,以前的经常用的call esp或者jmp esp的方法就不能使用,但是可以利用rop这种方法绕过
【4】PIE:PIE enabled如果程序开启这个地址随机化选项就意味着程序每次运行的时候地址都会变化,而如果没有开PIE的话那么No PIE (0x400000),括号内的数据就是程序的基地址 ;
这里主要用到的信息是stack里的,没有开启保护;
3.然后我们看看程序的功能:
先直接运行程序看看,发现只有一个用户输入的地方:
然后用objdump -R,查看一下程序的只要函数有哪些;
然后看到这里有一个关键的函数:system();
4,然后我们将文件载入IDA中分析一下:
这里我们看到一个明显的gets()函数,这是一个非常不安全的函数,会造成溢出覆盖到返回地址;
5,所以我们现在来看看多少字节的字符串会造成溢出覆盖到返回地址;
这里我们用cyclic命令来生成特定的字符串,cyclic生成的字符串的特点就是任意四个连续的字符串都是独一无二的,之后我们就可以通过检测这个字符串是多少来计算多少字节的字符串会造成溢出覆盖到返回地址了;
我们先生成200个这样的字符串:cyclic 200
然后复制这串字符串,用gdb运行epwn程序,并输入这段字符串:
(我的gdb安装了pwngdb插件);
因为根据调用约定,通常将函数的返回值放在EAX,这里明显返回地址被覆盖了,根据不同的程序报错的位置可能在DISASM中(由于我计算机的调用问题,通常情况应该是直接覆盖的eip,pwndbg中会在DISASM位置直接显示eip被覆盖的值,然后用下面的方法去算出多少个字符覆盖返回地址就可以了);
所以这里我们用cyclic –l 0x62616164 来计算多少个字符覆盖返回地址:
这里看到是112个字符;
6,最后我们就要找将返回地址修改为什么地方,才可以执行我们想要的东西,因为之前我们找到了一个sysytem()函数,所以我们只要找到这个函数的地址,用这个地址去覆盖返回地址,就可以了:
我们在IDA中看到了system()的地址是0x08048641,因为这个函数相当于需要一个参数”/bin/sh”,所以要将返回地址覆盖为0x0804863A;
7,知道了所有想要的信息了,我们就可以写shellcode了:
基本格式:
-
from pwn import *
-
-
p = process('文件相对路径')
-
-
p.sendline(需要填充的字符+ p32(修改的返回地址))
-
-
p.interactive()
此题shellcode:
-
from pwn import *
-
-
p = process('./ret')
-
-
p.sendline('a'*112+ p32(0x0804863A))
-
-
p.interactive()
这个是用python2写的,如果程序是64位的,需要将p32换为p64;
执行结果:
Ok,就这样了……
如果有哪里出错了请指出,感谢!