吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 7799|回复: 24
收起左侧

[CTF] CTF攻防世界Reverse018_zorropub逆向分析【原创】

[复制链接]
pk8900 发表于 2019-12-17 20:01
本帖最后由 pk8900 于 2019-12-17 22:16 编辑

0x00:前言
好久没有发贴了,现在论坛里大神好多啊,看完大神的帖子,真不知道该写点什么,只能水一贴了,写一下昨天逆向一个CFT的过程和思路吧。

0x01:程序32/64位识别
CTF题目没有说明,只提供一个附件,下载后,发现无扩展名,估计是Linux程序,于是用十六进制编辑器(Uedit)打开查看,在文件头部发现 ELF 字符,确定为Linux程序,再往下查看,发现“/lib64/ld-linux-x86-64.so”字符,确认为64位Linux程序。
说一下Linux程序识别的方法,因为Linux系统中文件并非是通过扩展名来标识文件类型的,所以linux程序在WINDOWS系统里只能通过查看文件内容进行确定,(估计有相关的工具,之前下载了一个,发现不好用,就放弃了。)通过十六进制编辑器查看更方便一些。
linux程序32位和64位的区别如图:
file02.png

我认为通过查看字符串资源:/lib/ld-linux.so  或 /lib64/ld-linux-x86-64.so 来区分更方便一些。也可以用Linux的 FILE 命令查看,这个CTF程序为64位程序,那就用IDA64打开进行分析。
file.png
0x02:分析过程
IDA64加载后,查看函数列表,找到Main函数,F5分析伪代码如下:
[C] 纯文本查看 复制代码
int __fastcall main(__int64 a1, char **a2, char **a3)
{
  size_t v3; // rax
  int v5; // [rsp+1Ch] [rbp-104h]
  int v6; // [rsp+20h] [rbp-100h]
  int i; // [rsp+24h] [rbp-FCh]
  unsigned int seed; // [rsp+28h] [rbp-F8h]
  unsigned int v9; // [rsp+2Ch] [rbp-F4h]
  char v10; // [rsp+30h] [rbp-F0h]
  char v11[16]; // [rsp+90h] [rbp-90h]
  char v12[32]; // [rsp+A0h] [rbp-80h]
  char s; // [rsp+C0h] [rbp-60h]
  char s1[40]; // [rsp+E0h] [rbp-40h]
  unsigned __int64 v15; // [rsp+108h] [rbp-18h]

  v15 = __readfsqword(0x28u);
  seed = 0;
  puts("Welcome to Pub Zorro!!");
  printf("Straight to the point. How many drinks you want?", a2);
  __isoc99_scanf("%d", &v5);                    // scanf 获取输入数字 drinks
  if ( v5 <= 0 )
  {
    printf("You are too drunk!! Get Out!!", &v5);
    exit(-1);
  }
  printf("OK. I need details of all the drinks. Give me %d drink ids:", (unsigned int)v5);
  for ( i = 0; i < v5; ++i )
  {
    __isoc99_scanf("%d", &v6);                  // scanf 获取输入数字 drink ids
    if ( v6 <= 16 || v6 > 65535 )               // drink ids 范围:16-65534
    {
      puts("Invalid Drink Id.");
      printf("Get Out!!", &v6);
      exit(-1);
    }
    seed ^= v6;
  }
  i = seed;
  v9 = 0;
  while ( i )
  {
    ++v9;
    i &= i - 1;
  }
  if ( v9 != 10 )                               // ids 循环位操作进行计数,最终计数必须为10
  {
    puts("Looks like its a dangerous combination of drinks right there.");
    puts("Get Out, you will get yourself killed");
    exit(-1);
  }
  srand(seed);                                  // 置随机数种子
  MD5_Init((__int64)&v10);
  for ( i = 0; i <= 29; ++i )
  {
    v9 = rand() % 1000;                         // 生成随机数除1000取余
    sprintf(&s, "%d", v9);
    v3 = strlen(&s);
    MD5_Update(&v10, &s, v3);
    v12[i] = v9 ^ LOBYTE(dword_6020C0[i]);      // V12前30位与6020C0数据异或
  }
  v12[i] = 0;                                   // V12第30位添0
  MD5_Final(v11, &v10);
  for ( i = 0; i <= 15; ++i )
    sprintf(&s1[2 * i], "%02x", (unsigned __int8)v11[i]);
  if ( strcmp(s1, "5eba99aff105c9ff6a1a913e343fec67") )
  {
    puts("Try different mix, This mix is too sloppy");
    exit(-1);
  }
  return printf("\nYou choose right mix and here is your reward: The flag is nullcon{%s}\n", v12);// flag为V12的内容
}

通过静态分析Main函数流程,发现程序写脚本得到FLAG:
1、程序要求输入:Straight to the point. How many drinks you want?
输入数:V5 >=0,且后续V5并没有引用,所以只要随意输入大于0的数就可以。
2、"OK. I need details of all the drinks. Give me %d drink ids:", (unsigned int)v5
输入ids:变量为v6,seed ^= v6;运行后,ids存入seed中,后续作为生成随机数的种子。
3、对IDS进行较验:

[C] 纯文本查看 复制代码
 i = seed;
  v9 = 0;
  while ( i )
  {
    ++v9;
    i &= i - 1;
  }
  if ( v9 != 10 )                               // ids 循环位操作进行计数,最终计数必须为10
  {
    puts("Looks like its a dangerous combination of drinks right there.");
    puts("Get Out, you will get yourself killed");
    exit(-1);
  }

此代码进行了一个自减1并位与操作,核对计数为10,实现就是对输入的ids(16-65534) WORD值进行位较验,如果数字中有正好有10个位是1,则符合要求,由此可知最小可满足要求的数是1023,1023的二进制中低10位全是1,因此满足这一条件的数字应该不少,但可以写代码逐一列出。
4、用上一步的IDS【seed】做为随机数种子,生成30个小于1000的随机数,并分别与LOBYTE(dword_6020C0)异或,结果存到V12中,最后的flag就是V12中的内容(nullcon{%s}\n", v12)。
以上步骤分析完后,总结一下,可以通过写一个程序进行计算。
于是用VS2013写代码如下:

[C++] 纯文本查看 复制代码
#include "IDA.h"
#include<stdio.h>
#include<stdlib.h>

bool myEnc(int n);//异或还原函数
int main()
{
        int i, j,n;
        for (int y = 16; y < 65534; y++){
                n = 0;
                int m = y;
                while (m)
                {
                        ++n;
                        m &= m - 1;
                        if (n>=11)
                                break;
                }
                if (n==10){
                        if (myEnc(y)){
                                printf("n=%d \n", y);
                                break;
                        }
                }
        }
system("pause");
return 0;
}
bool myEnc(int n){
        srand(n);
        int enclist[] = { 0x3C8, 0x32, 0x2CE, 0x302, 0x7F, 0x1B8, 0x37E, 0x188, 0x349, 0x27F, 0x5E, 0x234, 0x354, 0x1A3, 0x96, 0x340, 0x128, 0x2FC, 0x300, 0x28E, 0x126, 0x1B, 0x32A, 0x2F5, 0x15F, 0x368, 0x1EB, 0x79, 0x11D, 0x24E };
        unsigned char flag[31] = { 0 };
        int j;
        for (int i = 0; i < 29; i++)
        {
                j = rand() % 1000; 
                flag[i] = j ^ LOBYTE(enclist[i]);
                if (flag[i]>128)
                        return false;//如果字符不可见,返回false
        }
        flag[30] = '\0';
        printf(" %s \n", flag); //打印输出找到的flag
        return true;
}


编译运行,可是没有找到flag,于是对程序反复检查,发现没有错误啊,不行动态调试吧,对CTF程序进行动态调试,扔到虚拟机64位ubuntu中,用IDA进行远程调试,输入第2步ids值输入:1023,发现了问题所在:
WINDOWS中,种子为1023时,生成的随机数为: 379  59  741  439  368  145  906  571  287  595  385  624  524  884  895  300......
Linux中,种子为1023时,生成的随机数为:808,14,219,336,499,953,745,120,164,303,30,151,640,588.....
原来在两个系统中种子相同,生成的随机数却不同,看来只能在linux中试一下了,于是在ubuntu中安装了VSCODE进行调试,结果和CTF程序运行一致,找到Flag.

[Asm] 纯文本查看 复制代码
[Running] cd "/root/C++/Hello/" && g++ hello.cpp -o hello && "/root/C++/Hello/"hello
sh: 1: pause: not found
 nu11c0n_s4yz_x0r1n6_1s_4m4z1ng  
n=59306 

拼接后得到最终flag为:nullcon{nu11c0n_s4yz_x0r1n6_1s_4m4z1ng}
也就是原程序中输入ids:59306 即可得到flag
至此分析完成。至于程序中关于md5值计算的部分,大致分析应为生成的随机数除1000取余后,组成一个字串,对字串求MD5_32,这部分没进行验证,CTF中用的应该是OPENSSL库中的算法。
附上CTF程序:

Reverse018_zorropub.rar (2.97 KB, 下载次数: 23)

免费评分

参与人数 10威望 +1 吾爱币 +15 热心值 +7 收起 理由
YenKoc + 1 + 1 我很赞同!
笙若 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
Hmily + 1 + 7 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
pojieit + 1 + 1 用心讨论,共获提升!
lookerJ + 1 热心回复!
朱朱你堕落了 + 1 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
金戋夕夕夕夕 + 1 + 1 我很赞同!
smile5 + 1 用心讨论,共获提升!
FleTime + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
xiaoyou66 + 1 我很赞同!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

yz3781286 发表于 2020-3-30 14:46
@PK8900楼主麻烦看一下   大佬分享的2009文泰刻绘  出错补丁的  分享没有了   可以重新分享或者发我邮箱吗467183485@qq.com    那边回复不了   我没法发私信  只能这样回复了  实在是抱歉
yz3781286 发表于 2020-3-31 10:34
@PK8900楼主麻烦看一下   大佬分享的2009文泰刻绘  出错补丁的  分享没有了   可以重新分享下吗 那边回复不了   我没法发私信  只能这样回复了  实在是抱歉  我百度网盘加好友了
xiaoyou66 发表于 2019-12-17 20:13
一人游弋 发表于 2019-12-17 20:14
前排支持大佬
头像被屏蔽
若时光安好 发表于 2019-12-17 20:15
提示: 该帖被管理员或版主屏蔽
Devil太初 发表于 2019-12-17 20:20
感谢大佬分享,力挺
117882697 发表于 2019-12-17 21:10
看看,学习学习
Mino 发表于 2019-12-17 23:45
膜拜一下大神
huaekinvod 发表于 2019-12-17 23:51
的 FILE 命令查看,这个CTF程
2Burhero 发表于 2019-12-18 02:16
看看试试
xxpl123 发表于 2019-12-18 09:00
跟随学习一下,感谢分享
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-16 11:44

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表