专栏首页安恒网络空间安全讲武堂​CTF逆向——常规逆向篇(下)

​CTF逆向——常规逆向篇(下)

CTF逆向——常规逆向篇(下)

题目:

  1. CrackMe.exe(NSCTF reverse第一题)
  2. WHCTF2017 reverse
  3. HCTF reverse(第一题)

CrackMe.exe(NSCTF reverse)

首先查壳

并没有壳,IDA打开,找到main函数,如下所示:

这里可以看到,只要sub_401005函数返回1,说明输入的flag正确,点进入查看

很简单,flag已经在这里给出了,

flag: flag{wow_flag_is_here}

WHCTF2017 reverse

首先查壳

并没有壳,拖去IDA分析,可以看到main函数如下

很简单的一个逻辑,首先将judge的每一位数据和0xC进行异或得到judge函数的原本形式,然后开始要求用户输入flag,输入的flag限制条件为:

(1)长度为14

(2)满足Judge函数的返回值为真

接下来在hex view中找到judge的十六进制数据,复制下来,写个脚本分别和0xC进行异或,再F2复制回去。

修改前

修改后

接下来就可以去查看judge的函数了,如下所示:

signed __int64 __fastcall judge(__int64 a1)
{
  char v2; // [rsp+8h] [rbp-20h]
  char v3; // [rsp+9h] [rbp-1Fh]
  char v4; // [rsp+Ah] [rbp-1Eh]
  char v5; // [rsp+Bh] [rbp-1Dh]
  char v6; // [rsp+Ch] [rbp-1Ch]
  char v7; // [rsp+Dh] [rbp-1Bh]
  char v8; // [rsp+Eh] [rbp-1Ah]
  char v9; // [rsp+Fh] [rbp-19h]
  char v10; // [rsp+10h] [rbp-18h]
  char v11; // [rsp+11h] [rbp-17h]
  char v12; // [rsp+12h] [rbp-16h]
  char v13; // [rsp+13h] [rbp-15h]
  char v14; // [rsp+14h] [rbp-14h]
  char v15; // [rsp+15h] [rbp-13h]
  int i; // [rsp+24h] [rbp-4h]
  v2 = 102;
  v3 = 109;
  v4 = 99;
  v5 = 100;
  v6 = 127;
  v7 = 107;
  v8 = 55;
  v9 = 100;
  v10 = 59;
  v11 = 86;
  v12 = 96;
  v13 = 59;
  v14 = 110;
  v15 = 112;
  for ( i = 0; i <= 13; ++i )
    *(i + a1) ^= i;
  for ( i = 0; i <= 13; ++i )
  {
    if ( *(i + a1) != *(&v2 + i) )
      return 0LL;
  }
  return 1LL;
}

可以看到要令其返回1,只需要将用户输入的数据和处理后的数组一致即可,而处理数组的过程实际上就是将v2-v15分别与0-13进行异或,接下来就可以写脚本取得flag

flag = ''
 c = [0x66,0x6d,0x63,0x64,0x7f,0x6b,0x37,0x64,0x3b,0x56,0x60,0x3b,0x6e,0x70]
 for i in range(len(c)):
     flag += chr(c[i]^i)
 print flag
Flag:flag{n1c3_j0b}

HCTF reverse

首先查壳

没壳,拖进IDA,打开main函数,如图所示

跟进main_0函数,但是报错

Ok,在汇编界面找到main_0函数

选中整个main_0区域,点击u,再点击确定

再点击p,令IDA重新生成函数,接下来就可F5查看了,如下所示:

