首页
论坛
课程
招聘
[原创]看雪.TSRC 2017CTF秋季赛-第二题分析
2017-10-27 22:46 1273

[原创]看雪.TSRC 2017CTF秋季赛-第二题分析

2017-10-27 22:46
1273
IDA载入后
.text:00401000 ; int __cdecl main(int argc, const char **argv, const char **envp)
.text:00401000 _main           proc near               ; CODE XREF: start+AFp
.text:00401000                 push    offset aCrackmeForCtf2 ; "\n Crackme for CTF2017 @Pediy.\n"
.text:00401005                 call    sub_413D42
.text:0040100A                 add     esp, 4
.text:0040100D                 mov     dword_41B034, 2
.text:00401017                 call    sub_401050
.text:0040101C                 call    sub_401090
.text:00401021                 call    sub_4010E0
.text:00401026                 mov     eax, dword_41B034
.text:0040102B                 test    eax, eax
.text:0040102D                 jnz     short loc_40103F
.text:0040102F                 push    offset aYouGetIt ; "You get it!\n"
.text:00401034                 call    sub_413D42
.text:00401039                 add     esp, 4
.text:0040103C                 xor     eax, eax
.text:0040103E                 retn
.text:0040103F ; ---------------------------------------------------------------------------
.text:0040103F
.text:0040103F loc_40103F:                             ; CODE XREF: _main+2Dj
.text:0040103F                 push    offset aBadRegisterCod ; "Bad register-code, keep trying.\n"
.text:00401044                 call    sub_413D42
.text:00401049                 add     esp, 4
.text:0040104C                 xor     eax, eax
.text:0040104E                 retn
.text:0040104E _main           endp

从上面看变量41B034为0,则走“You get it!\n”分支。而变量41B034初始值为2,可以判断函数401050 401090 4010E0 是对key进行校验和处理的。跟进。
int *sub_401050()
{
  int v1; // [sp+0h] [bp-Ch]@1

  sub_413D42(aCodedByFpc_, v1);
  sub_413D42(aPleaseInputYou, v1);
  scanf(aS, &v1);
  return &v1;
}

void sub_401090()
{
  int v0; // [sp+4h] [bp-8h]@0
  int v1; // [sp+8h] [bp-4h]@0

  if ( v1 && v0 && v1 != v0 && 5 * (v1 - v0) + v1 == 0x8F503A42 && 13 * (v1 - v0) + v0 == 0xEF503A42 )
    --dword_41B034;
}

void sub_4010E0()
{
  int v0; // [sp+4h] [bp-8h]@0
  int v1; // [sp+8h] [bp-4h]@0

  if ( v1 && v0 && v1 != v0 && 17 * (v1 - v0) + v1 == 0x8F503A42&& 7 * (v1 - v0) + v0 == 0x33A94883 )
    --dword_41B034;
}
可以看出401090和4010E0 是对key进行校验的。看起来是一个二元一次方程的题。

  1. 5  * (v1 - v0)  + v1   =  0x8F503A42 
  2. 13 * (v1 - v0) + v0   =  0xEF503A42
  3. 17 * (v1 - v0) + v1   =  0xF3A94883 
  4. 7   * (v1 - v0) + v0   =  0x33A94883

这个方程式无解的。        

再看一下代码。发现在在4010E0函数下面一堆二进制数。

.text:0040112B                 db 5 dup(90h)
.text:00401130                 dd 4800h dup(0)
.text:00413130 ; ---------------------------------------------------------------------------
.text:00413130                 retn
.text:00413130 ; ---------------------------------------------------------------------------
.text:00413131                 db 83h, 0C4h, 0F0h
.text:00413134                 dd 20712A70h, 0F1C75F2h, 28741C71h, 2E0671DDh, 870F574h
.text:00413134                 dd 74F17169h, 0DC167002h, 0EA74C033h, 0DC261275h, 0F471E771h
.text:00413134                 dd 6903740Fh, 0EB75EB70h, 0FDF7069h, 22712C70h, 0B8261F7Dh
.text:00413134                 dd 2B741E71h, 3E067169h, 870F57Ch, 7CF17169h, 0DC197002h
.text:00413134                 dd 41B034A3h, 75E77400h, 0E571DC12h, 7CDCF271h, 0E9706903h

难道是SMC吗。看下是否有TLS,发现没有。先从输入开始跟进吧,看看函数401050到底干了啥。发现scanf函数竟然是单独实现的不是系统函数。

