CISCN2019线上re

可以说,ciscn是我至今为数不多能做出题的比赛了23333菜的真实

0x00 easyGO

看名字是go语言和题目,用ida打开看看,wdm这函数数量,怕了怕了。首先运行,然后ida搜索字符串,通过交叉引用,找到主要逻辑,简单分析了一下发现还是有点复杂,还是上手gdb调试看看。

设置断点在提示输入的地方,然后开始运行。发现输入后过了不久,程序就取出一长串字符串。

1.png

猜测可能是目标字符串,需要与之进行比对。继续调试。

在经过函数0x47e620这个函数之后,flag已经解出来了。

2.png

0x01 bbvvmm

文件使用ida打开,发现主要逻辑还是挺明显的。输入用户名和密码,分别校验,对了就能登陆拿到flag,是有远程环境的。

3.png

4.png

用户名

5.png

通过逆运算,sub_400AA6是个换了表的BASE64加密,通过写解密代码,解得正确的v33应该为“EF468DBAF985B2509C9E200CF3525AB6”。

然后观察到sub_401738函数的参数都与输入无关,且v10要作为sub_4018C4的输入,则通过调试,直接得到v10的值为:

6.png

然后对于函数sub_4018c4,除了v13以外所有的参数都已知,所以可以推断出v13 的值。查看这个函数

7.png

通过分析,这个函数中只有sub_201362起作用,循环只经历了一次,相当于只进行了一次sub_201362操作。

8.png

目前已知v5,这样可以知道v14,v13,v12,v11的值,while循环的初值是s,v8,v9,v10,循环中函数是异或操作,于是我们可以通过反推得到函数的输入v3。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#include <stdio.h>

#define __int64 long long
#define __int8 char
#define _BYTE unsigned char
#define _WORD unsigned short
#define _DWORD unsigned int

#define LOBYTE(x) (*((_BYTE*)&(x))) // low byte
#define LOWORD(x) (*((_WORD*)&(x))) // low word
#define LODWORD(x) (*((_DWORD*)&(x))) // low dword
#define HIBYTE(x) (*((_BYTE*)&(x)+1))
#define HIWORD(x) (*((_WORD*)&(x)+1))
#define HIDWORD(x) (*((_DWORD*)&(x)+1))
#define BYTEn(x, n) (*((_BYTE*)&(x)+n))
#define WORDn(x, n) (*((_WORD*)&(x)+n))
#define BYTE1(x) BYTEn(x, 1) // byte 1 (counting from 0)
#define BYTE2(x) BYTEn(x, 2)
#define BYTE3(x) BYTEn(x, 3)
#define BYTE4(x) BYTEn(x, 4)



