This article will be the first in a series detailing the infrastructure work and challenges for the Source Boston and BSides Boston CTF competitions I had the pleasure of working on this spring. MassHackers put on the Source Boston CTF and I was responsible for the hosting infrastructure and contributed two challenges that made it into the competition. I first want to thank Zach Lanier (@quine) for letting me help out with this CTF and Julian Cohen (@HockeyInJune) for giving me lots of advice on challenges and CTF organization.
Some competitors asked for very detailed walkthroughs they could use to learn. Below I’ll give a very detailed description of solving the challenges assuming almost no basic knowledge of the topic. Experienced competitors can feel free to skip to the end.
Challenge 1 – 192.168.11.101 – “Locked out”
This challenge directed players to the target host via http. The nginx web server on the system served up a single static html page with the following content:
This web page gives two clues and a long string of hex. The first clue is that “pdogg” is locked out. The second clue in the form of a quote from Alice’s Adventures in Wonderland eludes to the fact that to solve the challenge we need to find the right key.
When the long string of hex is interpreted as a file (there are multiple methods of achieving this, in challenge QA testing I used a simple python call to binascii.unhexlify(data). The file command on the resulting binary yields:$ file binary binary: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), BuildID[sha1]=0x9367c3163e2e5c67731758867d39ba4de8234658, stripped
We can see that this is a stripped 32 bit x86 executable. Running the executable if correctly decoded, produces no output and simply a clean exit. There are no inputs. This binary was inspired by work I’m currently doing on the SLAE class at Security Tube. The executable is just a call to a shellcode buffer, the shellcode is a simple XOR encoder using MMX. Since the binary is delivered stripped of symbols, finding correct point to begin debugging is a small bit of effort. This can be discovered as follows:$ objdump -f binary binary: file format elf32-i386 architecture: i386, flags 0×00000112: EXEC_P, HAS_SYMS, D_PAGED start address 0×08048300
Gives us the start address of the ELF and looking at the disassembly at that point we can see the arguments passed to libc start main.
Pushed to the top of the stack before the call is a pointer to main 0x080483b4. To skip the library calls to initialize we can set a breakpoint at this address or utilize a debugger that handles this automatically.
A pointer to the shellcode buffer is placed in EAX and called. This shellcode preforms a jmp, call, pop sequence to get the memory location of the key and relative buffer, then uses MMX instructions to XOR decode the payload. The key is 0xAAAAAAAAAAAAAAAA.
The payload buffer resides directly after the key (pointed to by EDI). After a few steps of the decode loop the decoded buffer is as follows:
After a few more steps through the decode loop an SSH private key can be seen in the buffer being decoded.
If the binary is allowed to keep executing eventually a jump to the payload will execute, @PDOGG77 forms a sequence of virtually useless instructions and the next block of code is an exit syscall.
Extracting this buffer results in a private key usable to ssh into the system as user “pdogg”—–BEGIN RSA PRIVATE KEY—– MIIEogIBAAKCAQEAtw8Tdn0jG8pPnf1oTRgzyp6c2LKPQxg12gGp5lg5zzzNZds8 d8Ttlg7enkAUrEt9EL95vanacJDQSrTJtjazAgxQcO7ir+30R38txaRlSXO4aj+0 1Zq5IRQU/pFYuto1WnyklKsoBmlLLtHBJ4ACVcGROEMONKXvlNWOtyGijMKWEqPA t2wDUmHNGJsIR3XPT3Z+YmRSuDb7xmbm/r/Inq2BAuAWdbSf49IRGNPVY1cBTujd SMB2L9LZDcoXhJ/2Ju33j2XRiYHc9QCiGeUU7VUTWv6vK5PNVWgaQ+EKS4g7CYCr Ne5YaY2EOOAR1rZ97jZsmI5dO5k1/tgws3V6FQIBIwKCAQAvEoFY+5tQSfc3QSly 6Pdf/OaA3XVLxGWedXTU1NuqUXalKb8Xe8gQpLzm3Uck/XfuXR9OBxrpvtZ5nDPe ZdZCWvAdCjpKfwRM5jBXZMmWi3iQWYZFji+ayqZQFr8LefB2WpC4g8h2rVx5wOiG gACZtW58Ln/+6Nc05nUnxtIG78XXcxKRi514Fz6f84OJZjm62ScYhqOTHpmN4utj 6euFqAZpgwWEr9VB/r6oMj1SQaRqXMrpTk0rme6NMCNUYxVKeZcAxy9mjnhbb8Z2 uXS2MNbJSNiOVpbXWIehWHZCqZWzGO+D/ECht92fjDZnDAF4w1lV1viusVBQiCxw x+0vAoGBAN67vXjKMr8I3qsGkWQX2cUGO9Qv1ZGub3rAqgXYYZBn6tQ2+dyaFnsN noWfrEvMOw1UnKz8+Eqjj5eoWTb0PJYsYg5l8H2CaBZi01lLkamvwVA02aqZO5Sx ydZpheO20ZyZ7+uG4FsfvSvTfl8Bcnrvch91jcODBbHFo8KH5gpHAoGBANJmX6ph 4W4hKLzAcxZunLgA0bzTLdMi+yvd9RTatBYSipPcPgf0DssOcVCyK0XJADux/8Xc 7P9w7KGyJ3OdjLfY6/NC4H8/YYC8z++rSVAHR5xQQp33B3xBt8Kfyj48Ix9hvf/K OQHxWqUxzqZg+ODTzJxjZ0RmjKE46fo8FCrDAoGBAJi7QBhQIswjVtusu3fV1ygE RkhbUJ5o+/xm2vyxofyfB2zyf3KyzZY1OYAy+c2TW7Fel1IMjP/7IKKCEUpBE5ot EAnfgFYQR1/OvM+ERqA+AOaKo+KyN3vnoFiC33eTTee6A5owmdgVw4vEOWW32Xje tKfblGjO31VUUwkMuv+7AoGAGAuzKWpFpi+s4l8jGIGrgr5D2xDSCYBXODafqpym 3fN9jT298kfHLSY41gW7zXYOp7ySQn+mDpCQEnrCriCiXidrbEIoSQ6OzOJg6DDV LbewaaLFyOkIK3U5kpXrOlAEA5YkV79W+OhiIYII/RJllgmTuhn9LGN9yUhVQStw BOMCgYEAtzkEEAyH5OmRzPJ4w4W0jz2hUBcA0Nfr7vD+DuKXMGk5FucS1RSauihX VyfmQ2AEFaJfM8VWDBwgWRhNOBJSLzLazi0RzQFAENb/Pp7sYdjbwCPcS/fZLprn fuApn3iVhVXNzxoUfrPGZ6j3DTB6nnW6o0PVJuhOJzqqJoFOAMI= —–END RSA PRIVATE KEY—–
Upon connection to the system the player sees there is a single file in pdogg’s home directory called “FlagInHere” This file is a pcap format packet capture.$ file FlagInHere FlagInHere: pcap-ng capture file – version 1.0
Reading this packet capture with any acceptable tool reveals that it is an HTTP GET of a jpeg image called flag.jpg
Carving out the jpeg image (in QA testing I did this with the foremost tool) and viewing the image reveals the challenge key.
Challenge 2 – 192.168.11.103 – “I’ll Have My People Call Your People”
Competitors were directed to “192.168.11.103 port 9091” to attempt this challenge. Listening on port 9091 was a service that prompted the player for a username and a password and then told them to “Wait by the phone…” This service waited between the prompts and had fairly unique prompts (to dissuade brute force attacks and hint at the true nature of the service). Special characters, spaces etc are stripped by the service and the resulting strings are echoed to the player.
$ nc 192.168.11.103 9091 Send me a username (50 characters max please):test I’m seeing: test I’m going to wait for 45 seconds and tell you now… guessing won’t work Send me a password (50 characters max please):test I’m seeing: test Wait by the phone…
Observant players noticed that 10 seconds after the service disconnected this session it attempted an ssh connection to the source IP address seen with the username and password provided as credentials. This connection can be detected via packet capture, logging, or any other good system/security administration practices. If the connection is successful the service executes a series of commands on the player’s system which.
- drop a seedfile.txt file in the current working directory
- build a script.sh file line by line in the current working directory, the script file calls various common tools to build the MD5 hash key out of the seedfile.txt
- sets the script.sh file to be executable
- executes script.sh
- creates a false .thehistory file which contains only “./script.sh” as a hint to the player
- deletes the script.sh file and disconnects
Players demonstrated several ways of preserving the script.sh file during the CTF event. The simplest method to solve this challenge is to set a symbolic link for script.sh which will be followed by the process building the script, executed, and unlinked on the removal (other demonstrated and discussed methods included using creation of a fifo pipe or somehow racing the service to preserve script.sh)
symlink method:# touch /tmp/script.sh # chown test /tmp/script.sh # ls -al total 24 drwx–x–x 3 test users 4096 Apr 23 17:05 ./ drwxr-xr-x 5 root root 4096 Apr 18 12:58 ../ -rw-r–r– 1 test users 3729 Jul 18 2011 .screenrc -rw-r–r– 1 test users 10 Apr 23 17:05 .thehistory drwxr-xr-x 2 root root 4096 Apr 23 17:03 old/ -rw-r–r– 1 test users 28 Apr 23 17:05 seedfile.txt # ln -s /tmp/script.sh script.sh # ls -al total 24 drwx–x–x 3 test users 4096 Apr 23 17:06 ./ drwxr-xr-x 5 root root 4096 Apr 18 12:58 ../ -rw-r–r– 1 test users 3729 Jul 18 2011 .screenrc -rw-r–r– 1 test users 10 Apr 23 17:05 .thehistory drwxr-xr-x 2 root root 4096 Apr 23 17:03 old/ lrwxrwxrwx 1 root root 14 Apr 23 17:06 script.sh -> /tmp/script.sh -rw-r–r– 1 test users 28 Apr 23 17:05 seedfile.txt # ls -al total 24 drwx–x–x 3 test users 4096 Apr 23 17:06 ./ drwxr-xr-x 5 root root 4096 Apr 18 12:58 ../ -rw-r–r– 1 test users 3729 Jul 18 2011 .screenrc -rw-r–r– 1 test users 10 Apr 23 17:06 .thehistory drwxr-xr-x 2 root root 4096 Apr 23 17:03 old/ -rw-r–r– 1 test users 28 Apr 23 17:06 seedfile.txt # cat /tmp/script.sh #!/bin/bash sha512sum seedfile.txt | base64 | base64 | base64 | base64 | md5sum #
Executing script.sh in the same directory as the seedfile.txt reveals the challenge key:./script.sh d0159b40d84e66f5ad07a83892cbf1e3 -
That’s all for this part. Stay tuned for write-ups on the hosting infrastructure, organizing the BSides CTF event and the challenges presented there.