Tags: quake3 network pcap 

Rating: 5.0

We were presented with a PCAP file and a video with some Openarena (Quake 3 clone) footage. The flag was written on the wall with the lightning gun.

We tried several things:

* Replaying the packets with tcpreplay. For this we patched openarena to use the same challenge every time. But this didn't lead to much. Probably because the timing of the recording was not accurate enough, due to being recorded in a VM. We didn't get anything useful, besides a "connecting" message from the client. The client timed out after some time.
* One packet had a "Quake3Arena" string, we couldn't reproduce this with Openarena and our own recordings, so we though that maybe Debian had changed something:

```
0000 00 0c 29 a4 60 cc 00 0c 29 8f 0f 2d 08 00 45 00 ..).`...)..-..E.
0010 00 43 a7 9a 40 00 40 11 e2 a6 c0 a8 97 8c c0 a8 .C..@.@.........
0020 97 8b 6d 39 6d 39 00 2f af 33 ff ff ff ff 67 65 ..m9m9./.3....ge
0030 74 63 68 61 6c 6c 65 6e 67 65 20 2d 39 35 34 35 tchallenge -9545
0040 34 35 33 34 33 20 51 75 61 6b 65 33 41 72 65 6e 45343 Quake3Aren
0050 61 a
```

But we couldn't find anything in the Debian packet changelog that would hint at a changed connection sequence, also tests showed that Debian and Openarena official versions were compatible.

We then found [q3tools](https://github.com/0xa/q3tools), with included a packet dump. But we couldn't open the pcap file with it, we thought that maybe Openarena (or ioquake) had changed the protocol too much for it to be decodable.

The next day, we tried again with q3dump and tried possible challenges with client and server IP, one had success:

`./q3dump.py -v --pass-exc --hs '192.168.151.140,192.168.151.139,-1338626257' /tmp/gra5.pcap`

We had already filtered the PCAP to only include server and client traffic, no IPv6 and query stuff.

After running this, we got a promising [output](https://pastebin.com/32sBEiFW).
A SPacket looked like this:

```
SPacket: #00000299: [00000002]
- Op: NcSvSnapshot
- server_time: 41650
- last_frame: 1
- flags: 4
- area_mask: b'\xfe'
- player_state: NcPlayerState
- fields: {'commandTime': 41570, 'viewangles[1]': -7.1246337890625, 'viewangles[0]': 16.9354248046875}
- player_stats: {}
- pers_stats: {}
- ammo: {}
- powerups: {}
- entities: NcPlayerState
```

And a client packet like this:

```
CPacket: #00000248: [00000003]
- Move: NcUserCmd(time=42628, values={'weapon': 262, 'angles[0]': 2182, 'angles[1]': 23965, 'buttons': 2048, 'forwardmove': 383, 'rightmove': 385, 'upmove': 0})
- Move: NcUserCmd(time=42649, values={'weapon': 262, 'angles[0]': 2182, 'angles[1]': 23965, 'buttons': 2048, 'forwardmove': 383, 'rightmove': 385, 'upmove': 0})
```

We focused on the client packets, as they had two fields for angles. After extracting all angles and plotting them, we get [this](https://i.imgur.com/gsV2wRe.png) picture. We scaled the values to avoid the big jumps you can see in the picture.

After plotting again, we can already see some curly brackets and "PCTF" so we were definitly on the right track. We plotted a picture for ~1000 angles and got the flag this way: ![PEW](https://i.imgur.com/pBmTsHa.png)

We made a [video](https://i.imgur.com/oXpncNu.gifv) afterwards.

The final flag was `PCTF{PEWPEWPEWWX}`. A very nice challenge.