unsigned char data[]={
0xD6, 0x90, 0xE9, 0xFE, 0xCC, 0xE1, 0x3D, 0xB7, 0x16, 0xB6,
0x14, 0xC2, 0x28, 0xFB, 0x2C, 0x05, 0x2B, 0x67, 0x9A, 0x76,
0x2A, 0xBE, 0x04, 0xC3, 0xAA, 0x44, 0x13, 0x26, 0x49, 0x86,
0x06, 0x99, 0x9C, 0x42, 0x50, 0xF4, 0x91, 0xEF, 0x98, 0x7A,
0x33, 0x54, 0x0B, 0x43, 0xED, 0xCF, 0xAC, 0x62, 0xE4, 0xB3,
0x1C, 0xA9, 0xC9, 0x08, 0xE8, 0x95, 0x80, 0xDF, 0x94, 0xFA,
0x75, 0x8F, 0x3F, 0xA6, 0x47, 0x07, 0xA7, 0xFC, 0xF3, 0x73,
0x17, 0xBA, 0x83, 0x59, 0x3C, 0x19, 0xE6, 0x85, 0x4F, 0xA8,
0x68, 0x6B, 0x81, 0xB2, 0x71, 0x64, 0xDA, 0x8B, 0xF8, 0xEB,
0x0F, 0x4B, 0x70, 0x56, 0x9D, 0x35, 0x1E, 0x24, 0x0E, 0x5E,
0x63, 0x58, 0xD1, 0xA2, 0x25, 0x22, 0x7C, 0x3B, 0x01, 0x21,
0x78, 0x87, 0xD4, 0x00, 0x46, 0x57, 0x9F, 0xD3, 0x27, 0x52,
0x4C, 0x36, 0x02, 0xE7, 0xA0, 0xC4, 0xC8, 0x9E, 0xEA, 0xBF,
0x8A, 0xD2, 0x40, 0xC7, 0x38, 0xB5, 0xA3, 0xF7, 0xF2, 0xCE,
0xF9, 0x61, 0x15, 0xA1, 0xE0, 0xAE, 0x5D, 0xA4, 0x9B, 0x34,
0x1A, 0x55, 0xAD, 0x93, 0x32, 0x30, 0xF5, 0x8C, 0xB1, 0xE3,
0x1D, 0xF6, 0xE2, 0x2E, 0x82, 0x66, 0xCA, 0x60, 0xC0, 0x29,
0x23, 0xAB, 0x0D, 0x53, 0x4E, 0x6F, 0xD5, 0xDB, 0x37, 0x45,
0xDE, 0xFD, 0x8E, 0x2F, 0x03, 0xFF, 0x6A, 0x72, 0x6D, 0x6C,
0x5B, 0x51, 0x8D, 0x1B, 0xAF, 0x92, 0xBB, 0xDD, 0xBC, 0x7F,
0x11, 0xD9, 0x5C, 0x41, 0x1F, 0x10, 0x5A, 0xD8, 0x0A, 0xC1,
0x31, 0x88, 0xA5, 0xCD, 0x7B, 0xBD, 0x2D, 0x74, 0xD0, 0x12,
0xB8, 0xE5, 0xB4, 0xB0, 0x89, 0x69, 0x97, 0x4A, 0x0C, 0x96,
0x77, 0x7E, 0x65, 0xB9, 0xF1, 0x09, 0xC5, 0x6E, 0xC6, 0x84,
0x18, 0xF0, 0x7D, 0xEC, 0x3A, 0xDC, 0x4D, 0x20, 0x79, 0xEE,
0x5F, 0x3E, 0xD7, 0xCB, 0x39, 0x48, 0xC6, 0xBA, 0xB1, 0xA3,
0x00, 0x00, 0x00, 0x00, 0x50, 0x33, 0xAA, 0x56, 0x00, 0x00,
0x00, 0x00, 0x97, 0x91, 0x7D, 0x67, 0x00, 0x00, 0x00, 0x00,
0xDC, 0x22, 0x70, 0xB2, 0x00, 0x00, 0x00, 0x00};

long long table[]={
0x0078da27f844fdd1,
0x0011508c60fc86a8, 0x00424adbca3c9b78,
0x001edff37133dadc, 0x002d6f30b72f5731,
0x00646f38d17560d5, 0x006a9ec9f150e4ad,
0x0047c478c16d51b7, 0x00654ac0925a0855,
0x002acd03e72b4d73, 0x006c607809a5a671,
0x00061673df68b5ba, 0x007723b0becf17c0,
0x004cd4e74b53dc65, 0x001d0f96c282ec15,
0x00547c7686512b09, 0x001b65c1b9383cbc,
0x006dd7967009d87f, 0x000afb8629d9217a,
0x00490d14437c248b, 0x001efc829bc5cfbe,
0x005b8ef37683e1b6, 0x0054de5a1d64849f,
0x00068a31fa1fa382, 0x004770760f09a64c,
0x00636d44915d5beb, 0x00621e68982b67bc,
0x003825cf5fd2e1e6, 0x004cd057e794f4f6,
0x00772696beb95357, 0x0045fd07fb3bcfc0,
0x0066505eb43dc7dd};