__int64 main_0()
{
  int v0; // edx
  __int64 v1; // ST08_8
  char v3; // [esp+0h] [ebp-11Ch]
  bool v4; // [esp+Fh] [ebp-10Dh]
  char v5; // [esp+D7h] [ebp-45h]
  int i; // [esp+E0h] [ebp-3Ch]
  bool v7; // [esp+EFh] [ebp-2Dh]
  bool v8; // [esp+FBh] [ebp-21h]
  bool v9; // [esp+107h] [ebp-15h]
  HMODULE v10; // [esp+110h] [ebp-Ch]
  v10 = GetModuleHandleW(0);
  sub_4113F7("Welcome to HCTF 2017\n\n", v3);
  sub_4113F7("Mark.09 is hijacking Shinji Ikari now...\n\n", v3);
  sub_4113F7("Check User: \n", v3);
  sub_411154("%s", (unsigned int)&Str);
  if ( !sub_411316() )
  {
    sub_41114A();
    exit(0);
  }
  sub_4111F9();
  sub_4113F7("Check Start Code: \n", v3);
  sub_411154("%s", byte_41B4F0, 128);
  while ( getchar() != 10 )
    ;
  if ( j_strlen(byte_41B4F0) != 35 )
  {
    sub_411398();
    sub_4110FF();
    exit(0);
  }
  sub_41114F(&unk_41B570, byte_41B4F0);
  sub_4110EB(sub_41105A, &sub_4111EA, dword_41B780, dword_41B784);
  if ( sub_411361(1) )
  {
    sub_411398();
    sub_4110FF();
    exit(0);
  }
  v4 = sub_4110EB(sub_411023, sub_41139D, dword_41B770, dword_41B774) != 0;
  v9 = v4;
  sub_411023(byte_41B5F0, &unk_41B570);
  sub_411258(dword_41B770, dword_41B774, 204);
  if ( sub_411361(2) )
  {
    sub_411398();
    sub_4110FF();
    exit(0);
  }
  v4 = sub_4110EB(sub_41106E, &sub_411046, dword_41B778, dword_41B77C) != 0;
  v8 = v4;
  sub_41106E(byte_41B670, &unk_41B570);
  sub_411258(dword_41B778, dword_41B77C, 205);
  if ( sub_411361(3) )
  {
    sub_411398();
    sub_4110FF();
    exit(0);
  }
  v4 = sub_4110EB(sub_41105A, &sub_4111EA, dword_41B780, dword_41B784) != 0;
  v7 = v4;
  sub_41105A(byte_41B6F0, &unk_41B570);
  sub_411258(dword_41B780, dword_41B784, 221);
  for ( i = 0; i < 7; ++i )
  {
    byte_41B577[i] = byte_41B5F0[i];
    byte_41B57E[i] = byte_41B670[i];
    byte_41B585[i] = byte_41B6F0[i];
  }
  if ( sub_411447(&unk_41B570, &unk_41B0DC) )
  {
    MessageBoxA(0, "> DETONATION FUNCTION\n    READY", "WILLE", 0);
    sub_4113F7("[Y/N]?\n", v3);
    sub_411154("%c", &v5, 1);
    if ( v5 != 89 && v5 != 121 )
    {
      sub_411398();
      sub_4110FF();
    }
    else
    {
      sub_411082();
      sub_4113F7("Prevent IMPACT success\n", v3);
    }
  }
  else
  {
    sub_411398();
    sub_4110FF();
  }
  system("pause");
  HIDWORD(v1) = v0;
  LODWORD(v1) = 0;
  return v1;
}

首先我们看到检查用户输入的user是否满足函数sub_411316,若满足,则继续,否则退出。点进该函数查看,如下所示:

第一个for循环的作用实际上就是将用户输入的user前后颠倒,下面是证明过程

A = A^B
B = B^A = B^(A^B) = A
A = A^B = (A^B)^A = B

然后第二个for循环对字符串进行一定的操作,然后再和v4-v14进行比较,若都一致,则说明用户输入的user正确,下面为求user的脚本

user_check = [164,169,170,190,188,185,179,169,190,216,190]
 user_name = ""
 for i in range(len(user_check)):
     user_name += chr(user_check[i]^((((i^0x76)-52)^0x80)+43))
 print user_name[::-1]

User为M.KATSURAGI

接下来回到主函数,我们看到sub_411398函数和sub_4110FF两个函数出现的特别多次,查看一下两个函数,可以知道这两个函数的作用是当用户输入错误时就通过这两个函数来弹窗,告诉用户输入错误。所以我们就可以通过避开这两个函数,找出一条通往正确结果的逻辑路径。

接下来我们来分析一下用户输入flag会经过什么操作,首先查看输入的长度是否为35

接下来查看sub_4114f函数,因为用户输入的字符串作为其参数传进去,然后它又传到了以下函数中:

可以看到它将用户输入的每一个字符的ascii码值与0x76异或,传给了地址为unk_41B570的字符串处,后面的处理都是对这个地址的字符串进行处理,所以不用再关心保存用户输入字符串的地址了。接下来紧跟着的sub_4110EB的参数中并没有unk_41B570,所以暂时不管它,我们继续跟进有使用unk_41B570这个地址的操作。

接下来,我们能看到三个几乎完全一样的部分

而且这三个部分也对地址unk_41B570处的字符串进行操作,所以我们点进去查看,首先是sub_411023函数,将unk_41B570处的字符串第7位开始后的七个字符进行一定的处理,保存在数组byte_41B5F0处

sub_41106E函数,将unk_41B570处的字符串第14位开始后的七个字符进行一定的处理,保存在数组byte_41B670处

Sub_41105A函数,将unk_41B570处的字符串第21位开始后的七个字符进行一定的处理,保存在数组byte_41B6F0处

接下来再查看下面代码

刚才的三个数组都保存到另外三个数组处,这个地址看着很熟悉,我们发现41B570刚好就是我们用户输入字符串的地址,所以上面我们分析的代码就是将用户输入字符串中第7位到第27位的字符进行一定的操作。最后再与unk_41B0DC处的字符比较是否相等,若相等,则输入的flag正确,因此我们就可以根据以上的分析,写出获取flag的脚本

