看雪·众安 2021 KCTF 秋季赛 | 第二题设计思路及解析

WriteUp 2年前 (2021) admin
448 0 0
看雪·众安 2021 KCTF 秋季赛 | 第二题设计思路及解析

看雪·众安 2021 KCTF秋季赛的第二题《迷失丛林》已于今天中午12点截止答题,经统计,本题围观人数多达2708人,共计38支战队成功破解。

看雪·众安 2021 KCTF 秋季赛 | 第二题设计思路及解析


该题开放之初,tekkens战队仅用13492秒就拿下比赛的“一血”。随后直到18点仅有6支队伍成功破解,可见该题确实是有一定的难度。但不少小伙伴们不畏困难、带着决心毅力迎头赶上,甚至今日凌晨四点还在提交答案!看雪·众安 2021 KCTF 秋季赛 | 第二题设计思路及解析

看雪·众安 2021 KCTF 秋季赛 | 第二题设计思路及解析


没过多久越来越多的战队传来捷报!看雪·众安 2021 KCTF 秋季赛 | 第二题设计思路及解析大家都太强啦!呱唧呱唧~看雪·众安 2021 KCTF 秋季赛 | 第二题设计思路及解析

现在第二题《迷失丛林》已截至答题,想必不少小伙伴对该赛题本身也充满兴趣,接下来和我一起来看看该赛题的设计思路和相关解析吧~


专家点评


下面由看雪专家:海风月影给大家带来第二道赛题的点评。


海风月影第二题属于小巧玲珑型题目,大小24KB,逆向工作量不大,本人很喜欢~ —> [24K纯金CTF]


虽然代码量小,但是作者设计的思路新颖,用了一张乱序的[0-255]表,隐藏掉前8字节,作为key的前8字节,通过算法扩展成256*256的表,统计256张256的表中,固定0,14,40,79位置上不为0的个数。对乱序表进行变形取前8字节,利用key的后8字节查表解密,最终变成 “GoodJob~” 这个明文提示,则验证成功。


如果把乱序的表认为是内置了RC4的密钥的置换表,整体算法看上去像是一个类似RC4的加密变换,先把前8个字节穷举出来,再解密得到明文字符串。



出题团队简介


第二题《迷失丛林》出题方 HU1战队:


看雪·众安 2021 KCTF 秋季赛 | 第二题设计思路及解析


lelfei(HU1战队队长),crack爱好者。学生时代对电脑产生了浓厚的兴趣,经历了很长时间的游戏沉迷后,开始慢慢转向学习技术,工作后自学了ASM、VB、VC、HTML、ASP、Python等语言的入门。对单机的逆向分析、算法比较感兴趣。



赛题设计思路


SN:B4D682C8BF2DE13AD9B6AEF24A80CB22

设计说明:

本题是个数字替换的小游戏。


预设一个【0-255】的乱序表,隐藏前8字节。用户输入32位16进制字符串,转换成16字节数值,前8字节填入乱序表。验证过程分三步:


1、统计表格,每一位分别按*p++和**p查表,查8次后,统计所有能到达的格子,形成256*256的方阵,分别统计第0、14、40、79列,验证col0==169 && col14==172 && col40==167 && col79>200。


2、变形表格,每一位按**p循环替换,要求256步之内能回到当前值。


3、验证表格,取表格前8位,分别按用户输入的后8位的二进制值进行查表,为0时取**p,为1时取*p++,查表8次后,验证结果是否为“GoodJob~”。成功则输出“GoodJob~”。否则输出“TryAgain”。


本题使用VC6+WTL制作。

破解建议:

1、程序没有任何ANTI,可以直接在IDA中查看源码,找到上述三步验证。


2、根据验证第2步分析可知,256个数在256个位置全部都能循环替换回来,对每一个数都必然存在*p=i这一步,也就是说0-255这256个数都要存在,统计给出的258位,找出缺失的8位为:[30, 40, 75, 109, 140, 163, 210, 251]。


3、把8位进行排列,分别用第1步的算法进行验证,一共有40320种组合,数量级很小,很快就能穷举出结果,得到唯一解:[0x4B, 0x6D, 0x28, 0x8C, 0xFB, 0xD2, 0x1E, 0xA3]。


