红明谷-g0

看名字就是go语言题目,用IDA-golang-helper还原符号表之后,看到只有几个函数,其中main_Encode就是加密函数

函数逻辑比较简单,输入长度等于20,打乱位置,进入main_Encode加密,最后进入main_fun1进行比较,直接看main_Encode中的加密算法

动态调试后发现一张表,表的长度为58位,判断为换表base58加密

进入main_fun1函数中找到加密后的字符串,注意 runtime_memequal这个比较的函数需要在汇编中寻找比较的字符串首地址,在伪代码中是找不到的

1
2
3
4
5
6
7
8
9
10
11
12
import base58

Cipher = '2GVdudkYo2CBXoQii7gfpkjTc4gT'
Plain = ''
new_table = '12Nrst6CDquvG7BefghJKLMEFHPQZabRSTUVmyzno89ApwxWXYcdkij345'
old_table = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'

for i in range(len(Cipher)):
Plain += old_table[new_table.index(Cipher[i])]
print(base58.b58decode(Plain.encode()))

# flag{We1CTFc0m_2345}

虎符-re

mips架构文件,本来想用qemu动态调试的,但是好像虚拟机的so文件出问题了,就静态分析算了,反正有IDA7.5不怕

看伪代码很浓厚的C++气息,两次判断,pre函数里面还判断了输入的长度

server_check_redemption_code函数大概的意思就是生成一张宽256长和字符串长度相同的表,当表的列值与输入的字符串的ASCII值相同时就做一个标记,用C语言还原后的代码如下

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
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main() {
char string[] = "";
char input[] = "";

int string_len = strlen(string);
int input_len = strlen(input);

int* s = (int*)malloc(input_len << 10);// input_len * 2^10
memset((void*)s, 0, input_len << 10);
int count = 0;
for (int i = 1; i < input_len; i++) {
for (int j = 0; j < 256; j++) {
if (j != input[i]) {
s[256 * i + j] = s[256 * count + j]; //其他全是填充这个
}
else
s[256 * i + j] = i + 1; //每一次循环只执行一次这个
}
count = s[256 * count + input[i]]; //count=i+1
}
int sign = 0;
for (int k = 0; k < string_len; k++) {
sign = s[256 * sign + string[k]];
if (sign == input_len) {
printf("%d", k - input_len + 1);
}
}
}
/// k-input_len+1=7
/// k=6+0xE=

题目中有两个字符串,所以生成了两张表,两张表中相同的值就是需要输入的flag

Ninja Must Die 3 Is A Cruel Game, So Hard For Me

I Love Ninja Must Die 3. Beautiful Art And Motive Operation Is Creative.

两个字符串中相同的值为Ninja Must Die

虎符-gocrypt

变种的xtea在写脚本的时候忘记了小端存储,这个地方搞了很久,以后遇到不能在犯错误了

用插件还原符号表后看到函数并没有多少,输入检测函数main_check,数据加密函数main_main__ptr_myCipher_Encrypt

main_check函数中有一个正则匹配来规定flag输入的格式

main_check

1
正则匹配格式:flag{([0-9a-f]{8})-([0-9a-f]{4})-([0-9a-f]{4})-([0-9a-f]{4})-([0-9a-f]{12})}

在进入main_check返回一个值给标志,判断是否进入下一个步骤

main__ptr_myCipher_Encrypt函数中的加密算法就是变种的xtea加密,随机数变成了0x12345678

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
#include <stdio.h>
#include <stdint.h>

void XTEA_decrypt(uint32_t rounds, uint32_t* v, uint32_t* k)
{
uint32_t delta = 0x12345678;
uint32_t sum = rounds * delta;
uint32_t v0 = v[0], v1 = v[1];
for (int i = 0; i < rounds; i++) {
v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + k[(sum >> 11) & 3]);
sum -= delta;
v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + k[sum & 3]);
}
v[0] = v0;
v[1] = v1;
}
int main(){
uint32_t rounds = 32;
uint32_t v[2][2] = { { 0x0ec311f0, 0x45c79af3 },
{ 0xedf5d910, 0x542702cb } };
uint32_t k[4] = { 0x00010203, 0x04050607, 0x08090a0b, 0x0c0d0e0f };

XTEA_decrypt(rounds, v[0], k);
XTEA_decrypt(rounds, v[1], k);
printf("%x-%x\n", v[0][0], v[0][1]);
printf("%x-%x\n", v[1][0], v[1][1]);
}
//flag{3bbcf9ea-2918-4fee-8a2e-201b47dfcb4e}

虎符-CrackMe

这个题需要输入两次,第一次输入后判断输入的长度,长度需要17位,输入后将输入的字符串的前7位和后10位分割,分别存储在不同的内存中

第二次输入需要输入一个数字,在经过两轮简单的计算后与指定的两个值进行比较,直接写脚本爆破,最后计算出需要输入的值为90038

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
// 爆破脚本,单线程大概需要半个小时左右

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

double cal(double a, double b)
{
double _a;
double var = 0.0;
_a = a;
a = pow(a, b - 1);
*(&var + 1) = *(&a + 1);
var = a / exp(_a);
return var;
}

int main(int argc, char* argv[])
{
double input_num;
for (int i = 0; i < 99999; i++) {
input_num = i;
printf("%d\n", i);
double v16 = 0.0, v17 = 0.0, v18 = 0.0, v19 = 0.0;
int num1 = 0x13B03, num2 = 0x5A2;
v19 = (double)((int)input_num / 0x305B) + 1.0;
do {
v17 = v17 + cal(v18, v19) * 0.001;
v18 = v18 + 0.001;
} while (v18 <= 100.0);

double v21 = 0.0;
double v22 = (double)((int)input_num % 0x305B) + 1.0;
do
{
v16 = v16 + cal(v21, v22) * 0.001;
v21 = v21 + 0.001;
} while (v21 <= 100.0);
if ((int)(v17 + v17 + 3.0) == num1 && (int)(v16 + v16 + 3.0) == num2) {
printf("%f", input_num);
break;
}
}

return 0;
}

后面就比较简单了,首先将输入的数字转为ascii码,然后在后面追加input_num*2,一共追加5次,取前7位进行异或计算出一个key供后面使用

1
2
3
4
5
6
Cipher = [8, 77, 89, 6, 115, 2, 64]
key = list(map(ord,list("9903819")))
Plain = bytes(key[i]^Cipher[i] for i in range(7))
print(Plain)

# 1ti5K3y

后面就是一个标准的RC4加密

1
2
3
4
5
6
7
8
from Cryptodome.Cipher import ARC4

Cipher = bytes([178, 214, 142, 63, 170, 20, 83, 84, 198, 6])
Key = b'1ti5K3y'
rc4 = ARC4.new(Key)
Plain = rc4.decrypt(Cipher)
print(Plain)
# RC4_crypt0