-
-
[原创] KCTF 2025 第10题 涅槃,亦是新生wp
-
发表于: 2025-9-3 10:11 2841
-
首先从入口函数中探索, 点进start->sub_140001010->sub_1400721F0->sub_140081F40->sub_140071D12->sub_140071BA4看到了特征字符串:
搜索发现是 e2fK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1k6Y4K9r3c8D9i4K6u0r3k6$3S2V1L8l9`.`. 该函数是库中ghdl\src\grt\grt-main.adb里的Check_Flag_String函数;
阅读该库得知是vhdl仿真库, 会将vhdl编译为机器码运行.
但程序中将很多特征字符串都抹除为了一串0oO..., 增加了识别grt函数代码的难度, 所以尝试hook+backtrace来找到主要逻辑.
这次用frida时要加上--kill-on-exit参数, 不然frida退出后会留下一个占满一个cpu的hardrock.exe进程需要手动结束.
用frida hook输入函数并打印调用栈, 发现程序中使用的是getc:
输出为:
其中关键位置为0x140059010, 属于函数sub_140057A20, 函数中有一个较大的类似switch指令码的switch case, hook switch的判断位置:
输入个1234得到:
虽然输出混在一起仍能得到switch的执行顺序为0 1 2 3 5 6 8 7 9 3 5, 其中0负责输入, 1 2 3为:
可以看到其中不存在算法, 重点在5; 观察case5中发生的函数调用, 发现有一个比较有趣的函数140044310:
hook该函数发现它处理的就是输入的字符:
之后case 6 8 7 9 重点在9:
compare_14000CB50函数为:
查看qword_1400C89D0内容为:
size8_1400C8998 + 12处的值为8, 所以此处比较大小为8;
写hook观察compare_14000CB50在拿什么与qword_1400C89D0比较:
发现与输入1234经conv_140044310函数处理后的结果不同; 尝试改变输入为2234, 再观察:
发现比较内容与经conv_140044310函数处理后的结果的变化满足异或关系;
于是写hook提取异或秘钥:
之后再次运行时不输入flag直接回车, 之后运行console.log(hexdump(xorkey, {length: ksize}))得到:
然后写代码计算flag:
得到flagKCTF{84e3229c-310b-4a9b-9977-b20db689d701}
__int64 sub_140071BA4(){ __int64 v0; // rax char v1; // dl __int64 result; // rax char *v3; // [rsp+20h] [rbp-18h] BYREF void *v4; // [rsp+28h] [rbp-10h] v0 = stdout(); sub_140077F00(v0); v1 = sub_140057150(); result = 0LL; if ( !v1 ) { if ( a08it[3] != 'T' || a08it[2] != 'i' ) { v3 = "GRT is not consistent with the flags used for your designerror during elaboration"; v4 = &unk_1400CE8F8; sub_140078292(&v3); } sub_140076562(); sub_140062D32(); sub_14006DFCE(); if ( Flag_Stats ) sub_14007F8E6(); if ( (int)Run_Through_Longjump(sub_140071B50) < 0 ) { v3 = "error during elaboration"; v4 = &unk_1400CE900; sub_140078292(&v3); } return 1LL; } return result;}__int64 sub_140071BA4(){ __int64 v0; // rax char v1; // dl __int64 result; // rax char *v3; // [rsp+20h] [rbp-18h] BYREF void *v4; // [rsp+28h] [rbp-10h] v0 = stdout(); sub_140077F00(v0); v1 = sub_140057150(); result = 0LL; if ( !v1 ) { if ( a08it[3] != 'T' || a08it[2] != 'i' ) { v3 = "GRT is not consistent with the flags used for your designerror during elaboration"; v4 = &unk_1400CE8F8; sub_140078292(&v3); } sub_140076562(); sub_140062D32(); sub_14006DFCE(); if ( Flag_Stats ) sub_14007F8E6(); if ( (int)Run_Through_Longjump(sub_140071B50) < 0 ) { v3 = "error during elaboration"; v4 = &unk_1400CE900; sub_140078292(&v3); } return 1LL; } return result;}const proc = Process.findModuleByName("hardrock.exe");const base = proc.base;const load_base = 0x140000000;function show_backtrace(context) { let bt = Thread.backtrace(context, Backtracer.ACCURATE).map(addr => { addr = ptr(addr); if(addr.compare(base) >= 0 && addr.compare(base.add(proc.size)) < 0) { return "hardrock.exe! " + addr.sub(base).add(load_base); } return addr.toString(); }).join("\n\t"); console.log('\n\t' + bt);}Interceptor.attach(Module.findGlobalExportByName("getc"), { onEnter: function(args) { show_backtrace(this.context); }});const proc = Process.findModuleByName("hardrock.exe");const base = proc.base;const load_base = 0x140000000;function show_backtrace(context) { let bt = Thread.backtrace(context, Backtracer.ACCURATE).map(addr => { addr = ptr(addr); if(addr.compare(base) >= 0 && addr.compare(base.add(proc.size)) < 0) { return "hardrock.exe! " + addr.sub(base).add(load_base); } return addr.toString(); }).join("\n\t"); console.log('\n\t' + bt);}Interceptor.attach(Module.findGlobalExportByName("getc"), { onEnter: function(args) { show_backtrace(this.context); }});hardrock.exe! 0x140072183hardrock.exe! 0x14006ea67hardrock.exe! 0x1400020b4hardrock.exe! 0x140059010hardrock.exe! 0x1400621fehardrock.exe! 0x14006423ahardrock.exe! 0x1400645e3hardrock.exe! 0x140071d46hardrock.exe! 0x140071fc0hardrock.exe! 0x140071c82hardrock.exe! 0x140071d29hardrock.exe! 0x140081f75hardrock.exe! 0x140072212hardrock.exe! 0x1400010c9hardrock.exe! 0x1400014160x7ffd26a07344hardrock.exe! 0x140072183hardrock.exe! 0x14006ea67hardrock.exe! 0x1400020b4hardrock.exe! 0x140059010hardrock.exe! 0x1400621fehardrock.exe! 0x14006423ahardrock.exe! 0x1400645e3hardrock.exe! 0x140071d46hardrock.exe! 0x140071fc0hardrock.exe! 0x140071c82hardrock.exe! 0x140071d29hardrock.exe! 0x140081f75hardrock.exe! 0x140072212hardrock.exe! 0x1400010c9hardrock.exe! 0x1400014160x7ffd26a07344Interceptor.attach(base.add(0x57A84), function() { console.log("op", this.context.rax);});Interceptor.attach(base.add(0x57A84), function() { console.log("op", this.context.rax);});KCTF 2025Flop 0x0ag:[Local::hardrock.exe ]op 0x1op 0x2op 0x3op 0x5op 0x6op 0x8op 0x7op 0x9op 0x3op 0x5Wrong!KCTF 2025Flop 0x0ag:[Local::hardrock.exe ]op 0x1op 0x2op 0x3op 0x5op 0x6op 0x8op 0x7op 0x9op 0x3op 0x5Wrong!case 1: v25 = a1->pbyte20; v152 = &a1->byte126D; a1->byte126D = 2; if ( v25[42] == 1 || *v25 != *v152 ) sub_140066FDC((__int64)v25); result = Ghdl_Process_Wait_Timeout(10000000LL, (__int64)"OoooOooooOOoO", 133u); a1->opid = 2; return result;case 2: opid = 3; continue;case 3: if ( a1->int1264 > 41 ) opid = 4; else opid = 5; continue;case 1: v25 = a1->pbyte20; v152 = &a1->byte126D; a1->byte126D = 2; if ( v25[42] == 1 || *v25 != *v152 ) sub_140066FDC((__int64)v25); result = Ghdl_Process_Wait_Timeout(10000000LL, (__int64)"OoooOooooOOoO", 133u); a1->opid = 2; return result;case 2: opid = 3; continue;case 3: if ( a1->int1264 > 41 ) opid = 4; else opid = 5; continue;void *__fastcall conv_140044310(_QWORD *a1, int a2, int a3){ ... v19 = v37; v37[0] = a3 - 1; v37[1] = 0; v38 = 1; v28 = a3 - 1; if ( a3 - 1 < 0 ) v41 = 0; else v41 = v28 + 1; v19[3] = v41; v14[0] = &v36; sub_14001D590(&v36); v42 = v36; if ( v36 >= 0x8000 ) sub_1400712C6(v42); v6 = alloca(sub_1400BCE80()); out = v14; v29 = v39; for ( i = 0; i != v29; ++i ) *((_BYTE *)out + i) = 0; arg2 = a2; if ( a3 <= 0 ) { v14[1] = &byte_1400E93C0; v20 = &byte_1400E93C0; v21 = &unk_1400C2CE8; v22 = &v20; v12 = (void *)sub_140063160(16LL); a1[1] = v12; memmove_0(v12, v21, 0x10uLL); v9 = (void *)sub_140063160(*(unsigned int *)(a1[1] + 12LL)); *a1 = v9; v10 = *(unsigned int *)(a1[1] + 12LL); v11 = (const void **)v22; } else { v45 = 0; v30 = v37[0]; if ( v37[0] >= 0 ) { while ( 1 ) { if ( !(arg2 % 2) ) goto LABEL_19; v7 = arg2 % 2 + 2; if ( arg2 >= 0 ) v7 = arg2 % 2; if ( v7 ) { // arg2为奇数时输出写入3 v24 = v37; v33 = v45; v18 = v37[0] - v45; v34 = v37[0] - v45; if ( (int)(v37[0] - v45) < 0 || v37[0] - v45 >= v39 ) sub_140070EB2("OOooOooOOOOOooOoooOOoOoOOooOOOOOoOoooOoO", 3084LL, v33, v24); v17 = v34; *((_BYTE *)out + (int)v34) = 3; } else {LABEL_19: // arg2为偶数时输出写入2 v23 = v37; v31 = v45; v16 = v37[0] - v45; v32 = v37[0] - v45; if ( (int)(v37[0] - v45) < 0 || v37[0] - v45 >= v39 ) sub_140070EB2("OOooOooOOOOOooOoooOOoOoOOooOOOOOoOoooOoO", 3083LL, v31, v23); v15 = v32; *((_BYTE *)out + (int)v32) = 2; } v35 = arg2 / 2; // 之后arg2自除2 if ( arg2 / 2 < 0 ) Ghdl_Bound_Check_Failed_140070D6C((__int64)"OOooOooOOOOOooOoooOOoOoOOooOOOOOoOoooOoO", 0xC0Eu); arg2 = v35; if ( v45 == v30 ) break; ++v45; } } if ( arg2 ) { v14[2] = &off_1400C68E0; sub_140070968( (__int64)"oOoooOOOoooOOoOOoOOOOoOoOoOOoOooooOooOOoO", dword_1400C6898[3], 1u, (__int64)&off_1400C6878); } v14[3] = out; v25 = out; Src = v37; v27 = (const void **)&v25; v8 = (void *)sub_140063160(16LL); a1[1] = v8; memmove_0(v8, Src, 0x10uLL); v9 = (void *)sub_140063160(*(unsigned int *)(a1[1] + 12LL)); *a1 = v9; v10 = *(unsigned int *)(a1[1] + 12LL); v11 = v27; } return memmove_0(v9, *v11, v10);}void *__fastcall conv_140044310(_QWORD *a1, int a2, int a3){ ... v19 = v37; v37[0] = a3 - 1; v37[1] = 0; v38 = 1; v28 = a3 - 1; if ( a3 - 1 < 0 ) v41 = 0; else v41 = v28 + 1; v19[3] = v41; v14[0] = &v36; sub_14001D590(&v36); v42 = v36; if ( v36 >= 0x8000 ) sub_1400712C6(v42); v6 = alloca(sub_1400BCE80()); out = v14; v29 = v39; for ( i = 0; i != v29; ++i ) *((_BYTE *)out + i) = 0; arg2 = a2; if ( a3 <= 0 ) { v14[1] = &byte_1400E93C0; v20 = &byte_1400E93C0; v21 = &unk_1400C2CE8; v22 = &v20; v12 = (void *)sub_140063160(16LL); a1[1] = v12; memmove_0(v12, v21, 0x10uLL); v9 = (void *)sub_140063160(*(unsigned int *)(a1[1] + 12LL)); *a1 = v9; v10 = *(unsigned int *)(a1[1] + 12LL); v11 = (const void **)v22; } else { v45 = 0; v30 = v37[0]; if ( v37[0] >= 0 ) { while ( 1 ) { if ( !(arg2 % 2) ) goto LABEL_19; v7 = arg2 % 2 + 2; if ( arg2 >= 0 ) v7 = arg2 % 2; if ( v7 ) { // arg2为奇数时输出写入3 v24 = v37; v33 = v45; v18 = v37[0] - v45; v34 = v37[0] - v45; if ( (int)(v37[0] - v45) < 0 || v37[0] - v45 >= v39 ) sub_140070EB2("OOooOooOOOOOooOoooOOoOoOOooOOOOOoOoooOoO", 3084LL, v33, v24); v17 = v34; *((_BYTE *)out + (int)v34) = 3; } else {LABEL_19: // arg2为偶数时输出写入2 v23 = v37; v31 = v45; v16 = v37[0] - v45; v32 = v37[0] - v45; if ( (int)(v37[0] - v45) < 0 || v37[0] - v45 >= v39 ) sub_140070EB2("OOooOooOOOOOooOoooOOoOoOOooOOOOOoOoooOoO", 3083LL, v31, v23); v15 = v32; *((_BYTE *)out + (int)v32) = 2; } v35 = arg2 / 2; // 之后arg2自除2 if ( arg2 / 2 < 0 )[培训]Windows内核深度攻防:从Hook技术到Rootkit实战!