unsigned char sub_400D38(unsigned char a1)
{
return data[a1];
}

unsigned __int64 __fastcall sub_400D87(int a1)
{
unsigned __int8 v1; // ST30_1
unsigned __int8 v2; // ST31_1
unsigned __int8 v3; // ST32_1
unsigned __int8 v4; // al
unsigned __int64 v5; // ST10_8

v1 = sub_400D38(BYTE3(a1));
v2 = sub_400D38(BYTE2(a1));
v3 = sub_400D38(BYTE1(a1));
v4 = sub_400D38(a1);
v5 = ((unsigned __int64)v3 << 8) | ((unsigned __int64)v2 << 16) | ((unsigned __int64)v1 << 24) | v4;
return (((unsigned __int64)((v3 << 8) | (v2 << 16) | (v1 << 24) | (unsigned int)v4) << 18) | (v5 >> 14)) ^ v5 ^ (4LL * ((v3 << 8) | (v2 << 16) | (v1 << 24) | (unsigned int)v4) | (v5 >> 30)) ^ (((unsigned __int64)(unsigned int)v5 << 10) | (v5 >> 22)) ^ (((unsigned __int64)((v3 << 8) | (v2 << 16) | (v1 << 24) | (unsigned int)v4) << 24) | (v5 >> 8));
}

void test(char c)
{
int i,j,k;
int a,b;
a = (c&0xf)+0x30;
b = (c>>4)+0x30;
if(b<=0x39)
printf("%02x ",b);
else
printf("%02x ",b+7);
if(a<=0x39)
printf("%02x ",a);
else
printf("%02x ",a+7);
printf("%c\n",c);
}

int main()
{
int res[64];
res[35] = 0xef468dba;
res[34] = 0xf985b250;
res[33] = 0x9c9e200c;
res[32] = 0xf3525ab6;
int i,j,k;
for(i=31;i>=0;i--)
{
res[i] = res[i+4]^sub_400D87(res[i+1]^res[i+2]^res[i+3]^table[i]);
}
printf("0x%x\n0x%x\n0x%x\n0x%x\n",res[0],res[1],res[2],res[3]);

int s = {0xe9,0x55,0x47,0x9b,0x8a,0x0a,0x0f,0xfd,0x82,0x24,0x5f,0x47,0x33,0x85,0x91,0xc4};

for(i=0;i<128;i++)
{
test(i);
}
return 0;
}

于是可以得到v3={0x36, 0x32, 0x36, 0x31, 0x36, 0x34, 0x37, 0x32, 0x36, 0x35, 0x37, 0x32, 0x33, 0x31, 0x33, 0x32};

这样我们得到v13的值,再进一步回推sub_4066c0,就可以到正确的输入。

9.png

可以发现是把一个字节扩展为两个字节的函数,而替换表刚刚的脚本已经一同打印出来了,通过比对,得到用户名为:’badrer12’

密码

密码部分是一个使用while循环实现的虚拟机,通过分析各个调用表的函数内容,得到的伪汇编代码如下(部分):

10.png

实现的功能是将输入与’x’,’y’,’z’,’{‘,’|’,’}’分别异或,然后把每次异或的结果异或,并且要求得到0,这样就说明密码就是’xyz{|}’。

最后远程需要借助pwntools,不然莫得回显

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#!/usr/bin/python
#-*- coding:UTF-8 -*-

from pwn import*

context.log_level = 'debug'

p = remote('39.106.224.151', 10001)

p.recvuntil('name')
p.sendline('badrer12')

p.recvuntil('word:')
p.send('xyz{|}')

p.interactive()

11.png

0x02 总结

emmm国赛只会做两个逆向。。。其中一个还是调试得到。。。

不过对于虚拟机这样的题又练了手,之前一直觉得这类题好难,看不懂,其实主要是不够耐心(卒。希望在接下来的比赛中能多做几道逆向。。。不然太划水感觉都要被t出队伍了QAQ