Link to challenge: https://academy.hacking-lab.com
Date Completed: 20 December 2019
Challenge
HV19.20 i want to play a game
1 2 3 4 5 6 7 |
Introduction Santa was spying you on Discord and saw that you want something weird and obscure to reverse? your wish is my command. Resources HV19-game.zip |
Resource mirror: HV19-game.zip
Solution
We are given a binary and told it is something obscure we have to reverse. We download the binary and open it in IDA. After some digging around we realise the file has something to do with the PS4 and this is consistent with the hint in the zip file name too.
We dig around in IDA where we find a single main() method. We see that we seem to read in a file called /mnt/usb0/PS4UPDATE.PUP and then take the MD5 hash of this file and compare it to f86d4f9d2c049547bd61f942151ffb55. After googling this hash we find the file in question is the PS4 5.05 firmware.
We decide to decompile the code to C and are presented with the following:
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 |
int __cdecl main(int argc, const char **argv, const char **envp) { __int64 v3; // rcx __int64 v4; // rcx __int64 v5; // r13 unsigned int v6; // eax __int64 v7; // rcx __int16 *v8; // r15 __int64 v9; // rcx __int64 v10; // r12 __int64 v11; // rdx __int64 i; // rax __int64 v13; // r13 __int64 v14; // rcx __int64 v15; // r12 __int64 j; // rax __int64 v17; // rcx __int64 v18; // rcx __int64 v20; // [rsp+8h] [rbp-520h] void (*v21)(void); // [rsp+10h] [rbp-518h] void (*v22)(void); // [rsp+18h] [rbp-510h] __int64 v23; // [rsp+27h] [rbp-501h] char v24; // [rsp+30h] [rbp-4F8h] __int16 v25; // [rsp+40h] [rbp-4E8h] __int16 v26; // [rsp+42h] [rbp-4E6h] int v27; // [rsp+44h] [rbp-4E4h] char v28[32]; // [rsp+50h] [rbp-4D8h] char v29[32]; // [rsp+70h] [rbp-4B8h] refptr_initKernel(argc, argv, envp); refptr_initLibc(); refptr_initNetwork(); (*(void (__fastcall **)(_QWORD, _QWORD, _QWORD, _QWORD))refptr_sceKernelLoadStartModule)(0i64, 0i64, 0i64, 0i64); refptr_sceKernelDlsym(v3, &v21); refptr_sceKernelDlsym(v4, &v22); (*(void (**)(void))refptr_malloc)(); (*(void (**)(void))refptr_malloc)(); v21(); v22(); v5 = (*(__int64 (**)(void))refptr_fopen)(); (*(void (**)(void))refptr_malloc)(); refptr_MD5Init(); while ( 1 ) { v6 = (*(__int64 (__fastcall **)(__int64, __int64))refptr_fread)(v5, 1024i64); if ( !v6 ) break; refptr_MD5Update(v7, v6); } v8 = (__int16 *)&v24; refptr_MD5Final(); (*(void (**)(void))refptr_fclose)(); v10 = v20; do { v11 = *(unsigned __int8 *)v8; v8 = (__int16 *)((char *)v8 + 1); v10 += 2i64; (*(void (__fastcall **)(__int64, __int64))refptr_sprintf)(v9, v11); } while ( &v25 != v8 ); if ( !(*(unsigned int (**)(void))refptr_strcmp)() ) { for ( i = 0i64; i != 26; ++i ) v28[i] = byte_300[i]; v13 = 4919i64; v15 = (*(__int64 (__fastcall **)(_BYTE *))refptr_fopen)(byte_300); do { (*(void (__fastcall **)(__int64, _QWORD))refptr_fseek)(v14, 0i64); (*(void (__fastcall **)(__int64, __int64))refptr_fread)(v15, 1i64); for ( j = 0i64; j != 26; ++j ) v28[j] ^= v29[j]; v13 += 4919i64; } while ( v13 != 24201480 ); (*(void (**)(void))refptr_fclose)(); strcpy((char *)&v23, "sendflag"); v25 = 528; v27 = 16777343; v26 = (*(__int64 (**)(void))refptr_sceNetHtons)(); (*(void (__fastcall **)(__int64, __int64))refptr_memset)(v17, 6i64); (*(__int64 (__fastcall **)(_QWORD, __int64))refptr_sceNetSocket)(0i64, 1i64); (*(void (__fastcall **)(__int64, __int64))refptr_sceNetConnect)(v18, 16i64); (*(void (__fastcall **)(_QWORD, __int64))refptr_sceNetSend)(0i64, 26i64); (*(void (**)(void))refptr_sceNetSocketClose)(); } return 0; } |
The above decompilation is not perfect but we see the general structure of the program. First we initialise an array of 32 bytes with some data from byte_300 and store this as our flag data. Next we open our /mnt/usb0/PS4UPDATE.PUP file. We initialise our file pointer value to 0x1337 and start looping, adding 0x1337 to our seek pointer each iteration. Finally, we read 26 bytes from the file and xor this with the current flag data. At the end, we should our flag in our array.
We translate this to python code and get the following:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
# Hackvent 2019 - Day 20 # Mo Beigi (https://mobeigi.com) flag = bytearray(b'\xCE\x55\x95\x4E\x38\xC5\x89\xA5\x1B\x6F\x5E\x25\xD2\x1D\x2A\x2B\x5E\x7B\x39\x14\x8E\xD0\xF0\xF8\xF8\xA5\x00') # Read PS4 firmware with MD5 f86d4f9d2c049547bd61f942151ffb55 f = open("PS4UPDATE.PUP", "rb") offset = 0x1337 while offset != 0x1714908: # Absolute seek to offset f.seek(offset, 0) read_bytes = f.read(26) # xor flag with read bytes for j in range(0, 26): flag[j] ^= read_bytes[j] offset += 0x1337 # Print flag print(''.join(chr(i) for i in flag)) |
Running this gives us our flag!
Flag: HV19{C0nsole_H0mebr3w_FTW}