2019 RoarCTF RE 部分 WriteUp
2019-10-18 17:44:13 Author: www.secpulse.com(查看原文) 阅读量:407 收藏

# 2019 RoarCTF RE 部分 WriteUp

## 坦克大战

本题虽然放在misc目录但个人感觉是逆向题,下载压缩包打开后是这样的:

image.png

可以看目录得知是unity框架写的游戏:
image.png

直接找到“Assembly-CSharp.dll”使用dnspy进行分析,很容易找到位于MapManager类的游戏判胜的逻辑函数public static void WinGame():

```

public static void WinGame()
{
    
if (!MapManager.winGame && (MapManager.nDestroyNum == 4 || MapManager.nDestroyNum == 5))
    {
        
string text = "clearlove9";
        
for (int i = 0; i < 21; i++)
        {
            
for (int j = 0; j < 17; j++)
            {
                text 
+= MapManager.MapState[i, j].ToString();
            }
        }
        
string a = MapManager.Sha1(text);
        
if (a == "3F649F708AAFA7A0A94138DC3022F6EA611E8D01")
        {
            
FlagText._instance.gameObject.SetActive(true);
            
FlagText.str = "RoarCTF{wm-" + MapManager.Md5(text) + "}";
            
MapManager.winGame = true;
        }
    }
}

```

WinGame函数被游戏每当刷新调用实时判断游戏是否获胜,当Manager.nDestroyNum 的数值等于4或5时,判断sha1(“clearlove9”+mapstate)是否为指定值,如果是则flag为"RoarCTF{wm-" + MapManager.Md5(text) + "}",这个md5是“clearlove9”+mapdata的md5的前十个字符。

MapState为游戏当前的地图数据,观察游戏初始时的地图数据(21x17)可以得出:

image.png  

8 空的

1 砖头

4 水

5 草

2 钢铁

0 家(炸了之后就是9)

其中只有砖头和家可以打碎,打碎后砖头变成空(1),家变成爆炸状态(9)。

总共有65个砖头,一个家,使用脚本遍历所有情况即可:

