PicoCTF - gogo
Source code
:::spoiler IDA Main Function
// main.main
void __cdecl main_main()
{
_slice_interface_ typ[2]; // [esp+0h] [ebp-58h] BYREF
string *second_flag; // [esp+20h] [ebp-38h]
string *flag; // [esp+24h] [ebp-34h]
_slice_interface_ v3; // [esp+28h] [ebp-30h] BYREF
string *v4; // [esp+34h] [ebp-24h]
_DWORD v5[2]; // [esp+38h] [ebp-20h] BYREF
_DWORD v6[2]; // [esp+40h] [ebp-18h] BYREF
_slice_interface_ v7; // [esp+48h] [ebp-10h] BYREF
string *v8; // [esp+54h] [ebp-4h]
flag = runtime_newobject(&RTYPE_string_0);
typ[0].array = "Enter Password: ";
typ[0].len = 16;
memset(&typ[0].cap, 0, sizeof(_slice_interface_));
fmt_Printf(*&typ[0].array, *&typ[0].cap);
v6[0] = &RTYPE__ptr_string;
v6[1] = flag;
typ[0].array = "%s\n";
typ[0].len = 3;
typ[0].cap = v6;
*&typ[1].array = 0x100000001LL;
fmt_Scanf(*&typ[0].array, *&typ[0].cap);
if ( main_checkPassword(*flag) )
{
v5[0] = &RTYPE_string_0;
v5[1] = &main_statictmp_0;
typ[0].array = v5;
*&typ[0].len = 0x100000001LL;
fmt_Println(typ[0]);
v3.cap = &RTYPE_string_0;
v4 = &main_statictmp_1;
typ[0].array = &v3.cap;
*&typ[0].len = 0x100000001LL;
fmt_Println(typ[0]);
v3.array = &RTYPE_string_0;
v3.len = &main_statictmp_2;
typ[0].array = &v3;
*&typ[0].len = 0x100000001LL;
fmt_Println(typ[0]);
second_flag = runtime_newobject(&RTYPE_string_0);
v7.cap = &RTYPE__ptr_string;
v8 = second_flag;
typ[0].array = "%s\n";
typ[0].len = 3;
typ[0].cap = &v7.cap;
*&typ[1].array = 0x100000001LL;
fmt_Scanf(*&typ[0].array, *&typ[0].cap);
main_ambush(*second_flag);
runtime_deferproc(0, &stru_81046A0);
}
else
{
v7.array = &RTYPE_string_0;
v7.len = &main_statictmp_3;
typ[0].array = &v7;
*&typ[0].len = 0x100000001LL;
fmt_Println(typ[0]);
}
runtime_deferreturn(typ[0].array);
}
:::
:::spoiler IDA First Stage Checker
// main.checkPassword
bool __golang main_checkPassword(string flag)
{
__int32 idx; // eax
int check_counter; // ebx
uint8 key[32]; // [esp+4h] [ebp-40h] BYREF
char enc_flag[32]; // [esp+24h] [ebp-20h]
if ( flag.len < 32 )
os_Exit(0);
(loc_8090B18)();
qmemcpy(key, "861836f13e3d627dfa375bdb8389214e", sizeof(key));
(loc_8090FE0)();
idx = 0;
check_counter = 0;
while ( idx < 32 )
{
if ( idx >= flag.len || idx >= 0x20 )
runtime_panicindex();
if ( (key[idx] ^ flag.str[idx]) == enc_flag[idx] )
++check_counter;
++idx;
}
return check_counter == 32;
}
:::
:::spoiler IDA Second Stage Checker
// main.ambush
void __golang main_ambush(string second_flag)
{
int j; // eax
_slice_uint8 v2; // [esp+0h] [ebp-94h]
_slice_uint8 s; // [esp+4h] [ebp-90h]
_slice_uint8 dataa; // [esp+Ch] [ebp-88h]
string data; // [esp+Ch] [ebp-88h]
string data_4; // [esp+10h] [ebp-84h]
uint8 v7; // [esp+1Fh] [ebp-75h]
unsigned __int32 i; // [esp+20h] [ebp-74h]
uint8 hashed[16]; // [esp+24h] [ebp-70h] BYREF
uint8 key[32]; // [esp+34h] [ebp-60h] BYREF
uint8 buf[32]; // [esp+54h] [ebp-40h] BYREF
uint8 v12[32]; // [esp+74h] [ebp-20h] BYREF
dataa = runtime_stringtoslicebyte(buf, second_flag);
crypto_md5_Sum(dataa);
(loc_8091008)();
(loc_8090B18)();
qmemcpy(key, "861836f13e3d627dfa375bdb8389214e", sizeof(key));
for ( j = 0; j < 16; j = i + 1 )
{
i = j;
v2.array = hashed;
*&v2.len = 0x1000000010LL;
data = encoding_hex_EncodeToString(v2);
if ( i >= data.len
|| (v7 = data.str[i],
s.array = key,
*&s.len = 0x2000000020LL,
data_4 = runtime_slicebytetostring(v12, s),
i >= data_4.len) )
{
runtime_panicindex();
}
if ( v7 != data_4.str[i] )
os_Exit(0);
}
}
:::
Recon
終於有一點像樣的題目出現了,這一題有兩個關卡需要克服
1 |
|
用IDA和gdb跟一下整體的流程
- 首先他先把我們輸入的flag,丟到main_checkPassword function檢查,而跟了一下gdb發現他是先跟
861836f13e3d627dfa375bdb8389214e
的每一個數值進行xor然後跟enc_flag的字元做比較,而enc_flag是run time的時候需要從memory撈的資料,這就需要慢慢跟然後慢慢看,大概就像下面撈的那樣,反著作就可以得到第一階段的flag - 過了第一階段後他還會叫你要再輸入一次另外一個flag,然後會丟到main_ambush function做檢查,他會先把我們輸入的second flag進行md5的hash,然後和
861836f13e3d627dfa375bdb8389214e
進行比對,所以我們要做的事情是推測甚麼樣的字串,他的md5 hash是861836f13e3d627dfa375bdb8389214e
,這個可以用online tool做到這件事情
Exploit
- Script For 1st Stage
1
2
3
4
5
6
7
8enc_flag = [74, 83, 71, 93, 65, 69, 3, 84, 93, 2, 90, 10, 83, 87, 69, 13, 5, 0, 93, 85, 84, 16, 1, 14, 65, 85, 87, 75, 69, 80, 70, 1] key = [0x38, 0x36, 0x31, 0x38, 0x33, 0x36, 0x66, 0x31, 0x33, 0x65, 0x33, 0x64, 0x36, 0x32, 0x37, 0x64, 0x66, 0x61, 0x33, 0x37, 0x35, 0x62, 0x64, 0x62, 0x38, 0x33, 0x38, 0x39, 0x32, 0x31, 0x34, 0x65] FLAG = [] for a, b in zip(enc_flag, key): FLAG.append(bytes.fromhex(hex(a ^ b)[2:]).decode('utf-8')) print("".join(FLAG))
-
Use online tool to unhash
- Conclusion
1
2
3
4
5
6
7$ nc mercury.picoctf.net 4052 Enter Password: reverseengineericanbarelyforward ========================================= This challenge is interrupted by psociety What is the unhashed key? goldfish Flag is: picoCTF{p1kap1ka_p1c09a4dd7f3}