import subprocess
import shlex
import os
import uuid
import datetime
from typing import Tuple, Dict, Any
from shutil import which
class ArjunError(Exception):
"""Custom exception for Arjun-related errors"""
pass
def run_arjun(url: str, args: str = "") -> Tuple[str, int]:
"""
Launch Arjun (HTTP parameter discovery tool) against the given target.
Arjun is a tool to find hidden HTTP parameters in web applications.
It helps in discovering undisclosed parameters that may be exploitable.
:param url: The target URL to scan (e.g. "https://example.com/page")
:param args: Additional arguments for Arjun
SCANNING:
-t, --threads INT Number of threads to use (default 5)
-d, --delay FLOAT Delay between requests in seconds
--timeout INT Request timeout in seconds
--proxy PROXY HTTP proxy to use (e.g. http://127.0.0.1:8080)
--headers FILE File containing HTTP headers
-c, --cookie COOKIE Cookie string to use
-H, --header HEADER Custom header (e.g. "Authorization: Bearer token")
OUTPUT:
-o, --output FILE Save output to file
-j, --json Output in JSON format
--verbose Verbose output
-q, --quiet Quiet mode
BEHAVIOR:
--get Use GET requests only
--post Use POST requests
--both Try both GET and POST
--stable Assume parameters are stable (skip verification)
-x, --method METHOD HTTP method to use
--no-color Disable colored output
:return: Tuple of (output_path, process_id)
"""
try:
if which("arjun") is None:
raise ArjunError(
"arjun not found in PATH. Please install arjun or ensure it's in your system PATH. "
"You can install it via: pip install arjun"
)
output_dir = os.path.join(os.getcwd(), "arjun_output")
os.makedirs(output_dir, exist_ok=True)
ts = datetime.datetime.now().strftime("%Y%m%d%H%M%S")
uid = uuid.uuid4().hex
filename = f"{ts}_{uid}.txt"
output_path = os.path.join(output_dir, filename)
args_list = args.split() if args else []
cmd = ["arjun", "-u", url] + args_list + ["-o", output_path]
if os.name == 'nt':
proc = subprocess.Popen(
cmd,
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
creationflags=subprocess.CREATE_NEW_PROCESS_GROUP
)
else:
proc = subprocess.Popen(
cmd,
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
start_new_session=True
)
pid = proc.pid
return output_path, pid
except FileNotFoundError:
raise ArjunError(
"arjun executable not found. Please ensure arjun is installed and in your PATH."
)
except Exception as e:
raise ArjunError(f"Error launching arjun scan for {url}: {str(e)}")
def get_arjun_output(file_path: str, pid: int) -> Dict[str, Any]:
"""
Retrieve Arjun scan results.
:param file_path: Path to the output file
:param pid: Process ID of the scan
:return: Dictionary containing scan results
"""
try:
import psutil
import platform
running = True
try:
if platform.system() == "Windows":
psutil.Process(pid)
else:
os.kill(pid, 0)
except (OSError, psutil.NoSuchProcess, psutil.AccessDenied):
running = False
if running:
if not os.path.isfile(file_path):
return {
"status": "running",
"message": f"Arjun scan running with PID {pid}",
"pid": pid
}
if not os.path.isfile(file_path):
return {
"status": "error",
"message": f"Output file not found: {file_path}",
"pid": pid
}
with open(file_path, 'r', encoding='utf-8', errors='ignore') as f:
content = f.read()
parameters = []
for line in content.split('\n'):
line = line.strip()
if line and not line.startswith('['):
parameters.append(line)
return {
"status": "completed",
"pid": pid,
"file_path": file_path,
"parameters_found": len(parameters),
"parameters": parameters,
"raw_output": content
}
except Exception as e:
return {
"status": "error",
"message": f"Error reading arjun output: {str(e)}",
"pid": pid
}