```

import hashlib

data = \

        [

            [

                8,

                8,

                8,

                8,

                8,

                8,

                8,

                8,

                8,

                8,

                8,

                8,

                8,

                8,

                8,

                8,

                8

            ],

            [

                8,

                8,

                4,

                5,

                8,

                1,

                1,

                1,

                1,

                1,

                1,

                8,

                8,

                8,

                8,

                4,

                8

            ],

            [

                8,

                2,

                8,

                1,

                8,

                8,

                5,

                1,

                8,

                8,

                8,

                1,

                8,

                1,

                8,

                4,

                8

            ],

            [

                8,

                5,

                8,

                2,

                8,

                8,

                8,

                8,

                1,

                8,

                8,

                4,

                8,

                1,

                1,

                5,

                8

            ],

            [

                8,

                8,

                8,

                8,

                2,

                4,

                8,

                1,

                1,

                8,

                8,

                1,

                8,

                5,

                1,

                5,

                8

            ],

            [

                8,

                8,

                8,

                8,

                5,

                8,

                8,

                1,

                5,

                1,

                8,

                8,

                8,

                1,

                8,

                8,

                8

            ],

            [

                8,

                8,

                8,

                1,

                8,

                8,

                8,

                8,

                8,

                8,

                8,

                8,

                1,

                8,

                1,

                5,

                8

            ],

            [

                8,

                1,

                8,

                8,

                1,

                8,

                8,

                1,

                1,

                4,

                8,

                8,

                8,

                8,

                8,

                1,

                8

            ],

            [

                8,

                4,

                1,

                8,

                8,

                5,

                1,

                8,

                8,

                8,

                8,

                8,

                4,

                2,

                8,

                8,

                8

            ],

            [

                1,

                1,

                8,

                5,

                8,

                2,

                8,

                5,

                1,

                4,

                8,

                8,

                8,

                1,

                5,

                1,

                8

            ],

            [

                9,#这里是家,正确结果状态下家是被打爆的

                1,

                4,

                8,

                8,

                8,

                8,

                8,

                8,

                8,

                8,

                8,

                8,

                8,

                8,

                8,

                8

            ],

            [

                1,

                1,

                8,

                1,

                8,

                8,

                2,

                1,

                8,

                8,

                5,

                2,

                1,

                8,

                8,

                8,

                8

            ],

            [

                8,

                8,

                8,

                8,

                4,

                8,

                8,

                2,

                1,

                1,

                8,

                2,

                1,

                8,

                1,

                8,

                8

            ],

            [

                8,

                1,

                1,

                8,

                8,

                4,

                4,

                1,

                8,

                4,

                2,

                4,

                8,

                4,

                8,

                8,

                8

            ],

            [

                8,

                4,

                8,

                8,

                1,

                2,

                8,

                8,

                8,

                8,

                1,

                8,

                8,

                1,

                8,

                1,

                8

            ],

            [

                8,

                1,

                1,

                5,

                8,

                8,

                8,

                8,

                8,

                8,

                8,

                8,

                1,

                8,

                8,

                8,

                8

            ],

            [

                8,

                8,

                1,

                1,

                5,

                2,

                8,

                8,

                8,

                8,

                8,

                8,

                8,

                8,

                2,

                8,

                8

            ],

            [

                8,

                8,

                4,

                8,

                1,

                8,

                2,

                8,

                1,

                5,

                8,

                8,

                4,

                8,

                8,

                8,

                8

            ],

            [

                8,

                8,

                2,

                8,

                1,

                8,

                8,

                1,

                8,

                8,

                1,

                8,

                2,

                2,

                5,

                8,

                8

            ],

            [

                8,

                2,

                1,

                8,

                8,

                8,

                8,

                2,

                8,

                4,

                5,

                8,

                1,

                1,

                2,

                5,

                8

            ],

            [

                8,

                8,

                8,

                8,

                8,

                8,

                8,

                8,

                8,

                8,

                8,

                8,

                8,

                8,

                8,

                8,

                8

            ]

        ];

text = ''

for i in range(21):

    for j in range(17):

        text += str(data[i][j])

text = list(text)

def go(data,index,num):

    if num == 3:

        temp = ''.join(data)

        if hashlib.sha1('clearlove9'+temp).hexdigest() == '3f649f708aafa7a0a94138dc3022f6ea611e8d01':

            print hashlib.md5('clearlove9'+temp).hexdigest().upper()[:10]

        return

    if index == 21*17:

        return

    if data[index] == '1':

        temp = list(data)

        temp[index] = '8'

        go(temp,index+1,num+1)

    go(data,index+1,num)

go(text,0,0)

```

最终得到flag:

RoarCTF{wm-805CEC3545}

## polyre

本题使用ollvm进行混淆,使用腾讯实验室的deflat脚本进行处理。

image.png

这样可读性就增加了不少,容易看出程序验证逻辑为:
```

For each_8_bytes in input:

For _ in range(64):
        if int64(each_8_bytes) >= 0:
            each_8_bytes *= 2

    Else:

        Each_8_bytes *= 2

        Each_8_bytes ^= 0xB0004B7679FA26B3

校验每个each_8_bytes == 指定常数

```

这里队友直接用z3解出来了:

```

from z3 import *

x = [BitVec('x[%d]'%i,64) for i in xrange(6)]

s = Solver()

cipher = [0xBC8FF26D43536296, 0x520100780530EE16, 0x4DC0B5EA935F08EC, 0x342B90AFD853F450, 0x8B250EBCAA2C3681, 0x55759F81A2C68AE4]

for i in xrange(6):

    for _ in xrange(64):

        x[i] = If(x[i] > 0, 2 *x[i], ((2 * x[i]) ^ 0xB0004B7679FA26B3))

    s.add(x[i] == cipher[i])

if s.check() == sat:

    m = s.model()

    import struct

    dic = [(str(m[i])[-2:-1], struct.pack('<Q', m[m[i]].as_long().real)) for i in xrange(6)]

    dic.sort(key = lambda x: x[0], reverse = False)

    flag = ''.join(map(lambda x: x[1], dic))

    print flag

else:

    print 'no'

```

