信息系统安全|ret2libc多函数调用获取秘密信息

网安 · 2023-05-06 · 679 人浏览
信息系统安全|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.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

截图 2023-05-05 19-00-54

②随后利用gcc -fno-stack-protector -z noexecstack -no-pie -g -m32 stack.c -o stack编译程序源代码,其中-fno-stack-protector关闭stack canary-z noexecstack开启NX保护。通过checksec指令可以确认当前可执行文件的架构和各种保护

截图 2023-05-05 19-03-52

③通过cyclic 150生成用来溢出目标程序的字符串,ulimit -c unlimited用来设置核心转存储

截图 2023-05-05 19-09-21

④找到核心转存储的core文件(ubuntu系统下core文件有点难找,可以设置sysctl -w kernel.core_pattern=/tmp/core-%e.%p.%h.%t让core文件生成在/tmp目录下),通过gdb stack core查看寄存器状态 发现此时EIP的值是'taaa'

截图 2023-05-05 19-11-18

⑤查看taaa在原字符串的位置,偏移值为76,说明写入的buffer起点与栈中的返回地址相差76个字节

截图 2023-05-05 19-11-04

⑥为了完成ret2libc多函数调用,需要找一些pop ret指令用来平衡栈,几个pop取决于调用函数需要几个参数,这里我们用到open/read/write/exit函数,所以带有1-3个pop语句的ret语句我们都需要.查看目标程序本身,只有一个pop ebx;ret;,那么其他的gadget需要去libc文件里找

image-20230506104945962

⑦首先确定程序用了哪些lib,通过ldd stack查看,定位libc.so.6

截图 2023-05-05 19-11-57

⑧在libc.so.6中寻找剩下的gadget,如下图所示

image-20230506105019355

⑨得到gadget后,接下来确定缓冲区BUF的位置,因为我们之后要使用read函数读入我们需要查看文件的路径,那么需要在进程空间里找一块可写的缓冲区。我们通过vmmap查看目标程序的进程空间,选择0x804c500作为缓冲区首地址

image-20230506105223186

⑩最后需要找read/open/write/exit这些函数的地址,可以使用上课老师使用的方法(如果没记错的话),即使用ropper指令去查找;也可以使用pwn使用p指令查看。

截图 2023-05-05 20-30-25

⑪编写shellcode,执行脚本。可以获取/tmp/flag里的内容flag file:U202012007JieHuang,攻击成功

主要思想:ROP链的流程是首先调用read函数得到需要查看的文件路径(输入为标准输入0),文件名写入缓冲区;其次调用open函数打开缓冲区里指示的文件,将文件句柄写入缓冲区(可以用同一块,因为之后不需要用到文件名了);调用write函数将文件内容输出到标准输出1;调用exit函数正常退出

为了实现多函数调用,前一个函数退出时,需要再调用一个pop ret的gadget(几个pop取决于参数个数),保证将前一个函数调用的参数都pop出去,保证系统调用pop eip时下一个函数的地址就在栈顶

image-20230506110651362

具体shellcode参见附件attack.py

截图 2023-05-05 20-55-21

32位系统 开启ASLR

①首先设置kernel.randomize_va_space=2,开启ASLR。通过ldd指令可以发现地址随机的现象,说明ASLR成功开启

截图 2023-05-05 22-28-46

②因为open/write函数还有部分pop ret函数都是来自libc.so.6,现在它的地址改变了。我们就无法静态调用它们,因此思路就是在目标程序通过plt/got表确定libc.so.6新的基地址,加上偏移就可以得到目前函数的真实地址。构造shellcode时我们可以将程序流执行两遍,第一遍确认新的基地址,第二遍执行普通的ret2libc(与未开启aslr一样).

③通过disass start可以确定puts函数的在plt表中的地址

截图 2023-05-05 22-30-23

④可以进一步确定puts在got表中的位置,这些位置不会随着ASLR随机而改变

截图 2023-05-05 22-41-41

⑤同理可以找到read函数在got表中的位置,接下来就可以构造程序流执行第一遍的shellcode

shellcode主要思想:通过puts函数打印出当前read函数的实际地址,减去read函数相较于libc基地址的偏移,可以得到libc的基地址,在这个基础上可以获得其他函数和gadget的真实地址(偏移+基地址)

细节代码见附件:attack_aslr_on.py

1

⑥运行shellcode,recv函数出现错误。发现是python高版本的问题,需要将所有字符串声明为二进制流类型,即字符串前加b

截图 2023-05-05 23-01-23

⑦重新运行,这次可以攻击成功

截图 2023-05-05 23-25-53

64位系统 开启ASLR

①编译64位程序,照样开启ASLR和NX,关闭stack canary

截图 2023-05-06 09-34-07

②编写shellcode,因为64位程序运行时,参数不再从栈中获取,而是从寄存器中得到(前三个参数的寄存器为rdi/rsi/rdx)。所以传入参数需要找到例如pop rdi;ret;类似的gadget。因此64位程序的shellcode除了修改一些基地址/偏移地址外(因为libc变了),还需要修改参数传入的方式。

③修改后的部分shellcode如下图所示。

完整代码见附件attack_64.py

code

④但是现在存在一个问题:类似pop rdi;ret;的gadegt都找不到,因此shellcode中第一遍程序流都没法跑,暂时卡在这个地方.......(如果找到了pop rdi;ret;,其他的pop ret可以通过偏移地址在libc里找到)

截图 2023-05-06 09-34-07

信息系统安全 shellcode
  1. hhh 2023-05-11

    hhh

  2. hhh 2023-05-11

    123

  3. 匿名菜狗 2023-05-07

    哇博主好牛好牛好牛!如果能有装环境教程就好了(bushi)

Theme Jasmine by Kent Liao