int scanf(const char *a1, ...) { va_list va; // [sp+8h] [bp+8h]@1 va_start(va, a1); return _input(&stru_41B0D0, (int)a1, (int)va); }
跟进发现有很多看似系统函数却都是单独实现,比如read  getc等函数。在这些函数中没发现什么问题。
函数read:将结尾回车的0D0A改成了0A0A。
函数_whiteout:如果起始字符是空格则直接过滤掉。
函数_input:key中间有空格则直接将后面的字符截断。
以上虽然对输入key有判断以及调整,但是并没有进行真正的校验。里面也没有SMC的解密。
但是在进行上面分析时发现401050函数存在溢出。如下:
int *sub_401050()
{
  int v1; // [sp+0h] [bp-Ch]@1

  sub_413D42(aCodedByFpc_, v1);
  sub_413D42(aPleaseInputYou, v1);
  scanf(aS, &v1);
  return &v1;
}

其中v1的值是局部变量属于堆栈,其数值是:18FF34 见下图:
从上图可知存储key的buf是局部变量,地址为18FF1C。如果输入的字符长度大于8,则会将堆栈中的数据覆盖掉。因此可以将401050函数的返回值改成输入成功字串位置,也就是0x40102F。堆 栈中存储其返回值的地址为18FF40,将其数值由40101C改成40102F就可以达成目标了。而key的地址是18FF34,因此输入的key长度在13到15之间。但是scanf函数会在输入的字符中最后添加一个0,如果输入13个字符,将1C改成2F,但此时会将0x10改成00,也就是将地址改成了40002F,这样肯定不对。那么只能输入15位了。因为恰好40102F的最高字节也是00,不怕被00覆盖。

     这样又面临另外二个问题,前面的12位可以是任意字符,题目出现无数个解这样的状况,而且0x10对应的字符也无法输入。先不管这些,用编辑器构造一个看看,构造如下key "111111111111/@" ,果然提示成功。如下图:

看起来成功了,去提交,结果没通过。看题目要求指导输入的必须是字符数字组合。

再次对上面的那段IDA无法分析的代码怀疑。先搜索下"You got it! \n",是否在这段代码中存在,没搜到。再搜索下面几个可疑的特征:

41B034 其如果为0则获得正确key 

41102F 如果函数返回值为这个数值,则获得正确的key

无一例外,都没搜到。
但是如果我们把上面的溢出返回值构造到这段看起来加密的代码中,是否可行呢?而真正的校验是在这段代码中。先看一下这段代码的起始位置:

.text:0040112A ; ---------------------------------------------------------------------------
.text:0040112B                 db 5 dup(90h)
.text:00401130                 dd 4800h dup(0)
.text:00413130 ; ---------------------------------------------------------------------------
.text:00413130                 retn
.text:00413130 ; ---------------------------------------------------------------------------
.text:00413131                 db 83h, 0C4h, 0F0h
.text:00413134                 dd 20712A70h, 0F1C75F2h, 28741C71h, 2E0671DDh, 870F574h
.text:00413134                 dd 74F17169h, 0DC167002h, 0EA74C033h, 0DC261275h, 0F471E771h
.text:00413134                 dd 6903740Fh, 0EB75EB70h, 0FDF7069h, 22712C70h, 0B8261F7Dh
.text:00413134                 dd 2B741E71h, 3E067169h, 870F57Ch, 7CF17169h, 0DC197002h
.text:00413134                 dd 41B034A3h, 75E77400h, 0E571DC12h, 7CDCF271h, 0E9706903h
.text:00413134                 dd 6965E97Dh, 70B8DC70h, 3E1D7127h, 710F1971h, 0DD257019h
.text:00413134                 dd 0F6700571h, 71DD0870h, 700270F2h, 70580F14h, 0F1171ECh
.text:00413134                 dd 0F671EA71h, 0DD03700Fh, 0ED71ED70h, 0FE170DDh, 7F36217Eh
.text:00413134                 dd 671A7D27h, 1D2A74B8h, 65690D7Eh, 67C067Fh, 1D361C7Eh
.text:00413134                 dd 8BDC0E7Fh, 75EA74C8h, 7E69DC14h, 0C1F47FEFh, 0F97CFB7Fh
.text:0043134                 dd 0EA7DE27Fh, 0D87E6965h, 772076B8h, 2E1A7F27h, 0DD2978B8h
从上面代码中可以看到这段代码是以413130开始,而输入的字符要求是字母和数字,而这段代码的地址是符合要求的,但是对于403130这个位置是retn,明显不是我们想要的。先让IDA重新分析一下:

.text:00413131                 add     esp, 0FFFFFFF0h
.text:00413134                 jo      short near ptr loc_41315F+1
.text:00413136                 jno     short near ptr loc_413157+1
.text:00413138                 repne jnz short loc_413157
.text:00413138 ; ---------------------------------------------------------------------------
.text:0041313B unk_41313B      db  0Fh                 ; CODE XREF: .text:00413143j
.text:0041313C                 db  71h ; q
.text:0041313D                 db  1Ch
.text:0041313E ; ---------------------------------------------------------------------------
.text:0041313E
.text:0041313E loc_41313E:                             ; CODE XREF: .text:00413152j
.text:0041313E                 jz      short loc_413168
.text:00413140                 fnsave  byte ptr [ecx+6]
.text:00413143                 hnt jz  short near ptr unk_41313B
.text:00413146                 jo      short loc_413150
.text:00413148                 imul    esi, [ecx-0Fh], 16700274h


看起来有戏。先输入“11111111111111A” 将PC定位到413131位置。再往下分析就简单了,虽然里面有一些花指令,但是很快就可以看到判断逻辑 逻辑具体如下:

(x-y)*4 + x + z = 0xEAF917E2 

(x-y)*3 + x + z = 0xE8F508C8   

(x-y)*3 + x - z = 0xC0A3C68h

是一个3元一次方程,求解如下:

x=7473754A 

y=726F6630 

z=6E756630


调整下顺序, 对应key=“Just0for0fun11A”







[培训]12月3日2020京麒网络安全大会《物联网安全攻防实战》训练营,正在火热报名中!地点:北京 · 新云南皇冠假日酒店

收藏
点赞0
打赏
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回