后来想了一下这个是可以逆向算的,也就是说加密的每个分支通过加密后的数据是可以推算出来的:

因为每次乘以2后,数据最低位为0,而抑或0xB0004B7679FA26B3之后数据最低位必然为1,这样根据最低为是否为1即可反向推出上一次是走了哪个分支。

## driverCuora

本题是linux驱动逆向,但是和逆用户层感觉没啥区别,就是不会调试。。。

大致流程如下:

1.     初始化函数中,从/home/ppprocce/ssooor文件中读取一个17字节的路径,并计算了一个类似于crc32的东西:

```

  v2 = -1;

  v3 = a1 + a2;

  while ( a1 != v3 )

  {

    ++a1;

    v5 = 0;

    v6 = 0;

    do

    {

      v4 = *(unsigned __int8 *)(a1 - 1);

      if ( _bittest(&v4, v6) )

        v5 |= 1 << (7 - v6);

      ++v6;

    }

    while ( v6 != 8 );

    v2 ^= *(unsigned __int8 *)(a1 - 1) << 24;

    v7 = 8;

    do

    {

      if ( v2 >= 0 )

        v2 *= 2;

      else

        v2 = 2 * v2 ^ 0x4C11DB7;

      --v7;

    }

    while ( v7 );

  }

```

对之前读到的路径字符串每个字节为一轮进行计算,先把每个字节按bit倒序,然后算crc32的一轮,初始为-1,二项式常数0x4C11DB7,这样算出来的“crc32“把低16bit在倒序,然后整个“crc32”取反。

