系统配置
实验平台:Ubuntu 22.04 实机
Linux内核版本:v5.15
完成情况
- 完成32位系统下,关闭/开启ASLR两种情况的作业内容
- 完成64位系统下,开启ASLR情况下的部分作业内容
部分作业内容:完成64位情况shellcode的编写,但是暂时没找到gadget,例如
pop rdi;ret;
附件内容
附件:https://typora-img-1311051873.cos.ap-beijing.myqcloud.com/typora/202305061227449.zip
stack.c
:程序源代码attack.py
:32位情况下,未开启ASLR的shellcode注入程序attack_aslr_on.py
:32位情况下,开启ASLR的shellcode注入程序attack_64.py
:64位情况下,开启ASLR的shellcode注入程序test32.txt
:32位下若干函数的地址test.txt
:64位下若干函数的地址
作业内容
32位系统 未开启ASLR
①首先设置kernel.randomize_va_space=0
,关闭ASLR
②随后利用gcc -fno-stack-protector -z noexecstack -no-pie -g -m32 stack.c -o stack
编译程序源代码,其中-fno-stack-protector
关闭stack canary
,-z noexecstack
开启NX保护。通过checksec
指令可以确认当前可执行文件的架构和各种保护
③通过cyclic 150
生成用来溢出目标程序的字符串,ulimit -c unlimited
用来设置核心转存储
④找到核心转存储的core文件(ubuntu系统下core文件有点难找,可以设置sysctl -w kernel.core_pattern=/tmp/core-%e.%p.%h.%t
让core文件生成在/tmp
目录下),通过gdb stack core
查看寄存器状态 发现此时EIP的值是'taaa'
⑤查看taaa
在原字符串的位置,偏移值为76,说明写入的buffer起点与栈中的返回地址相差76个字节
⑥为了完成ret2libc多函数调用,需要找一些pop ret指令用来平衡栈,几个pop取决于调用函数需要几个参数,这里我们用到open/read/write/exit函数,所以带有1-3个pop语句的ret语句我们都需要.查看目标程序本身,只有一个pop ebx;ret;
,那么其他的gadget需要去libc文件里找
⑦首先确定程序用了哪些lib,通过ldd stack
查看,定位libc.so.6
⑧在libc.so.6
中寻找剩下的gadget,如下图所示
⑨得到gadget后,接下来确定缓冲区BUF的位置,因为我们之后要使用read函数读入我们需要查看文件的路径,那么需要在进程空间里找一块可写的缓冲区。我们通过vmmap查看目标程序的进程空间,选择0x804c500
作为缓冲区首地址
⑩最后需要找read/open/write/exit这些函数的地址,可以使用上课老师使用的方法(如果没记错的话),即使用ropper指令去查找;也可以使用pwn使用p指令查看。
⑪编写shellcode,执行脚本。可以获取/tmp/flag里的内容flag file:U202012007JieHuang
,攻击成功
主要思想:ROP链的流程是首先调用read函数得到需要查看的文件路径(输入为标准输入0),文件名写入缓冲区;其次调用open函数打开缓冲区里指示的文件,将文件句柄写入缓冲区(可以用同一块,因为之后不需要用到文件名了);调用write函数将文件内容输出到标准输出1;调用exit函数正常退出。
为了实现多函数调用,前一个函数退出时,需要再调用一个
pop ret
的gadget(几个pop取决于参数个数),保证将前一个函数调用的参数都pop出去,保证系统调用pop eip
时下一个函数的地址就在栈顶具体shellcode参见附件
attack.py
32位系统 开启ASLR
①首先设置kernel.randomize_va_space=2
,开启ASLR。通过ldd
指令可以发现地址随机的现象,说明ASLR成功开启
②因为open/write函数还有部分pop ret函数都是来自libc.so.6,现在它的地址改变了。我们就无法静态调用它们,因此思路就是在目标程序通过plt/got表确定libc.so.6新的基地址,加上偏移就可以得到目前函数的真实地址。构造shellcode时我们可以将程序流执行两遍,第一遍确认新的基地址,第二遍执行普通的ret2libc(与未开启aslr一样).
③通过disass start
可以确定puts函数的在plt表中的地址
④可以进一步确定puts在got表中的位置,这些位置不会随着ASLR随机而改变
⑤同理可以找到read函数在got表中的位置,接下来就可以构造程序流执行第一遍的shellcode
shellcode主要思想:通过puts函数打印出当前read函数的实际地址,减去read函数相较于libc基地址的偏移,可以得到libc的基地址,在这个基础上可以获得其他函数和gadget的真实地址(偏移+基地址)
细节代码见附件:
attack_aslr_on.py
⑥运行shellcode,recv函数出现错误。发现是python高版本的问题,需要将所有字符串声明为二进制流类型,即字符串前加b
⑦重新运行,这次可以攻击成功
64位系统 开启ASLR
①编译64位程序,照样开启ASLR和NX,关闭stack canary
②编写shellcode,因为64位程序运行时,参数不再从栈中获取,而是从寄存器中得到(前三个参数的寄存器为rdi/rsi/rdx)。所以传入参数需要找到例如pop rdi;ret;
类似的gadget。因此64位程序的shellcode除了修改一些基地址/偏移地址外(因为libc变了),还需要修改参数传入的方式。
③修改后的部分shellcode如下图所示。
完整代码见附件
attack_64.py
④但是现在存在一个问题:类似pop rdi;ret;
的gadegt都找不到,因此shellcode中第一遍程序流都没法跑,暂时卡在这个地方.......(如果找到了pop rdi;ret;
,其他的pop ret可以通过偏移地址在libc里找到)
hhh
123
哇博主好牛好牛好牛!如果能有装环境教程就好了(bushi)