Skip to content

Commit

Permalink
Refactor MoodleScanner execution and error handling
Browse files Browse the repository at this point in the history
- Updated the MoodleScanner class to improve subprocess execution and error handling.
- Replaced subprocess.call with subprocess.run for better output capture and error management.
- Enhanced logging for stdout and stderr during the moodlescan process.
- Implemented detailed parsing of the output to extract server info, version info, and vulnerabilities.
- Adjusted task result saving logic based on the findings from the moodlescan output.
- Updated Dockerfile to clone the correct Moodle Scanner repository.
  • Loading branch information
kshitijk4poor committed Jan 17, 2025
1 parent 2ce64eb commit c12b466
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 76 deletions.
143 changes: 69 additions & 74 deletions artemis/modules/moodle_scanner.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,103 +74,98 @@ class MoodleScanner(ArtemisBase):

def __init__(self, *args: Any, **kwargs: Any) -> None:
super().__init__(*args, **kwargs)
# Backup existing Moodle-Scanner user agents if any
subprocess.call(["cp", "/moodle_scanner/config/user_agents.txt", "/moodle_scanner/config/user_agents.txt.bak"])

def run(self, current_task: Task) -> None:
base_url = get_target_url(current_task)
self.log.info(f"Starting moodlescan for {base_url}")

try:
data = subprocess.check_output(
# Run moodlescan with error output captured
process = subprocess.run(
[
"python3",
"scanner.py",
"moodlescan.py",
"-u",
base_url,
"--output",
"json",
"-r"
"-r",
"-k"
],
cwd="/moodle_scanner",
stderr=subprocess.DEVNULL,
capture_output=True,
text=True,
check=True
)
except subprocess.CalledProcessError:
self.log.error(f"Failed to run Moodle-Scanner for {base_url}")
self.db.save_task_result(
task=current_task,
status=TaskStatus.ERROR,
status_reason="Failed to execute Moodle-Scanner",
data={},
)
return

self.log.info(f"Moodlescan stdout: {process.stdout}")
if process.stderr:
self.log.warning(f"Moodlescan stderr: {process.stderr}")

# Parse the output for relevant information
output_lines = process.stdout.splitlines()
server_info = None
version_info = None
vulnerabilities = []

for i, line in enumerate(output_lines):
if "Error: Can't connect" in line:
self.log.info(f"Connection error: {line}")
self.db.save_task_result(
task=current_task,
status=TaskStatus.OK,
status_reason=line,
data={"raw_output": process.stdout}
)
return

if "server" in line.lower() and ":" in line:
server_info = line.split(":", 1)[1].strip()
elif "version" in line.lower() and not line.startswith("."):
# Look at next line for version info if it's not dots or error
if i + 1 < len(output_lines):
next_line = output_lines[i + 1].strip()
if next_line and not next_line.startswith(".") and "error" not in next_line.lower():
version_info = next_line
elif "vulnerability" in line.lower() or "cve" in line.lower():
vulnerabilities.append(line.strip())

result = {
"server": server_info,
"version": version_info,
"vulnerabilities": vulnerabilities,
"raw_output": process.stdout
}

# Determine if anything interesting was found
if vulnerabilities:
status = TaskStatus.INTERESTING
status_reason = f"Found: {', '.join(vulnerabilities)}"
elif version_info and version_info != "Version not found":
status = TaskStatus.INTERESTING
status_reason = f"Found version: {version_info}"
else:
status = TaskStatus.OK
status_reason = "Version not found" if version_info == "Version not found" else None

# Extract filename from the output
output_prefix = "\n Running Moodle-Scanner and saving the report...\n\n Report saved to "
decoded_data = data.decode("ascii", errors="ignore")
if output_prefix in decoded_data:
filename = decoded_data.split(output_prefix)[-1].strip()
else:
self.log.error(f"Unexpected Moodle-Scanner output format for {base_url}")
self.db.save_task_result(
task=current_task,
status=TaskStatus.ERROR,
status_reason="Unexpected Moodle-Scanner output format",
data={},
status=status,
status_reason=status_reason,
data=result
)
return

try:
with open(filename, "r") as f:
data_str = f.read()
except FileNotFoundError:
self.log.error(f"Report file {filename} not found for {base_url}")
except subprocess.CalledProcessError as e:
self.log.error(f"Failed to run moodlescan for {base_url}")
self.log.error(f"Exit code: {e.returncode}")
self.log.error(f"Stdout: {e.stdout}")
self.log.error(f"Stderr: {e.stderr}")
self.db.save_task_result(
task=current_task,
status=TaskStatus.ERROR,
status_reason="Report file not found",
data={},
status_reason=f"Failed to execute moodlescan: {e.stderr}",
data={"stdout": e.stdout, "stderr": e.stderr},
)
return

# Cleanup
os.unlink(filename)

if data_str.strip():
try:
result = json.loads(data_str)
except json.JSONDecodeError:
self.log.error(f"Invalid JSON format in report for {base_url}")
self.db.save_task_result(
task=current_task,
status=TaskStatus.ERROR,
status_reason="Invalid JSON format in report",
data={},
)
return
else:
result = {}

# Parse the JSON data
messages = process_moodle_json(result)

if messages:
status = TaskStatus.INTERESTING
status_reason = ", ".join([message.message for message in messages])
else:
status = TaskStatus.OK
status_reason = None

self.db.save_task_result(
task=current_task,
status=status,
status_reason=status_reason,
data={
"original_result": result,
"message_data": [dataclasses.asdict(message) for message in messages],
"messages": [message.message for message in messages],
},
)


if __name__ == "__main__":
MoodleScanner().loop()
3 changes: 1 addition & 2 deletions docker/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,7 @@ RUN apk add --no-cache --virtual .build-deps gcc git libc-dev make libffi-dev li
GOBIN=/usr/local/bin/ go install -modfile go.mod github.com/projectdiscovery/nuclei/v3/cmd/nuclei && \
cd / && \
git clone https://github.com/rfc-st/humble.git --branch master /humble && \
git clone https://github.com/LuemmelSec/Moodle-Scanner.git /moodle_scanner && \
mkdir -p /moodle_scanner/config && \
git clone https://github.com/inc0d3/moodlescan.git /moodle_scanner && \
pip install --no-cache-dir -r requirements.txt -r /humble/requirements.txt -r /moodle_scanner/requirements.txt $ADDITIONAL_REQUIREMENTS && \
apk del .build-deps

Expand Down

0 comments on commit c12b466

Please sign in to comment.