2.     在驱动退出回调中,将之前的路径字符串冒泡排序,然后每个字节^1,看是否等于给定数据,(这里可以获取到乱序的正确路径///CFRpTagframol),然后还会对crc32进行校验,不对则直接退出。

3.     若是正确,会从刚刚的路径中读取对应的文件,并对文件中的内容(即flag),进行校验,校验逻辑为:

```

Data1 = 正确路径*2

Data2 = flag #34字节

For byte1,byte2 in data1,data2:
    ROL(byte1^0x55+byte2^0xAA,2) == table1[i]

    ((Byte2^0x55+byte1^0xAA)>>2) | ((byte1^0x55+byte2^0xAA)<<6) == table2[i]

```

当时的思路是首先算出正确路径的顺序,想到全排序爆破,但是失败了,主要由于:
1.ida的f5出来的crc32那段代码有点问题,后来才发现。

2.实际试了爆破速度爆不完。

```

#include <stdio.h>

#include <stdlib.h>

__int64 sub_F5(__int64 a1, unsigned int a2)

{

  int v2; // edx

  __int64 v3; // r11

  int v4; // esi

  int v5; // er8

  unsigned int v6; // eax

  signed int v7; // eax

  int v8; // eax

  int v9; // esi

  v2 = -1;

  v3 = a1 + a2;

  while ( a1 != v3 )

  {

    ++a1;

    v5 = 0;

    v6 = 0;

    do

    {

      v4 = *(unsigned __int8 *)(a1 - 1);

      if ( (v4>>v6)&1 )

        v5 |= 1 << (7 - v6);

      ++v6;

    }                 //这里f5给出的伪代码和实际不符

    while ( v6 != 8 );

    v2 ^= *(unsigned __int8 *)(a1 - 1) << 24;

    v7 = 8;

    do

    {

      if ( v2 >= 0 )

        v2 *= 2;

      else

        v2 = 2 * v2 ^ 0x4C11DB7;

      --v7;

    }

    while ( v7 );

  }

  v8 = 0;

  v9 = 0;

  do

  {

    if ( v2 & (1 << v9) )

      v8 |= 1 << (15 - v9);

    ++v9;

  }

  while ( v9 != 32 );

  return (unsigned int)~v8;

}

#define N 17

char a[17] = {47, 47, 47, 67, 70, 82, 84, 97, 97, 102, 103, 108, 109, 111, 112, 114, 116};

void swap(int i, int offset)

{

    int temp;

    temp = a[offset];

    a[offset] = a[i];

    a[i] = temp;

}

void print()

{

    if(sub_F5((__int64)&a,17)==0x5A9E037C)

    {

        int i;

        for(i = 0; i < 17; i++)

            printf(" %c ",a[i]);

        printf("\n");

    }

}

void perm(int offset)

{

    int i, temp;

    if(offset == N-1)

    {

        print();

        return;

    }

    for(i = offset; i < N; i++)

    {

        swap(i, offset);

        perm(offset + 1);

        swap(i, offset);

    }

}

int main()

{

    perm(0);

}

```

最后路径是通过flag猜出来的。。。首先根据flag前面是RoarCTF{反向猜出路径前几个,然后根据猜测补齐。

最终得到/tmp/RoarCTF/flag,根据算法直接解密:

```

res = [0x000000C9,0x0000009B,0x0000000C,0x000000F7,0x0000008D,0x00000014,0x00000098,0x00000014,0x00000010,0x00000077,0x00000022,0x00000063,0x000000F0,0x000000A0,0x000000DC,0x000000DB,0x00000037,0x0000004D,0x00000058,0x000000EF,0x00000013,0x000000BD,0x00000096,0x000000BC,0x00000090,0x00000084,0x000000BB,0x0000001B,0x000000C7,0x00000025,0x000000F3,0x0000005C,0x000000FE,0x00000024]

#这个表就是之前说的table1

for i in range(len(res)):

    res[i] = ((res[i]>>2)|(res[i]<<6))&0xff

#这里反过来算就好了

data1 ='/tmp/RoarCTF/flag'*2

data1 = map(ord,data1)

data2 = [0]*34

for i in range(34):

    data2[i] = ((res[i]-(data1[i]^0x55))&0xff)^0xAA

print ''.join(chr(i%128) for i in data2)

```

所以这里只用了第一个table就出来了,后来想想其实根本不用猜路径,直接不管crc32把路径和flag都当作符号变量,直接根据两个table表的数据用z3解就行了,虽然没试但感觉应该能解出来。

## math

这题需要解一个浮点数方程用sympy没有解出来,后来用室友的matlab发现可以秒解。

程序首先验证了一个输入是否为sqrt(2),好像测试用的,没啥用。

然后再有两个输入x y,满足如下条件:

```

1.((a-(sqrt(2*sqrt(5)+10)+1))*(sqrt(5)-1)-(b-1)*((sqrt(2*sqrt(5)+10)+1)-(sqrt(2*sqrt(5)+10)+1)))**2/((b-1)**2+(a-(sqrt(2*sqrt(5)+10)+1))**2)==0.38197**2

2. ((a-1)*(sqrt(5)-1)-(b-1)*((sqrt(2*sqrt(5)+10)+1)-1))**2/((b-1)**2+(a-1)**2)==(sqrt(5)-1)**2

3.a=x*cos(y)

4.b=x*sin(y)

```

其中0.38197这个常数是用一系列随机数生成的,具体的生成好像很复杂。。。这个数值我是通过二分法直接手工爆破的。

使用matlab解方程:

```

syms a b x y;

[a_,b_,x_,y_]=vpasolve([((a-1)*(sqrt(5)-1)-(b-1)*((sqrt(2*sqrt(5)+10)+1)-1))^2/((b-1)^2+(a-1)^2)==(sqrt(5)-1)^2,((a-(sqrt(2*sqrt(5)+10)+1))*(sqrt(5)-1)-(b-1)*((sqrt(2*sqrt(5)+10)+1)-(sqrt(2*sqrt(5)+10)+1)))^2/((b-1)^2+(a-(sqrt(2*sqrt(5)+10)+1))^2)==0.38197^2,a==x*cos(y),b==x*sin(y)],[a,b,x,y]);

```

最终得到:

X = -5.2057229787614023021024241671716

Y = 35.228348316759497246192425417098

image.png


文章来源: https://www.secpulse.com/archives/115908.html
如有侵权请联系:admin#unsafe.sh