虎符CTF 游记

警告
本文最后更新于 2021-04-18,文中内容可能已过时。

今天收到邮件知道进入了线下赛,这篇文章会记录一下这个我参加的第一次线下决赛(awd赛)。

线上赛简易Writeup

WEB

签到

根据hint找到下面几篇文章

https://github.com/php/php-src/commit/c730aa26bd52829a49f2ad284b181b7e82a68d7d

https://www.infoq.cn/article/WLYCrBZxwMzFNbNNMgui

https://news-web.php.net/php.internals/113838

根据文章ua头开头插入字符zerodium后即可执行命令,根据上面github上的源码,要讲ua头变成User-Agentt后才能执行命令

最后payload:User-Agentt: zerodiumsystem(‘cat /flag’)

unsetme

经过查询后得知此题位php的Fat Free Framework框架,进一步查询得到了一个此框架的一个CVE

https://nvd.nist.gov/vuln/detail/CVE-2020-5203

https://github.com/fgsec/Exploits/commit/2873f1a1b0a1726a8f86dcbb7174d417c9345b2d

在上面的第二个链接中得到一个payload:0);echo id;print(''

首先尝试此exp无效,后来又经过慢慢尝试,发现需要变成0[])后才生效,最终payload

1
?a=0[]);system('cat /flag');print(''

Reverse

redemption_code

 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
#include <cstdio>
#include <cstring>
#include "defs.h"
int __fastcall server_check_redemption_code(char* key, char* input)
{
    int k; // [sp+18h] [+18h]
    int i; // [sp+1Ch] [+1Ch]
    int j; // [sp+20h] [+20h]
    int v7; // [sp+24h] [+24h]
    int x; // [sp+28h] [+28h]
    int key_len; // [sp+34h] [+34h]
    int inp_len; // [sp+38h] [+38h]
    _DWORD s[0xE][256]; // [sp+3Ch] [+3Ch]
    key_len = strlen(key);
    inp_len = 0xE;
    inp_len = inp_len;
    memset(s, 0, inp_len * 1024);
    s[0][input[0]] = 1;
    x = 0;
    for (i = 1; i < inp_len; ++i)
    {
        for (j = 0; j < 256; ++j) s[i][j] = s[x][j];
        s[i][input[i]] = i + 1;
        x = s[x][input[i]];
    }
    v7 = 0;
    for (k = 0; k < key_len; ++k)
    {
        v7 = s[v7][key[k]];
        if (v7 == 14) 
            return k - 13;
    }
    return -1;
}
int main()
{
    char s[] = "Ninja Must Die 3 Is A Cruel Game, So Hard For Me";
    char s2[] = "I Love Ninja Must Die 3. Beautiful Art And Motive Operation Is Creative.";
    char s3[] = "Ninja Must Die";
    server_check_redemption_code(s2, s3);
    return 0;
}

图片

长度限制为0xE

图片

程序要求匹配到7这个位置,也就是Ninja Must Die字符串即可

CrackMe

图片

这里的验证,爆破即可。

图片

异或即可,前半部分是7字节。

图片

发现这里有很像是RC4的东西,我们直接记录RC4异或的内容即可。复杂的RC4转变为简单的异或运算。

解题代码

 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
#include <cstdio>
#include <cmath>
double calc(double a1, double a2)
{
	double v2 = a1;
	a1 = pow(a1, a2 - 1.0);
	return a1 / exp(v2);
}
void part1()
{
	int v95 = 1;
	double v19 = (v95 / 0x305B) + 1.0, v17;
	int ans1, ans2;
	for (int v19 = 1; v19 <= 10000; v19++)
	{
		v17 = 0.0;
		for (double v18 = 0; v18 <= 100.0; v18 += 0.001)
		{
			v17 += calc(v18, v19) * 0.001;
		}
		int v20 = v17 + v17 + 3;
		if (v20 == 0x13B03)
		{
			ans1 = v19;
			break;
		}
	}



	double v21 = 0.0;
	double v22 = (v95 % 0x305B) + 1.0, v16;
	for (int v22 = 1; v22 <= 10000; v22++)
	{
		v16 = 0;
		for (double v21 = 0; v21 <= 100.0; v21 += 0.001)
		{
			v16 += calc(v21, v22) * 0.001;
		}
		int v23 = v16 + v16 + 3;
		if (v23 == 0x5A2)
		{
			ans2 = v22;
			break;
		}
	}
	printf("%d\n", (ans1 - 1) * 0x305B + (ans2 - 1));
}
void part2()
{
	char s[] = "99038198076198076198076198076198076";
	unsigned char ida_chars[] =
	{
	  0x08, 0x4D, 0x59, 0x06, 0x73, 0x02, 0x40
	};
	for (int i = 0; i < 7; i++)
	{
		printf("%c", s[i] ^ ida_chars[i]);
	}
}
void part3()
{
	unsigned char s[] =
	{
	  0xB2, 0xD6, 0x8E, 0x3F, 0xAA, 0x14, 0x53, 0x54, 0xC6, 0x06
	};
	unsigned char ida_chars[] =
	{
	  0xE0, 0x95, 0xBA, 0x60, 0xC9, 0x66, 0x2A, 0x24, 0xB2, 0x36
	};
	for (int i = 0; i < 10; i++)
	{
		printf("%c", s[i] ^ ida_chars[i]);
	}
}
int main()
{
	part1();
	part2();
	part3();
	return 0;
}

1ti5K3y RC4_crypt0 99038

GoEncrypt

还原加密代码并编写解密代码。发现是一种类似于TEA的算法。

 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
#include <cstdio>
#include "defs.h"

int rev(int x)
{
    unsigned int data = 0;
    unsigned char a2[4];
    for (int i = 0; i < 4; ++i) a2[i] = x >> (24 - 8 * i);
    for (int i = 0; i < 4; i++) data ^= a2[4 - i - 1] << (24 - 8 * i);
    return data;
}
void encode()
{
    int i = 0;
    __int64 v13; // r8
    unsigned int  a1; // r8
    unsigned int part2; // eax
    unsigned int part1; // rdx
    __int64 v16; // rbx
    unsigned int sum; // rsi
    unsigned int v18; // eax
    unsigned __int64 v19; // rdi
    unsigned int k[4] = {
        0x00010203, 0x04050607, 0x08090A0B, 0x0C0D0E0F
    };
    int v21; // er10
    unsigned __int64 v22; // rsi
    unsigned int v23; // er11
    unsigned __int64 v24; // rdx
    __int64 v25; // r8
    unsigned int v27; // [rsp+20h] [rbp-18h]
    void* retaddr; // [rsp+38h] [rbp+0h] BYREF
    v19 = 4;
    sum = 0;
    //TEST
    part2 = 0xBBBBCCCC;
    part1 = 0xAAAAAAAA;
    while (i < 32)
    {
        v13 = part2;
        v18 = part2 + ((part2 >> 5) ^ (16 * part2));
        
        v21 = sum;
        v22 = sum & 3;
        v23 = part1 + (v18 ^ (v21 + k[v22]));
        sum += 0x12345678;
        v24 = ((unsigned int)sum >> 11) & 3;
        part2 += (v23 + ((v23 >> 5) ^ (16 * v23))) ^ (v21 + (k[v24] + 0x12345678));
        part1 = v23;
        i++;
    }
    part1 = rev(part1);
    part2 = rev(part2);
    return;
}
void decode(unsigned int* v)
{
    unsigned int k[4] = {
        0x00010203, 0x04050607, 0x08090A0B, 0x0C0D0E0F
    };
    unsigned int v0 = v[0], v1 = v[1], sum = 0;
    v0 = rev(v0);
    v1 = rev(v1);
    for (int i = 0; i < 32; i++) sum += 0x12345678;
    for (int i = 0; i < 32; i++)
    {
        v1 -= (v0 + ((v0 >> 5) ^ (16 * v0))) ^ (sum + k[((unsigned int)sum >> 11) & 3]);
        sum -= 0x12345678;
        v0 -= (v1 + ((v1 >> 5) ^ (16 * v1))) ^ (sum + k[sum & 3]);
    }
    v[0] = v0;
    v[1] = v1;
}
int main()
{
    unsigned int k[4] = {
        0x00010203, 0x04050607, 0x08090A0B, 0x0C0D0E0F
    };
    unsigned int v[2] = {
        0xAAAAAAAA, 0xBBBBCCCC
    };
    unsigned int endata[4] = {
        0xF011C30E, 0xF39AC745, 0x10D9F5ED, 0xCB022754
    };
    unsigned int test[2] = {
        0x9dab8361, 0x9b1230b6
    };
    //encode();
    decode(endata);
    decode(&endata[2]);
    //encrypt(v, k);
	return 0;
}

flag{3bbcf9ea-2918-4fee-8a2e-201b47dfcb4e}

0%