Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

implements a simple grep command for msfconsole #820

Closed
wants to merge 2 commits into from

5 participants

@kernelsmith
Collaborator

example usage:
grep https show payloads
grep -i iPhone show exploits
grep -i sp3 show targets
grep '^[\s]*generic/c' show payloads

Usage: grep [options] pattern cmd

Grep the results of a console command (similar to Linux grep command)

OPTIONS:
-c Only print a count of matching lines.
-h Help banner.
-i Ignore case.
-m Stop after arg matches.
-v Invert match.

I've always wanted to add this... esp for with the show command, but it works on any command

kernelsmith implements a simple grep feature for msfconsole
example usage:
grep https show payloads
grep -i iPhone show exploits
grep -i sp3 show targets
grep '^[\s]*generic/c' show payloads

Usage: grep [options] pattern cmd

Grep the results of a console command (similar to Linux grep command)

OPTIONS:
    -c        Only print a count of matching lines.
    -h        Help banner.
    -i        Ignore case.
    -m <opt>  Stop after arg matches.
    -v        Invert match.
77a6469
@kernelsmith
Collaborator

Some use cases

msf exploit(ie_execcommand_uaf) > grep uaf show exploits
windows/browser/ie_execcommand_uaf 2012-09-14 good Microsoft Internet Explorer execCommand Use-After-Free Vulnerability

msf exploit(ie_execcommand_uaf) > grep db ?
db_connect Connect to an existing database
db_disconnect Disconnect from the current database instance
db_export Export a file containing the contents of the database
db_import Import a scan result file (filetype will be auto-detected)
db_nmap Executes nmap and records the output automatically
db_rebuild_cache Rebuilds the database-stored module cache
db_status Show the current database status

msf exploit(ie_execcommand_uaf) > grep -i save ?
makerc Save commands entered since start to a file
save Saves the active datastores

msf exploit(ie_execcommand_uaf) > grep -i CVE info
http://cve.mitre.org/cgi-bin/cvename.cgi?name=2012-4969

msf exploit(ie_execcommand_uaf) > grep -m 25 -i -v meterpreter|shell show payloads

Compatible Payloads
|------------------------------

Name Disclosure Date Rank Description
|---- ------------------- ---- -----------
generic/custom normal Custom Payload
generic/debug_trap normal Generic x86 Debug Trap
generic/tight_loop normal Generic x86 Tight Loop
windows/dllinject/bind_ipv6_tcp normal Reflective DLL Injection, Bind TCP Stager (IPv6)
windows/dllinject/bind_nonx_tcp normal Reflective DLL Injection, Bind TCP Stager (No NX or Win7)
windows/dllinject/bind_tcp normal Reflective DLL Injection, Bind TCP Stager
windows/dllinject/reverse_http normal Reflective DLL Injection, Reverse HTTP Stager
windows/dllinject/reverse_ipv6_http normal Reflective DLL Injection, Reverse HTTP Stager (IPv6)
windows/dllinject/reverse_ipv6_tcp normal Reflective DLL Injection, Reverse TCP Stager (IPv6)
windows/dllinject/reverse_nonx_tcp normal Reflective DLL Injection, Reverse TCP Stager (No NX or Win7)
windows/dllinject/reverse_ord_tcp normal Reflective DLL Injection, Reverse Ordinal TCP Stager (No NX or Win7)
windows/dllinject/reverse_tcp normal Reflective DLL Injection, Reverse TCP Stager
windows/dllinject/reverse_tcp_allports normal Reflective DLL Injection, Reverse All-Port TCP Stager
windows/dllinject/reverse_tcp_dns normal Reflective DLL Injection, Reverse TCP Stager (DNS)
windows/dns_txt_query_exec normal DNS TXT Record Payload Download and Execution
windows/download_exec_https normal Windows Executable Download (http,https,ftp) and Execute
windows/exec normal Windows Execute Command
windows/loadlibrary normal Windows LoadLibrary Path
windows/messagebox normal Windows MessageBox

@sempervictus

Found a small bug here - setting hosts from command output doesnt work properly, the filter doesnt apply to -R output.

Example:
"services -S http -R" produces a file with the IPs of all the hosts which have http running
"grep http services -R" produces a file with the IPs of all the hosts which have services.

kernelsmith adds the -A and -B options to grep
-A arg, show arg lines after match
-B arg, show arg lines before match
example:
grep -i -A 2 Reverse show advanced
267221b
@jlee-r7
Collaborator

Syntax on this is hard to get your head around since it doesn't match the way you do it with real grep on a real shell. Some day we'll have to break down and implement bash in msfconsole.

@kernelsmith
Collaborator

If you treat "show payloads" as a filename, the usage is the same as normal grep, like:
grep -i pattern filename
grep -i pattern show payloads

@kernelsmith
Collaborator

so what's up w/this? it's pretty low threat and is super handy

