plaidCTF 2014 - bbos (for350)
bbos
Forensics (350 pts)
-------------------
You have traveled back in time, but look, hunting The Plague is tough.
You're really just going back to relax for a while without having to
worry about all that nonsense. As you walk in the park you stumble
across someone's BlackBerry. Wow, people still use BlackBerry phones
(time travel gets so confusing)? You figure you should return it to the
owner, but you have a hard time getting inside. Figure out what's on
the phone, and maybe we'll be able to return it to the rightful owner.
BlackBerry was this fancy pager thing, right?
Part 1
I’ve never touched a BlackBerry before, but myths of “enterprise”, “security” and “data protection” keep rushing through my mind. WE WILL ALL DIE DUE TO ENCRYPTION WITH TWOHUNDREDFIFTYSIX BIT SECURITY, or something like that.
So there’s an emulator. Surely it does JIT from the ARM code (BlackBerrys are ARM-based, after all), and if the BlackBerry software is implemented in a higher-level language (that may JIT itself on the device), debugging this with an x86 host debugger is going to be FUUUUN.
But don’t despair. Let’s fire up the emulator.
We start the “fledge” thingie, which appears to be a x86 windows
application, by running 9930.bat
, and are greeted by a
loading screen on a virtual BlackBerry. Is this a regular BlackBerry boot screen, or is this the
emulator loading up? I have no idea. A few second later we get this screen:
The message indicates that content protection is just about to cleansweep the device’s memory and remove all the secrets. Maybe that’s the attack - creating a memory dump before this happens? But I’m too slow for that when trying to attach the debugger, and it doesn’t start properly with a debugger already attached.
But let’s see what happens first. We can enter a password:
and are greeted with this screen:
Uh oh, this thing is going to explode after a few more tries:
Let’s attach IDA to fledge.exe. Surely the emulated BlackBerry must be in
memory, so even if all the something-to-ARM-to-x86 JIT-compiled instructions
are hard to disassemble, memory should be fine. Let’s apply the strings
theory (the strings theory is that strings
is faster in finding gold
nuggets than me), and search for… hm… “Password”.
debug020:0030852C aPasswordapi db 'PasswordApi',0
debug020:003091FC aDopasswordapi db ' &doPasswordApi',0
debug020:00309C10 aClassFledgePas db 'class fledge::PasswordApi',0
debug020:00390990 aClassCommonpas db 'class CommonPasswordApi',0
debug020:00394C70 aCommonpassword db 'CommonPasswordApi',0
debug020:00394CE8 aCommonpasswo_0 db 'CommonPasswordApi',0
debug020:00394EC8 aCommonpasswo_1 db 'CommonPasswordApi',0
debug020:003B2988 aWxpasswordentr db 'wxPasswordEntryDialog',0
debug020:003E26B0 aCommonpasswo_2 db 'CommonPasswordApi',0
debug020:003F0E18 aWxte_password db 'wxTE_PASSWORD',0
fledge.exe:00DDBACC aEnterPassword db 'Enter Password',0
fledge.exe:00F08A84 aRimsetpassword db 'RimSetPassword( %p, %p )',0
fledge.exe:00F08AA0 aRimsetpasswo_0 db 'RimSetPassword',0
fledge.exe:00F08ADC aRimgetpassword db 'RimGetPasswordFailureCount( )',0
fledge.exe:00F08AFC aRimgetpasswo_0 db 'RimGetPasswordFailureCount',0
fledge.exe:00F08B18 aRimresetpasswo db 'RimResetPassword( )',0
fledge.exe:00F08B30 aRimresetpass_0 db 'RimResetPassword',0
fledge.exe:00F08B44 aRiminitiateres db 'RimInitiateResetWithCode( %u )',0
fledge.exe:00F08B64 aRiminitiater_0 db 'RimInitiateResetWithCode',0
fledge.exe:00F08B80 aRimverifypassw db 'RimVerifyPasswordChallenge( %p, %lu, %p )',0
fledge.exe:00F08BAC aRimverifypas_0 db 'RimVerifyPasswordChallenge',0
fledge.exe:00F08E88 aRimverifypas_1 db 'RimVerifyPassword( %p )',0
fledge.exe:00F08EA0 aRimverifypas_2 db 'RimVerifyPassword',0
fledge.exe:00F08F40 aRimverifypas_3 db 'RimVerifyPasswords( %p, %p )',0
fledge.exe:00F08F60 aRimverifypas_4 db 'RimVerifyPasswords',0
fledge.exe
is the x86-based emulator. We even see references to these strings
from native x86 code. Let’s breakpoint them all, and re-enter a password,
let’s say the string 2312
.
First, we see that it calls RimGetPasswordFailureCount
(at 007A9CE0
)
before displaying the password prompt. Wait - this is native x86 code. This
is good news. This means that the password checking does not happen in crazy
double-JIT’ed code. It means that this is not an emulator, but a simulator.
It does not emulate an ARM cpu at all. It appears that the BlackBerry OS
is running in JVM with native implementations of - the password API (among
other things). And fledge.exe
implements these in plain x86 code.
Next, we see that it reaches RimVerifyPasswords
(at 007AB950
). We trace
the code, eventually reach 0089DB70
, 10013E50
(fledge9930.dll
’s
RimVerifyPasswordsAPI
; seems there is a device-specific version).
That code is interesting: There’s a magic 0x2801
constant here:
fledge9930.dll:10013DD0 loc_10013DD0: ; CODE XREF:j
fledge9930.dll:10013DD0 sub esp, 80h
fledge9930.dll:10013DD6 push 80h
fledge9930.dll:10013DDB lea eax, [esp+4]
fledge9930.dll:10013DDF push eax
fledge9930.dll:10013DE0 push 2801h
fledge9930.dll:10013DE5 call loc_104FD0B0
fledge9930.dll:10013DEA add esp, 0Ch
fledge9930.dll:10013DED test eax, eax
fledge9930.dll:10013DEF jnz short loc_10013E07
fledge9930.dll:10013DF1 push offset unk_68037B
fledge9930.dll:10013DF6 call near ptr unk_104FCF72
fledge9930.dll:10013DFB add esp, 4
fledge9930.dll:10013DFE xor eax, eax
fledge9930.dll:10013E00 add esp, 80h
fledge9930.dll:10013E06 retn
If we follow loc_104FD0B0, we reach a function that has a debug string of
"NvGetRecordCopy"
. Could 0x2801
be an NV record ID?
We can see that this function fills in this structure:
260BFA30 02 00 01 00 3C 00 00 00 3E 27 0F 54 C6 EB 31 75
260BFA40 B4 EF 8B 20 08 07 95 EF 2E E1 55 89 FF FF FF FF
260BFA50 FF FF FF FF FF FF FF FF 01 00 00 00 0A 00 00 00
260BFA60 CF 2C B0 00 E9 97 92 B2 F0 F8 18 00 A8 2A B0 00
260BFA70 50 2A B0 00 90 8A 70 0D 00 00 00 00 60 8F F0 00
Damn, no plaintext password in sight. Let’s continue to trace.
A few instructions later, we reach this loop:
fledge9930.dll:10013C10 loc_10013C10: ; CODE XREF:j
fledge9930.dll:10013C10 mov dl, [esi+ecx]
fledge9930.dll:10013C13 cmp dl, [ecx]
fledge9930.dll:10013C15 jnz short loc_10013C2A
fledge9930.dll:10013C17 add eax, 1
fledge9930.dll:10013C1A add ecx, 1
fledge9930.dll:10013C1D cmp eax, 14h
fledge9930.dll:10013C20 jb short loc_10013C10
fledge9930.dll:10013C22 pop esi
fledge9930.dll:10013C23 mov eax, 1
fledge9930.dll:10013C28 pop ebp
fledge9930.dll:10013C29 retn
Hey, this is a memcmp()
!. But it has a hardcoded compare length of 0x14
bytes. What is 0x14 bytes in size and doesn’t
look like a plaintext password? A 160-bit SHA1 digest of a password!
Let’s look at the digests that it compares:
260BF9D8 DC A6 84 4C 09 9C E1 CA BD 68 90 E2 F5 31 01 66
260BF9E8 B1 17 30 B8
What does hash to DCA6844C099CE1CABD6890E2F5310166B11730B8
? Is it the
secret password? Question: What is the fastest SHA-1 brute-forcer for
dictionaries? Answer:
google.
“2312”? Wut? Fail, that was the password we have entered. But it confirms that it’s SHA-1.
Ok, let’s take a look at the other argument then:
260BFA38 3E 27 0F 54 C6 EB 31 75 B4 EF 8B 20 08 07 95 EF
260BFA48 2E E1 55 89
Got it! Good thing we can paste into the simulator. We’re greeted with a home screen now:
Let’s just open the email or messages app, read the flag, and be home before dawn.
Except, there is no message. Nor email. But there is a contact!
fuckfuckfucky0uh4h4h4
. Cha-ching 250 pts! And the rest? We’ll follow the
link, and find a NAND dump.
Part 2
(This part was solved by Thice, one of our Eindbazen friends.)
Ok, now we got a raw NAND image. In the original 9930-nv.dmp
, Thice found
this:
0000053000: 00 01 01 28 03 00 00 00 10 CF FF EF 00 00 00 00
0000053010: 00 10 00 00 3C 00 00 00 6F 4A 98 6F 02 00 01 00
0000053020: 3C 00 00 00 3E 27 0F 54 C6 EB 31 75 B4 EF 8B 20
0000053030: 08 07 95 EF 2E E1 55 89 FF FF FF FF FF FF FF FF
0000053040: FF FF FF FF 00 00 00 00 0A 00 00 00 CF 2C B0 00
0000053050: E9 97 92 B2 F0 F8 18 00 4E 56 52 45 FF FF FF FF
Now, 01 28
rings a bell. Looking back, this is what NvGetRecordCopy
loaded into memory when called with the argument 0x2801:
260BFA30 02 00 01 00 3C 00 00 00 3E 27 0F 54 C6 EB 31 75
260BFA40 B4 EF 8B 20 08 07 95 EF 2E E1 55 89 FF FF FF FF
260BFA50 FF FF FF FF FF FF FF FF 01 00 00 00 0A 00 00 00
260BFA60 CF 2C B0 00 E9 97 92 B2 F0 F8 18 00 A8 2A B0 00
260BFA70 50 2A B0 00 90 8A 70 0D 00 00 00 00 60 8F F0 00
So, let’s apply this knowledge to the NAND dump, searching for 00 01 01 28
:
00000B0030: 00 01 01 28 01 00 00 00 F0 26 97 F6 00 00 00 00
00000B0040: D0 0F 00 00 3C 00 00 00 B1 59 BC A1 02 00 01 00
00000B0050: 3C 00 00 00 FF FF FF FF FF FF FF FF FF FF FF FF
00000B0060: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
00000B0070: FF FF FF FF 00 00 00 00 0A 00 00 00 00 00 00 00
00000B0080: FF FF FF FF 00 00 00 00 4E 56 52 45 FF FF FF FF
No dice. No password set. Let’s look further:
0000110030: 00 01 01 28 20 00 00 00 22 38 0F 37 00 00 00 00
0000110040: D0 0F 00 00 3C 00 00 00 B4 15 DB 72 02 00 01 00
0000110050: 3C 00 00 00 5B AA 61 E4 C9 B9 3F 3F 06 82 25 0B
0000110060: 6C F8 33 1B 7E E6 8F D8 FF FF FF FF FF FF FF FF
0000110070: FF FF FF FF 00 00 00 00 0A 00 00 00 00 00 00 00
YES. We got it. The SHA-1 of the flag for the second part is
5BAA61E4C9B93F3F0682250B6CF8331B7EE68FD8
. Let’s google it
up and submit the flag…
password
? Fail.
But never mind. A few instances later we find:
00002E67F0: 00 01 01 28 38 00 00 00 C5 DD 4F 9F 00 00 00 00
00002E6800: 60 00 00 00 3C 00 00 00 C6 17 AD 80 02 00 01 00
00002E6810: 3C 00 00 00 AC 0C FE 7B D0 AE 22 B4 47 22 F1 A0
00002E6820: 1E CB 6C E1 02 CA 27 C5 FF FF FF FF FF FF FF FF
00002E6830: FF FF FF FF 00 00 00 00 0A 00 00 00 00 00 00 00
AC0CFE7BD0AE22B44722F1A01ECB6CE102CA27C5
resolves to
BerryGood
- which is correct. 100 more points for us.