Alles CTF 2020 Writeups
[Rev] Flag Service Revolution
Given a boot.dol file, a Nintendo GameCube file. Opened it with the dolphin-emu. Then searched how we can disassemble the .dol files and found this https://mkwii.com/showthread.php?tid=1193 used ghidraThis is a stripped and statically linked binary, it's hard to trace the functions.
Searched for strings appearing on app -> `Cross References` - `main function FUN_8003d4c4`.
The decompiled code of ghidra is too messy with the stripped func names, var names.
Anyway gone through the code and renamed `variables` and the `functions` based on arguments, codeflow, values etc.. by tracing to make it convinient.
Finally modified decompiled code :
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
void FUN_8003d4c4(void) | |
{ | |
int counter; | |
uint key_code; | |
int iVar1; | |
undefined4 extraout_r4; | |
undefined4 *flag_status; | |
int iVar2; | |
int iVar3; | |
int iVar4; | |
undefined total_display_string [100]; | |
undefined Array_8 [8]; | |
short local_18c; | |
short local_18a; | |
ushort local_16a; | |
undefined4 s_no_flag_0-4; | |
undefined4 s_no_flag_4-4; | |
undefined4 s_no_flag_8-4; | |
undefined4 s_no_flag_12-4; | |
undefined Array_36 [36]; | |
undefined4 s_no_buttons_0-4; | |
undefined4 s_no_buttons_4-4; | |
undefined4 s_no_buttons_8-4; | |
undefined4 s_no_buttons_12-4; | |
undefined4 s_no_buttons_16-4; | |
undefined4 s_no_buttons_20-4; | |
undefined2 s_no_buttons_24-2; | |
char s_no_buttons_26-1; | |
undefined4 local_111; | |
undefined4 local_10d; | |
undefined4 local_109; | |
undefined4 local_105; | |
undefined4 local_101; | |
undefined2 local_fd; | |
undefined local_fb; | |
undefined Frame [26]; | |
undefined2 local_de; | |
undefined Array_40 [40]; | |
char local_a0; | |
char local_9f; | |
char local_9e; | |
char local_9d; | |
char local_9c; | |
undefined local_9b; | |
undefined local_9a; | |
undefined local_99; | |
undefined local_98; | |
undefined local_97; | |
char local_96; | |
undefined local_95; | |
undefined local_94; | |
undefined local_93; | |
undefined local_92; | |
undefined local_91; | |
undefined local_90; | |
undefined local_8f; | |
undefined local_8e; | |
undefined local_8d; | |
undefined local_8c; | |
undefined local_8b; | |
undefined local_8a; | |
undefined local_89; | |
char local_88; | |
char local_87; | |
char local_86; | |
char local_85; | |
undefined local_84; | |
undefined local_83; | |
char local_82; | |
undefined local_81; | |
char local_80; | |
undefined local_7f; | |
char local_7e; | |
undefined local_7d; | |
undefined local_7c; | |
undefined4 s_service_revolution_0-4; | |
undefined4 s_service_revolution_4-4; | |
undefined4 s_service_revolution_8-4; | |
undefined4 s_service_revolution_12-4; | |
undefined4 s_service_revolution_16-4; | |
undefined2 s_service_revolution_20-2; | |
undefined4 s_welcome_0-4; | |
undefined4 s_welcome_4-4; | |
undefined4 s_great_0-4; | |
undefined2 s_great_4-2; | |
undefined4 s_flag_0-4; | |
char s_to_4-1; | |
undefined4 s_our_0-4; | |
undefined2 s_to_0-2; | |
char s_to_2-1; | |
FUN_8003cf48(); | |
FUN_8003dac4(); | |
FUN_8003ed74(); | |
FUN_8009e1e8(0); | |
FUN_8009846c(extraout_r4); | |
Create_Frame(Frame,&DAT_800b9840,0xf1088,0x18); | |
s_to_0-2 = s_to_803900a8._0_2_; | |
s_great_4-2 = s_Great_803900a0._4_2_; | |
s_flag_0-4 = s_Flag_803900ac._0_4_; | |
s_service_revolution_4-4 = s_{Service_Revolution}!_803900b4._4_4_; | |
s_service_revolution_8-4 = s_{Service_Revolution}!_803900b4._8_4_; | |
s_to_2-1 = s_to_803900a8[2]; | |
s_to_4-1 = s_Flag_803900ac[4]; | |
s_great_0-4 = s_Great_803900a0._0_4_; | |
s_service_revolution_0-4 = s_{Service_Revolution}!_803900b4._0_4_; | |
s_service_revolution_12-4 = s_{Service_Revolution}!_803900b4._12_4_; | |
s_service_revolution_16-4 = s_{Service_Revolution}!_803900b4._16_4_; | |
s_service_revolution_20-2 = s_{Service_Revolution}!_803900b4._20_2_; | |
s_welcome_0-4 = s_Welcome_80390098._0_4_; | |
s_welcome_4-4 = s_Welcome_80390098._4_4_; | |
s_our_0-4 = 0x6f757200; | |
s_no_buttons_12-4 = s_No_buttons_pressed_yet_..._800a7fc0._12_4_; | |
s_no_buttons_16-4 = s_No_buttons_pressed_yet_..._800a7fc0._16_4_; | |
s_no_buttons_20-4 = s_No_buttons_pressed_yet_..._800a7fc0._20_4_; | |
s_no_buttons_24-2 = s_No_buttons_pressed_yet_..._800a7fc0._24_2_; | |
s_no_buttons_26-1 = s_No_buttons_pressed_yet_..._800a7fc0[26]; | |
s_no_flag_0-4 = s_No_flag_yet_..._800a7ff4._0_4_; | |
local_de = 0x111; | |
s_no_buttons_0-4 = s_No_buttons_pressed_yet_..._800a7fc0._0_4_; | |
s_no_buttons_4-4 = s_No_buttons_pressed_yet_..._800a7fc0._4_4_; | |
s_no_buttons_8-4 = s_No_buttons_pressed_yet_..._800a7fc0._8_4_; | |
s_no_flag_4-4 = s_No_flag_yet_..._800a7ff4._4_4_; | |
s_no_flag_8-4 = s_No_flag_yet_..._800a7ff4._8_4_; | |
s_no_flag_12-4 = s_No_flag_yet_..._800a7ff4._12_4_; | |
local_fb = 0; | |
local_111 = 0; | |
local_10d = 0; | |
local_109 = 0; | |
local_105 = 0; | |
local_101 = 0; | |
local_fd = 0; | |
FUN_800971b4(Array_36,0,0x22); | |
counter = Display_png(Array_40,Array_8,PNG_801aa8e0,300,200); | |
if (counter == 0) { | |
return; | |
} | |
iVar3 = 0xf; | |
flag_status = &s_no_flag_0-4; | |
counter = 0; | |
FUN_80040594(Array_8,0x4c,0x3e); | |
iVar2 = 0; | |
iVar4 = 0x14; | |
FUN_800406e4((double)DAT_803900cc,Array_8); | |
local_16a = 0; | |
FUN_8003eb1c(); | |
do { | |
iVar1 = FUN_8003eb74(); | |
if (iVar1 == 0) { | |
FUN_8003eba0(&audio_file.mp4,0x1b70d8); | |
} | |
if (DAT_8044b998 != 0) { | |
FUN_8003eb54(); | |
FUN_80041db0(Array_40); | |
FUN_80040458(); | |
} | |
FUN_800568f4(); | |
if (DAT_8044b958 == 0) { | |
iVar4 = iVar4 + ((uint)(DAT_8044b954 == 0) - 1); | |
if (DAT_8044b950 == 0) goto LAB_8003d84c; | |
LAB_8003d74c: | |
iVar3 = iVar3 + 1; | |
} | |
else { | |
iVar4 = iVar4 + 1; | |
if (DAT_8044b950 != 0) goto LAB_8003d74c; | |
LAB_8003d84c: | |
iVar3 = iVar3 + ((uint)(DAT_8044b94c == 0) - 1); | |
} | |
Combine_strings(total_display_string,s_%s_%s_%s_%s_%s%s_80390084,&s_welcome_0-4,&s_to_0-2, | |
&s_our_0-4,&s_great_0-4,&s_flag_0-4,&s_service_revolution_0-4); | |
Display_text(Frame,iVar4,iVar3,total_display_string); | |
key_code = Read_keyPress(0); | |
if (key_code != 0) { | |
Check_button(key_code,&s_no_buttons_0-4); | |
if (counter == 9) { | |
if ((key_code & 0x800) != 0) { | |
flag_status = (undefined4 *)&local_a0; | |
local_8e = s_welcome_4-4._2_1_; | |
local_90 = s_service_revolution_12-4._0_1_; | |
} | |
LAB_8003d8e4: | |
if (counter == 0) { | |
LAB_8003d8ec: | |
counter = 0; | |
if ((key_code & 8) != 0) { | |
counter = 1; | |
local_80 = (char)s_great_0-4; | |
local_7e = s_service_revolution_0-4._1_1_ + ' '; | |
local_81 = s_welcome_0-4._2_1_; | |
local_a0 = (char)s_great_0-4 + -0x20; | |
local_83 = s_service_revolution_8-4._0_1_; | |
} | |
} | |
} | |
else { | |
if (counter == 8) { | |
if ((key_code & 0x800) == 0) goto LAB_8003d8ec; | |
local_93 = s_great_0-4._2_1_; | |
counter = 9; | |
local_98 = s_service_revolution_16-4._0_1_; | |
} | |
else { | |
if (counter == 7) { | |
if ((key_code & 0x400) == 0) goto LAB_8003d8ec; | |
counter = 8; | |
local_85 = (char)s_great_0-4; | |
local_82 = s_flag_0-4._0_1_ + ' '; | |
local_92 = s_service_revolution_8-4._0_1_; | |
local_8d = s_service_revolution_16-4._2_1_; | |
} | |
else { | |
if (counter == 6) { | |
if ((key_code & 0x400) == 0) goto LAB_8003d8ec; | |
counter = 7; | |
local_7d = (undefined)s_service_revolution_16-4; | |
local_9f = s_flag_0-4._1_1_ + -0x20; | |
local_9c = s_service_revolution_0-4._1_1_; | |
local_95 = (undefined)s_to_0-2; | |
} | |
else { | |
if (counter == 5) { | |
if ((key_code & 0x100) == 0) goto LAB_8003d8ec; | |
counter = 6; | |
local_7f = (undefined)s_flag_0-4; | |
local_9d = (char)s_service_revolution_4-4 + -0x20; | |
local_7c = 0; | |
local_91 = s_great_4-2._0_1_; | |
} | |
else { | |
if (counter == 4) { | |
if ((key_code & 0x200) == 0) goto LAB_8003d8ec; | |
counter = 5; | |
local_96 = s_flag_0-4._1_1_; | |
local_88 = s_great_0-4._0_1_ + ' '; | |
local_8b = s_welcome_0-4._1_1_; | |
local_97 = s_service_revolution_8-4._0_1_; | |
} | |
else { | |
if (counter == 3) { | |
if ((key_code & 0x100) == 0) goto LAB_8003d8ec; | |
local_8a = s_great_0-4._1_1_; | |
counter = 4; | |
local_8f = s_service_revolution_8-4._0_1_; | |
local_9b = s_service_revolution_0-4._0_1_; | |
local_89 = local_8f; | |
} | |
else { | |
if (counter == 2) { | |
if ((key_code & 0x200) == 0) goto LAB_8003d8ec; | |
counter = 3; | |
local_94 = (undefined)s_service_revolution_8-4; | |
local_87 = s_service_revolution_8-4._1_1_ + ' '; | |
local_86 = (char)s_service_revolution_4-4; | |
local_99 = s_service_revolution_4-4._1_1_; | |
} | |
else { | |
if (counter != 1) goto LAB_8003d8e4; | |
if ((key_code & 4) == 0) goto LAB_8003d8ec; | |
counter = 2; | |
local_84 = s_to_0-2._0_1_; | |
local_9e = s_service_revolution_12-4._1_1_ + -0x20; | |
local_8c = (undefined)s_service_revolution_12-4; | |
local_9a = s_welcome_0-4._0_1_; | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
iVar2 = iVar2 + 1; | |
key_code = (uint)local_16a; | |
if ((uint)(iVar2 * -0x33333333) < 0x33333334) { | |
key_code = key_code + 1 & 0xffff; | |
if (key_code == 0x1b) { | |
key_code = 0; | |
local_16a = 0; | |
} | |
else { | |
local_16a = (ushort)key_code; | |
} | |
} | |
FUN_80040630(Array_8,(int)local_18c,(int)local_18a,key_code); | |
Display_text(Frame,0xf,100,&s_no_buttons_0-4); | |
Display_text(Frame,0xf,0x82,flag_status); | |
FUN_80040270(); | |
} while( true ); | |
} |
By looking the game window, assumed that `No flag yet ...` is the status message.
Looked for it in code, checked if that status message changes anywhere and found line 179
From the declaration part, found that `local_a0 is a char array upto local_7c`.
From the code found that these values are get initiated based on some conditions, and finally that message goes to status message.
That constructed message is most likely a flag. Boom :)
It just modifying that array using the strings used previously in code
Written a python script based on those modifications. Got the flag :)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
wlc = b"Welcome" | |
grt = b"Great" | |
to = b"to" | |
our = b"our" | |
flg = b"Flag" | |
srv = b"{Service_Revolution}!" | |
local = [0 for x in range(37)] | |
local[0xa0-0x7c] = grt[3] - 0x20 | |
local[0x9f-0x7c] = flg[1] - 0x20 | |
local[0x9e-0x7c] = srv[13]- 0x20 | |
local[0x9d-0x7c] = srv[7] - 0x20 | |
local[0x9c-0x7c] = srv[1] | |
local[0x9b-0x7c] = srv[0] | |
local[0x9a-0x7c] = wlc[0] | |
local[0x99-0x7c] = srv[5] | |
local[0x98-0x7c] = srv[16] | |
local[0x97-0x7c] = srv[8] | |
local[0x96-0x7c] = flg[1] | |
local[0x95-0x7c] = to[1] | |
local[0x94-0x7c] = srv[11] | |
local[0x93-0x7c] = grt[2] | |
local[0x92-0x7c] = srv[8] | |
local[0x91-0x7c] = grt[4] | |
local[0x90-0x7c] = srv[12] | |
local[0x8f-0x7c] = srv[8] | |
local[0x8e-0x7c] = wlc[6] | |
local[0x8d-0x7c] = srv[18] | |
local[0x8c-0x7c] = srv[15] | |
local[0x8b-0x7c] = wlc[1] | |
local[0x8a-0x7c] = grt[1] | |
local[0x89-0x7c] = srv[8] | |
local[0x88-0x7c] = grt[0] + ord(' ') | |
local[0x87-0x7c] = srv[9] + ord(' ') | |
local[0x86-0x7c] = srv[7] | |
local[0x85-0x7c] = grt[3] | |
local[0x84-0x7c] = to[0] | |
local[0x83-0x7c] = srv[8] | |
local[0x82-0x7c] = flg[0] + ord(' ') | |
local[0x81-0x7c] = wlc[2] | |
local[0x80-0x7c] = grt[3] | |
local[0x7f-0x7c] = flg[3] | |
local[0x7e-0x7c] = srv[1] + ord(' ') | |
local[0x7d-0x7c] = srv[19] | |
local[0x7c-0x7c] = 0 | |
final = local[1:][::-1] | |
Str = ''.join(chr(x) for x in final) | |
print(Str) |
Solution - 2
But i want to complete this game in it's way :). skip;(next-chall, menu)In previous part in the urge of getting flag i have left those conditions.
The conditions are checking the key strokes, 🤔.
Biseds the key_code check, the counter is increment, which makes leads it to next check.
Game wants us to click 10 keys (based on counter checks 0-9), in a sequence.
Key-code sequence : `0x8, 0x4, 0x200, 0x100, 0x200, 0x100, 0x400, 0x400, 0x800, 0x800`
Need to find the keys for those codes, Luckily it gives the key press status on game.
By tracing the status message variable, found a function for updating that message.
Used that function to extracted key-code, status message pairs.
Surprisigly, on Mouse clicks the game is displaying A, B. So ML(Mouse Left) = A ; MR(Mouse Right) = B.
Finally: Key-Sequence = `ML, MR, RIGHT, LEFT, RIGHT, LEFT, DOWN, DOWN, UP, UP`.
Here we go :)
[Rev] prehistoric_mario
Given a prehistoric-mario.apk file, a Game simmilar to mario. given a map (100 x 100), with 11 question tiles, which changes there color on hit. (green-> red-> blue-> yellow-> green -> ..)Decompiled the Apk and gone through the source code. (MyPlatformer.java)
checkFlag function drabbed the attention, It's grabbing `questionmarkType` property values of 11 tiles(based on length of bArr), might be from those 11 questionMark tiles.
Constructing a string with those values and checking its sha256 with some hash.
Note : the code is skipping tile with 1337 value, there might be 12th questionMark Tile some where in map.
Now we have to check for where 'questionmarkType' values are modified and where this checkFlag is called.
Surprisingly both are at same place.
This is the code for hitting questionMark tiles event.
Things to notice:
- we need to find the tile with 1337 value, and hit it to call check Flag
- The questionmarkType value is changing on hit (4 values), same like color.
Extracted the apk, to get (map.tmx) in assets. Used pytmx and loaded (map.tmx).
And found there is 12 tile(with 1337 value as expected) on [15, 90] grid. which is below the map. it's impossible to reach there.
2. questionmarkType values
Each color denotes each value. We need to set the colors of 11 question Mark tiles in a correct manner, then call checkFlag.
11 tiles, 4 colors ; Total possibilites = 4**11 = 4194304. Nothing for a brite force :)
Python code for getting Key (colors):
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#/usr/bin/python3 | |
from hashlib import sha256 | |
def check_Hash(Num): | |
hh = sha256() | |
hh.update(Num.to_bytes(11, 'big')) | |
hh.update(b'P4ssw0rdS4lt') | |
if hh.hexdigest() == '024800ace2ec394e6af68baa46e81dfbea93f0f6730610560c66ee9748d91420': | |
print("[+] Foun the Key !..."+' '*10) | |
return Num | |
def to_num_array(Hex): | |
Num = 0 | |
for i in range(11): | |
Num = Num * 256 + Pos[ Hex % 4 ] | |
Hex = Hex >> 2 | |
return Num | |
Pos = [0, 21, 97, 37] | |
Color = { | |
0 : 'GREEN', | |
21 : 'RED', | |
97 : 'BLUE', | |
37 : 'YELLOW' | |
} | |
for i in range(4**11): | |
num = to_num_array(i) | |
print(num, end='\r') | |
fin = check_Hash(num) | |
if fin: | |
break | |
tmp = fin.to_bytes(11, 'big') | |
for i in tmp: | |
print(Color[i], end=", ") | |
print('') |
Note: We need to set those colors from left -> right manner.
Now the only challenge with which we left is calling checkFlag
There might be many ways like patching apk, patching map, dynamic debugging.
I choose calling the function[checkFlag] using objection tool
The script i used :
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
console.log("Script loaded successfully "); | |
function callSecretFun() { | |
Java.perform(function () { | |
Java.choose("com.alles.platformer.MyPlatformer", { | |
onMatch: function (instance) { | |
console.log("[+] Found instance: " + instance); | |
console.log("Result of secret func: " + instance.checkFlag()); | |
}, | |
onComplete: function () { | |
console.log("[+] Completed") | |
} | |
}); | |
}); | |
} | |
callSecretFun(); |
Expliotation:
1. Solved the color of questionMark tiles as Color-Key (above), by hand.
2. Then injected that script using objection, then dumping the map_flag.tmx file
Now we need the see the dumped flag map.
I have unpacked it , and changed the map.tmx with this map_flag.tmx and packed it using apktool.
Then installed, opened. Everything is same as before (walls, questionMarkstiles, structure) :(
Again came to pytmx, loaded map_flag.tmx. to check if ther are any hidden layers etc.
Found that there are many(100+) questionMark tiles than normal, something is fishy
Extracted there cordinates, and drawn them with python for rough figure
Those 11 tiles on the upper half are similar to normal map.
Means those extra questionMarks are for drawing the flag , flag is below the map. It's time to jump 👀.
Boom :) Flag : ALLES{1TS_A_DINO}
Awesome writeup!
ReplyDelete