@scriptjunkie
Collaborator

Wouldn't it break RPC consoles? e.g. for gui's?

@scriptjunkie
Collaborator

The right way to do this is get a reference to your console, and temporarily redirect the output to a text buffer rather than whatever it was before. See the console driver code in lib/msf/ui/console/driver.rb, which will by default assign output to a Rex::Ui::Text::Output::Stdio.new [your classic msfconsole] or rpc consoles, which are actually "Web" consoles (see lib/msf/ui/web/console.rb) which use a WebConsolePipe, which is basically a Rex::IO::BidirectionalPipe. As the user interacts with one end, the other end is handled by the backend. You would want to do the same thing adding your own pipe as another layer.

At least, that's how I'd do it.

@kernelsmith
Collaborator

@hmoore-r7 had suggested Rex::Ui::Text::Output::* or similar so I ended up using *Buffer, but you make a good point, I will look into it and see if I can use the Rex::IO::BidirectionalPipe approach, it sounds great and it would be nice to have this work on other UI's

@kernelsmith
Collaborator

Ultimately I'd like to implement full msfconsole piping, but that might be a little ambitious for me, we'll see

@bperry-r7

Closing, when scriptjunkie's comments are addressed, please reopen (RE: IRC).

@bperry-r7 bperry-r7 closed this
@kernelsmith
Collaborator

Couldn't even give me the weekend. Weak.
@scriptjunkie do you think GUI's will ever make use of this command? If so, I'd like to irc w/you on your suggested solution to understand it better

@kernelsmith
Collaborator

@scriptjunkie I can't seem to find a method to redirect the output of an already instantiated console. I can see where you'd provide an output during init, but not a way to change it dynamically, do you know of a way? I could however create a new driver instance w/its output redirected, run the command & grep it, dispose of the new instance and return to the original. Although technically results could have some delta due to it being a different driver instance, but I highly doubt it's likely

@kernelsmith
Collaborator

FTR, I also added -s and -k options for skip and keep respectively. It allows you to skip or keep arg lines of text. skip is good when you don't want your grep to match the title in a table output etc, and keep is good for when you want to maintain the table column headers et w/o grepping them, like grep -k 5 https show payloads... so you can still see the column headers

@scriptjunkie
Collaborator

Well, yes, msfgui does need a fully-functioning console; it's the easiest way afaik to have two pentesters open up consoles on the same metasploit instance and hack together, and if they prefer the console, they should be able to use it. I figured you could directly access the console driver, but if you can't, you might need to modify the console classes to add a method to do that. I don't think new driver instances would work when interacting with meterpreter sessions for example, so that's probably not a good idea.

@kernelsmith
Collaborator

Understood. GUI just gives the impression that they aren't using console. Regardless, I believe I was able to make it happen. Getting a reference to the driver was easy. Checkout the repo if you can at https://github.com/kernelsmith/metasploit-framework/blob/msfconsole-grep/lib/msf/ui/console/command_dispatcher/core.rb#L2415 and let me know if you think that will work. I'm not real familiar with the RPC stuff. I have written a lua script for nmap that uses it, just for fun, but that's all.

I am still working on the code, but just the -A and -B options, not the stuff we're talking about. I will submit a PR as soon as I fix the -A/-B stuff unless you have more comments

@JonValt JonValt referenced this pull request from a commit
kernelsmith changes to address scriptjunkie's rpc concerns
as described in #820
9ad7261
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Sep 21, 2012
  1. implements a simple grep feature for msfconsole

    kernelsmith authored
    example usage:
    grep https show payloads
    grep -i iPhone show exploits
    grep -i sp3 show targets
    grep '^[\s]*generic/c' show payloads
    
    Usage: grep [options] pattern cmd
    
    Grep the results of a console command (similar to Linux grep command)
    
    OPTIONS:
        -c        Only print a count of matching lines.
        -h        Help banner.
        -i        Ignore case.
        -m <opt>  Stop after arg matches.
        -v        Invert match.
Commits on Sep 24, 2012
  1. adds the -A and -B options to grep

    kernelsmith authored
    -A arg, show arg lines after match
    -B arg, show arg lines before match
    example:
    grep -i -A 2 Reverse show advanced
This page is out of date. Refresh to see the latest.
Showing with 124 additions and 0 deletions.
  1. +124 −0 lib/msf/ui/console/command_dispatcher/core.rb
