首页
社区
课程
招聘
[原创]看雪.TSRC 2017CTF秋季赛-第二题分析
发表于: 2017-10-27 22:46 3146

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

2017-10-27 22:46
3146

这个方程式无解的。        

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

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

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

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

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

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

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

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

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

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

x=7473754A 

y=726F6630 

z=6E756630


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

.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进行校验的。看起来是一个二元一次方程的题。
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等函数。在这些函数中没发现什么问题。
.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等函数。在这些函数中没发现什么问题。

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。
函数read:将结尾回车的0D0A改成了0A0A。
函数read:将结尾回车的0D0A改成了0A0A。
函数_whiteout:如果起始字符是空格则直接过滤掉。
函数_whiteout:如果起始字符是空格则直接过滤掉。
函数_input:key中间有空格则直接将后面的字符截断。
函数_input:key中间有空格则直接将后面的字符截断。

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

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