信息系统安全|ret2libc多函数调用获取秘密信息
系统配置实验平台：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.zipstack.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.py32位系统 开启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表中的位置，接下来就可以构造程序流执行第一遍的shellcodeshellcode主要思想：通过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里找到)