4、把8位值放入256数表格,运行第2步进行表格变换。


5、取变换后的表格的前8位[193, 155, 127,  88, 100, 213, 119,  33],按第1步的算法列举出每一位能到达的值,然后查表找出“GoodJob~”每一位的运行步骤为[0x9D, 0x6B, 0xEA, 0x2F, 0xA4, 0x08, 0xBC, 0x22],都是唯一解。


6.把前8位的解与后面的运行步骤组合并按输入逆序排列,得到答案:B4D682C8BF2DE13AD9B6AEF24A80CB22。



赛题解析


本赛题解析由看雪论坛 HHHso 给出:

看雪·众安 2021 KCTF 秋季赛 | 第二题设计思路及解析

正向检验算法还算直观,其唯一解的数学原理未知,但不妨碍我们直接爆破。




正向算法


1、着力点

我们直接关注图1-1中代码,通过GetDlgItemTextA交叉索引得到。


通过基本分析,我们得到:


(1)Hi_this_obuf_icode_len__hex2bytes 将输入的32字节长lv_code通过16进制转换胃16字节,应该注意lv_code与转换后的Hi_codeLH的差异性,如:

input code hex:= "0123456789ABCDEF" +  "0123456789ABCDEF"经过转换inner code bin:=  1032547698BADCFE  ::  1032547698BADCFEunsigned char inner_code_bin[0x10] = {0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, ...}'01'转换为0x10,'23'转换为0x32,以此类推。

(2)转换后的16字节Hi_codeLH ,我们分为codeL,codeH高低(各8字节)两部分,其中抵8字节codeL填充了codeLSalt数组;


(3)Hi_last_check函数是核心检验函数。


看雪·众安 2021 KCTF 秋季赛 | 第二题设计思路及解析

着手代码片段


2、核心校验框架

如Hi_last_check的伪码和图1-2,代码框架分割为四部分。

(1)第一部分,检测codeLSalt的有效性,codeLSalt大小为0x100字节,如上所述,前8字节来自输入的codeL。


(2)第二部分,对codeLSalt进行变换;


(3)第三部分,利用codeLSalt和codeH对bsuk进行变换,bsuk初始值为codeLsalt前8字节;


(4)第四部分,变换后的bsuk是否为“GoodJob~”。


看雪·众安 2021 KCTF 秋季赛 | 第二题设计思路及解析

Hi_last_check主要业务逻辑

