nc arkos.atredis.com 4444

Johnny Yu (@straight_blast)
30 min readJul 24, 2018

The folks at Atredis (https://twitter.com/Atredis) recently posted a binary challenge to get the community pumped up for the upcoming Blackhat/Defcon events in Las Vegas.

https://twitter.com/Atredis/status/1018921636337258496

Poking Around

I connected to the server (arkos.atredis.com:4444) and it displayed information that are useful to solving the challenge:

  1. I learn the memory layout for this machine
  2. I learn it has a /etc/motd, so the file system is UNIX based
  3. It indicated to be a 8-bits computing machine
  4. There is e-mail
  5. The attachment is not included in the e-mail, but is “extracted to disk”

Based on the above observation, it appears the goal is to recover the e-mail’s attachment.

At the prompt, I entered “ls” and it returned an error. I entered “help” and it returned some useful information:

Now that I learned about the existence of the “read <address>” command, I can use it to dump the entire memory space.

Dumping Memory Map

A python script was created to dump the memory:

#!/usr/bin/python
# arkos_memory_dump.py
import socket
host = 'arkos.atredis.com'
port = 4444
socket.setdefaulttimeout(10)
s = socket.create_connection((host,port))
f = s.makefile('rw', bufsize=0)
def readuntil(delim='arkos>'):
data = ''
while not data.endswith(delim):
data += f.read(1)
return data
def extract(begin, end):
buf = ''
for i in xrange(begin, end + 1):
cmd = 'read %04X' % i
f.write(cmd + '\n')
output = readuntil()
byte = output.split('=')[1][2:4]
byte = chr(int(byte, 16))
buf += byte
return buf
def save(filename, begin, end):
fio = open(filename, 'w')
content = extract(begin, end)
fio.write(content)
fio.close()
if __name__ == '__main__':
readuntil()
print 'Extracting RAM1 [0x000 - 0x00FF]'
save('ram1', 0x0000, 0x00FF)
print 'Finish Extracting - ram1'
print
print 'Extracting RAM2-STACK [0x0100 - 0x01FF]'
save('ram2_stack', 0x0100, 0x01FF)
print 'Finish Extracting - ram2 - stack'
print

print 'Extracting RAM3 [0x0200 - 0x1FFF]'
save('ram3', 0x0200, 0x1fff)
print 'Finish Extracting - ram3'
print

print 'Extracting UNKNOWN [0x2000 - 0x3FFF]'
save('unknown', 0x2000, 0x3fff)
print 'Finish Extracting - unknown'
print
print 'Extracting PROM1 [0x4000 - 0xEFFF]'
save('prom1', 0x4000, 0xefff)
print 'Finish Extracting - prom1'
print
# Skipped extracting content at 0xF000
# The value cannot be retrieved
print 'Extracting MMIO [0xF001 - 0xFF00]'
print 'Skipped 0xF000'
save('mmio', 0xF001, 0xFF00)
print 'Finish Extracting MMIO'
print

print 'Extracting PROM2 [0xFF00 - 0xFFFF]'
save('prom2', 0xFF00, 0xFFFF)
print 'Finish Extracting - PROM2'
print

The above script connects to the game box and run the “read <address>” command starting at address 0x0000 to 0xFFFF and write the content into a file. It should be noted that the content at address 0xF000 cannot be retrieved. I later found out that 0xF000 holds the content of STDIN.

Reading the dump

The following are what I observed as interesting from the memory dump:

The following dump is the ram and ram-stack, the stack starts at 0x0100 and runs to 0x01FF. Based on the dump, partial file content are stored in this area. The ram that starts at 0x0000 to 0x00FF contains data I have no clue of.

00000000: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000010: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000020: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000030: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000040: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000050: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000060: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000070: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000080: 8c41 1040 a741 4501 0000 0000 2401 4501 .A.@.AE.....$.E.
00000090: 9000 0000 0032 4117 0002 2401 0000 2501 .....2A...$...%.
000000a0: 0900 0000 0000 0000 0000 0000 0000 0000 ................
000000b0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
000000c0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
000000d0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
000000e0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
000000f0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000100: 6d0a 0a3c 3c20 4154 5441 4348 4d45 4e54 m..<< ATTACHMENT
00000110: 2045 5854 5241 4354 4544 2054 4f20 4449 EXTRACTED TO DI
00000120: 534b 203e 3e0a 0000 0000 0000 0000 0000 SK >>...........
00000130: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000140: 7265 6164 2030 3134 3800 0000 0000 0000 read 0148.......
00000150: 0000 0000 0000 0000 0000 0000 0000 0000 ................

The following dump is prom1. It runs from 0x4000 to 0xEFFF and is where the firmware resides. The first section appears to be strings that is used in the firmware, I recognized them from the console output when I connected to the game box. When I looked carefully at line 0x41a0, it indicates there is a “write” and “call” command.

00003ff0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00004000: 3031 3233 3435 3637 3839 6162 6364 6566 0123456789abcdef
00004010: 6469 736b 5f72 6561 645f 7365 6374 6f72 disk_read_sector
00004020: 0053 7461 7274 696e 6720 4172 6b4f 532e .Starting ArkOS.
00004030: 2e2e 0046 6972 6d77 6172 6520 7665 7273 ...Firmware vers
00004040: 696f 6e3a 2000 312e 312e 4200 4861 7264 ion: .1.1.B.Hard
00004050: 7761 7265 2076 6572 7369 6f6e 3a20 004d ware version: .M
00004060: 656d 6f72 7920 6d61 703a 0a00 2020 2430 emory map:.. $0
00004070: 3030 303a 2430 3046 4620 2d20 5241 4d0a 000:$00FF - RAM.
00004080: 0020 2024 3031 3030 3a24 3031 4646 202d . $0100:$01FF -
00004090: 2052 414d 2028 7374 6163 6b29 0a00 2020 RAM (stack)..
000040a0: 2430 3230 303a 2431 4646 4620 2d20 5241 $0200:$1FFF - RA
000040b0: 4d0a 0020 2024 3430 3030 3a24 4546 4646 M.. $4000:$EFFF
000040c0: 202d 2050 524f 4d0a 0020 2024 4630 3030 - PROM.. $F000
000040d0: 3a24 4646 3030 202d 204d 4d49 4f0a 0020 :$FF00 - MMIO..
000040e0: 2024 4646 3030 3a24 4646 4646 202d 2050 $FF00:$FFFF - P
000040f0: 524f 4d0a 002f 6574 632f 6d6f 7464 0045 ROM../etc/motd.E
00004100: 5252 4f52 3a20 6661 696c 6564 2074 6f20 RROR: failed to
00004110: 6669 6e64 202f 6574 632f 6d6f 7464 0a00 find /etc/motd..
00004120: 466f 756e 6420 2f65 7463 2f6d 6f74 6421 Found /etc/motd!
00004130: 0a00 2f76 6172 2f6d 6169 6c2f 7370 6f6f ../var/mail/spoo
00004140: 6c2f 6174 7265 6469 7300 4368 6563 6b69 l/atredis.Checki
00004150: 6e67 206d 6169 6c20 666f 7220 7573 6572 ng mail for user
00004160: 2061 7472 6564 6973 2e2e 2e0a 0046 6f75 atredis.....Fou
00004170: 6e64 206d 6169 6c21 0a0a 004e 6f20 6d61 nd mail!...No ma
00004180: 696c 2e0a 0061 726b 6f73 3e20 0049 6e76 il...arkos> .Inv
00004190: 616c 6964 2063 6f6d 6d61 6e64 0a00 6865 alid command..he
000041a0: 6c70 7265 6164 2077 7269 7465 2063 616c lpread write cal
000041b0: 6c20 0a43 6f6d 6d61 6e64 733a 0a20 2068 l .Commands:. h
000041c0: 656c 700a 2020 2020 5468 6973 206d 6573 elp. This mes
000041d0: 7361 6765 0a20 2072 6561 640a 2020 2020 sage. read.
000041e0: 2772 6561 6420 4634 3030 2720 7265 6164 'read F400' read
000041f0: 7320 7468 6520 6279 7465 2061 7420 2446 s the byte at $F
00004200: 3430 300a 0000 0000 0000 0000 0000 0000 400.............
00004210: 0000 0000 0000 0000 0000 0000 0000 0000 ................

The remaining content from prom 1 is a bunch of gibberish. I suspect these content are assembly code.

00008000: 60a5 88c9 00d0 09a5 89c9 00d0 03a9 0060  `..............`
00008010: a200 a184 c186 f003 a901 60e6 84d0 02e6 ..........`.....
00008020: 85e6 86d0 02e6 87a5 88c9 00d0 02c6 89c6 ................
00008030: 884c 0180 a910 8582 a940 8583 2000 80a5 .L.......@.. ...
00008040: 8c8d 10f2 a58d 8d11 f2a9 008d 20f2 a901 ............ ...
00008050: 8d21 f2a9 818d 01f2 60a9 0085 99a5 9985 .!......`.......
00008060: 8ca9 0085 8d20 3480 a595 8584 a596 8585 ..... 4.........
00008070: a900 8586 a901 8587 a597 8588 a598 8589 ................
00008080: 2001 80c9 00f0 0be6 99a5 99c9 40d0 cea9 ...........@...
00008090: 0160 a900 60ad 00f0 608d 01f0 60a2 00a1 .`..`...`...`...
000080a0: 808d 01f0 c900 f009 e680 d002 e681 4c9d ..............L.
000080b0: 8060 c930 3014 c940 3019 c941 300c c947 .`.00..@0..A0..G
000080c0: 300b c961 3004 c967 3003 a9ff 6029 0f18 0..a0..g0...`)..
000080d0: 6909 6029 0f60 a200 a18e 20b2 80c9 fff0 i.`).`.... .....
000080e0: 380a 0a0a 0a85 91a0 01b1 8e20 b280 c9ff 8.......... ....
000080f0: f027 0591 8591 a002 b18e 20b2 80c9 fff0 .'........ .....
00008100: 180a 0a0a 0a85 90a0 03b1 8e20 b280 c9ff ........... ....
00008110: f007 0590 8590 a900 60a9 ff60 a200 a192 ........`..`....
00008120: 20b2 80c9 fff0 180a 0a0a 0a85 94a0 01b1 ...............
00008130: 9220 b280 c9ff f007 0594 8594 a900 60a9 . ............`.
00008140: ff60 aa4a 4a4a 4aa8 b900 4020 9980 8a29 .`.JJJJ...@ ...)
00008150: 0fa8 b900 4020 9980 60a9 0a20 9980 a90d ....@ ..`.. ....
00008160: 2099 8060 a000 9848 b18a 2042 81a9 2020 ..`...H.. B..
00008170: 9980 68a8 c8c0 10d0 ed20 5981 60a9 5f85 ..h...... Y.`._.
00008180: 80a9 4085 8120 9d80 a96c 8580 a940 8581 ..@.. ...l...@..
00008190: 209d 80a9 8185 80a9 4085 8120 9d80 a99e .......@.. ....
000081a0: 8580 a940 8581 209d 80a9 b385 80a9 4085 ...@.. .......@.
000081b0: 8120 9d80 a9c9 8580 a940 8581 209d 80a9 . .......@.. ...
000081c0: df85 80a9 4085 8120 9d80 60a9 2185 80a9 ....@.. ..`.!...
000081d0: 4085 8120 9d80 2059 81a9 4c85 80a9 4085 @.. .. Y..L...@.
000081e0: 8120 9d80 a900 8580 a9f4 8581 209d 8020 . .......... ..
000081f0: 5981 a933 8580 a940 8581 209d 80a9 4685 Y..3...@.. ...F.
00008200: 80a9 4085 8120 9d80 2059 8120 7d81 60a5 ..@.. .. Y. }.`.
00008210: 9a85 8ca5 9b85 8d20 3480 a200 bd00 01c9 ....... 4.......
00008220: 00f0 0820 9980 e8e0 40d0 f160 a230 bd00 ... ....@..`.0..
00008230: 0185 9ee8 bd00 0185 9fe8 bd00 0185 9ce8 ................
00008240: bd00 0185 9da5 9cc9 00d0 06a5 9dc9 00f0 ................
00008250: 1ea5 9e85 9aa5 9f85 9b20 0f82 a59c c900 ......... ......
00008260: d002 c69d c69c e69e d002 e69f 4c45 8260 ............LE.`
00008270: a9f5 8595 a940 8596 a907 8597 a900 8598 .....@..........
00008280: 2059 80c9 00d0 0fa9 2085 80a9 4185 8120 Y...... ...A..
00008290: 9d80 202c 8260 a9ff 8580 a940 8581 209d .. ,.`.....@.. .
000082a0: 8060 a94a 8580 a941 8581 209d 80a9 3285 .`.J...A.. ...2.
000082b0: 95a9 4185 96a9 1785 97a9 0085 9820 5980 ..A.......... Y.
000082c0: c900 d00f a96d 8580 a941 8581 209d 8020 .....m...A.. ..
000082d0: 2c82 60a9 7b85 80a9 4185 8120 9d80 60a9 ,.`.{...A.. ..`.
000082e0: 0085 a020 9580 c90a f00c a6a0 9d40 01e8 ... .........@..
000082f0: 86a0 e03f d0ed a6a0 a900 9d40 0160 a99e ...?.......@.`..
00008300: 8584 a941 8585 a940 8586 a901 8587 a904 ...A...@........
00008310: 8588 a900 8589 2001 80c9 00f0 03a9 0060 ...... ........`
00008320: a9b2 8580 a941 8581 209d 80a9 0160 a9a2 .....A.. ....`..
00008330: 8584 a941 8585 a940 8586 a901 8587 a905 ...A...@........
00008340: 8588 a900 8589 2001 80c9 00f0 03a9 0060 ...... ........`
00008350: a940 858e a901 858f e68e d002 e68f e68e .@..............
00008360: d002 e68f e68e d002 e68f e68e d002 e68f ................
00008370: e68e d002 e68f 20d6 80a9 2420 9980 a591 ...... ...$ ....
00008380: 2042 81a5 9020 4281 a920 2099 80a9 3d20 B... B.. ...=
00008390: 9980 a920 2099 80a9 2420 9980 a200 a190 ... ...$ ......
000083a0: 2042 8120 5981 a901 60a9 a785 84a9 4185 B. Y...`.....A.
000083b0: 85a9 4085 86a9 0185 87a9 0685 88a9 0085 ..@.............
000083c0: 8920 0180 c900 f003 a900 60a9 4085 8ea9 . ........`.@...
000083d0: 0185 8fe6 8ed0 02e6 8fe6 8ed0 02e6 8fe6 ................
000083e0: 8ed0 02e6 8fe6 8ed0 02e6 8fe6 8ed0 02e6 ................
000083f0: 8fe6 8ed0 02e6 8fa5 8e85 92a5 8f85 93e6 ................
00008400: 92d0 02e6 93e6 92d0 02e6 93e6 92d0 02e6 ................
00008410: 93e6 92d0 02e6 93e6 92d0 02e6 9320 d680 ............. ..
00008420: 201c 81a9 2420 9980 a591 2042 81a5 9020 ...$ .... B...
00008430: 4281 a920 2099 80a9 3a20 9980 a93d 2099 B.. ...: ...= .
00008440: 80a9 2020 9980 a924 2099 80a5 9420 4281 .. ...$ .... B.
00008450: 2059 81a2 00a5 9481 90a9 0160 a9ad 8584 Y.........`....
00008460: a941 8585 a940 8586 a901 8587 a905 8588 .A...@..........
00008470: a900 8589 2001 80c9 00f0 03a9 0060 a940 .... ........`.@
00008480: 858e a901 858f e68e d002 e68f e68e d002 ................
00008490: e68f e68e d002 e68f e68e d002 e68f e68e ................
000084a0: d002 e68f 20d6 80a9 6a20 9980 a973 2099 .... ...j ...s .
000084b0: 80a9 7220 9980 a920 2099 80a9 2420 9980 ..r ... ...$ ..
000084c0: a591 2042 81a5 9020 4281 2059 81a2 00a9 .. B... B. Y....
000084d0: 209d 8001 e8a5 909d 8001 e8a5 919d 8001 ...............
000084e0: e8a9 609d 8001 e820 8001 a901 6020 fe82 ..`.... ....` ..
000084f0: c900 d022 202e 83c9 00d0 1b20 a983 c900 ..." ...... ....
00008500: d014 205c 84c9 00d0 0da9 8d85 80a9 4185 .. \..........A.
00008510: 8120 9d80 a901 6020 5981 a985 8580 a941 . ....` Y......A
00008520: 8581 209d 8020 df82 20ed 84c9 ffd0 e860 .. .. .. ......`
00008530: 20cb 8120 7082 20a2 8220 1785 4c3c 8560 .. p. .. ..L<.`
00008540: 4040 0000 0000 0000 0000 0000 0000 0000 @@..............

The arkOS memory map can be downloaded from appendix I

The “write” and “call” command

The “write” command takes two arguments, the address to store the value, and the byte to write. The “call” command takes one argument, and is the address to jump to:

It should be noted that when the “call” command is executed, it outputted “jsr <address>”. Googling what “jsr” with “8 bits assembly” indicates it to be 6502 assembly instruction.

Arbitrary File Read?

When I observed the console output, I noticed that it checks to see if mail exists on the system. Further review of the firmware indicated the path of where the mail is at on address 0x4130.

00004130: 0a00 2f76 6172 2f6d 6169 6c2f 7370 6f6f  ../var/mail/spoo
00004140: 6c2f 6174 7265 6469 7300 4368 6563 6b69 l/atredis.Checki
00004150: 6e67 206d 6169 6c20 666f 7220 7573 6572 ng mail for user
00004160: 2061 7472 6564 6973 2e2e 2e0a 0046 6f75 atredis.....Fou
00004170: 6e64 206d 6169 6c21 0a0a 004e 6f20 6d61 nd mail!...No ma
00004180: 696c 2e0a 0061 726b 6f73 3e20 0049 6e76 il...arkos> .Inv

My goal is to change the path “/var/mail/spool/atredis” to another path and see if I can retrieve arbitrary files.

I created the following script that will alter the address that currently holds the path “/var/mail/spool/atredis” to arbitrary path:

#!/usr/bin/python
import socket
import sys
host = 'arkos.atredis.com'
port = 4444
socket.setdefaulttimeout(10)
s = socket.create_connection((host,port))
f = s.makefile('rw', bufsize=0)
def readuntil(delim='\n\n'):
data = ''
while not data.endswith(delim):
data += f.read(1)
return data
if __name__ == '__main__':
print readuntil('arkos>')
i = 0
s = 0x40FF + 0x33
e = 0x40FF + 0x50
path = sys.argv[1]
max_len = 23
if len(path) <= max_len:
for i in xrange(len(path)):
f.write('write %04X %02X\n' % (s+i, ord(path[i])))
print readuntil('arkos>')
for i in xrange(len(path), max_len):
f.write('write %04X %02X\n' % (s+i, 0))
print readuntil('arkos>')
f.write('call 0000\n')
print readuntil('arkos>')

I tested out by trying to retrieve “/etc/motd” since I know it exists, based on the console output.

The result:

./read_file.py /etc/motd
Starting ArkOS...
Hardware version: 1.0.3 rev A
Firmware version: 1.1.B
Memory map:
$0000:$00FF - RAM
$0100:$01FF - RAM (stack)
$0200:$1FFF - RAM
$4000:$EFFF - PROM
$F000:$FF00 - MMIO
$FF00:$FFFF - PROM
Found /etc/motd!
************************************************************
This service is restricted to authorized users only. All
activities on this system are logged. Unauthorized access
will be fully investigated and reported to the appropriate
lifestyle assessment organization for permanent lifestyle
adjustment treatment.
************************************************************
_ ___ ____ ____
dM. `MM 6MMMMb 6MMMMb\
,MMb MM 8P Y8 6M' `
d'YM. ___ __ MM __ 6M Mb MM
,P `Mb `MM 6MM MM d' MM MM YM.
d' YM. MM69 " MM d' MM MM YMMMMb
,P `Mb MM' MM d' MM MM `Mb
d' YM. MM MMdM. MM MM MM
,MMMMMMMMb MM MMPYM. YM M9 MM
d' YM. MM MM YM. 8b d8 L ,M9
_dM_ _dMM_MM_ _MM_ YM._ YMMMM9 MYMMMM9
"Supervising" your computing 8-bits at a timegr33tz: merlin, chumbo, and m4xzChecking mail for user atredis...
Found mail!
From: Some Person <office-of-indoctrination@atredis.com>
Subject: Blackhat Tickets for the Contest
Date: Mon, 9 Jul 2018 07:12:48 -0700
To: Player <atredis@arkos.atredis.com>
Content-Type: text/plain; charset=us-ascii
Friend,Please find more details regarding the BH ticket contest attached.--
http://www.atredis.com
<< ATTACHMENT EXTRACTED TO DISK >>arkos>
$4132 := $2f
arkos>
$4133 := $65
arkos>
$4134 := $74
arkos>
$4135 := $63
arkos>
$4136 := $2f
arkos>
$4137 := $6d
arkos>
$4138 := $6f
arkos>
$4139 := $74
arkos>
$413a := $64
arkos>
$413b := $00
arkos>
$413c := $00
arkos>
$413d := $00
arkos>
$413e := $00
arkos>
$413f := $00
arkos>
$4140 := $00
arkos>
$4141 := $00
arkos>
$4142 := $00
arkos>
$4143 := $00
arkos>
$4144 := $00
arkos>
$4145 := $00
arkos>
$4146 := $00
arkos>
$4147 := $00
arkos>
$4148 := $00
arkos>
jsr $0000
Starting ArkOS...
Hardware version: 1.0.3 rev A
Firmware version: 1.1.B
Memory map:
$0000:$00FF - RAM
$0100:$01FF - RAM (stack)
$0200:$1FFF - RAM
$4000:$EFFF - PROM
$F000:$FF00 - MMIO
$FF00:$FFFF - PROM
Found /etc/motd!
************************************************************
This service is restricted to authorized users only. All
activities on this system are logged. Unauthorized access
will be fully investigated and reported to the appropriate
lifestyle assessment organization for permanent lifestyle
adjustment treatment.
************************************************************
_ ___ ____ ____
dM. `MM 6MMMMb 6MMMMb\
,MMb MM 8P Y8 6M' `
d'YM. ___ __ MM __ 6M Mb MM
,P `Mb `MM 6MM MM d' MM MM YM.
d' YM. MM69 " MM d' MM MM YMMMMb
,P `Mb MM' MM d' MM MM `Mb
d' YM. MM MMdM. MM MM MM
,MMMMMMMMb MM MMPYM. YM M9 MM
d' YM. MM MM YM. 8b d8 L ,M9
_dM_ _dMM_MM_ _MM_ YM._ YMMMM9 MYMMMM9
"Supervising" your computing 8-bits at a timegr33tz: merlin, chumbo, and m4xzChecking mail for user atredis...
Found mail!
************************************************************
This service is restricted to authorized users only. All
activities on this system are logged. Unauthorized access
will be fully investigated and reported to the appropriate
lifestyle assessment organization for permanent lifestyle
adjustment treatment.
************************************************************
_ ___ ____ ____
dM. `MM 6MMMMb 6MMMMb\
,MMb MM 8P Y8 6M' `
d'YM. ___ __ MM __ 6M Mb MM
,P `Mb `MM 6MM MM d' MM MM YM.
d' YM. MM69 " MM d' MM MM YMMMMb
,P `Mb MM' MM d' MM MM `Mb
d' YM. MM MMdM. MM MM MM
,MMMMMMMMb MM MMPYM. YM M9 MM
d' YM. MM MM YM. 8b d8 L ,M9
_dM_ _dMM_MM_ _MM_ YM._ YMMMM9 MYMMMM9
"Supervising" your computing 8-bits at a timegr33tz: merlin, chumbo, and m4xzarkos>

It works, and I immediately went to try and retrieve things like “/etc/passwd”, and just guessing file path like “/home/atredis/flag.txt”, which all leads to failure.

Before I give up in despair, I saw the following tweet that suggested there should be another way.

https://twitter.com/natronkeltner/status/1019256574659956741

Is R2 time

I decided to take a look at the gibberish content starting at address 0x8000 to 0x8540. Based on the output “jsr” from the “call” command, I decided to see if the gibberish could be interpreted as something meaningful in 6502 assembly.

I extracted the byte code from the firmware and dropped it into http://www.masswerk.at/6502/disassembler.html

» xxd -g1 arkos_map | grep "00008000" -A 84 | cut -c 11- | cut -c -48
60 a5 88 c9 00 d0 09 a5 89 c9 00 d0 03 a9 00 60
a2 00 a1 84 c1 86 f0 03 a9 01 60 e6 84 d0 02 e6
85 e6 86 d0 02 e6 87 a5 88 c9 00 d0 02 c6 89 c6
88 4c 01 80 a9 10 85 82 a9 40 85 83 20 00 80 a5
8c 8d 10 f2 a5 8d 8d 11 f2 a9 00 8d 20 f2 a9 01
8d 21 f2 a9 81 8d 01 f2 60 a9 00 85 99 a5 99 85
8c a9 00 85 8d 20 34 80 a5 95 85 84 a5 96 85 85
a9 00 85 86 a9 01 85 87 a5 97 85 88 a5 98 85 89
20 01 80 c9 00 f0 0b e6 99 a5 99 c9 40 d0 ce a9
01 60 a9 00 60 ad 00 f0 60 8d 01 f0 60 a2 00 a1
80 8d 01 f0 c9 00 f0 09 e6 80 d0 02 e6 81 4c 9d
80 60 c9 30 30 14 c9 40 30 19 c9 41 30 0c c9 47
30 0b c9 61 30 04 c9 67 30 03 a9 ff 60 29 0f 18
69 09 60 29 0f 60 a2 00 a1 8e 20 b2 80 c9 ff f0
38 0a 0a 0a 0a 85 91 a0 01 b1 8e 20 b2 80 c9 ff
f0 27 05 91 85 91 a0 02 b1 8e 20 b2 80 c9 ff f0
18 0a 0a 0a 0a 85 90 a0 03 b1 8e 20 b2 80 c9 ff
f0 07 05 90 85 90 a9 00 60 a9 ff 60 a2 00 a1 92
20 b2 80 c9 ff f0 18 0a 0a 0a 0a 85 94 a0 01 b1
92 20 b2 80 c9 ff f0 07 05 94 85 94 a9 00 60 a9
ff 60 aa 4a 4a 4a 4a a8 b9 00 40 20 99 80 8a 29
0f a8 b9 00 40 20 99 80 60 a9 0a 20 99 80 a9 0d
20 99 80 60 a0 00 98 48 b1 8a 20 42 81 a9 20 20
99 80 68 a8 c8 c0 10 d0 ed 20 59 81 60 a9 5f 85
80 a9 40 85 81 20 9d 80 a9 6c 85 80 a9 40 85 81
20 9d 80 a9 81 85 80 a9 40 85 81 20 9d 80 a9 9e
85 80 a9 40 85 81 20 9d 80 a9 b3 85 80 a9 40 85
81 20 9d 80 a9 c9 85 80 a9 40 85 81 20 9d 80 a9
df 85 80 a9 40 85 81 20 9d 80 60 a9 21 85 80 a9
40 85 81 20 9d 80 20 59 81 a9 4c 85 80 a9 40 85
81 20 9d 80 a9 00 85 80 a9 f4 85 81 20 9d 80 20
59 81 a9 33 85 80 a9 40 85 81 20 9d 80 a9 46 85
80 a9 40 85 81 20 9d 80 20 59 81 20 7d 81 60 a5
9a 85 8c a5 9b 85 8d 20 34 80 a2 00 bd 00 01 c9
00 f0 08 20 99 80 e8 e0 40 d0 f1 60 a2 30 bd 00
01 85 9e e8 bd 00 01 85 9f e8 bd 00 01 85 9c e8
bd 00 01 85 9d a5 9c c9 00 d0 06 a5 9d c9 00 f0
1e a5 9e 85 9a a5 9f 85 9b 20 0f 82 a5 9c c9 00
d0 02 c6 9d c6 9c e6 9e d0 02 e6 9f 4c 45 82 60
a9 f5 85 95 a9 40 85 96 a9 07 85 97 a9 00 85 98
20 59 80 c9 00 d0 0f a9 20 85 80 a9 41 85 81 20
9d 80 20 2c 82 60 a9 ff 85 80 a9 40 85 81 20 9d
80 60 a9 4a 85 80 a9 41 85 81 20 9d 80 a9 32 85
95 a9 41 85 96 a9 17 85 97 a9 00 85 98 20 59 80
c9 00 d0 0f a9 6d 85 80 a9 41 85 81 20 9d 80 20
2c 82 60 a9 7b 85 80 a9 41 85 81 20 9d 80 60 a9
00 85 a0 20 95 80 c9 0a f0 0c a6 a0 9d 40 01 e8
86 a0 e0 3f d0 ed a6 a0 a9 00 9d 40 01 60 a9 9e
85 84 a9 41 85 85 a9 40 85 86 a9 01 85 87 a9 04
85 88 a9 00 85 89 20 01 80 c9 00 f0 03 a9 00 60
a9 b2 85 80 a9 41 85 81 20 9d 80 a9 01 60 a9 a2
85 84 a9 41 85 85 a9 40 85 86 a9 01 85 87 a9 05
85 88 a9 00 85 89 20 01 80 c9 00 f0 03 a9 00 60
a9 40 85 8e a9 01 85 8f e6 8e d0 02 e6 8f e6 8e
d0 02 e6 8f e6 8e d0 02 e6 8f e6 8e d0 02 e6 8f
e6 8e d0 02 e6 8f 20 d6 80 a9 24 20 99 80 a5 91
20 42 81 a5 90 20 42 81 a9 20 20 99 80 a9 3d 20
99 80 a9 20 20 99 80 a9 24 20 99 80 a2 00 a1 90
20 42 81 20 59 81 a9 01 60 a9 a7 85 84 a9 41 85
85 a9 40 85 86 a9 01 85 87 a9 06 85 88 a9 00 85
89 20 01 80 c9 00 f0 03 a9 00 60 a9 40 85 8e a9
01 85 8f e6 8e d0 02 e6 8f e6 8e d0 02 e6 8f e6
8e d0 02 e6 8f e6 8e d0 02 e6 8f e6 8e d0 02 e6
8f e6 8e d0 02 e6 8f a5 8e 85 92 a5 8f 85 93 e6
92 d0 02 e6 93 e6 92 d0 02 e6 93 e6 92 d0 02 e6
93 e6 92 d0 02 e6 93 e6 92 d0 02 e6 93 20 d6 80
20 1c 81 a9 24 20 99 80 a5 91 20 42 81 a5 90 20
42 81 a9 20 20 99 80 a9 3a 20 99 80 a9 3d 20 99
80 a9 20 20 99 80 a9 24 20 99 80 a5 94 20 42 81
20 59 81 a2 00 a5 94 81 90 a9 01 60 a9 ad 85 84
a9 41 85 85 a9 40 85 86 a9 01 85 87 a9 05 85 88
a9 00 85 89 20 01 80 c9 00 f0 03 a9 00 60 a9 40
85 8e a9 01 85 8f e6 8e d0 02 e6 8f e6 8e d0 02
e6 8f e6 8e d0 02 e6 8f e6 8e d0 02 e6 8f e6 8e
d0 02 e6 8f 20 d6 80 a9 6a 20 99 80 a9 73 20 99
80 a9 72 20 99 80 a9 20 20 99 80 a9 24 20 99 80
a5 91 20 42 81 a5 90 20 42 81 20 59 81 a2 00 a9
20 9d 80 01 e8 a5 90 9d 80 01 e8 a5 91 9d 80 01
e8 a9 60 9d 80 01 e8 20 80 01 a9 01 60 20 fe 82
c9 00 d0 22 20 2e 83 c9 00 d0 1b 20 a9 83 c9 00
d0 14 20 5c 84 c9 00 d0 0d a9 8d 85 80 a9 41 85
81 20 9d 80 a9 01 60 20 59 81 a9 85 85 80 a9 41
85 81 20 9d 80 20 df 82 20 ed 84 c9 ff d0 e8 60
20 cb 81 20 70 82 20 a2 82 20 17 85 4c 3c 85 60
40 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00

The outputted assembly appears to make senses:

Now, I am more confident the byte code are 6502 assembly, and I can further review them using Radare2.

# r2 -a 6502 arkos_map
-- Your r2 was built 20h ago. TOO OLD!
[0x00000000]> aaa
[x] Analyze all flags starting with sym. and entry0 (aa)
[ ]
[Value from 0x00000000 to 0x00010000
aav: 0x00000000-0x00010000 in 0x0-0x10000
[ WARNING : block size exceeding max block size at 0x00005441
[+] Try changing it with e anal.bb.maxsize
WARNING : block size exceeding max block size at 0x00005845
[+] Try changing it with e anal.bb.maxsize
WARNING : block size exceeding max block size at 0x00004f54
[+] Try changing it with e anal.bb.maxsize
WARNING : block size exceeding max block size at 0x00004944
[+] Try changing it with e anal.bb.maxsize
WARNING : block size exceeding max block size at 0x00003130
[+] Try changing it with e anal.bb.maxsize
WARNING : block size exceeding max block size at 0x00007241
[+] Try changing it with e anal.bb.maxsize
WARNING : block size exceeding max block size at 0x00002420
[+] Try changing it with e anal.bb.maxsize
WARNING : block size exceeding max block size at 0x00007328
[+] Try changing it with e anal.bb.maxsize
WARNING : block size exceeding max block size at 0x00006166
[+] Try changing it with e anal.bb.maxsize
WARNING : block size exceeding max block size at 0x00006f74
[+] Try changing it with e anal.bb.maxsize
WARNING : block size exceeding max block size at 0x00006966
[+] Try changing it with e anal.bb.maxsize
WARNING : block size exceeding max block size at 0x0000652f
[+] Try changing it with e anal.bb.maxsize
WARNING : block size exceeding max block size at 0x0000616d
[+] Try changing it with e anal.bb.maxsize
WARNING : block size exceeding max block size at 0x00006f66
[+] Try changing it with e anal.bb.maxsize
WARNING : block size exceeding max block size at 0x00007375
[+] Try changing it with e anal.bb.maxsize
WARNING : block size exceeding max block size at 0x00007461
[+] Try changing it with e anal.bb.maxsize
WARNING : block size exceeding max block size at 0x00006f63
[+] Try changing it with e anal.bb.maxsize
WARNING : block size exceeding max block size at 0x00007277
[+] Try changing it with e anal.bb.maxsize
WARNING : block size exceeding max block size at 0x00006820
[+] Try changing it with e anal.bb.maxsize
WARNING : block size exceeding max block size at 0x00002020
[+] Try changing it with e anal.bb.maxsize
WARNING : block size exceeding max block size at 0x00006854
[+] Try changing it with e anal.bb.maxsize
WARNING : block size exceeding max block size at 0x0000656d
[+] Try changing it with e anal.bb.maxsize
WARNING : block size exceeding max block size at 0x00007220
[+] Try changing it with e anal.bb.maxsize
WARNING : block size exceeding max block size at 0x00007227
[+] Try changing it with e anal.bb.maxsize
WARNING : block size exceeding max block size at 0x00003446
[+] Try changing it with e anal.bb.maxsize
WARNING : block size exceeding max block size at 0x00006572
[+] Try changing it with e anal.bb.maxsize
WARNING : block size exceeding max block size at 0x00006874
[+] Try changing it with e anal.bb.maxsize
WARNING : block size exceeding max block size at 0x00004624
[+] Try changing it with e anal.bb.maxsize
[x] Analyze function calls (aac)
[x] Analyze len bytes of instructions for references (aar)
[x] Constructing a function name for fcn.* and sym.func.* functions (aan)
[x] Type matching analysis for all functions (afta)
[x] Use -AA or aaaa to perform additional experimental analysis.
[0x00000000]> afl
0x00000000 1 132 fcn.00000000
0x00000180 1 118 fcn.00000180
0x00002020 1 1020 fcn.00002020
0x00002420 1 1020 fcn.00002420
0x00003130 1 790 fcn.00003130
0x00003446 1 1020 fcn.00003446
0x00003e3e 2 453 fcn.00003e3e
0x00004624 1 1020 fcn.00004624
0x00004944 1 1020 fcn.00004944
0x00004f54 1 1020 fcn.00004f54
0x00005441 1 1020 fcn.00005441
0x00005845 1 1020 fcn.00005845
0x00006166 1 7 fcn.00006166
0x0000616d 1 1020 fcn.0000616d
0x0000652f 1 62 fcn.0000652f
0x0000656d 1 5 fcn.0000656d
0x00006572 1 770 fcn.00006572
0x00006820 1 52 fcn.00006820
0x00006854 1 1020 fcn.00006854
0x00006874 1 1020 fcn.00006874
0x00006966 1 1020 fcn.00006966
0x00006f63 1 701 fcn.00006f63
0x00006f66 1 705 fcn.00006f66
0x00006f74 1 1020 fcn.00006f74
0x00007220 1 577 fcn.00007220
0x00007227 1 1020 fcn.00007227
0x00007241 1 231 fcn.00007241
0x00007277 1 1020 fcn.00007277
0x00007328 1 77 fcn.00007328
0x00007375 1 236 fcn.00007375
0x00007461 1 1020 fcn.00007461
0x00008000 1 1 fcn.00008000
0x00008001 12 51 fcn.00008001
0x00008034 1 37 fcn.00008034
0x00008059 5 60 fcn.00008059
0x00008095 1 4 fcn.00008095
0x00008099 1 4 fcn.00008099
0x0000809d 5 21 fcn.0000809d
0x000080b2 9 36 fcn.000080b2
0x000080d6 6 70 fcn.000080d6
0x0000811c 4 38 fcn.0000811c
0x00008142 1 23 fcn.00008142
0x00008159 1 11 fcn.00008159
0x0000817d 1 78 fcn.0000817d
0x000081cb 1 68 fcn.000081cb
0x0000820f 4 29 fcn.0000820f
0x0000822c 9 68 fcn.0000822c
0x00008270 3 50 fcn.00008270
0x000082a2 3 61 fcn.000082a2
0x000082df 4 31 fcn.000082df
0x000082fe 3 48 fcn.000082fe
0x0000832e 13 123 fcn.0000832e
0x000083a9 25 179 fcn.000083a9
0x0000845c 13 145 fcn.0000845c
0x000084ed 6 42 fcn.000084ed
0x00008517 2 25 fcn.00008517
[0x00000000]>

At this point, I have to review each function and try to make sense of it. After looking at the assembly code and getting a sense of what each function does, I zoom in on method fcn.00008270

0x000081cb]> s 0x8270
[0x00008270]> pdf @ print_motd_8270
/ (fcn) print_motd_8270 50
| print_motd_8270 (int arg_ffh, int arg_101h);
| ; arg int arg_ffh @ sp+0xff
| ; arg int arg_101h @ sp+0x101
| ; CALL XREF from fcn.00008517 (+0x1c)
| 0x00008270 a9f5 lda #0xf5
| 0x00008272 8595 sta 0x95
| 0x00008274 a940 lda #0x40
| 0x00008276 8596 sta 0x96
| 0x00008278 a907 lda #0x07
| 0x0000827a 8597 sta 0x97
| 0x0000827c a900 lda #0x00
| 0x0000827e 8598 sta 0x98
| 0x00008280 205980 jsr does_file_exists_8059
| 0x00008283 c900 cmp #0x00
| ,=< 0x00008285 d00f bne 0x008296
| | 0x00008287 a920 lda #0x20
| | 0x00008289 8580 sta 0x80
| | 0x0000828b a941 lda #0x41
| | 0x0000828d 8581 sta 0x81
| | 0x0000828f 209d80 jsr print_string_809d
| | 0x00008292 202c82 jsr fcn.0000822c
| | 0x00008295 60 rts
| | ; CODE XREF from print_motd_8270 (0x8285)
| `-> 0x00008296 a9ff lda #0xff
| 0x00008298 8580 sta 0x80
| 0x0000829a a940 lda #0x40
| 0x0000829c 8581 sta 0x81
| 0x0000829e 209d80 jsr print_string_809d
\ 0x000082a1 60 rts
[0x00008270]>

Both the function 0x8270 (print /etc/motd) and function 0x82A2 (print ‘mail’) calls the function 0x8059 (does file exists).

Digging into (does file exists) method:

0x00008001]> pdf @ does_file_exists_8059 
/ (fcn) does_file_exists_8059 60
| does_file_exists_8059 (int arg_ffh, int arg_101h);
| ; arg int arg_ffh @ sp+0xff
| ; arg int arg_101h @ sp+0x101
| ; CALL XREF from print_motd_8270 (0x8280)
| ; CALL XREF from fcn.000082a2 (0x82bd)
| 0x00008059 a900 lda #0x00
| 0x0000805b 8599 sta 0x99
| ; CODE XREF from does_file_exists_8059 (0x808d)
| .-> 0x0000805d a599 lda 0x99
| : 0x0000805f 858c sta 0x8c
| : 0x00008061 a900 lda #0x00
| : 0x00008063 858d sta 0x8d
| : 0x00008065 203480 jsr disk_read_sector_8034
| : 0x00008068 a595 lda 0x95
| : 0x0000806a 8584 sta 0x84
| : 0x0000806c a596 lda 0x96
| : 0x0000806e 8585 sta 0x85
| : 0x00008070 a900 lda #0x00
| : 0x00008072 8586 sta 0x86
| : 0x00008074 a901 lda #0x01
| : 0x00008076 8587 sta 0x87
| : 0x00008078 a597 lda 0x97
| : 0x0000807a 8588 sta 0x88
| : 0x0000807c a598 lda 0x98
| : 0x0000807e 8589 sta 0x89
| : 0x00008080 200180 jsr strcmp_8001 ; int strcmp(const char *s1, const char *s2)
| : 0x00008083 c900 cmp #0x00
| ,==< 0x00008085 f00b beq 0x008092
| |: 0x00008087 e699 inc 0x99
| |: 0x00008089 a599 lda 0x99
| |: 0x0000808b c940 cmp #0x40
| |`=< 0x0000808d d0ce bne 0x00805d
| | 0x0000808f a901 lda #0x01
| | 0x00008091 60 rts
| | ; CODE XREF from does_file_exists_8059 (0x8085)
| `--> 0x00008092 a900 lda #0x00
\ 0x00008094 60 rts

From the above code, it appears memory slot 0x8C and 0x8D holds the argument into function 0x8034 (disk read sector). In this case, address 0x8C holds 0x00 and address 0x8D holds 0x00 as well.

Digging into (disk read sector) reveals:

[0x00008000]> pdf @ disk_read_sector_8034 
/ (fcn) disk_read_sector_8034 37
| disk_read_sector_8034 (int arg_ffh, int arg_101h);
| ; arg int arg_ffh @ sp+0xff
| ; arg int arg_101h @ sp+0x101
| ; CALL XREF from does_file_exists_8059 (0x8065)
| ; CALL XREF from fcn.0000820f (0x8217)
| 0x00008034 a910 lda #0x10
| 0x00008036 8582 sta 0x82
| 0x00008038 a940 lda #0x40
| 0x0000803a 8583 sta 0x83
| 0x0000803c 200080 jsr rts_8000
| 0x0000803f a58c lda 0x8c
| 0x00008041 8d10f2 sta 0xf210
| 0x00008044 a58d lda 0x8d
| 0x00008046 8d11f2 sta 0xf211
| 0x00008049 a900 lda #0x00
| 0x0000804b 8d20f2 sta 0xf220
| 0x0000804e a901 lda #0x01
| 0x00008050 8d21f2 sta 0xf221
| 0x00008053 a981 lda #0x81
| 0x00008055 8d01f2 sta 0xf201
\ 0x00008058 60 rts

The above method utilized addresses in the mmio, so this method is making some IO calls. It is also the only function that make uses of those address in the 0xf2XX range.

So I concluded that parameter [0x83 0x82] = 0x4010 and parameter [0x8D 8C] = 0x0000. Looking at what 0x4010 is, reveals the string “disk_read_sector”:

[0x00008000]> px @ 0x4010
- offset - 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF
0x00004010 6469 736b 5f72 6561 645f 7365 6374 6f72 disk_read_sector
0x00004020 0053 7461 7274 696e 6720 4172 6b4f 532e .Starting ArkOS.

The string “disk_read_sector” could perhaps be a debug string, or be the function name to be called by the “backend”. I did not investigate it further.

Another function of interest is the 0x822C (read file):

0x0000820f]> pdf @ read_file_822c 
/ (fcn) read_file_822c 68
| read_file_822c (int arg_ffh, int arg_101h);
| ; arg int arg_ffh @ sp+0xff
| ; arg int arg_101h @ sp+0x101
| ; CALL XREF from print_motd_8270 (0x8292)
| ; CALL XREF from fcn.000082a2 (0x82cf)
| 0x0000822c a230 ldx #0x30
| 0x0000822e bd0001 lda 0x0100,x
| 0x00008231 859e sta 0x9e
| 0x00008233 e8 inx
| 0x00008234 bd0001 lda 0x0100,x
| 0x00008237 859f sta 0x9f
| 0x00008239 e8 inx
| 0x0000823a bd0001 lda 0x0100,x
| 0x0000823d 859c sta 0x9c
| 0x0000823f e8 inx
| 0x00008240 bd0001 lda 0x0100,x
| 0x00008243 859d sta 0x9d
| ; CODE XREF from read_file_822c (0x826c)
| .-> 0x00008245 a59c lda 0x9c
| : 0x00008247 c900 cmp #0x00
| ,==< 0x00008249 d006 bne 0x008251
| |: 0x0000824b a59d lda 0x9d
| |: 0x0000824d c900 cmp #0x00
| ,===< 0x0000824f f01e beq 0x00826f
| ||: ; CODE XREF from read_file_822c (0x8249)
| |`--> 0x00008251 a59e lda 0x9e
| | : 0x00008253 859a sta 0x9a
| | : 0x00008255 a59f lda 0x9f
| | : 0x00008257 859b sta 0x9b
| | : 0x00008259 200f82 jsr read_disk_and_print_820f
| | : 0x0000825c a59c lda 0x9c
| | : 0x0000825e c900 cmp #0x00
| |,==< 0x00008260 d002 bne 0x008264
| ||: 0x00008262 c69d dec 0x9d
| ||: ; CODE XREF from read_file_822c (0x8260)
| |`--> 0x00008264 c69c dec 0x9c
| | : 0x00008266 e69e inc 0x9e
| |,==< 0x00008268 d002 bne 0x00826c
| ||: 0x0000826a e69f inc 0x9f
| ||| ; CODE XREF from read_file_822c (0x8268)
| |``=< 0x0000826c 4c4582 jmp 0x8245
| | ; CODE XREF from read_file_822c (0x824f)
\ `---> 0x0000826f 60 rts

The above function is reading content at address 0x0100 + offset and doing the following:

[0x9D 0x9C] = [0x01033 0x1032]

[0x9F 0x9E] = [0x01031 0x1030]

The content in memory slot 0x9E and 0x9F, will get copied to memory slot 0x9A 0x9B, and by the time it hits the (read disk and print) function 0x820F, it passes the content to memory slot 0x8C 0x8D.

The memory slot 0x9C and 0x9D in function (read file) appears to be a counter of some sort. It also looks like the 8 bits system is simulating a 16 bits register treating the 0x9D as the higher significant byte and 0x9C as the lower significant byte. This is apparent as slot 0x9C is checked to see if it contains 0, if not, decrements it, else, decrements the content in slot 0x9D.

[0x00008099]> pdf @ read_disk_and_print_820f 
/ (fcn) read_disk_and_print_820f 29
| read_disk_and_print_820f (int arg_ffh, int arg_101h);
| ; arg int arg_ffh @ sp+0xff
| ; arg int arg_101h @ sp+0x101
| ; CALL XREF from read_file_822c (0x8259)
| 0x0000820f a59a lda 0x9a
| 0x00008211 858c sta 0x8c
| 0x00008213 a59b lda 0x9b
| 0x00008215 858d sta 0x8d
| 0x00008217 203480 jsr disk_read_sector_8034
| 0x0000821a a200 ldx #0x00
| ; CODE XREF from read_disk_and_print_820f (0x8229)
| .-> 0x0000821c bd0001 lda 0x0100,x
| : 0x0000821f c900 cmp #0x00
| ,==< 0x00008221 f008 beq 0x00822b
| |: 0x00008223 209980 jsr stdout_8099
| |: 0x00008226 e8 inx
| |: 0x00008227 e040 cpx #0x40
| |`=< 0x00008229 d0f1 bne 0x00821c
| | ; CODE XREF from read_disk_and_print_820f (0x8221)
\ `--> 0x0000822b 60 rts

In the function 0x820F (read disk and print), it takes the content in memory slot [0x8D 0x8C] and passes it to (disk read sector). It then retrieves the content from memory slot [0x0100 + offset] and print it through STDOUT. The memory slot from 0x0100 to 0x01FF is the stack space.

Debugging and making sense of things

At this stage, I wanted to simulate the call to function (disk read sector) by using the “call” command. Since the (disk read sector) takes on the parameter from memory slot [0x8D 0x8C], I used the “write” command to set content at 0x8D and 0x8C to 0x00. Then I used the “call” command to call address 0x8034.

I ran the following script and then use the “read” command to print the content of the stack [0x0100–0x01FF]. I choose to print the stack because I recall seeing partial file content being stored on the stack.

Script:

#!/usr/bin/python
import socket
import sys
host = 'arkos.atredis.com'
port = 4444
socket.setdefaulttimeout(10)
s = socket.create_connection((host,port))
f = s.makefile('rw', bufsize=0)
def readuntil(delim='\n\n'):
data = ''
while not data.endswith(delim):
data += f.read(1)
return data
def extract(begin, end):
buf = ''
for i in xrange(begin, end + 1):
cmd = 'read %04X' % i
f.write(cmd + '\n')
output = readuntil('arkos>')
byte = output.split('=')[1][2:4]
byte = chr(int(byte, 16))
buf += byte
print buf
return buf
def save(filename, begin, end):
fio = open(filename, 'w')
content = extract(begin, end)
fio.write(content)
fio.close()
if __name__ == '__main__':
print readuntil('arkos>')
f.write('write %04X %02X\n' % (0x008C, int(sys.argv[1])))
print readuntil('arkos>')
f.write('write %04X %02X\n' % (0x008D, int(sys.argv[2])))
print readuntil('arkos>')
f.write('call 8034\n')
print readuntil('arkos>')
print 'Saving stack'
save('stack', 0x0100, 0x01FF)
print 'Done Saving stack'

Output:

#./pull.py 0 0
Starting ArkOS...
Hardware version: 1.0.3 rev A
Firmware version: 1.1.B
Memory map:
$0000:$00FF - RAM
$0100:$01FF - RAM (stack)
$0200:$1FFF - RAM
$4000:$EFFF - PROM
$F000:$FF00 - MMIO
$FF00:$FFFF - PROM
Found /etc/motd!
************************************************************
This service is restricted to authorized users only. All
activities on this system are logged. Unauthorized access
will be fully investigated and reported to the appropriate
lifestyle assessment organization for permanent lifestyle
adjustment treatment.
************************************************************
_ ___ ____ ____
dM. `MM 6MMMMb 6MMMMb\
,MMb MM 8P Y8 6M' `
d'YM. ___ __ MM __ 6M Mb MM
,P `Mb `MM 6MM MM d' MM MM YM.
d' YM. MM69 " MM d' MM MM YMMMMb
,P `Mb MM' MM d' MM MM `Mb
d' YM. MM MMdM. MM MM MM
,MMMMMMMMb MM MMPYM. YM M9 MM
d' YM. MM MM YM. 8b d8 L ,M9
_dM_ _dMM_MM_ _MM_ YM._ YMMMM9 MYMMMM9
"Supervising" your computing 8-bits at a timegr33tz: merlin, chumbo, and m4xzChecking mail for user atredis...
Found mail!
From: Some Person <office-of-indoctrination@atredis.com>
Subject: Blackhat Tickets for the Contest
Date: Mon, 9 Jul 2018 07:12:48 -0700
To: Player <atredis@arkos.atredis.com>
Content-Type: text/plain; charset=us-ascii
Friend,Please find more details regarding the BH ticket contest attached.--
http://www.atredis.com
<< ATTACHMENT EXTRACTED TO DISK >>arkos>
$008c := $00
arkos>
$008d := $00
arkos>
jsr $8034
arkos>
Saving stack
/
/h
/ho
/hom
/home
/home/
/home/a
/home/at
/home/atr
/home/atre
/home/atred
/home/atredi
/home/atredis
/home/atredis/
/home/atredis/m
/home/atredis/ma
/home/atredis/map
/home/atredis/map.
/home/atredis/map.p
/home/atredis/map.pn
/home/atredis/map.png

So that’s pretty cool, the disk read sector appears to take on some “index” from memory slot 0x8D 0x8C, which returns the path of a file. But enumerating the different values into the memory slot at 0x8D 0x8C, I collected the following paths as well:

[0x8C = 1, 0x8D = 0] -> /etc/motd
[0x8C = 2, 0x8D = 0] -> /var/spool/mail/atredis
[0x8C = 3, 0x8D = 0] -> /home/atredis/.mail/attachment123.txt

The stack actually revealed more information that made the assembly code makes sense:

00000100: 2f68 6f6d 652f 6174 7265 6469 732f 2e6d  /home/atredis/.m
00000110: 6169 6c2f 6174 7461 6368 6d65 6e74 3132 ail/attachment12
00000120: 332e 7478 7400 0000 0000 0000 0000 0000 3.txt...........
00000130: 2501 0300 0000 0000 0000 0000 0000 0000 %...............
00000140: 7265 6164 2030 3134 3800 2030 3000 0000 read 0148. 00...

On address 0x1030, the first two bytes is “2501”, and it is followed by “0300”. So if we were to role play function 0x822C (read file), the memory slot [0x9F 0x9E] = 0x0125, and memory slot [0x9D 0x9C] = 0x0003. Recalling how function 0x822C (read file) works, it reads from memory slot 0x0130 to 0x133, storing the content from those memory slots into memory slots 0x9C to 0x9F. Eventually, the content of [0x9F 0x9E] will be passed to (disk read sector), so therefore 0x01 0x25 is the disk sector index that contains the content of the attachment. The content [0x9F 0x9E] is used as a counter, and gets decrement each time after the (disk read and print) is executed, which also increments the value stored in [0x9F 0x9E]. So this explains that the attachment lives in sector index 0x0125, 0x0126, 0x0127, therefore it requires looping three times.

Since the function 0x8034 (disk read sector) will populate the proper disk sector value and the number of incremental sectors needed for a particular file. I could use it along with function 0x822C (read file) as gadgets, to print the content of the attachment.

My Solution

My answer composes of 4 commands:

write 003c 03
write 003d 00
call 8034
call 822c

References

Appendix I — arkOS Memory Map Dump

echo -ne "H4sIAPmtUlsAA+3cT2wc1R3A8RmHAFlACRJSqFpVv1SuQqpiz/pPSN003SV4SYIdI8dSQULKDPYkXuz1WrOboKiqtOt4QoKywUkdSEicGEsDDBIH4MShElwiVkjIJ65wsnyJZCzoselvZmOvYxoOFY6l9vux9f783nvzfn7z7JvX8YbyhcM5Z9RYO5ba2dYW1cmn2q241u84brXEpZFsbW1pbW9v37mz1bCSSW0bYq1hTsuOFYqOJ2K8cuLYT847mB9x70U+/2fOprek3kt3mlG70ew0J6JGS3qr0dCosd+am9Z4/1wisXu3pPv60nv3dXce7JPOF/p603v7Op+Rvh55Zv+h52TPnsTd13uuMyBWsm3XGuf58/pL+crJf47/zv+jv96ZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABqrGRLa1v7zqd2/cF5uX/APTKQLQwdjv6p/XDB7S/mPeNQ0fGK2ZGjkvaGeg41NTUZmayXe9XxXDnueoVsfqRDjGRTsulpY5/jDawa6HZzee+E5JzRjoQh0hh91kOHlpmMPCm96e5aMBkHk0tBeaJQdPqHdtQGW6JBHVu5oi1+TGct+HxvTy2aiaMZrTTa3b2/pxbN1KIr5ja7xf7mXL44YHT29vb0dsgRJzvsDkgxL0eyIwOyPJ4wMvljKwPbdPFxx2vO6YLmwmg+P9zsFD1XT83YO+j2D0UHFY3JkbwnxwquJ7eH9eCWHhaNb0skjIP5uKlxJ/oQjj1i7B857gxnB6Q/n8s5I7r7oDs8Gn/CwKtetuhKvzM8LIm9tdFCR0IkmqCVSN9gtiA5t1BwjroaiBbF8e3x8owe2PY4WJDioCsvn9CnOUU9HB34iU83AAAAAAAAAAAAAAAAAAAAAAAAAAAAAADcK3ZwumrMbgrOaLkhNOwZ453xz08tbAhNe258tmHOnzul5WvxrIYbZ26c7jJL4RZ/LEz5J8UoBWcrWxaDSuXRxdCoyGJoVrYthuWKuWiHhn85uOyf1boibaXgoj8evOn72j0Vmv5rwVv+6eCSf0bMUtVYeGhO51ZTs1/ptprEh8aCXTEXomRKWuuETXMlTaPcNVWyq5b1WDVl/aKath6uPms9VHWs+6pHrQ3hLXvH5sezm7SMFp6Tj0vVWwu7Eso/P21+dDuwfeN57TYsdR+PxyemNywFHtg44U9oDvo4fcqFlbMm9SkXlmZN+pO1WR8cUO9/aqTkcun1HZtvt+wwoWX4SNScNi7t++h1ebocinYH3//isy2zN+XFsh0e9kt6kGWZKoXD9Wa53rxWb35Sb1brzW+Wm3a4bbmtDw+76pMMbX6/PNBaH8isXCF/K9vB2/7Z4Er8xmaMfximHv2DmvP8t6nZ7+wZSyP+tfmovB6XV+NyKriqt+P+YEpn/zq45r8dXPevyOaxONxwY+rG1blr+vaud3WO2eEP/kXd8s3wAf8tzeuSvKjvf3ZzKJpJupbJ73XWrRU/1oHlobBFF6d18dY7F+fuXPzX5W50C6flYqmaWHj43emplDl/avrbP8/efHc6NLRn6/mO61Rf94pvZXiff1qX3L6V0e9D+HF9d50/s2r+xh/NT/nndOSNuXP6E9+1lK9LYaOea3Beb0UwsXQ1wj9FRdyKRvX+RUPRO9Ot31u19f3/3da1MjjnXwje8P8+d0F7dy01TflV+T9m2vHjdIPJWrIzRjBZnohS/vDnO61Xol0KUeHduelyXvHOob4ncz6YiMvzURnaUSklUxOSf43pffmNNJ3U6pcSRtVj8tK4Vo+ElZUvOjpzv36rvhmTm+PVW7PztnxZltExmRmTrX7Xbt9Opdb7LzgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADupcb1TmB9vbPeCay38p3dRnPV+Oo+/qckm6ymVvHc45Je71QAAAAArB3Lj77WOwsAAAAAAAAAwNr4N9x51UYAGAEA" | base64 -d > arkos_memory_map.tar.gz ; tar -xvzf arkos_memory_map.tar.gz ; xxd arkos_map

--

--