首页
社区
课程
招聘
[原创] KCTF 2025 第10题 涅槃,亦是新生wp
发表于: 2025-9-3 10:11 2841

[原创] 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! 0x140072183
hardrock.exe! 0x14006ea67
hardrock.exe! 0x1400020b4
hardrock.exe! 0x140059010
hardrock.exe! 0x1400621fe
hardrock.exe! 0x14006423a
hardrock.exe! 0x1400645e3
hardrock.exe! 0x140071d46
hardrock.exe! 0x140071fc0
hardrock.exe! 0x140071c82
hardrock.exe! 0x140071d29
hardrock.exe! 0x140081f75
hardrock.exe! 0x140072212
hardrock.exe! 0x1400010c9
hardrock.exe! 0x140001416
0x7ffd26a07344
hardrock.exe! 0x140072183
hardrock.exe! 0x14006ea67
hardrock.exe! 0x1400020b4
hardrock.exe! 0x140059010
hardrock.exe! 0x1400621fe
hardrock.exe! 0x14006423a
hardrock.exe! 0x1400645e3
hardrock.exe! 0x140071d46
hardrock.exe! 0x140071fc0
hardrock.exe! 0x140071c82
hardrock.exe! 0x140071d29
hardrock.exe! 0x140081f75
hardrock.exe! 0x140072212
hardrock.exe! 0x1400010c9
hardrock.exe! 0x140001416
0x7ffd26a07344
Interceptor.attach(base.add(0x57A84), function() {
    console.log("op", this.context.rax);
});
Interceptor.attach(base.add(0x57A84), function() {
    console.log("op", this.context.rax);
});
KCTF 2025
Flop 0x0
ag:[Local::hardrock.exe ]op 0x1
op 0x2
op 0x3
op 0x5
op 0x6
op 0x8
op 0x7
op 0x9
op 0x3
op 0x5
Wrong!
KCTF 2025
Flop 0x0
ag:[Local::hardrock.exe ]op 0x1
op 0x2
op 0x3
op 0x5
op 0x6
op 0x8
op 0x7
op 0x9
op 0x3
op 0x5
Wrong!
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实战!

收藏
免费 1
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回