a1 = [0x1E ,0x15 ,0x02 ,0x10,0x0D ,0x48 ,0x48 ]
 a2 = [0x6F ,0xDD ,0xDD ,0x48,0x64 ,0x63 ,0xD7 ]
 a3 = [0x2E ,0x2C ,0xFE ,0x6A,0x6D ,0x2A ,0xF2 ]
 a4 = [0x6F ,0x9A ,0x4D ,0x8B,0x4B ,0x1A ,0xEA ]
 a5 = [0x43 ,0x42 ,0x42 ,0x42 ,0x44 ,0x47 ,0x0B]
 flag = ""
 
 for i in range(7):
         a1[i] = a1[i]^0x76
         a5[i] = a5[i] ^0x76
 
 for i in range(7):
     for j in range(33, 127):
         k1 = j ^ 0xad ^0x76
         k1 = 2 * k1 & 0xaa | ((k1 & 0xaa) >> 1)
         if k1 == a2[i]:
             a2[i] = j
             break
 
 for i in range(7):
     for j in range(33, 127):
         k2 = j ^ 0xbe^0x76
         k2 = (4 * k2 & 0xcc) | ((k2 & 0xcc) >> 2)
         if k2 == a3[i]:
             a3[i] = j
             break
 
 for i in range(7):
     for j in range(33, 127):
         k3 = j ^ 0xef^0x76
         k3 = (16 * k3 & 0xf0) | ((k3 & 0xf0) >> 4)
         if k3 == a4[i]:
             a4[i] = j
             break
 
 
 for i in a1:
     flag += chr(i)
 for i in a2:
     flag += chr(i)
 for i in a3:
     flag += chr(i)
 for i in a4:
     flag += chr(i)
 for i in a5:
     flag += chr(i)
 
 print flag

这里将字符串分成了5组,其中第一和第五组与0x76异或,其它的通过爆破的方式得到正确的字符串。

Flag: hctf{>>D55_CH0CK3R_B0o0M!-87544421}

本文分享自微信公众号 - 安恒网络空间安全讲武堂(gh_fa1e45032807),作者:jfciru

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2018-01-27

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Python编写渗透工具学习笔记一 | 0x03用多线程扫描某一网段中存活的主机

    0x03用多线程扫描 某一网段中存活的主机 (如果渗透进了内网,还可以扫描内网上里的存活主机) 脚本利用演示+实现思路分析 实现思路: 调用终端执行ping命令...

    安恒网络空间安全讲武堂
  • 由suctf一道题学到的中国余子式定理

    安恒网络空间安全讲武堂
  • 翻译 | python利用shodan搜集信息

    文中提及的部分技术、工具可能带有一定的攻击性、仅供安全学习和教学用途,禁止非法使用! 安装 为了开始使用Shodan的Python库,首先要确保你已经收到了AP...

    安恒网络空间安全讲武堂
  • 业界 | 谷歌发布机器学习工具库Kubeflow:可提供最佳OSS解决方案

    选自GitHub 机器之心编译 Kubeflow 是谷歌发布的一个机器学习工具库,致力于使运行在 Kubernetes 上的机器学习变的更轻松、便捷和可扩展;K...

    机器之心
  • 13 个设计 REST API 的最佳实践

    之所以翻译这篇文章,是因为自从成为一名前端码农之后,调接口这件事情就成为了家常便饭,并且,还伴随着无数的争论与无奈。编写友好的 restful api 不论对于...

    littlelyon
  • 大咖谈Kubernetes的建模应用

    说起建模,很多小伙伴都不陌生,就是为了理解某一事物而对该事物做出的某一种抽象,是对这个事物没有歧义的一种描述,也叫建立模型。当然,建模也分系统建模,数据建模等好...

    IT大咖说
  • 正经的我,做了个不正经的项目

    今天逛「掘金」的时候,发现一个特别有趣的项目,所以我跟作者申请了一下授权,把项目分享给大家看看。

    五分钟学算法
  • Java漫谈5

    吴军老师有在他的《硅谷来信》中分享过他对于人工智能的看法,吴老师就认为,人工智能不会发展成黑客帝国的那种恐怖境地,原因是当初科学家在创立计算机之前先把人类要解决...

    用户1335799
  • Json取值工具类

    喜欢总结一些工作中写的代码,将部分代码抽离出来,形成一个小的工具类或者jar包,方便在各个项目中使用,这样时间久了、总结的多了就形成了自己的代码库,这些都是自己...

    JavaQ
  • 陈天奇:机器学习科研的十年

    十年前,MSRA的夏天,刚开始尝试机器学习研究的我面对科研巨大的不确定性,感到最多的是困惑和迷茫。十年之后,即将跨出下一步的时候,未来依然是如此不确定,但是期待...

    新智元

扫码关注云+社区

领取腾讯云代金券