int __thiscall Hi_last_check(HWND *this, char *codeH){  int lv_i; // ebp  char *v3; // eax  int *v4; // esi  char *btsx; // ecx  int v6; // edi  _BYTE *v7; // ecx  int v8; // edx  char *v9; // eax  int v10; // ecx  int v11; // esi  int v12; // eax  unsigned __int8 v13; // dl  int v14; // edi  int v15; // eax  int v16; // ecx  int chi; // esi  int i; // eax  char v19; // dl  char lv_a; // [esp+10h] [ebp-Ch]  char lv_b; // [esp+11h] [ebp-Bh]  char lv_c; // [esp+12h] [ebp-Ah]  unsigned __int8 lv_d; // [esp+13h] [ebp-9h]  char (*lv_gbsptr)[256]; // [esp+14h] [ebp-8h]   //-----------------第一部分开始  lv_a = 0;  lv_b = 0;  lv_c = 0;  lv_d = 0;  lv_i = 1;  lv_gbsptr = Hi_gbsA;  do  {    Hi_bts[0] = codeLSalt[lv_i - 1];    Hi_bts[1] = lv_i;    v3 = Hi_bts;    v4 = &Hi_cns;    btsx = &Hi_bts[Hi_cns];    do    {      v6 = *v4;      if ( *v4 > 0 )      {        do        {          v7 = btsx + 1;          *(v7 - 1) = codeLSalt[(unsigned __int8)*v3];          *v7 = *v3 + 1;          btsx = v7 + 1;          ++v3;          --v6;        }        while ( v6 );      }      ++v4;    }    while ( (int)v4 < (int)&Hi_cns_end );    v8 = 256;    do    {      ++(*lv_gbsptr)[(unsigned __int8)*v3++];      --v8;    }    while ( v8 );    ++lv_i;    ++lv_gbsptr;  }  while ( lv_i - 1 < 256 );  v9 = &Hi_gbsA[0][40];  v10 = 256;  do  {    if ( *(v9 - 40) )      ++lv_a;    if ( *(v9 - 26) )      ++lv_b;    if ( *v9 )      ++lv_c;    if ( v9[39] )      ++lv_d;    v9 += 256;    --v10;  }  while ( v10 );  if ( lv_a == (char)0xA9 && lv_b == (char)0xAC && lv_c == (char)0xA7 && lv_d > 0xC8u )  {    //-------------------------第二部分开始    v11 = 0;    while ( 2 )    {      v12 = 0;      while ( (unsigned __int8)codeLSalt[v12] != v11 )      {        if ( ++v12 >= 256 )          goto LABEL_32;      }      v13 = codeLSalt[v11];      v14 = 0;      v15 = v11;      if ( v11 != v13 )      {        do        {          ++v14;          v16 = (unsigned __int8)codeLSalt[v15];          codeLSalt[v15] = codeLSalt[v16];          v15 = v16;          if ( v14 >= 256 )            return 0;        }        while ( v11 != (unsigned __int8)codeLSalt[v16] );      }      codeLSalt[v15] = v13;LABEL_32:      if ( ++v11 < 256 )        continue;      break;    }    //------------------------------第三部分开始    chi = 0;    *(_QWORD *)&bsuk = *(_QWORD *)codeLSalt;    do    {      for ( i = 0; i < 8; ++i )      {        if ( chi >= 8 )        {          if ( !i || i == 7 )            --*(&bsuk + i);        }        else        {          if ( (codeH[i] & 1) != 0 )            v19 = *(&bsuk + i) + 1;          else            v19 = codeLSalt[(unsigned __int8)*(&bsuk + i)];          *(&bsuk + i) = v19;          codeH[i] = (unsigned __int8)codeH[i] >> 1;        }      }      ++chi;    }    while ( chi < 9 );    //-------------------------------第四部分开始,作最后检测校对    if ( !Hi_strncmp(&bsuk, bsC, 8) )    {      MessageBoxA(this[1], bsC, Caption, 0x40u);      return 1;    }  }  return 0;}



直接爆破


针对核心算法操作的四个部分(忽略最后的strncmp,实际是三部分)进行爆破。


1、有效的codeLSalt

如图,对codeLSalt的有效性检测,实际也分为四各小步骤,基本算法描述为:

(1)定义全局变量unsigned char codeLSalt[0x100] = {...};unsigned char bts[0x200] = {0}; //细分各小段长度依次为 0x02+0x04+0x08+0x10+0x20+0x40+0x80+0x100+0x02 int cns[8]={0x02,0x04,0x08,0x10,0x20,0x40,0x80,0x00} //unsigned char gbsA[0x100][0x100] = {...}; (2)演化对于每个codeLSalt[i],其中i=0,1,...0xFFbts[0]=codeLSalt[i],bts[1]=i+1; 即初始化bts最开始的两字节片段,然后利用codeLSalt和cns,逐段衍生后续片段,直到完成bts中最后0x100大小片段的衍生 (3)统计对于每个i对应codeLSaolt[i]衍生的最后0x100大小片段中出现的数字,进行个数统计,记录仔gbsA[i]中,  (3.1)举例说明 假如codeSalt[0x100]={  0x4B,0x6D,0x28,0x8C,0xFB,0xD2,0x1E,0xA3,0xA2,0x9B,0xF4,0xDF,0xAC,0x7C,0xA1,0xC6,  0x16,0xD0,0x0F,0xDD,0xDC,0x73,0xC5,0x6B,0xD1,0x96,0x47,0xC2,0x26,0x67,0x4E,0x41,  0x82,0x20,0x56,0x9A,0x6E,0x33,0x92,0x88,0x29,0xB5,0xB4,0x71,0xA9,0xCE,0xC3,0x34,  0x50,0x59,0xBF,0x2D,0x57,0x22,0xA6,0x30,0x04,0xB2,0xCD,0x36,0xD5,0x68,0x4D,0x5B,  0x45,0x9E,0x85,0xCF,0x9D,0xCC,0x61,0x78,0x32,0x76,0x31,0xE3,0x80,0xAD,0x39,0x4F,  0xFA,0x72,0x83,0x4C,0x86,0x60,0xB7,0xD7,0x63,0x0C,0x44,0x35,0xB3,0x7B,0x19,0xD4,  0x69,0x08,0x0B,0x1F,0x3D,0x11,0x79,0xD3,0xEE,0x93,0x42,0xDE,0x23,0x3B,0x5D,0x8D,  0xA5,0x77,0x5F,0x58,0xDB,0x97,0xF6,0x7A,0x18,0x52,0x15,0x74,0x25,0x62,0x2C,0x05,  0xE8,0x0D,0x98,0x2A,0x43,0xE2,0xEF,0x48,0x87,0x49,0x1C,0xCA,0x2B,0xA7,0x8A,0x09,  0x81,0xE7,0x53,0xAA,0xFF,0x6F,0x8E,0x91,0xF1,0xF0,0xA4,0x46,0x3A,0x7D,0x54,0xEB,  0x2F,0xC1,0xC0,0x0E,0xBD,0xE1,0x6C,0x64,0xBE,0xE4,0x02,0x3C,0x5A,0xA8,0x9F,0x37,  0xAF,0xA0,0x13,0xED,0x1B,0xEC,0x8B,0x3E,0x7E,0x27,0x99,0x75,0xAB,0xFE,0xD9,0x3F,  0xF3,0xEA,0x70,0xF7,0x95,0xBA,0x1D,0x40,0xB0,0xF9,0xE5,0xF8,0x06,0xBC,0xB6,0x03,  0xC9,0x10,0x9C,0x2E,0x89,0x5C,0x7F,0xB1,0x1A,0xD6,0x90,0xAE,0xDA,0xE6,0x5E,0xB9,  0x84,0xE9,0x55,0xBB,0xC7,0x0A,0xE0,0x66,0xF2,0xD8,0xCB,0x00,0x12,0xB8,0x17,0x94,  0x6A,0x4A,0x01,0x24,0x14,0x51,0x07,0x65,0x21,0xC8,0x38,0xFD,0x8F,0xC4,0xF5,0xFC,};   对于i=0,则有bts[0x200] = {4B 01       E3 4C 6D 02                   BB E4 80 4D 3B 6E 28 03                                           75 BCC7 E5 E8 81 AD 4E 36 3C 5D 6F 29 29 8C 04                                           97 76AB BD 40 C8 0A E6 F2 E9 0D 82 A8 AE 39 4F A6 37D5 3D 7B 5E 8D 70 B5 2A B5 2A 2B 8D FB 05                                           91 98F6 77 3C AC FE BE 45 41 B0 C9 F4 0B E0 E7 01 F3D8 EA 7C 0E 98 83 BE A9 9F AF B2 3A 4F 50 6C A730 38 5C D6 68 3E 74 7C 19 5F A7 8E A5 71 EC B6B4 2B EC B6 B4 2B 71 2C A7 8E FD FC D2 06                                           E7 92F1 99 07 F7 7A 78 D5 3D 5A AD F5 FF D9 BF CC 469E 42 AF B1 F9 CA 14 F5 DF 0C 84 E1 66 E8 6D 0224 F4 1A D9 CB EB 25 7D A1 0F F1 99 2A 84 D9 BFE4 AA EB A0 37 B0 13 B3 CD 3B 4F 50 FA 51 23 6D64 A8 50 31 04 39 B3 5D 7F D7 EE 69 4D 3F DB 7525 7D 96 1A D4 60 64 A8 8A 8F E1 A6 77 72 12 ED8B B7 1B B5 71 2C 12 ED 8B B7 1B B5 71 2C 77 72A9 2D 64 A8 8A 8F C4 FE 8F FD 9C D3 1E 07                                           66 E853 93 4A F2 F0 9A A3 08 65 F8 15 7B 18 79 5C D668 3E 44 5B A8 AE 51 F6 FC 00 D6 DA 3F C0 06 CD61 47 54 9F 85 43 37 B0 A0 B2 C8 FA E5 CB DC 1551 F6 B9 E0 AC 0D 43 85 E9 E2 79 67 F2 E9 3B 6E28 03 6E 25 14 F5 47 1B D6 DA F8 CC 00 EC 33 2662 7E C1 A2 C6 10 4A F2 F0 9A B4 2B 43 85 D6 DA3F C0 C7 E5 02 AB 00 EC 2F A1 30 38 AF B1 DD 14ED B4 BC CE 36 3C 4F 50 FA 51 38 FB 72 52 9A 243B 6E 3D 65 BE A9 FA 51 59 32 FB 05 B2 3A ED B47B 5E 05 80 B1 D8 17 EF 93 6A AD 4E 5B 40 AE DC97 76 33 26 62 7E 8E 97 47 1B 89 D5 69 61 3D 65BE A9 1C 8B 09 90 E9 E2 6C A7 7A 78 5F 73 0F 13B8 EE CA 8C 3E B8 C2 1C EC B6 77 72 A9 2D 0F 13B8 EE CA 8C 3E B8 C2 1C EC B6 77 72 A9 2D 7A 785F 73 E4 AA CE 2E 3D 65 BE A9 1C 8B 09 90 95 C5F5 FF 09 90 C4 FE 3A 9D 2E D4 4E 1F A3 08                                           00 00} 因为,对于i=0,bts[0x200]第1片段为0x02字节长,为codeLSalt[i],i+1,则对应 4B 01;然后利用codeLSalt和cns[0] = 2,得到codeLSalt[0x4B],0x4B+1,codeLSalt[0x01],0x01+1,则对应 E3 4C 6D 02;同理,利用codeLSalt和cns[1] = 0x04,得到BB E4 80 4D 3B 6E 28 03 ;以此类推,直到得到最后0x100长的片段。 由最后0x100长片段,我们得到gbsA[i];其中 gbsA[i][0] = 0x03,表示统计最后0x100长片段中0x00出现了3次,同理,通过统计,0x01没有出现,所以gbsA[i][1]==0x00,以此类推 gbsA[i][] = {03 00 01 01 00 02 01 00 02 03 00 00 00 01 00 0201 00 00 02 02 02 00 01 01 00 00 02 04 00 00 0100 00 00 00 01 01 02 00 01 00 00 01 00 02 02 0101 00 01 02 00 00 01 01 02 00 02 02 01 03 03 0201 00 00 03 01 00 00 03 00 00 02 00 00 00 02 0101 04 01 01 01 00 00 00 00 01 00 02 01 00 01 0200 02 02 00 00 04 01 01 01 01 01 00 01 00 03 0000 00 03 02 00 00 01 02 02 02 02 02 00 00 02 0001 00 00 00 00 03 00 00 00 01 00 02 02 00 01 0003 00 00 02 00 01 00 02 00 00 03 00 00 01 00 0101 01 01 02 00 00 00 01 01 05 01 01 01 01 02 0101 02 02 00 03 00 02 00 04 01 00 00 01 00 03 0002 01 02 00 01 01 01 01 01 00 02 01 01 01 02 0000 00 00 00 01 01 04 00 01 00 03 00 02 01 00 0001 00 02 00 01 02 00 00 01 03 00 00 04 02 02 0102 00 03 00 00 02 02 00 02 00 03 02 01 00 01 01} (4)针对性统计,校对针对通过所有的gbsA[i][],其中i=0,1,..0xFF统计所有衍生的最后0x100长度片段中,0, 14, 40, 79分别出现的总此书,依次记录为a,b,c,d要求a == 0xA9 && b == 0xAC && c == 0xA7 && d > 0xC8,如果满足,则codeLSalt有效


看雪·众安 2021 KCTF 秋季赛 | 第二题设计思路及解析
codeLSalt有效性

枚举爆破得到有效codeLSalt,如图,我们直到codeLSalt的大小为0x100,且初始末端的0x100-8字节都已经固定,通过观察,我们可以判定,其为0x00-0xFF的非重复排列,作为基准映射表使用。

由此出发,我们可以确定codeLSalt前8字节的取值集合,执行下述idapython。

cst = set(ida_bytes.get_bytes(0x404000+8,0x100-8)) #cs mapping's tail bytes' setcsa = set([i for i in range(0x100)])               #cs mapping's all  bytes' setcsl = list(csa - cst)                                    #cs mapping's first head 8-bytes' set #Out:==> [30, 40, 75, 109, 140, 163, 210, 251]
即codeL为[30, 40, 75, 109, 140, 163, 210, 251]的排列,有多少排列?
from itertools import permutationspl = [p for p in permutations(csl, 8)]len(pl)#Out==》 40320  #we have 40320 permutations for csl (or inner_code_bin[0,1,...7])
即codeL有40320种情形,我们以此为爆破入口,遍历所有情形,找到有效排列,通过下述pythn代码,我们将所有可能排列,顺序存放到pbs.bin文件中备用。
#here we try to save all 40320 cases of {cs[i]===inner_code_bin[i] | i = 0,1,...,7} to pbs.bin file#with open(r'D:CTF2021KCTFPKCTF02pbs.bin','wb') as fout:  fout.write(b''.join([bytes(list(p)) for p in pl]))

看雪·众安 2021 KCTF 秋季赛 | 第二题设计思路及解析

codeLSalt初始值


(1)编译执行附件find_codeLSalt.c代码,如下cl find_codeLSalt.c cutils.cind_codeLSalt.exe 0 40230 .pbs.bin (2)我们得到find_codeLSalt.exe 0 40230 .pbs.bin[Start Time]: 2021/11/17 22:38:10Read pbs from .pbs.bin ok.Check from 0 to 40230 start:=======> Found i := 12399       at 2021/11/17 22:38:35        pbs[i][] = {0x4B,0x6D,0x28,0x8C,0xFB,0xD2,0x1E,0xA3};Check from 0 to 40230 end![End   Time]: 2021/11/17 22:39:31 (3)即我们仔40230种排列中,找到唯一的有效codeL为 0x4B,0x6D,0x28,0x8C,0xFB,0xD2,0x1E,0xA3,这位codeLSalt的前8字节,其余字节参考图1-4内容。  于是我们由codeL得到code的前16字节输入为 "B4D682C8BF2DE13A"
3、codeLSalt的变换xcs
(1)编译执行附件cl gen_xcs.c cutils.cgen_xcs.exe 12399 .pbs.bin (2)我们得到第二部分codeLSalt的变换xcsgen_xcs.exe 12399 .pbs.bin[Start Time]: 2021/11/17 22:48:42Read pbs from .pbs.bin ok.The cs is:  0x4B,0x6D,0x28,0x8C,0xFB,0xD2,0x1E,0xA3,0xA2,0x9B,0xF4,0xDF,0xAC,0x7C,0xA1,0xC6,  0x16,0xD0,0x0F,0xDD,0xDC,0x73,0xC5,0x6B,0xD1,0x96,0x47,0xC2,0x26,0x67,0x4E,0x41,  0x82,0x20,0x56,0x9A,0x6E,0x33,0x92,0x88,0x29,0xB5,0xB4,0x71,0xA9,0xCE,0xC3,0x34,  0x50,0x59,0xBF,0x2D,0x57,0x22,0xA6,0x30,0x04,0xB2,0xCD,0x36,0xD5,0x68,0x4D,0x5B,  0x45,0x9E,0x85,0xCF,0x9D,0xCC,0x61,0x78,0x32,0x76,0x31,0xE3,0x80,0xAD,0x39,0x4F,  0xFA,0x72,0x83,0x4C,0x86,0x60,0xB7,0xD7,0x63,0x0C,0x44,0x35,0xB3,0x7B,0x19,0xD4,  0x69,0x08,0x0B,0x1F,0x3D,0x11,0x79,0xD3,0xEE,0x93,0x42,0xDE,0x23,0x3B,0x5D,0x8D,  0xA5,0x77,0x5F,0x58,0xDB,0x97,0xF6,0x7A,0x18,0x52,0x15,0x74,0x25,0x62,0x2C,0x05,  0xE8,0x0D,0x98,0x2A,0x43,0xE2,0xEF,0x48,0x87,0x49,0x1C,0xCA,0x2B,0xA7,0x8A,0x09,  0x81,0xE7,0x53,0xAA,0xFF,0x6F,0x8E,0x91,0xF1,0xF0,0xA4,0x46,0x3A,0x7D,0x54,0xEB,  0x2F,0xC1,0xC0,0x0E,0xBD,0xE1,0x6C,0x64,0xBE,0xE4,0x02,0x3C,0x5A,0xA8,0x9F,0x37,  0xAF,0xA0,0x13,0xED,0x1B,0xEC,0x8B,0x3E,0x7E,0x27,0x99,0x75,0xAB,0xFE,0xD9,0x3F,  0xF3,0xEA,0x70,0xF7,0x95,0xBA,0x1D,0x40,0xB0,0xF9,0xE5,0xF8,0x06,0xBC,0xB6,0x03,  0xC9,0x10,0x9C,0x2E,0x89,0x5C,0x7F,0xB1,0x1A,0xD6,0x90,0xAE,0xDA,0xE6,0x5E,0xB9,  0x84,0xE9,0x55,0xBB,0xC7,0x0A,0xE0,0x66,0xF2,0xD8,0xCB,0x00,0x12,0xB8,0x17,0x94,  0x6A,0x4A,0x01,0x24,0x14,0x51,0x07,0x65,0x21,0xC8,0x38,0xFD,0x8F,0xC4,0xF5,0xFC,The xcs is:  0xC1,0x9B,0x7F,0x58,0x64,0xD5,0x77,0x21,0x74,0xEB,0x14,0xBF,0xDF,0x25,0x5A,0x37,  0x85,0x2C,0xAF,0x8C,0xDA,0x26,0xE2,0x7A,0x87,0x4C,0x60,0x99,0x54,0x3C,0x95,0xC0,  0xB9,0x0C,0xBC,0x0E,0xE7,0x2D,0x86,0xBE,0x67,0xD3,0xD8,0xFC,0x30,0xB6,0xC8,0x57,  0x1E,0x62,0x3E,0xCE,0xA0,0xCD,0xF5,0xEE,0xA7,0xCF,0x45,0xFE,0xD0,0x80,0x05,0xAD,  0x13,0xF3,0xB7,0x6B,0x22,0x2B,0xBD,0x69,0x42,0x4B,0xA5,0xEA,0xA6,0xD2,0x6F,0x4F,  0x4E,0x07,0xE1,0x36,0x01,0xB5,0xAA,0xB1,0x94,0x0B,0x35,0x3A,0xC7,0x49,0x53,0x82,  0xC3,0x7B,0x32,0xFF,0x19,0xC4,0xF1,0xC9,0xE8,0xF7,0x56,0x15,0xA3,0x46,0x89,0x43,  0x9D,0x8F,0x20,0xEF,0xBB,0x2A,0xCB,0x09,0x93,0x4A,0x1C,0xE3,0x33,0xD1,0xE0,0x1D,  0x72,0x7C,0x27,0xE9,0x17,0x28,0x6D,0x6A,0xD9,0x00,0x9A,0xE5,0x63,0xDE,0x23,0x9F,  0x0D,0x47,0x3B,0x65,0x08,0x84,0x6C,0x1A,0x88,0x12,0xA1,0xA4,0xB3,0x18,0x24,0x1B,  0xD7,0x44,0xDB,0xAC,0x6E,0x7D,0x51,0x5E,0xED,0x50,0xD6,0x11,0x5B,0x9C,0xB4,0x68,  0x3D,0x2F,0x03,0x40,0xBA,0x2E,0xCA,0x02,0xE6,0xA8,0xEC,0x83,0x06,0x5D,0xB8,0x4D,  0x97,0x66,0xF0,0xFB,0x8A,0x55,0xAB,0xB2,0x04,0xFA,0x0A,0x31,0x71,0xCC,0x8B,0x73,  0xA9,0x48,0x5C,0xF9,0x98,0xE4,0xC6,0x34,0xC5,0x7E,0x81,0x75,0x90,0x1F,0x92,0x3F,  0x9E,0x10,0x29,0x52,0x39,0xF4,0x41,0x78,0x5F,0x16,0x79,0xC2,0xB0,0xDD,0xF2,0x61,  0x0F,0x70,0xD4,0x91,0xDC,0xF6,0xF8,0xFD,0x59,0x38,0x8D,0x96,0xAE,0x8E,0x76,0xA2,[End   Time]: 2021/11/17 22:48:42


4、codeH的爆破

第三部分如下图,bsuk初始值为xcs的前8字节,即0xC1,0x9B,0x7F,0x58,0x64,0xD5,0x77,0x21;其经过9次变换,得到最终的bsuk;

每次通过codeLSalt的变换受codeH的影响;仔细分析我们可以发现,实际上bsuk各个字节的变换时独立的,受codeH对应单字节的影响;

于是我们可以枚举codeH[i]的值,从0x00到0xFF,对bsuk进行变换,如果得到最终“GoodJob~”对应字节,则表示找到了对应的codeH[i]

看雪·众安 2021 KCTF 秋季赛 | 第二题设计思路及解析

bsuk的变换

(1)编译执行附件 find_codeH.c代码cl find_codeH.c cutils.cfind_codeH.exe GoodJob~cH[0]:        0x9DcH[1]:        0x6BcH[2]:        0xEAcH[3]:        0x2FcH[4]:        0xA4cH[5]:        0x08cH[6]:        0xBCcH[7]:        0x22         (2) 于是我们得到codeH  = [0x9D,0x6B,0xEA,0x2F,0xA4,0x08,0xBC,0x22]即codeH的输入部分为D9B6AEF24A80CB22
结合codeL对应输入为”B4D682C8BF2DE13A”,和codeH对应输入为D9B6AEF24A80CB22,我们得到code = “B4D682C8BF2DE13AD9B6AEF24A80CB22″



总结


爆破代码,主要直接模仿业务逻辑的汇编代码,以免C伪码或python伪码产生误差,实际也依然会一个小心存在缺漏而导致错误出现,相对而言,直接模仿汇编查漏补缺和灵活复用上比较中庸。

也尝试了利用idapython的ida_dbg和ida_idd进行自动化重复条用,但事件和指针回滚间隔响应时间有缺陷而停止,其他就是以python或api方式干预样本进程运行,又或者以shellcode方式,甚至unicorn模式方式运行重复利用核心代码,这些都可以作为尝试思路。看雪·众安 2021 KCTF 秋季赛 | 第二题设计思路及解析

附件(https://bbs.pediy.com/thread-270339.htm可去解析原帖下载)为所产生的数据和使用代码,编译一般直接仔命令行通过cl.exe编译。


看雪·众安 2021 KCTF 秋季赛 | 第二题设计思路及解析

看雪·众安 2021 KCTF 秋季赛 | 第二题设计思路及解析
看雪·众安 2021 KCTF 秋季赛 | 第二题设计思路及解析

第三题《蒙混过关》正在火热进行中,

?还在等什么,快来参赛吧!


看雪·众安 2021 KCTF 秋季赛 | 第二题设计思路及解析
– End –



看雪·众安 2021 KCTF 秋季赛 | 第二题设计思路及解析
公众号ID:ikanxue
官方微博:看雪安全
商务合作:[email protected]




看雪·众安 2021 KCTF 秋季赛 | 第二题设计思路及解析

球分享

看雪·众安 2021 KCTF 秋季赛 | 第二题设计思路及解析

球点赞

看雪·众安 2021 KCTF 秋季赛 | 第二题设计思路及解析

球在看



看雪·众安 2021 KCTF 秋季赛 | 第二题设计思路及解析
“阅读原文展开第三题的角逐!

原文始发于微信公众号(看雪学苑):看雪·众安 2021 KCTF 秋季赛 | 第二题设计思路及解析

版权声明:admin 发表于 2021年11月18日 上午9:59。
转载请注明:看雪·众安 2021 KCTF 秋季赛 | 第二题设计思路及解析 | CTF导航

相关文章

暂无评论

您必须登录才能参与评论!
立即登录
暂无评论...