diff --git a/modules/vulnerabilities/unix/ssh/ssh_erlangotp_rce/files/erlang-otp-prebuilt_26.2.5.10-1_amd64.deb b/modules/vulnerabilities/unix/ssh/ssh_erlangotp_rce/files/erlang-otp-prebuilt_26.2.5.10-1_amd64.deb new file mode 100644 index 000000000..2bc4bf842 Binary files /dev/null and b/modules/vulnerabilities/unix/ssh/ssh_erlangotp_rce/files/erlang-otp-prebuilt_26.2.5.10-1_amd64.deb differ diff --git a/modules/vulnerabilities/unix/ssh/ssh_erlangotp_rce/files/start_ssh.escript b/modules/vulnerabilities/unix/ssh/ssh_erlangotp_rce/files/start_ssh.escript new file mode 100644 index 000000000..ee42662f1 --- /dev/null +++ b/modules/vulnerabilities/unix/ssh/ssh_erlangotp_rce/files/start_ssh.escript @@ -0,0 +1,31 @@ +#!/usr/bin/env escript +%%! -sname ssh_runner -noinput + +main([PortStr]) -> + Port = list_to_integer(PortStr), + + io:format("Starting Erlang SSH daemon on port ~p~n", [Port]), + + case application:ensure_all_started(ssh) of + {ok, _StartedApps} -> + ok; + {error, StartReason} -> + io:format("Failed to start ssh application dependencies: ~p~n", [StartReason]), + halt(1) + end, + + KeyDir = "/opt/erlang_ssh/ssh_keys", + + case ssh:daemon(Port, [ + {system_dir, KeyDir}, + {idle_time, infinity} + ]) of + {ok, Pid} -> + io:format("SSH daemon started successfully on port ~p, pid: ~p~n", [Port, Pid]), + receive + stop -> ok + end; + {error, DaemonReason} -> + io:format("Failed to start SSH daemon: ~p~n", [DaemonReason]), + halt(1) + end. \ No newline at end of file diff --git a/modules/vulnerabilities/unix/ssh/ssh_erlangotp_rce/manifests/config.pp b/modules/vulnerabilities/unix/ssh/ssh_erlangotp_rce/manifests/config.pp new file mode 100644 index 000000000..444d5a9b3 --- /dev/null +++ b/modules/vulnerabilities/unix/ssh/ssh_erlangotp_rce/manifests/config.pp @@ -0,0 +1,39 @@ +class ssh_erlangotp_rce::config { + $secgen_parameters = secgen_functions::get_parameters($::base64_inputs_file) + $leaked_filenames = $secgen_parameters['leaked_filenames'] + $strings_to_leak = $secgen_parameters['strings_to_leak'] + $ssh_username = $secgen_parameters['unix_username'][0] + $ssh_home = "/home/${ssh_username}" + + file { '/opt/erlang_ssh': + ensure => directory, + owner => 'root', + group => 'root', + mode => '0755', + } + + file { '/opt/erlang_ssh/ssh_keys': + ensure => directory, + owner => $ssh_username, + group => $ssh_username, + mode => '0700', + } + + file { '/opt/erlang_ssh/start_ssh.escript': + ensure => present, + owner => 'root', + group => 'root', + mode => '0755', + source => 'puppet:///modules/ssh_erlangotp_rce/start_ssh.escript', + require => File['/opt/erlang_ssh'], + } + + ::secgen_functions::leak_files { 'erlang_ssh-flag': + storage_directory => $ssh_home, + leaked_filenames => $leaked_filenames, + strings_to_leak => $strings_to_leak, + owner => $ssh_username, + mode => '0600', + leaked_from => 'ssh_erlangotp_rce', + } +} \ No newline at end of file diff --git a/modules/vulnerabilities/unix/ssh/ssh_erlangotp_rce/manifests/install.pp b/modules/vulnerabilities/unix/ssh/ssh_erlangotp_rce/manifests/install.pp new file mode 100644 index 000000000..ab460213c --- /dev/null +++ b/modules/vulnerabilities/unix/ssh/ssh_erlangotp_rce/manifests/install.pp @@ -0,0 +1,53 @@ +class ssh_erlangotp_rce::install { + $secgen_parameters = secgen_functions::get_parameters($::base64_inputs_file) + $ssh_username = $secgen_parameters['unix_username'][0] + $ssh_home = "/home/${ssh_username}" + $status_log = '/var/log/ssh_erlangotp_rce/stage_status.log' + + ensure_packages([ + 'openssh-client', + ]) + + file { '/var/log/ssh_erlangotp_rce': + ensure => directory, + owner => 'root', + group => 'root', + mode => '0755', + } + + file { '/tmp/erlang-otp-prebuilt_26.2.5.10-1_amd64.deb': + ensure => file, + source => 'puppet:///modules/ssh_erlangotp_rce/erlang-otp-prebuilt_26.2.5.10-1_amd64.deb', + mode => '0644', + } + + exec { 'install-erlang-otp-prebuilt': + command => "/bin/sh -c 'echo \"$(date -Is) install:start\" >> ${status_log}; if /usr/bin/dpkg -i /tmp/erlang-otp-prebuilt_26.2.5.10-1_amd64.deb > /var/log/ssh_erlangotp_rce/install.log 2>&1; then echo \"$(date -Is) install:ok\" >> ${status_log}; touch /var/log/ssh_erlangotp_rce/.install_ok; else rc=$?; echo \"$(date -Is) install:fail rc=\$rc\" >> ${status_log}; touch /var/log/ssh_erlangotp_rce/.install_fail; tail -n 120 /var/log/ssh_erlangotp_rce/install.log >> ${status_log}; exit \$rc; fi'", + creates => '/usr/local/bin/erl', + path => ['/usr/bin', '/bin', '/usr/sbin', '/sbin'], + logoutput => true, + require => [ + File['/var/log/ssh_erlangotp_rce'], + File['/tmp/erlang-otp-prebuilt_26.2.5.10-1_amd64.deb'], + ], + } + + user { $ssh_username: + ensure => present, + home => $ssh_home, + managehome => true, + shell => '/bin/bash', + } + + group { $ssh_username: + ensure => present, + } + + file { $status_log: + ensure => file, + owner => 'root', + group => 'root', + mode => '0644', + require => File['/var/log/ssh_erlangotp_rce'], + } +} \ No newline at end of file diff --git a/modules/vulnerabilities/unix/ssh/ssh_erlangotp_rce/manifests/service.pp b/modules/vulnerabilities/unix/ssh/ssh_erlangotp_rce/manifests/service.pp new file mode 100644 index 000000000..685a76c53 --- /dev/null +++ b/modules/vulnerabilities/unix/ssh/ssh_erlangotp_rce/manifests/service.pp @@ -0,0 +1,81 @@ +class ssh_erlangotp_rce::service { + $secgen_parameters = secgen_functions::get_parameters($::base64_inputs_file) + $ssh_port = pick($secgen_parameters['ssh_port'], ['2222']) + $port = $ssh_port[0] + $ssh_username = $secgen_parameters['unix_username'][0] + + exec { 'generate-ssh-host-rsa-key': + command => "/bin/sh -c '/usr/sbin/runuser -u ${ssh_username} -- ssh-keygen -t rsa -b 2048 -f /opt/erlang_ssh/ssh_keys/ssh_host_rsa_key -N \"\" > /var/log/ssh_erlangotp_rce/ssh_keygen_rsa.log 2>&1'", + path => ['/usr/sbin', '/usr/bin', '/sbin', '/bin'], + creates => '/opt/erlang_ssh/ssh_keys/ssh_host_rsa_key', + logoutput => true, + require => [ + File['/var/log/ssh_erlangotp_rce'], + File['/opt/erlang_ssh/ssh_keys'], + User[$ssh_username], + ], + } + + exec { 'generate-ssh-host-ecdsa-key': + command => "/bin/sh -c '/usr/sbin/runuser -u ${ssh_username} -- ssh-keygen -t ecdsa -b 256 -f /opt/erlang_ssh/ssh_keys/ssh_host_ecdsa_key -N \"\" > /var/log/ssh_erlangotp_rce/ssh_keygen_ecdsa.log 2>&1'", + path => ['/usr/sbin', '/usr/bin', '/sbin', '/bin'], + creates => '/opt/erlang_ssh/ssh_keys/ssh_host_ecdsa_key', + logoutput => true, + require => Exec['generate-ssh-host-rsa-key'], + } + + file { '/etc/systemd/system/erlang-otp-ssh-rce.service': + ensure => file, + owner => 'root', + group => 'root', + mode => '0644', + content => @("UNIT"), +[Unit] +Description=Erlang OTP vulnerable SSH daemon +After=network-online.target +Wants=network-online.target + +[Service] +Type=simple +User=${ssh_username} +Group=${ssh_username} +WorkingDirectory=/opt/erlang_ssh +ExecStart=/usr/local/bin/escript /opt/erlang_ssh/start_ssh.escript ${port} +Restart=on-failure +RestartSec=3 +StandardOutput=append:/var/log/ssh_erlangotp_rce/ssh_daemon_start.log +StandardError=append:/var/log/ssh_erlangotp_rce/ssh_daemon_start.log + +[Install] +WantedBy=multi-user.target +| UNIT + notify => Exec['systemd-daemon-reload'], + require => [ + File['/var/log/ssh_erlangotp_rce'], + Exec['generate-ssh-host-ecdsa-key'], + File['/opt/erlang_ssh/start_ssh.escript'], + Exec['install-erlang-otp-prebuilt'], + User[$ssh_username], + ], + } + + exec { 'systemd-daemon-reload': + command => '/bin/systemctl daemon-reload', + path => ['/usr/bin', '/bin', '/usr/sbin', '/sbin'], + refreshonly => true, + } + + service { 'erlang-otp-ssh-rce': + ensure => running, + enable => true, + provider => 'systemd', + subscribe => [ + File['/etc/systemd/system/erlang-otp-ssh-rce.service'], + File['/opt/erlang_ssh/start_ssh.escript'], + ], + require => [ + Exec['systemd-daemon-reload'], + Exec['generate-ssh-host-ecdsa-key'], + ], + } +} \ No newline at end of file diff --git a/modules/vulnerabilities/unix/ssh/ssh_erlangotp_rce/secgen_metadata.xml b/modules/vulnerabilities/unix/ssh/ssh_erlangotp_rce/secgen_metadata.xml new file mode 100644 index 000000000..03c763587 --- /dev/null +++ b/modules/vulnerabilities/unix/ssh/ssh_erlangotp_rce/secgen_metadata.xml @@ -0,0 +1,59 @@ + + + Erlang/OTP SSH Unauthenticated RCE + Rosie Fletcher + MIT + Erlang/OTP SSH server allows unauthenticated remote code execution via crafted SSH protocol messages. CVE-2025-32433 affects versions prior to OTP-27.3.3, OTP-26.2.5.11, and OTP-25.3.2.20. The vulnerability exists in the SSH handshake message handling where message types >= 80 are incorrectly processed before authentication. + + erlang_ssh + user_rwx + remote + linux + low + + strings_to_leak + leaked_filenames + unix_username + + + + + + + + + + + + + + CVE-2025-32433 + https://github.com/erlang/otp/security/advisories/GHSA-37cp-fgq5-7wc2 + https://nvd.nist.gov/vuln/detail/CVE-2025-32433 + erlang + Apache-2.0 + + Erlang/OTP SSH server running on 2222 port + Erlang/OTP SSH is vulnerable to pre-authentication RCE. Exploit via metasploit module (linux/ssh/ssh_erlangotp_rce). + + + erlang + + + update + + + + EXPLOITATION + EXPLOITATION FRAMEWORKS + + + CVEs and CWEs + + + PENETRATION TESTING - SOFTWARE TOOLS + PENETRATION TESTING - ACTIVE PENETRATION + + \ No newline at end of file diff --git a/modules/vulnerabilities/unix/ssh/ssh_erlangotp_rce/ssh_erlangotp_rce.pp b/modules/vulnerabilities/unix/ssh/ssh_erlangotp_rce/ssh_erlangotp_rce.pp new file mode 100644 index 000000000..48ea0a419 --- /dev/null +++ b/modules/vulnerabilities/unix/ssh/ssh_erlangotp_rce/ssh_erlangotp_rce.pp @@ -0,0 +1,3 @@ +include ssh_erlangotp_rce::install +include ssh_erlangotp_rce::config +include ssh_erlangotp_rce::service \ No newline at end of file diff --git a/scenarios/ctf/SSH_it_happens.xml b/scenarios/ctf/SSH_it_happens.xml new file mode 100644 index 000000000..ddeec712c --- /dev/null +++ b/scenarios/ctf/SSH_it_happens.xml @@ -0,0 +1,109 @@ + + + + SSH-it happens + Rosie Fletcher + + A server is running an Erlang/OTP SSH daemon vulnerable to CVE-2025-32433. + Exploit the pre-authentication RCE to gain root access and capture the flag. + + + ctf + attack-ctf + intermediate + + + server-side misconfiguration and vulnerable components + Missing Authentication + + + EXPLOITATION + EXPLOITATION FRAMEWORKS + + + CVEs and CWEs + + + PENETRATION TESTING - SOFTWARE TOOLS + PENETRATION TESTING - ACTIVE PENETRATION + + + + attack_vm + + + + 172.16.0.2 + 172.16.0.3 + + + + + {"username":"kali","password":"kali","super_user":"true","strings_to_leak":[],"leaked_filenames":[]} + + + + + + + {"username":"kali","password":"kali","super_user":"true","strings_to_leak":[],"leaked_filenames":[]} + + + false + + + + + + + + + + + IP_addresses + + + + + + + + spoiler_admin_pass + + + + + + server + + + + + + + + 2222 + + + + + + + + + + + + IP_addresses + + + + + spoiler_admin_pass + + + + + \ No newline at end of file