Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file not shown.
90 changes: 90 additions & 0 deletions modules/vulnerabilities/unix/http/raspap_rce/manifests/config.pp
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
# Class: raspap_rce::config
# Configure RaspAP in its vulnerable state and set up the CTF challenge
class raspap_rce::config {
Exec { path => [ '/bin/', '/sbin/' , '/usr/bin/', '/usr/sbin/' ] }
$secgen_parameters = secgen_functions::get_parameters($::base64_inputs_file)
$port = $secgen_parameters['port'][0]
$strings_to_leak = $secgen_parameters['strings_to_leak']
$leaked_filenames = $secgen_parameters['leaked_filenames']
$strings_to_pre_leak = $secgen_parameters['strings_to_pre_leak']
$admin_password = $secgen_parameters['admin_password'][0]

$user = 'www-data'
$install_dir = '/var/www/raspap'

# Configure RaspAP - config.php must be in includes/ directory
# The vulnerable code does: require_once '../../includes/config.php'
file { "${install_dir}/includes/config.php":
ensure => file,
content => template('raspap_rce/config.php.erb'),
owner => $user,
group => $user,
mode => '0644',
require => Class['raspap_rce::install'],
}

# Create raspap.php in config directory (required by index.php)
file { "${install_dir}/config/raspap.php":
ensure => file,
content => template('raspap_rce/raspap.php.erb'),
owner => $user,
group => $user,
mode => '0644',
require => Class['raspap_rce::install'],
}

# Create raspap.auth file with bcrypt hashed admin password
# RaspAP expects: line 1 = username, line 2 = bcrypt hash
# htpasswd outputs username:hash format, so we extract and create separate lines
exec { 'create-raspap-auth':
command => "htpasswd -bcB /tmp/raspap_auth_temp admin '${admin_password}' && awk -F: '{print $1; print $2}' /tmp/raspap_auth_temp > ${install_dir}/config/raspap.auth && rm /tmp/raspap_auth_temp",
require => [Class['raspap_rce::install'], Package['apache2-utils']],
creates => "${install_dir}/config/raspap.auth",
}
-> file { "${install_dir}/config/raspap.auth":
owner => $user,
group => $user,
mode => '0644',
}

# Configure lighttpd
file { '/etc/lighttpd/lighttpd.conf':
ensure => file,
content => template('raspap_rce/lighttpd.conf.erb'),
owner => 'root',
group => 'root',
mode => '0644',
notify => Service['lighttpd'],
}

# Create vulnerable OpenVPN configuration directory
exec { 'create-openvpn-dir':
command => 'mkdir -p /etc/openvpn/client',
creates => '/etc/openvpn/client',
}

# Create a dummy OpenVPN config for realism
file { '/etc/openvpn/client/example.ovpn':
ensure => file,
content => "# Dummy OpenVPN configuration for realism\n",
owner => 'root',
mode => '0644',
require => Exec['create-openvpn-dir'],
}

# Set log directory permissions
exec { 'set-log-perms':
command => 'chmod 755 /var/log/lighttpd',
require => Class['raspap_rce::install'],
}

# Leak flag files for students to find
::secgen_functions::leak_files { 'raspap-file-leak':
storage_directory => '/var/www',
leaked_filenames => $leaked_filenames,
strings_to_leak => $strings_to_leak,
owner => $user,
mode => '0600',
leaked_from => 'raspap_rce',
}
}
79 changes: 79 additions & 0 deletions modules/vulnerabilities/unix/http/raspap_rce/manifests/install.pp
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# Class: raspap_rce::install
# Install RaspAP v2.8.7 and all required dependencies
# All packages are available in Debian 12 standard repositories
class raspap_rce::install {
Exec { path => [ '/bin/', '/sbin/' , '/usr/bin/', '/usr/sbin/' ] }
$user = 'www-data'
$install_dir = '/var/www/raspap'
$user_home = '/var/www'

# Install required packages (all available in Debian 12)
ensure_packages([
'lighttpd',
'php-cgi',
'php-curl',
'php-json',
'php-mbstring',
'php-xml',
'php-sqlite3',
'hostapd',
'dnsmasq',
'unzip',
'apache2-utils' # for htpasswd (bcrypt password hashing)
])

# Enable PHP in lighttpd
exec { 'enable-php-fastcgi':
command => 'lighttpd-enable-mod fastcgi-php',
require => Package['lighttpd', 'php-cgi'],
}

# Create installation directory
file { $install_dir:
ensure => directory,
owner => $user,
group => $user,
mode => '0755',
require => Package['lighttpd'],
}

# Copy RaspAP archive to the system
# Note: File is named with capital AP but is actually a ZIP archive
file { "${user_home}/raspAP-webgui-2.8.7.tar.gz":
source => 'puppet:///modules/raspap_rce/raspAP-webgui-2.8.7.tar.gz',
owner => $user,
mode => '0644',
require => Package['lighttpd'],
}

# Extract RaspAP archive (it's a ZIP file despite the .tar.gz extension)
# Note: GitHub archives extract to raspap-webgui-2.8.7 (with version number)
-> exec { 'extract-raspap':
cwd => $user_home,
command => 'unzip -o raspAP-webgui-2.8.7.tar.gz',
creates => "${user_home}/raspap-webgui-2.8.7",
require => Package['unzip'],
}

# Move RaspAP files to installation directory
-> exec { 'move-raspap':
cwd => $user_home,
command => "mv raspap-webgui-2.8.7/* ${install_dir}/",
creates => "${install_dir}/index.php",
}

# Set proper ownership
-> exec { 'set-raspap-permissions':
command => "chown -R ${user}:${user} ${install_dir}",
}

# Create necessary directories
-> exec { 'create-raspap-dirs':
command => "mkdir -p ${install_dir}/config ${install_dir}/tmp",
}

# Set permissions on config and tmp directories
-> exec { 'set-raspap-dir-permissions':
command => "chown ${user}:${user} ${install_dir}/config ${install_dir}/tmp",
}
}
12 changes: 12 additions & 0 deletions modules/vulnerabilities/unix/http/raspap_rce/manifests/service.pp
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Class: raspap_rce::service
# Start the lighttpd web server service
class raspap_rce::service {
require raspap_rce::config
Exec { path => [ '/bin/', '/sbin/' , '/usr/bin/', '/usr/sbin/' ] }

service { 'lighttpd':
ensure => running,
enable => true,
require => Class['raspap_rce::config'],
}
}
3 changes: 3 additions & 0 deletions modules/vulnerabilities/unix/http/raspap_rce/raspap_rce.pp
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
include raspap_rce::install
include raspap_rce::config
include raspap_rce::service
85 changes: 85 additions & 0 deletions modules/vulnerabilities/unix/http/raspap_rce/secgen_metadata.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
<?xml version="1.0"?>
<vulnerability xmlns="http://www.github/cliffe/SecGen/vulnerability"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.github/cliffe/SecGen/vulnerability">

