class: center, middle # SecTalks 0x18 ## covfefe CTF walkthrough ### 2017-08-24 --- # Outline 1. Intros 1. Setup 1. Service discovery 1. Enumerate web server 1. Attempt ssh login 1. Crack ssh key passphrase 1. Investigate user directory 1. Vulnerable local messaging application 1. Investigate root directory 1. Exploit the messaging application 1. Obtain final flag --- # Intros ### Me - Linux since 1994; my primary work & personal machines since 1998 - Newbie at CTFs & hacking - Software libertarian ??? I don't use Linux because it's faster, more secure, more reliable, or cheaper (although I think good arguments can be made for all those things), but because it increases my freedom, my ability to choose for myself, and my ability to fix that are broken or change things I don't like. --- # Intros ### covfefe CTF - newbie-friendly: if you've done Justin Steven's [dostackbufferoverflowgood](https://github.com/justinsteven/dostackbufferoverflowgood), this should be easier, since there's no exploit to build - If you haven't done it, run - don't walk! - to get a copy and do it straight away after this - Only my 2nd ever boot-to-root - Built on Debian 9 (stretch) 32-bit - 3 flags in total, last one only possible when you get root - Disappointingly few references to negative press covfefe --- # Intros ### This presentation - newbie-focused: I'll err on the side of over-explaining - Will try to do as much as possible live - Using Kali rolling release - Screwups FTW! ??? - You could use Debian or Ubuntu with not much extra work, Fedora & CentOS should work too if that's your thing - Learning from mistakes is how most of us roll, so I'll focus on these quite a bit - They might be mistakes I made, or rabbit holes I went down, but they were all things which didn't really help me solve the boot-to-root --- # Setup - VirtualBox - Configure host-only network - Import VM - Change network adaptor to host-only network --- # Service discovery - passive # tshark -i vboxnet0 -n Running as user "root" and group "root". This could be dangerous. tshark: Lua: Error during loading: [string "/usr/share/wireshark/init.lua"]:44: dofile has been disabled due to running Wireshark as superuser. See https://wiki.wireshark.org/CaptureSetup/CapturePrivileges for help in running Wireshark as an unprivileged user. Capturing on 'vboxnet0' 1 0.000000000 0.0.0.0 → 255.255.255.255 DHCP 342 DHCP Discover - Transaction ID 0xb064e274 2 0.000027133 0.0.0.0 → 255.255.255.255 DHCP 342 DHCP Discover - Transaction ID 0xb064e274 3 0.000085696 192.168.56.99 → 255.255.255.255 DHCP 590 DHCP Offer - Transaction ID 0xb064e274 4 0.000087806 192.168.56.99 → 255.255.255.255 DHCP 590 DHCP Offer - Transaction ID 0xb064e274 5 0.000375243 0.0.0.0 → 255.255.255.255 DHCP 342 DHCP Request - Transaction ID 0xb064e274 6 0.000377161 0.0.0.0 → 255.255.255.255 DHCP 342 DHCP Request - Transaction ID 0xb064e274 7 0.000394967 192.168.56.99 → 255.255.255.255 DHCP 590 DHCP ACK - Transaction ID 0xb064e274 8 0.000396728 192.168.56.99 → 255.255.255.255 DHCP 590 DHCP ACK - Transaction ID 0xb064e274 9 0.009052400 :: → ff02::16 ICMPv6 90 Multicast Listener Report Message v2 10 0.009056726 :: → ff02::16 ICMPv6 90 Multicast Listener Report Message v2 11 0.962496841 :: → ff02::16 ICMPv6 90 Multicast Listener Report Message v2 12 0.962503355 :: → ff02::16 ICMPv6 90 Multicast Listener Report Message v2 13 0.993586175 :: → ff02::1:ffab:72c8 ICMPv6 78 Neighbor Solicitation for fe80::a00:27ff:feab:72c8 14 0.993594159 :: → ff02::1:ffab:72c8 ICMPv6 78 Neighbor Solicitation for fe80::a00:27ff:feab:72c8 15 2.019438221 fe80::a00:27ff:feab:72c8 → ff02::16 ICMPv6 90 Multicast Listener Report Message v2 16 2.019446460 fe80::a00:27ff:feab:72c8 → ff02::16 ICMPv6 90 Multicast Listener Report Message v2 17 2.019662951 fe80::a00:27ff:feab:72c8 → ff02::2 ICMPv6 70 Router Solicitation from 08:00:27:ab:72:c8 18 2.019666800 fe80::a00:27ff:feab:72c8 → ff02::2 ICMPv6 70 Router Solicitation from 08:00:27:ab:72:c8 19 2.340641722 fe80::a00:27ff:feab:72c8 → ff02::16 ICMPv6 90 Multicast Listener Report Message v2 20 2.340654225 fe80::a00:27ff:feab:72c8 → ff02::16 ICMPv6 90 Multicast Listener Report Message v2 21 5.208191660 fe80::800:27ff:fe00:0 → ff02::2 ICMPv6 70 Router Solicitation from 0a:00:27:00:00:00 22 6.466572089 fe80::a00:27ff:feab:72c8 → ff02::2 ICMPv6 70 Router Solicitation from 08:00:27:ab:72:c8 23 6.466581693 fe80::a00:27ff:feab:72c8 → ff02::2 ICMPv6 70 Router Solicitation from 08:00:27:ab:72:c8 24 14.913647930 fe80::a00:27ff:feab:72c8 → ff02::2 ICMPv6 70 Router Solicitation from 08:00:27:ab:72:c8 25 14.913656739 fe80::a00:27ff:feab:72c8 → ff02::2 ICMPv6 70 Router Solicitation from 08:00:27:ab:72:c8 26 32.839565276 fe80::a00:27ff:feab:72c8 → ff02::2 ICMPv6 70 Router Solicitation from 08:00:27:ab:72:c8 27 32.839570854 fe80::a00:27ff:feab:72c8 → ff02::2 ICMPv6 70 Router Solicitation from 08:00:27:ab:72:c8 ??? - Nothing much to see in tshark; it gets addresses for IPv4 & IPv6 and then is silent --- # Screwup #1 Rewind to VM setup: I missed the fact that, by default, VirtualBox uses two separate addresses on the host-only adaptor: one for the gateway and one for the DHCP server. And conveniently, only the host address shows up in `ip addr`. So I scanned the first address that wasn't the host address, and got no services, because I was scanning my own laptop. :-| ### Takeaways - Standardise your VM environment to minimise differences between runs - There might be some downsides to this; YMMV - Make sure DHCP server address is the same as the host's --- # Service discovery - active # nmap -v -A -p1-65535 192.168.56.101 ... PORT STATE SERVICE VERSION 22/tcp open ssh OpenSSH 7.4p1 Debian 10 (protocol 2.0) | ssh-hostkey: | 2048 d0:6a:10:e0:fb:63:22:be:09:96:0b:71:6a:60:ad:1a (RSA) | 256 ac:2c:11:1e:e2:d6:26:ea:58:c4:3e:2d:3e:1e:dd:96 (ECDSA) |_ 256 13:b3:db:c5:af:62:c2:b1:60:7d:2f:48:ef:c3:13:fc (EdDSA) 80/tcp open http nginx 1.10.3 | http-methods: |_ Supported Methods: GET HEAD |_http-server-header: nginx/1.10.3 |_http-title: Welcome to nginx! 31337/tcp open http Werkzeug httpd 0.11.15 (Python 3.5.3) | http-robots.txt: 3 disallowed entries |_/.bashrc /.profile /taxes |_http-server-header: Werkzeug/0.11.15 Python/3.5.3 |_http-title: 404 Not Found ... ??? --- # Research time - There's a local copy of exploit-db on your Kali system: - `searchsploit werkzeug` - No known exploits for these versions of ssh & nginx - At the time a seemingly fully-patched Debian system # Rabbit-hole #1 Spent a bit of time researching Werkzeug vuln - needs more Metasploit knowledge than I have - seems like more of a development feature than an exploit - it's not enabled by default ## Takeaway - I need to metasploit better (even though it wouldn't have helped this time) --- # Where to next? - crack passwords on ssh? - ssh is configured securely (i.e. password auth disabled) - poke around web servers? - already have the initial hints from `nmap`, so hopefully this is more fruitful --- # Enumerate web server gobuster or dirbuster - both in Kali, both work; I used gobuster - someone from Google has a competing program called exactly the same thing as OJ's: - https://github.com/Matir/gobuster - But OJ was there first: - https://github.com/OJ/gobuster/commit/8adc387394e2e1ef61bce888ae8a97e54e633700 - https://github.com/Matir/gobuster/commit/983cebe39964f690e655c4d727e3409bf5a19ce8 `gobuster -w /usr/share/dirb/wordlists/big.txt -u http://192.168.56.101:31337/ -r -t 4` ### Flag #1 While gobuster is running, we have a look at the files `nmap` gave us, and we get the first flag in http://192.168.56.101:31337/taxes --- # Screwup #2 The first time I did this, I used a wordlist from the collection of password lists on Kali. These are tuned for password cracking, not directory enumeration, and came up with nothing after running for *hours*. So using the right tool for the job is important, and tuning it makes a decent difference to performance: - big.txt: 0:32 - combined list of everything in /usr/share/dirb/wordlists: 3:26 - no additional directory hits Gobuster gives us 2 things not found by nmap: - .bash_history: shows user running a program called read_message - .ssh: gives a listing of files, which can all be downloaded --- # Attempt ssh login Downloaded ssh files: - authorized_keys: list of keys which can login as us - id_rsa, id_rsa.pub: private & public keys, respectively Username is simon, as found in authorized_keys & id_rsa.pub (which are identical), so this is our likely target username on the system Try ssh with that key file: # ssh -i id_rsa simon@192.168.56.101 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @ WARNING: UNPROTECTED PRIVATE KEY FILE! @ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ Permissions 0644 for 'id_rsa' are too open. It is required that your private key files are NOT accessible by others. This private key will be ignored. Load key "id_rsa": bad permissions Permission denied (publickey). # chmod 600 id_rsa # ssh -i id_rsa simon@192.168.56.101 Enter passphrase for key 'id_rsa': So this ssh key is encrypted, & we need to crack it ??? Explain the purpose of authorized_keys, id_rsa, & id_rsa.pub --- # Tip #1 `ssh -v simon@192.168.56.101` gives a lot more info so you can watch the key exchanges and authentication negotiation happen. There are lots of ways for an ssh connection to fail - reading the output of `-v` carefully can help you pinpoint why. # Rabbit-hole #2 I spent a bit of time looking for ssh key cracking utilities. Eventually I asked for help and someone pointed out that there's one that ships with John the Ripper, our faithful offline password cracker. --- # Crack ssh key passphrase `# ssh2john id_rsa > shadow` `# zcat /usr/share/wordlists/rockyou.txt.gz | john --pipe --rules shadow` This gives us the password to use for simon's key very quickly # Takeaway Use key authentication (as opposed to password), but protect your keys! --- # Investigate user directory # ssh -i id_rsa simon@192.168.56.101 Enter passphrase for key 'id_rsa': Linux covfefe 4.9.0-3-686 #1 SMP Debian 4.9.30-2+deb9u2 (2017-06-26) i686 The programs included with the Debian GNU/Linux system are free software; the exact distribution terms for each program are described in the individual files in /usr/share/doc/*/copyright. Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent permitted by applicable law. simon@covfefe:~$ id uid=1000(simon) gid=1000(simon) groups=1000(simon),24(cdrom),25(floppy),29(audio),30(dip),44(video),46(plugdev),108(netdev) simon@covfefe:~$ ls -la total 36 drwxr-xr-x 3 simon simon 4096 Jul 9 22:37 . drwxr-xr-x 3 root root 4096 Jun 28 21:16 .. -rw------- 1 simon simon 19 Jun 28 22:28 .bash_history -rw-r--r-- 1 simon simon 220 Jun 28 21:16 .bash_logout -rw-r--r-- 1 simon simon 3526 Jun 28 21:16 .bashrc -rwxr-xr-x 1 simon simon 449 Jul 9 22:37 http_server.py -rw-r--r-- 1 simon simon 675 Jun 28 21:16 .profile -rw-r--r-- 1 simon simon 70 Jul 9 21:43 robots.txt drwx------ 2 simon simon 4096 Jun 28 21:39 .ssh --- # Vulnerable messaging system simon@covfefe:~$ read_message What is your name? simon Sorry simon, you're not Simon! The Internet Police have been informed of this violation. simon@covfefe:~$ read_message What is your name? Simon Hello Simon! Here is your message: Hi Simon, I hope you like our private messaging system. I'm really happy with how it worked out! If you're interested in how it works, I've left a copy of the source code in my home directory. - Charlie Root --- # Investigate root directory simon@covfefe:~$ cd /root simon@covfefe:/root$ ls -la total 24 drwxr-xr-x 2 root root 4096 Jul 9 20:24 . drwxr-xr-x 21 root root 4096 Jun 28 21:07 .. -rw-r--r-- 1 root root 570 Jan 31 2010 .bashrc -rw------- 1 root root 75 Jul 9 20:24 flag.txt -rw-r--r-- 1 root root 148 Aug 18 2015 .profile -rw-r--r-- 1 root root 767 Jul 9 20:24 read_message.c ### Flag #2 is in read_message.c ### Flag #3 is right there but we can't get to it yet --- # Exploit the messaging program - `/usr/local/bin/read_message` is what we're running; it's setuid to root - `/usr/local/sbin/message` is the program it execs; we'll change this to our chosen program - All variables in `main()` are allocated on the stack - Put `/bin/bash` into the 21st and subsequent bytes in the stack and voila! A shell that has exactly the same permissions as our current shell! --- # Rabbit-hole #3 The first time I tried the buffer overflow, I got it wrong by a couple of characters, and the `execve()` didn't work. I spent a lot of time messing around in `gdb` looking at memory trying to work out the exact layout. # Takeaways - Get the simplest possible thing working first - run `id` to confirm euid is root - I need to get better at `gdb`; `edb` looks like it might be useful, but I didn't have any joy using it to more easily disassemble code or ferret out memory addresses. --- # Screwup #3 Here's where I asked for help: `bash` doesn't work because it needs `-p` for an interactive shell whenever it's called setuid (see man page). This is an explicit feature to protect against exactly this situation. Workaround: `/bin/dash` Other alternatives, depending on distro/age: - `/bin/sh`: symlink to `/bin/dash` on modern Debian-based distros - `/bin/ash`: older Debian-based systems (and maybe others?) - `/bin/busybox`: statically-linked Swiss-army shell utility - good for when you can control the arguments but a full execution environment isn't available ??? The `-p` flag tells `bash`, "Yes, I know I called you from a setuid program; I meant to do that." --- # Trivia item #1 - The string that you're replacing doesn't actually appear in the code. I think this is because the string is not in the data segment, and the 3-byte separators between parts of the string are actually the instructions in the code segment to push the string onto the stack. --- # Obtain final flag Using `/bin/dash` for our shell, we can get our flag from `/root/flag.txt`. Mission accomplished! --- class: center, middle # Thanks for listening! IRC/Slack: blahdeblah [@paulgear1](https://twitter.com/paulgear1) https://libertysys.com.au/ ## Shameless plug I'm running the Bridge to Brisbane on Sunday to support victims of child sex trafficking: https://b2b2017.everydayhero.com/au/paul-gear