View
124 lib/msf/ui/console/command_dispatcher/core.rb
@@ -65,6 +65,15 @@ class Core
"-w" => [ true, "Specify connect timeout." ],
"-z" => [ false, "Just try to connect, then return." ])
+ @@grep_opts = Rex::Parser::Arguments.new(
+ "-h" => [ false, "Help banner." ],
+ "-i" => [ false, "Ignore case." ],
+ "-m" => [ true, "Stop after arg matches." ],
+ "-v" => [ false, "Invert match." ],
+ "-A" => [ true, "Show arg lines after a match." ],
+ "-B" => [ true, "Show arg lines before a match." ],
+ "-c" => [ false, "Only print a count of matching lines." ])
+
@@search_opts = Rex::Parser::Arguments.new(
"-h" => [ false, "Help banner." ])
@@ -82,6 +91,7 @@ def commands
"connect" => "Communicate with a host",
"color" => "Toggle color",
"exit" => "Exit the console",
+ "grep" => "Grep the output of another command",
"help" => "Help menu",
"info" => "Displays information about one or more module",
"irb" => "Drop into irb scripting mode",
@@ -2330,6 +2340,106 @@ def cmd_version(*args)
return true
end
+ def cmd_grep_help
+ print_line "Usage: grep [options] pattern cmd"
+ print_line
+ print_line "Grep the results of a console command (similar to Linux grep command)"
+ print(@@grep_opts.usage())
+ end
+
+ ##
+ # Greps the output of another console command
+ #
+ # :call-seq:
+ # cmd_grep(grep_opt1, grep_opt2, pattern, command, cmd_arg)
+ # cmd_grep(pattern, command)
+ def cmd_grep(*args)
+ return cmd_grep_help if args.length < 2
+ match_mods = {:insensitive => false}
+ output_mods = {:count => false, :invert => false}
+ @@grep_opts.parse(args.dup) do |opt, idx, val|
+ case opt
+ when "-h"
+ return cmd_grep_help
+ when "-m"
+ # limit to arg matches
+ match_mods[:max] = val.to_i
+ # delete opt and val from args list
+ args.shift
+ args.shift
+ when "-A"
+ # also return arg lines after a match
+ output_mods[:also] = val.to_i
+ # delete opt and val from args list
+ args.shift
+ args.shift
+ when "-B"
+ # also return arg lines before a match
+ output_mods[:also] = (val.to_i * -1)
+ # delete opt and val from args list
+ args.shift
+ args.shift
+ when "-v"
+ # invert match
+ match_mods[:invert] = true
+ # delete opt from args list
+ args.shift
+ when "-i"
+ # case insensitive
+ match_mods[:insensitive] = true
+ args.shift
+ when "-c"
+ # just count matches
+ output_mods[:count] = true
+ args.shift
+ end
+ end
+ # after deleting parsed options, the only args left should be the pattern, the cmd to run, and cmd args
+ pattern = args.shift
+ if match_mods[:insensitive]
+ rx = Regexp.new(pattern, true)
+ else
+ rx = Regexp.new(pattern)
+ end
+ cmd = args.join(" ")
+
+ # redirect stdout (only) temporarily
+ # we use a rex buffer but add a write method to the instance, which is required in order to be valid $stdout
+ orig_stdout = $stdout
+ buf = Rex::Ui::Text::Output::Buffer.new
+ def buf.write(msg = '')
+ self.print_raw(msg)
+ end
+ $stdout = buf # stdout is now redirected to buf
+ driver.run_single(cmd)
+ $stdout = orig_stdout # stdout is now restored
+ cmd_output = buf.dump_buffer
+ # put lines into an array so we can access them more easily and split('\n') doesn't work
+ all_lines = cmd_output.lines.select {|line| line}
+ # control matching based on remaining match_mods (:insensitive was already handled)
+ statement = 'line =~ rx'
+ statement = 'not line =~ rx' if match_mods[:invert]
+ our_lines = []
+ count = 0
+ all_lines.each_with_index do |line, line_num|
+ # we don't wan't to keep processing if we have a :max and we've reached it already
+ break if ( match_mods[:max] and count >= match_mods[:max] )
+ if (eval statement)
+ count += 1
+ our_lines += get_grep_lines(all_lines,line_num,output_mods[:also])
+ end
+ end
+
+ # now control output based on remaining output_mods such as :count
+ return print_status(count.to_s) if output_mods[:count]
+ our_lines.each {|line| print line}
+ end
+
+ def cmd_grep_tabs(str, words)
+ # TODO, make sure this works, just guessed to start
+ tab_complete(words.join(" "))
+ end
+
#
# Tab complete module names
#
@@ -2792,6 +2902,20 @@ def generate_module_table(type) # :nodoc:
'Columns' => [ 'Name', 'Disclosure Date', 'Rank', 'Description' ]
)
end
+ #
+ # Returns array of matched line at +line_num+ plus any after/before lines requested as
+ # integer +also+ from the lines specified as +all_lines+. +also+ is positive for "after"
+ # and negative for "before" lines
+ #
+ def get_grep_lines(all_lines,line_num, also=nil)
+ return [all_lines[line_num]] unless also
+ also = also.to_i
+ if also < 0
+ return all_lines.slice(line_num + also, also.abs + 1)
+ else
+ return all_lines.slice(line_num, also + 1)
+ end
+ end
end
Something went wrong with that request. Please try again.