Over the past few weeks, mortal frailty has caused me to take a break from the usual cyber excellence, in favor of rest, inducing an unfortunate gap in posting. The (very) limited time which I devoted to cyber was spent mostly on continuing exploration of the M3 console. I will document my progress here.
The Quest for an NVRam Primitive
The initial purpose of my investigation of the E5573 device was to implement a “clean” jailbreak, without reliance on previous reverse-engineering black boxes – that is, I would seek to understand every step of the reverse engineering process. In my last post, I demonstrated successfully executing arbitrary code on the device – in this post, we will attempt to leverage this to interact more meaningfully with the device.
From reverse engineering of packaged firmware, we can understand that a password hash is stored in nvram “item” 34 – extracting this would lead to a “clean console”. We continue on from our last post, by reverse engineering the M3 Console application. We start by looking for references to nvram, and can find a few spread throughout the application, for example, at 0x01000557C:
Note that this program doesn’t come with symbols, so we’re reliant on error messages to tell us if we’re in the right place; the symbol names are my own artwork. We want to use this function call to make our own read operations to NVRam – diving in a little deeper now:
000000001000556C 01 20 MOVS R0, #1 ; Rd = Op2 ROM:1000556E 4D F2 28 11 MOVW R1, #0xD128 ; Rd = Op2 ROM:10005572 41 4A LDR R2, =0x1000D638 ; Load from Memory ROM:10005574 0C 23 MOVS R3, #0xC ; Rd = Op2 ROM:10005576 42 4C LDR R4, =(nv_read_wrap+1) ; Load from Memory ROM:10005578 A0 47 BLX R4 ; nv_read_wrap ; Branch with
In the complete abscence of documentaiton, we can start by making some guesses at what’s happening here. My guesswork was as follows:
- R0 is generally “1”, but not always. Let’s call this a reference to the NVRam item.
- R1 is unpredictable. Let’s call it also a reference to an NVRam item.
- R2 is the buffer where output data is stored
- R3 is the length of data read
- R4 is the function call.
We can then build an nvram read probe, as follows:
m 0x10000fcc 0x2001b570 m 0x10000fd0 0x00002131 m 0x10000fd4 0x23224a06 m 0x10000fd8 0x47a04c04 m 0x10000fdc 0x4c02bd70 m 0x10000fe0 0xbd7047a0 m 0x10000fe4 0x100098a0 m 0x10000fe8 0x10000f51 m 0x10000fec 0x100022a5 m 0x10000ff0 0x100098a0 help d 0x100098a0 0x20
The portion in red is a modified version of the above function, setting R1 to “31”. and R0 to “1”, then calling 0x100022a5 (nv_read_wrap in the above) and then writing data to 0x100098a0. This is wrapped in a PUSH / POP wrapper to reset the program counter / return correctly, and is written over the memory address of the “help” function (so “help” does this instead of an actual help call).
Another version is also available, for setting large numbers into R1 (mind the endianness):
m 0x10000fcc 0x2001b570 m 0x10000fd0 0x210ff24d m 0x10000fd4 0x23144a06 m 0x10000fd8 0x47a04c04 m 0x10000fdc 0x4c02bd70 m 0x10000fe0 0xbd7047a0 m 0x10000fe4 0x100098a0 m 0x10000fe8 0x10000f51 m 0x10000fec 0x100022a5 m 0x10000ff0 0x100098a0 help d 0x100098a0 0x20
From here, we can perform some experiments to attempt to dump items from NVRam (I’ll spare you the read: no dice). (Also apologies about the broken formatting below, I’ll fix this eventually).
Large/Small Read Primitive
Data (Paste from ‘d’)
[0040E083][0x100098a0] 00000001 00000000 00000000 00000000 [0040E085][0x100098b0] 00000000 00000000 00000000 00000000
[0163A244][0x100098a0] 00010000 000007d0 000003e8 02008000 [0163A247][0x100098b0] 02058005 01008000 01078002 03008000
[017CDA6A][0x00000019] 00100043 00000000 00000000 00000000 [017CDA6D][0x00000029] 11000000 b310008f 00100002 7b000000
[018E0852][0x100098a0] 00000000 00000000 00000000 00000000 [018E0855][0x100098b0] 00000003 00000000 00000000 00000000
[0238FCB0][0x100098a0] 088dffec 07f0fff6 072c0000 0649000a [0238FCB3][0x100098b0] 05590014 046e001e 03990028 03020030
[02BE7136][0x100098a0] 00000000 00000190 00050001 00000002 [02BE7139][0x100098b0] 00190046 00190046 00000000 00000000
[031E44C2][0x100098a0] ffffffff ffffffff ffffffff ffffffff [031E44C5][0x100098b0] ffffffff ffffffff ffffffff ffffffff
(everything above 0x56 seems to just lock the device or reboot it - watchdog timer?)
[000238D2][0x100098a0] 00010101 00000001 0b22007d 01000100 [000238D5][0x100098b0] 00000001 203a5d73 61096425 2578303d <--- dafuq?
|0x10||Small – Safe||
[011EADF4][0x100098a0] 00000000 000493e0 00000011 00010000 [011EADF7][0x100098b0] ffffffff ffffffff ffffffff ffffffff
|0x20||Small – Safe||
[0011A1DA][0x100098a0] 00000000 00000000 00000000 00000000 [0011A1DD][0x100098b0] 6f695b00 203a5d73 61096425 2578303d
|0x2c||Small – Safe||
[003FD8C5][0x100098a0] 2e323931 2e383631 00312e31 00000000 "192.168.1.1" [003FD8C8][0x100098b0] 6f695b00 203a5d73 61096425 2578303d
|0x2b||Small – Safe||
[0x100098a0] 50475748 30323130 00003131 00000000 "HWGP021011" [0x100098b0] 6f695b00 203a5d73 61096425 2578303d
|0x28||Small – Safe||
[001B2A16][0x100098a0] 00000001 00000000 0000003d 0000003c [001B2A19][0x100098b0] 6f695b00 203a5d73 61096425 2578303d
|0x00 R0 – 0x28||Small – Safe||
[001F5EE3][0x100098a0] 0237003d 022a003e 021d003f 02030041 [001F5EE6][0x100098b0] 6f695b00 203a5d73 61096425 2578303d
|0x00 R0 – 0x20||Small – Safe||
[0046D211][0x100098a0] 00000000 00000000 00000000 00000000 [0046D213][0x100098b0] 6f695b00 203a5d73 61096425 2578303d
|0x00 R0 – 0x2b||Small – Safe||
[00A5877D][0x100098a0] 00010000 00007530 0000ca80 00000000 [00A58780][0x100098b0] 6f695b00 203a5d73 61096425 2578303d
|0x00 R0 – 0x2c||Small – Safe||
[00C4D4AA][0x100098a0] 0000004b 28281428 00000005 00000000 [00C4D4AC][0x100098b0] 6f695b00 203a5d73 61096425 2578303d
|0x00 R0 – 0x41||Small – Safe||
[001667B8][0x100098a0] 10890000 000000b4 00000000 00040000 [001667BB][0x100098b0] 6f695b00 203a5d73 61096425 2578303d
|0x00 R0 – 0x42||Small – Safe||
[003BDB96][0x100098a0] 00000000 00000000 00000000 00000000 [003BDB99][0x100098b0] 6f695b00 203a5d73 61096425 2578303d
Reverse engineering a little further, we can review the actual nvram read operation. We start by diving into the nv_read_wrap function:
Diving in a bit further, we can identify what appears to be a simple memory copy operation, as follows:
A little bit of exploration around the 0x54666BA0 region reveals a few reverences to files which appear to be portions of NVRam (though why these would need filenames, I don’t know). Our next step is to dump the entirety of this memory region.
Stabilizing Memory Dumping
Our first step is to build ourselves a more flexible memory dumping script, as the previous one which we used was prone to dying on resets, and required manual file surgery to fix. This result of this is two Python scripts, as follows:
With these, I am able to dump large chunks of memory. Going back to the device, we can identify two areas of potential interest in the UART boot log:
[000006Bms] [000006Bms]kernel @ 54b10000 (4003784 bytes) [000006Bms]ramdisk @ 55b08000 (494419 bytes) [000006Bms]
We use the above two scripts to dump these memory regions, which you can download here.
Leaving these aside for now, we can attempt to dump the memory region around 0x54666BA0. We can cross-reference our memory dump with forth32’s balong-nvtool, which should hopefully allow us to extract some structure from the nvram file in a useful format. We dd the memory dump such that it begins with the magic signature which nvtool expects (0x224e4944, nvfile.h), and dump the output.
Unfortunately, while this shows slivers of hope, the majority of the file remains unreadable, and the ever-elusive root shell remains tantalizingly close, yet out of grasp.
From here, the next steps in the exploration of the M3 console environment are likely to be:
- Further exploration of the memory space (probably a 4GB dump to an external HDD, followed by strings)
- Understanding how to call regular kernel functions in the 0x54b10000 memory space.
Unfortunately, this project will likely go on hold for a little while, as I seek a return to regular CTF’s, and progression with my electronics / voltage glitching learning.