Last updated at Wed, 27 Sep 2017 20:56:08 GMT
I have to admit, parsing a URI is tricky. Most Metasploit modules try to do it with some kind of crazy custom regex-fu, but unfortunately most of them are kind of buggy. Because of this, I've committed a new patch to HttpClient -- a target_uri function that can automatically parse the URI for you. It's only a 4-line change, but should change the way we code HTTP-related modules.
Before I demonstrate how you can take advantage of target_uri, I should briefly explain why you should avoid doing this manually. First off, the URI structure looks like this:
Scheme | Hierarchical URI Indicator | Credential | Host | Port | Path to resource | Query string | Fragment |
---|
- Scheme: A string that indicates the protocol, such as: http, https, smb, ftp, etc.
- Hierarchical URL indicator: Optional. A string of "//".
- Credential: Optional. In this format: username:password@
- Host: An address to the server (note this can be IPv4, IPv6, 32-bit integer, etc)
- Port: Optional. This is pretty self-explanatory.
- Path To Resource: A directory or file path. This is trickier than you think, because how do you determine if "test" is a directory, or file? Keep in mind that when you do "set TARGETURI test" in a browser exploit in Metasploit, 'test' is treated as a directory, not file.
- Query String: Optional. Pretty much anything that comes after "?".
- Fragment: Optional. Pretty much anything that comes after "#".
RFC-3986 covers the generic URI syntax pretty well in case you'd like to read up more, but as you can see, it's really a lot of hassle to break it down. To ease off this process, we came up with a simple solution by using Ruby's stdlib -- or to be specific, the URI module. The following is a basic usage example:
require 'msf/core'
class Metasploit3 < Msf::Auxiliary
include Msf::Exploit::Remote::HttpClient
def initialize(info = {})
super(update_info(info,
'Name' => 'URI test case',
'Description' => %q{This module tests the target_uri function},
'Author' => [ 'sinn3r' ],
'License' => MSF_LICENSE
))
register_options(
[
# You must use TARGETURI, or target_uri won't work
OptString.new('TARGETURI', [true, 'The URI Path', '/cms/index.php?page=1&cmd=id'])
], self.class)
end
def run
uri = target_uri
print_status(uri.inspect)
end
end
The above example should return something like this:
msf auxiliary(test_case) > run
[*] #<URI::Generic:0x0000010c8c05e8 URL:/cms/index.php?page=1&cmd=id>
To retrieve just the resource path, you can simply do this (note: If there's no path, you will get a nil, so make sure you handle that properly. Same thing goes to scheme, port, query, fragment, etc):
uri = target_uri
print_status(uri.path) #We get "/cms/index.php"
If you want the query string (or a specific parameter), here's another trick on how to handle it:
require 'msf/core'
class Metasploit3 < Msf::Auxiliary
include Msf::Exploit::Remote::HttpClient
include Msf::Auxiliary::WmapScanUniqueQuery
def initialize(info = {})
super(update_info(info,
'Name' => 'URI test case',
'Description' => %q{This module tests the target_uri function},
'Author' => [ 'sinn3r' ],
'License' => MSF_LICENSE
))
register_options(
[
#You must use TARGETURI, or target_uri won't work
OptString.new('TARGETURI', [true, 'The URI Path', '/cms/index.php?page=1&cmd=id'])
], self.class)
end
def run
uri = target_uri
query = queryparse(uri.query || "")
param_page = query['page']
param_cmd = query['cmd']
print_status("Query is a #{query.class}")
print_status("Page is: #{param_page}")
print_status("CMD is : #{param_cmd}")
end
end
And this gives us the following output:
msf auxiliary(testme) > rerun
[*] Reloading module...
[*] Query is a Hash
[*] Page is: 1
[*] CMD is : id
[*] Auxiliary module execution completed
And that's it for now. In case you're interested in other HttpClient functions, please feel free to check out the following documentation: