默小白 发表于 2019-3-22 14:27

【转帖】Pragyan CTF 19 逆向详解

转自:https://xz.aliyun.com/t/4429

CTFtime平台上发现的一场比赛,记录一下其中的2道逆向题

# Feed_me

题目打开,发现一个`scanf("%s",s)`,明显有栈溢出倾向,而IDA将变量识别如下

!(https://xzfile.aliyuncs.com/media/upload/picture/20190313160044-1a9aa73a-4566-1.png)

注意后面的三个`atoi`,后两个的参数比较迷,相对`s`的偏移分别为10和20,这里我把`s`的类型重新定义为`char s`

因为这题保护全开,不是考察pwn,应该是考察栈上变量偏移的识别

那么我们输入的字符串每10个字符被解析成3个`int`型数据

主要的判断可以看做三元一次方程

```
input1 + input2 = num1
    input2 + input3 = num2
    input3 + input1 = num3
    =>
    input1 = num1 + num3 - num2 / 2
    input2 = num1 + num2 - num3 / 2
    input3 = num2 + num3 - num1 / 2
```

多说一句,解方程时把三个式子加起来除以二后,分别减去每一个式子,即可得到方程的解

根据`srand(time(0))`和`rand()`的特性:随机种子确定,生成的序列也确定,写出python脚本扔程序跑就可以了

但是我不太熟悉python对rand的处理,直接C程序跑出来,手动喂给程序了

## 补充

解题过程中有一些想法

!(https://xzfile.aliyuncs.com/media/upload/picture/20190313160119-2f49f582-4566-1.png)

这里num1,num2,num3都是`unsigned int`,而它们都被以`%d`的形式输出

因为`rand()`返回值为`int`型,但是必定返回一个正数,模10000后再乘以`-2`,相当于把一个绝对值很小的负数赋值给了`unsigned int`

以`%d`有符号数输出结果,是三个负数,是应该的

!(https://xzfile.aliyuncs.com/media/upload/picture/20190313160139-3b523902-4566-1.png)

可是num系列数据的实际类型是无符号的,是一个很大的正数

而我们输入的字符串被解析成了3个`int`数据,而且都是负数,在判断时,如何比较一个`正unsigned int`和`负int`?

看一下汇编代码

!(https://xzfile.aliyuncs.com/media/upload/picture/20190313160159-47787340-4566-1.png)

2个`int`数据`add`后与`unsigned int`比较,实际上应该是比较的二进制数据

只要二进制的32个bit相等,那么就判断相等

做一个小实验

```
#include<stdio.h>
#include<stdlib.h>

int main(int argc,char**argv){
    int num1 = -1;
    unsigned int num2 = -1;
    if(num1==num2){
      printf("num1==num2");
    }
    return 0;
}
```

`num1`就是单纯的-1,而num2会是`0xffffffff`,是一个大正数

实际上`if`判断为真,会输出`num1==num2`

> 发现这个问题的原因主要是,我本地写C代码测试时,发现以`%d`输出预期的值input1、input2、input3时,都是长度为10的int数据,而连起来就是30长度的纯数字字符串,这不能被`atoi`识别,超过范围会返回`-1`,于是有了上文的一些想法,发现原来是二进制比较的问题

# Super Secure Vault

IDA打开,主逻辑如下

!(https://xzfile.aliyuncs.com/media/upload/picture/20190313160218-5266bd84-4566-1.png)

发现函数名都在,而且`getNum`和`mod`函数都接收了一个字符串作为参数,实际上是指向字符串的指针

先看一下`getNum`函数

!(https://xzfile.aliyuncs.com/media/upload/picture/20190313160241-60642b92-4566-1.png)

它的作用实际上是从字符串中取出一段数据并返回int64型

`mod`函数的行为也和名字一样

!(https://xzfile.aliyuncs.com/media/upload/picture/20190313160307-6f7f6812-4566-1.png)

注意到程序虽然用了`scanf`,但是保护全开,也就没有`REpwn`这种要改数据的可能性了,输入的长度姑且认为是30

因为`getNum`返回的值不受我们输入字符串的影响,只要动态调出来就可以了

!(https://xzfile.aliyuncs.com/media/upload/picture/20190313160335-805f5f5c-4566-1.png)

比如第一个值是27644437,要求`input % 27644437 == 213`

同样的,可以得出以下5个线性同余方程组

```
input % 27644437 == 213
input % 10459    == 229
input % 1489   == 25
input % 1046527== 83
input % 16127    == 135
```

和中国剩余定理有关,网上找个脚本解一下

```
from functools import reduce

def egcd(a, b):
    if 0 == b:
      return 1, 0, a
    x, y, q = egcd(b, a % b)
    x, y = y, (x - a // b * y)
    return x, y, q


def Chinese_remainder(pairs):
    mod_list, remainder_list = for p in pairs], for p in pairs]
    mod_product = reduce(lambda x, y: x * y, mod_list)
    mi_list =
    mi_inverse = , mod_list) for i in range(len(mi_list))]
    x = 0
    for i in range(len(remainder_list)):
      x += mi_list * mi_inverse * remainder_list
      x %= mod_product
    return x


if __name__=='__main__':
    print(Chinese_remainder([(27644437, 213), (10459, 229), (1489, 25),(1046527,83),(16127,135)]))
```

出结果:

!(https://xzfile.aliyuncs.com/media/upload/picture/20190313160402-90bfbaa4-4566-1.png)

长度也符合要求,是一个符合条件的解

然后我们就被要求输入`password`

主要逻辑在`func2`中

!(https://xzfile.aliyuncs.com/media/upload/picture/20190313160422-9c3d9a04-4566-1.png)

我们第一轮输入的字符串会被追加"27644437104591489104652716127"

再被追加`0x3038`和`\x00`

!(https://xzfile.aliyuncs.com/media/upload/picture/20190313160437-a55eedae-4566-1.png)

然后基本就是查表了,由于程序开了PIE,我不知道怎么用angr秒解它,于是只能patch程序,用gdb下断点看了

!(https://xzfile.aliyuncs.com/media/upload/picture/20190313160453-aeb9e0c0-4566-1.png)

这里把两行中的`!=`改成了`==`,并且下断点观察矩阵中给出的值

密码随便输入`!!!!!!!!!!!!!!`

然后RAX中的值,也就是`cmp cl,al`中会给出应该输入的字符

收集一下就是:`pctf{R3v3rS1Ng_#s_h311_L0t_Of_Fun}`

我猜测程序中可能是手动把符合同余方程组的解都算了一遍?然后把数据填入那个巨型矩阵?

最后其他位置乱放了一些字符?

# 总结一下

这两道题的基本是一个递进的关系,其中第二题的函数编写值得学习一下,C语言如何处理这种大数的mod,之前我没有仔细想过,这段代码实现也没有彻底的理解......

Hi朽木自雕 发表于 2019-3-22 15:24

确认过眼神,是个大佬!

大王叫我来搬砖 发表于 2019-3-22 22:49

看的出 是个大佬,收藏了

沉默挺好的 发表于 2019-3-23 00:20

看不懂,是个大佬!

你清哥 发表于 2019-3-23 10:11

可以可以

hs_f 发表于 2019-3-23 13:10

学习了!感谢研究思路。
页: [1]
查看完整版本: 【转帖】Pragyan CTF 19 逆向详解