<name>RaspAP Unauthenticated Command Injection</name>
<author>Rosie Fletcher</author>
<module_license>MIT</module_license>
<description>
RaspAP versions 2.8.0 through 2.8.7 are vulnerable to unauthenticated
remote command execution via CVE-2022-39986. The vulnerability exists
in ajax/openvpn/del_ovpncfg.php due to insufficient input validation
on the cfg_id parameter, allowing attackers to inject arbitrary shell
commands. No authentication is required to exploit this vulnerability.

RaspAP is a web interface for managing wireless access points on
Raspberry Pi devices. This module installs RaspAP 2.8.7 in its
vulnerable configuration.
</description>

<type>http</type>
<privilege>user_rwx</privilege>
<access>remote</access>
<platform>linux</platform>
<difficulty>low</difficulty>

<read_fact>port</read_fact>
<read_fact>strings_to_leak</read_fact>
<read_fact>leaked_filenames</read_fact>
<read_fact>strings_to_pre_leak</read_fact>
<read_fact>admin_password</read_fact>

<default_input into="port">
<value>80</value>
</default_input>

<default_input into="strings_to_leak">
<generator type="message_generator"/>
</default_input>

<default_input into="leaked_filenames">
<generator type="filename_generator"/>
</default_input>

<default_input into="strings_to_pre_leak">
<generator type="message_generator"/>
</default_input>

