Insomnihack Teaser 2022: Herald
Read more write-ups at kitctf.de.
Challenge description:
Our lab administrator has just passed out from a strange virus. Please help us find the password to his messaging app so we can identify what he was working on and save his life.
We are given an APK (Android Package). When we start it, it asks for a username and password. It does not require any network connection, so it is a classic crackme.
APKs are just ZIP archives, so we can get the contained files by just renaming it to Herald.zip and unzipping. Looking at the source, it becomes clear that this is a React Native application. The real source of a React Native application is located in assets/index.android.bundle. This used to be just minified JavaScript in a webpack bundle. With the file command, however, we can see that it is a modern app with Hermes bytecode. Judging by the challenge name (Herald, like Hermes, the herald of the gods), this is what the challenge is about.
index.android.bundle: Hermes JavaScript bytecode, version 84
There is hbctool that can disassemble Hermes bytecode. The code for version 76 works well for our purposes.
hbctool disasm index.android.bundle labasm
This gives us a 275284 line file of disassembly. Searching through it, we find the Function<tryAuth>4087(3 params, 13 registers, 0 symbols) function. It seems to call all the relevant functions and do the checks. We invert the marked checks (the end-of-line comments show the patched instructions) to get access.
Function<tryAuth>4087(3 params, 13 registers, 0 symbols):
LoadThisNS Reg8:2
GetByIdShort Reg8:0, Reg8:2, UInt8:1, UInt8:121
; Oper[3]: String(121) 'state'
GetById Reg8:0, Reg8:0, UInt8:2, UInt16:4142
; Oper[3]: String(4142) 'username'
LoadConstString Reg8:1, UInt16:801
; Oper[1]: String(801) 'admin'
JStrictNotEqual Addr8:38, Reg8:0, Reg8:1 ; > JStrictEqual Addr8:38, Reg8:0, Reg8:1
GetByIdShort Reg8:0, Reg8:2, UInt8:1, UInt8:121
; Oper[3]: String(121) 'state'
GetById Reg8:3, Reg8:0, UInt8:3, UInt16:4120
; Oper[3]: String(4120) 'password'
GetById Reg8:4, Reg8:2, UInt8:4, UInt16:3485
; Oper[3]: String(3485) 'decodedText'
NewArrayWithBuffer Reg8:0, UInt16:28, UInt16:28, UInt16:9398
Call2 Reg8:0, Reg8:4, Reg8:2, Reg8:0
JStrictEqual Addr8:105, Reg8:3, Reg8:0 ; > JStrictNotEqual Addr8:105, Reg8:3, Reg8:0
GetByIdShort Reg8:0, Reg8:2, UInt8:1, UInt8:121
; Oper[3]: String(121) 'state'
GetById Reg8:0, Reg8:0, UInt8:2, UInt16:4142
; Oper[3]: String(4142) 'username'
JStrictEqual Addr8:45, Reg8:0, Reg8:1 ; > JStrictNotEqual Addr8:45, Reg8:0, Reg8:1
GetEnvironment Reg8:0, UInt8:1
LoadFromEnvironment Reg8:0, Reg8:0, UInt8:6
GetById Reg8:3, Reg8:0, UInt8:5, UInt16:4460
; Oper[3]: String(4460) 'Alert'
GetById Reg8:0, Reg8:3, UInt8:6, UInt16:5067
; Oper[3]: String(5067) 'alert'
LoadConstString Reg8:1, UInt16:1772
; Oper[1]: String(1772) 'Wrong Username/Password combination'
Call2 Reg8:0, Reg8:0, Reg8:3, Reg8:1
GetById Reg8:0, Reg8:2, UInt8:7, UInt16:3904
; Oper[3]: String(3904) 'setPrint'
Call2 Reg8:0, Reg8:0, Reg8:2, Reg8:1
Jmp Addr8:66
GetEnvironment Reg8:0, UInt8:1
LoadFromEnvironment Reg8:0, Reg8:0, UInt8:6
GetById Reg8:3, Reg8:0, UInt8:5, UInt16:4460
; Oper[3]: String(4460) 'Alert'
GetById Reg8:1, Reg8:3, UInt8:6, UInt16:5067
; Oper[3]: String(5067) 'alert'
LoadConstString Reg8:0, UInt16:800
; Oper[1]: String(800) 'You are not the admin, Liar!'
Call2 Reg8:0, Reg8:1, Reg8:3, Reg8:0
GetById Reg8:1, Reg8:2, UInt8:7, UInt16:3904
; Oper[3]: String(3904) 'setPrint'
LoadConstString Reg8:0, UInt16:1312
; Oper[1]: String(1312) 'Attack attempt detected'
Call2 Reg8:0, Reg8:1, Reg8:2, Reg8:0
Jmp Addr8:21
GetById Reg8:1, Reg8:2, UInt8:8, UInt16:3839
; Oper[3]: String(3839) 'decodedFlag'
NewArrayWithBuffer Reg8:0, UInt16:43, UInt16:43, UInt16:9512
Call2 Reg8:0, Reg8:1, Reg8:2, Reg8:0
GetEnvironment Reg8:0, UInt8:1
LoadFromEnvironment Reg8:0, Reg8:0, UInt8:6
GetById Reg8:1, Reg8:0, UInt8:9, UInt16:3819
; Oper[3]: String(3819) 'Keyboard'
GetById Reg8:0, Reg8:1, UInt8:10, UInt16:3822
; Oper[3]: String(3822) 'dismiss'
Call1 Reg8:0, Reg8:0, Reg8:1
LoadConstUndefined Reg8:0
Ret Reg8:0
EndFunction
We can reassemble it, repackage the apk and sign it.
hbctool asm labasm ./Herald/assets/index.android.bundle
apktool b Herald/
java -jar signapk.jar certificate.pem key.pk8 ./Herald/dist/Herald.apk signed.apk
Running the app and logging in with KITCTF, KITCTF gives us the flag.
INS{Y0u_Kn0W_aB0uT_Th3_Her4ld_0F_the_G0ds?}