Skip to main content
  1. Posts/

Insomnihack Teaser 2022: Herald

Read more writeups 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) starting it, it asks for username and password to enter. It does not require any network connection, so it is a classical CrackMe.

apks are just zips, 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 a React Native application. The real source is 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, it is about that.

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 (EOL Comments are patches) checks in order 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?}