<default_input into="admin_password">
<generator type="password_generator"/>
</default_input>

<cve>CVE-2022-39986</cve>
<cvss_base_score>9.8</cvss_base_score>
<reference>https://nvd.nist.gov/vuln/detail/CVE-2022-39986</reference>
<reference>https://github.com/advisories/GHSA-7c28-wg7r-pg6f</reference>
<reference>https://github.com/tucommenceapousser/RaspAP-CVE-2022-39986-PoC</reference>
<reference>https://github.com/billz/raspap-webgui/</reference>

<software_name>RaspAP Web GUI</software_name>
<software_license>GPL-3.0</software_license>

<requires>
<type>update</type>
</requires>

<CyBOK KA="WAM" topic="Server-Side Vulnerabilities and Mitigations">
<keyword>server-side misconfiguration and vulnerable components</keyword>
<keyword>Command injection</keyword>
<keyword>Input validation</keyword>
</CyBOK>
<CyBOK KA="MAT" topic="Attacks and exploitation">
<keyword>EXPLOITATION</keyword>
<keyword>EXPLOITATION FRAMEWORKS</keyword>
<keyword>Command Injection</keyword>
</CyBOK>
<CyBOK KA="SS" topic="Categories of Vulnerabilities">
<keyword>CVEs and CWEs</keyword>
<keyword>CWE-78: OS Command Injection</keyword>
</CyBOK>
<CyBOK KA="SOIM" topic="PENETRATION TESTING">
<keyword>PENETRATION TESTING - SOFTWARE TOOLS</keyword>
<keyword>PENETRATION TESTING - ACTIVE PENETRATION</keyword>
</CyBOK>
</vulnerability>
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<?php
// RaspAP Configuration File - Standalone for CTF (CVE-2022-39986)
// Define all constants directly (defaults.php has a circular dependency bug)
// This file is placed in /var/www/raspap/includes/config.php

define('RASPI_CONFIG', '/var/www/raspap/config/');
define('RASPI_BRAND_TEXT', 'RaspAP');
define('RASPI_VERSION', '2.8.7');
define('RASPI_CONFIG_NETWORK', RASPI_CONFIG.'/networking/defaults.json');
define('RASPI_ADMIN_DETAILS', RASPI_CONFIG.'raspap.auth');
define('RASPI_WIFI_AP_INTERFACE', 'wlan0');
define('RASPI_CACHE_PATH', sys_get_temp_dir() . '/raspap');
define('RASPI_DNSMASQ_LEASES', '/var/lib/misc/dnsmasq.leases');
define('RASPI_DNSMASQ_PREFIX', '/etc/dnsmasq.d/090_');
define('RASPI_ADBLOCK_LISTPATH', '/etc/raspap/adblock/');
define('RASPI_ADBLOCK_CONFIG', RASPI_DNSMASQ_PREFIX.'adblock.conf');
define('RASPI_HOSTAPD_CONFIG', '/etc/hostapd/hostapd.conf');
define('RASPI_DHCPCD_CONFIG', '/etc/dhcpcd.conf');
define('RASPI_DHCPCD_LOG', '/var/log/dnsmasq.log');
define('RASPI_WPA_SUPPLICANT_CONFIG', '/etc/wpa_supplicant/wpa_supplicant.conf');
define('RASPI_HOSTAPD_CTRL_INTERFACE', '/var/run/hostapd');
define('RASPI_WPA_CTRL_INTERFACE', '/var/run/wpa_supplicant');
define('RASPI_OPENVPN_CLIENT_PATH', '/etc/openvpn/client/');
define('RASPI_OPENVPN_CLIENT_CONFIG', '/etc/openvpn/client/client.conf');
define('RASPI_OPENVPN_CLIENT_LOGIN', '/etc/openvpn/client/login.conf');
define('RASPI_WIREGUARD_PATH', '/etc/wireguard/');
define('RASPI_WIREGUARD_CONFIG', RASPI_WIREGUARD_PATH.'wg0.conf');
define('RASPI_TORPROXY_CONFIG', '/etc/tor/torrc');
define('RASPI_LIGHTTPD_CONFIG', '/etc/lighttpd/lighttpd.conf');
define('RASPI_ACCESS_CHECK_IP', '1.1.1.1');
define('RASPI_ACCESS_CHECK_DNS', 'one.one.one.one');
define('RASPI_5GHZ_ISO_ALPHA2', array('NL','US'));
define('RASPI_5GHZ_MAX_CHANNEL', 165);

