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
|
CTFd is too insufferably slow. You know why? Because they use an SQL database
that's bogged down by JOINs instead of a web scale database like MongoDB.
MongoDB is web scale. You turn it on and it scales right up. You know what's
more web scale though? Nothing. That's right, the throughput of /dev/null is
off the charts. Behold, CTFd+, the first databaseless CTF platform. Can you
get the flag for the only challenge?
RE
--
We are given a binary that presents a welcome message along with a dummy PWN
challenge, then asks for the flag for said challenge. As this is a mock CTF
platform, it is a flag checker RE challenge. The content of the embedded PWN
is not relevant: the program just calls `puts` then exits.
Ghidra shows that the flag we supply is validated character by character
against the result of some computation performed on a static array of data.
(Some markup provided by me).
```
undefined8 main(void)
{
int flag_check_char;
size_t flag_in_len;
long idx;
int *static_data;
char flag_in [256];
puts("Welcome to CTFd+!");
puts(
"So far, we only have one challenge, which is one more than the number of databases we have.\n "
);
puts("Very Doable Pwn - 500 points, 0 solves");
puts("Can you help me pwn this program?");
puts("#include <stdio.h>\nint main(void) {\n puts(\"Bye!\");\n return 0;\n}\n");
puts("Enter the flag:");
fgets(flag_in,0x100,stdin);
flag_in_len = strcspn(flag_in,"\n");
idx = 0;
static_data = INT_ARRAY_00104060;
flag_in[flag_in_len] = '\0';
do {
flag_check_char = flag_gen(static_data[idx]);
if ((char)flag_check_char != flag_in[idx]) {
puts("Incorrect flag.");
return 0;
}
idx = idx + 1;
} while (idx != 0x2f);
puts("You got the flag! Unfortunately we don\'t exactly have a database to store the solve in...")
;
return 0;
}
```
If at any point in the validation a character fails, the whole flag is
considered incorrect.
Solution
--------
To extract the expected flag, I ported the static data and the `flag_gen`
computation logic to a standalone C program and simply print out the value of
each character. We know the expected size of the flag string from the bounds
of `main`'s while loop (`while (idx != 0x2f)`).
```
#include <stdio.h>
#include <stdint.h>
#include <sys/types.h>
typedef unsigned char byte;
static const unsigned char DATA[] = {
0x74, 0x92, 0x7f, 0x9c, 0xe9, 0x0c, 0xbb, 0xc2, 0x29, 0x19, 0x9b, 0x40,
0xd7, 0x6e, 0x3d, 0xbe, 0x04, 0xe1, 0x83, 0x4f, 0x83, 0xd4, 0x85, 0x91,
0xaf, 0x70, 0x5d, 0xfd, 0xf1, 0x7f, 0xc4, 0x88, 0x71, 0xfa, 0x78, 0xe6,
0x0d, 0xdf, 0xcb, 0x72, 0xa7, 0x3d, 0xb6, 0xf4, 0x3d, 0x9e, 0x29, 0x54,
0xf4, 0x7b, 0x05, 0xaa, 0xa3, 0x4d, 0x14, 0x14, 0x3c, 0x02, 0xc6, 0xe1,
0x39, 0xb5, 0xb9, 0x74, 0x0f, 0xd8, 0x5f, 0x54, 0x29, 0x73, 0x7a, 0x04,
0x3f, 0xd9, 0x41, 0xad, 0xd0, 0xbc, 0x16, 0x96, 0x50, 0x62, 0x59, 0x76,
0x0f, 0xec, 0xa7, 0xaa, 0x2f, 0xf2, 0xb1, 0x21, 0x7e, 0xb3, 0x80, 0x87,
0x15, 0x14, 0x8d, 0x76, 0x60, 0xad, 0xf3, 0x56, 0x4d, 0x6f, 0x84, 0x2c,
0x3e, 0x57, 0x38, 0x15, 0x9e, 0x7b, 0x95, 0x6a, 0x70, 0x08, 0x03, 0xaa,
0xbc, 0xbf, 0xc7, 0x27, 0x4d, 0x88, 0x2e, 0x47, 0x71, 0x09, 0x34, 0xbc,
0x94, 0xc0, 0x70, 0x95, 0xea, 0x21, 0x55, 0xd6, 0xbe, 0x14, 0x84, 0x86,
0x8d, 0xec, 0xf7, 0xff, 0xff, 0x65, 0x14, 0xaa, 0xa7, 0x6a, 0xd1, 0x21,
0x0c, 0xc1, 0x97, 0x84, 0xf7, 0xd2, 0x3a, 0x51, 0xca, 0xbb, 0x11, 0x62,
0xe5, 0xc8, 0x99, 0x87, 0xbd, 0xfc, 0x37, 0xb5, 0xed, 0x29, 0xcc, 0x44,
0x5d, 0xd9, 0x8a, 0x40, 0xb1, 0x02, 0x09, 0x2d };
int flag_gen(uint param_1)
{
byte bVar1;
uint uVar2;
int iVar3;
uVar2 = 0;
iVar3 = 0;
do {
bVar1 = (byte)iVar3 & 0x1f;
iVar3 = iVar3 + 1;
param_1 = (param_1 * param_1 >> bVar1 | param_1 * param_1 << 0x20 - bVar1) * 0x1337 + 0x4201337
^ uVar2;
uVar2 = uVar2 + 0x13371337;
} while (iVar3 != 0x20);
return (param_1 >> 8) + (param_1 >> 0x10) + param_1 + (param_1 >> 0x18);
}
int main(void) {
const int *arr = (void *)DATA;
for (int i = 0; i < 47; i++) {
int c = flag_gen(arr[i]);
printf("%c", (char)c);
}
printf("\n");
return 0;
}
```
lactf{m4yb3_th3r3_1s_s0m3_m3r1t_t0_us1ng_4_db}
|