// Disable authentication for CTF (unauthenticated CVE-2022-39986)
define('RASPI_AUTH_ENABLED', false);

// Optional services
define('RASPI_WIFICLIENT_ENABLED', true);
define('RASPI_HOTSPOT_ENABLED', true);
define('RASPI_NETWORK_ENABLED', true);
define('RASPI_DHCP_ENABLED', true);
define('RASPI_ADBLOCK_ENABLED', false);
define('RASPI_OPENVPN_ENABLED', false);
define('RASPI_WIREGUARD_ENABLED', false);
define('RASPI_TORPROXY_ENABLED', false);
define('RASPI_CONFAUTH_ENABLED', true);
define('RASPI_CHANGETHEME_ENABLED', true);
define('RASPI_VNSTAT_ENABLED', true);
define('RASPI_SYSTEM_ENABLED', true);
define('RASPI_MONITOR_ENABLED', false);

// Locale settings
define('LOCALE_ROOT', 'locale');
define('LOCALE_DOMAIN', 'messages');
?>
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# Lighttpd configuration for RaspAP
# Configured for CVE-2022-39986 vulnerability module

server.modules = (
"mod_access",
"mod_alias",
"mod_redirect",
"mod_rewrite",
"mod_fastcgi",
"mod_accesslog",
)

server.document-root = "/var/www/raspap"
server.upload-dirs = ( "/var/cache/lighttpd/uploads" )
server.errorlog = "/var/log/lighttpd/error.log"
server.pid-file = "/var/run/lighttpd.pid"
server.username = "www-data"
server.groupname = "www-data"
server.port = <%= @port %>
server.bind = "0.0.0.0"

# PHP configuration
fastcgi.server = (
".php" => ((
"bin-path" => "/usr/bin/php-cgi",
"socket" => "/tmp/php.socket",
"max-procs" => 1,
"bin-environment" => (
"PHP_FCGI_CHILDREN" => "4",
"PHP_FCGI_MAX_REQUESTS" => "10000"
),
"bin-copy-environment" => (
"PATH", "SHELL", "USER"
),
"broken-scriptfilename" => "enable"
))
)

# Static file caching
static-file.exclude-extensions = ( ".php", ".pl", ".fcgi" )

# MIME types
mimetype.assign = (
".php" => "application/x-httpd-php",
".html" => "text/html",
".txt" => "text/plain",
".jpg" => "image/jpeg",
".png" => "image/png",
".css" => "text/css",
".js" => "application/javascript"
)

# Access log
accesslog.filename = "/var/log/lighttpd/access.log"

# Directory listing disabled
dir-listing.activate = "disable"

# Redirect root URL to index.php
url.redirect = (
"^/$" => "/index.php"
)

# URL rewriting for RaspAP - exclude ajax endpoints to preserve vulnerability
url.rewrite-if-not-file = (
"^/([^?]+)(\?.*)?$" => "/index.php?page=$1$2"
)
Loading