New content and modules on the way

•November 15, 2011 • 1 Comment

The Shodan search module for Metasploit is something I created over a year ago as a fun project. Several months ago, I submitted it to the Metasploit Project for inclusion and was told to rewrite it using the native MSF libraries and not Ruby libraries (net/http). Of course, I ended up frustrated because I followed the example of 3 other MSF auxiliary modules that used net/http.

I’ve since rewritten the module with native MSF libs, removed the dependency on an external JSON rubygem, added support for the “page” Shodan variable, and more. The final thing to do before resubmitting (via the new git system) is to debug an issue where my results differ from a Shodan web search with the same parameters.

There are some additional modules I’ve been thinking of writing related to my interest in forensics and incident response that would work well in a penetration testing scenario. I also will likely be putting together a module or two related to my mobile security research with Kevin Johnson of SecureIdeas for the presentation we submitted to ShmooCon.

More to come…


Metasploit Auxiliary Module: SHODAN Enumerator

•September 7, 2010 • 5 Comments

SHODAN is an extremely useful tool for scanning the Internet without having to do any scanning. It provides a search engine for banners and SNMP information that have been harvested from Internet-facing systems. I wrote a couple of scripts to leverage the API but wanted to go further by creating a module for the Metasploit Framework.

The SHODAN Enumerator module (download here) requires two options, APIKEY and QUERY, to work. There is a third option (OUTFILE) to write the IPs from the search to a file along with advanced options for sending the request through a web proxy. Database support is included and the services information for each IP is populated with the port, protocol, and banner. NOTE: Some systems will require ruby json gem to be installed (gem install json).

=[ metasploit v3.4.2-dev [core:3.4 api:1.0]
+ — –=[ 585 exploits – 301 auxiliary
+ — –=[ 224 payloads – 27 encoders – 8 nops
=[ svn r10253 updated today (2010.09.07)

msf > use auxiliary/gather/shodan_enumerator
msf auxiliary(shodan_enumerator) > info

Name: Shodan Enumerator
Version: 0.1
License: Metasploit Framework License (BSD)
Rank: Normal

Provided by:
John Sawyer – –

Basic options:
Name Current Setting Required Description
—- ————— ——– ———–
OUTFILE no A filename to store the list of IPs
QUERY yes Keywords you want to search for

This module uses the SHODAN API to query the database and returns
the first 50 IPs. SHODAN accounts are free & output can be sent to a
file for use by another program. Results are also populated into the
services table in the database. NOTE: SHODAN filters (port,
hostname, os, before, after) can be used in queries, but the API
does not allow net and country filters. See “show advanced” for
proxy settings. API: FILTERS:

msf auxiliary(shodan_enumerator) > set APIKEY -=REMOVED=-

msf auxiliary(shodan_enumerator) > set query schneider etg3021
query => schneider etg3021

msf auxiliary(shodan_enumerator) > run

[*] Running SHODAN query …..
[*] Country Statistics:
[*] France (FR): 1
[*] United Kingdom (GB): 1
[*] Total: 2
[*] IP Results:
[*] Auxiliary module execution completed

msf auxiliary(shodan_enumerator) > set OUTFILE /tmp/cisco-ios
OUTFILE => /tmp/cisco-ios

The QUERY options supports multiple keywords and SHODAN filters including port, hostname, os, before and after. The API does not support filters net and country.

msf auxiliary(shodan_enumerator) > set QUERY cisco-ios last-modified after:20/08/2010
QUERY => cisco-ios last-modified after:20/08/2010

msf auxiliary(shodan_enumerator) > run

[*] Running SHODAN query …..
[*] Country Statistics:
[*] United States (US): 61
[*] China (CN): 16
[*] United Kingdom (GB): 14
[*] Mexico (MX): 11
[*] Italy (IT): 11
[*] Total: 264
[*] IP Results:
[*] Writing IPs to /tmp/cisco-ios…
[*] Auxiliary module execution completed

SHODAN search scripts

•September 3, 2010 • 3 Comments

I had several requests for the additional Ruby scripts from the previous SHODAN API post. Here they are. The first one is the API calls and the last three let you query and return all results, query and get back just the IPs, and query information about a single IP. An API key is required but is free after you create a free SHODAN account.

Quick ‘n Dirty Ruby SHODAN API

•August 31, 2010 • Leave a Comment

Here’s some code I threw together last night that mimics the Python code achillean published here to interface with the SHODAN API. The first contains shodan_query and shodan_host that can be used to query for a string like VxWorks and dig deeper into a particular IP, respectively. Note: You will need to register with SHODAN and get an API key. Also, you’ll need to install the JSON gem.

Eventually, I plan to turn this into an auxiliary module for Metasploit so you can enter your API key, the IP or search term, and have resulting data stored in a log file or database.

require ‘rubygems’
require ‘json’
require ‘net/http’

def shodan_query(query, apikey)
base_url = “”
url = “#{base_url}&q=#{URI.encode(query)}&key=#{apikey}”
resp = Net::HTTP.get_response(URI.parse(url))
data = resp.body

result = JSON.parse(data)

return result

def shodan_host(ip, apikey)
base_url = “”
url = “#{base_url}&ip=#{URI.encode(ip)}&key=#{apikey}”
resp = Net::HTTP.get_response(URI.parse(url))
data = resp.body

result = JSON.parse(data)

return result

This next part shows them in use within irb. The returned JSON is parsed and stored as a hash that can be printed however you want using pp or yaml.

irb(main):001:0> require ‘shodan_api.rb’
=> true
irb(main):002:0> query_results = shodan_query(‘vxworks’, ‘my_key’)
=> {“matches”=>[{“updated”=>”23.08.2010”, “ip”=>””, “hostnames”=>[“”], “country”=>”US”, “data”=>”HTTP/1.0 200 OK\r\nDate: Mon, 03 Oct 2033 17:10:43 GMT\r\nServer: Jetty/4.2.x (VxWorks/WIND version 2.9 ppc java/1.1-rr-std-b12)\r\nTransfer-Encoding: chunked\r\nContent-Length: 767\r\nLast-Modified: Tue, 19 Jul 2033 14:21:36 GMT\r\n\r\n”, “port”=>80}, {“updated”=>”23.08.2010”, “ip”=>””, “hostnames”=>[“”], “country”=>”US”, “data”=>”HTTP/1.0 200 OK\r\nDate: Mon, 23 Aug 2010 01:59:19 GMT\r\nServer: Jetty/4.2.x (VxWorks/WIND version 2.9 ppc java/1.1-rr-std-b12)\r\nTransfer-Encoding: chunked\r\nContent-Length: 767\r\nLast-Modified: Fri, 11 Sep 2009 20:55:48 GMT\r\n\r\n”, “port”=>80}, {“updated”=>”23.08.2010”, “ip”=>””, “hostnames”=>[“”], “country”=>”FR”, “data”=>”HTTP/1.0 302 Moved Temporarily\r\nDate: Mon, 23 Aug 2010 05:39:32 GMT\r\nServer: Jetty/4.2.x (VxWorks/WIND version 2.9 ppc java/1.1-rr-std-b12)\r\nExpires: Thu, 01 Jan 1970 00:00:00 GMT\r\nSet-Cookie: JSESSIONID=15roktflvbrw3;Path=/\r\nLocation:\r\nTransfer-Encoding: chunked\r\n\r\n”, “port”=>80}, {“updated”=>”23.08.2010”, “ip”=>””, “hostnames”=>[“”],

irb(main):003:0> host_info = shodan_host(‘’, ‘my_key’)
=> {“city”=>”Madison”, “ip”=>””, “data”=>[{“timestamp”=>”21.06.2010”, “banner”=>”HTTP/1.0 302 Moved Temporarily\r\nDate: Sun, 20 Jun 2010 19:52:36 GMT\r\nServer: Jetty/4.2.x (VxWorks/WIND version 2.9 ppc java/1.1-rr-std-b12)\r\nExpires: Thu, 01 Jan 1970 00:00:00 GMT\r\nSet-Cookie: JSESSIONID=3tii8gafp66tb;Path=/\r\nLocation:\r\nTransfer-Encoding: chunked\r\n\r\n”, “port”=>80}, {“timestamp”=>”20.08.2010”, “banner”=>”HTTP/1.0 302 Moved Temporarily\r\nDate: Thu, 19 Aug 2010 19:55:24 GMT\r\nServer: Jetty/4.2.x (VxWorks/WIND version 2.9 ppc java/1.1-rr-std-b12)\r\nExpires: Thu, 01 Jan 1970 00:00:00 GMT\r\nSet-Cookie: JSESSIONID=206sonikg4toh;Path=/\r\nLocation:\r\nTransfer-Encoding: chunked\r\n\r\n”, “port”=>80}, {“timestamp”=>”27.08.2010”, “banner”=>”HTTP/1.0 302 Moved Temporarily\r\nDate: Fri, 27 Aug 2010 02:06:55 GMT\r\nServer: Jetty/4.2.x (VxWorks/WIND version 2.9 ppc java/1.1-rr-std-b12)\r\nExpires: Thu, 01 Jan 1970 00:00:00 GMT\r\nSet-Cookie: JSESSIONID=5b9gjbl5drm9t;Path=/\r\nLocation:\r\nTransfer-Encoding: chunked\r\n\r\n”, “port”=>80}], “hostnames”=>[], “country”=>”United States”, “os”=>”F5 BigIP LB 4.1.x (sometimes FreeBSD)”}

Pwtent Pwnables 500 Solution?

•May 26, 2010 • 4 Comments

During the DEFCON Capture the Flag qualifiers (aka quals) run by ddtek this past weekend, I was banging my head against forensics 300 for much longer than I care to admit. When I wasn’t working on one of the other challenges, I’d go back and dig deeper into it. There’s something to be said for a good challenge, but it’s an altogether different beast when you have more red herrings than…well, I don’t have a good analogy, but if you worked f300, you know.

On Sunday evening in the Hack-V, wrffr or JRod called my name through Skype. “Mezzy, look at Pwtent Pwnables 500–there’s a PCAP.” Sweet! Being the team’s nose, sniffer, or whatever @tlas wants to call me, I have an affinity for digging into packets during CTF at DEFCON. It’s what I did for two of the three years we competed, and I think it’s fun. It’s exciting to what exploits as they’re being fired off from one of the other 7 teams against our server.

One of my duties was ripping apart the attacks as they came through to see if it wasn’t something we already had. If we hadn’t seen it or exploited that particular service yet, then I’d dissect it, replay it if I could or pass it off to our core reversers, and write a Snort rule to drop future attacks.

The challenge said, “Kenshoto never handed you 0day! Use it wisely and a key shall be yours.” (PCAP here) Sounds right up my alley and the guys knew it.

I started off looking through the PCAP with Wireshark to see what the service looked like, how it had to be interacted with in order to exploit it, and information about where it was running.

The target was running on port 6913/tcp. It was easy to see the prompts, password, and exploit in the PCAP. Below is an example.

? to see the menu.>
How many bytes to donate?

….followed by d, 141, the payload, and shell interaction (ls, uname, etc.)

At first, I started scripting up the interaction with Ruby exactly as you see above. I got to the payload and tried to cheat by piping it through a couple of different tools to get it in a nice \x format to deliver via print. Nothing worked quite right, so Cutaway stepped in seeing my frustration and typed it for me while I laid on the couch. You’ll see why that was important in a moment.

I hopped into irb and pasted my script to watch it exploit pp500. While watching the exploit via tcpdump in another window, I noticed something was wrong as I wasn’t getting the same response. I tried it a few different ways until I realized the difference. The 0day wasn’t interactive–it pushed the entire sequence of password, menu interaction, and exploit during the initial connection. Crap!

So, I went back and took out the code where I was accepting a response back from the server and starting putting all of my side of the conversation into one print statement. When I was done, I tried again. This time it still didn’t work. Cutaway noticed that my bytes didn’t match. When I was converting “antagonist” to hex, I botched it. I sometimes transpose numbers and I did it more than once here. That’s why I was glad cutaway typed in all of the payload for me earlier.

I fixed all my screwups, pasted it back into IRB, and BLAM! Tcpdump started scrolling looking just like example PCAP. Bingo! We did it. Now, all I had to do with confirm my shell was there and cat the key. Typing in mysocket.print “ls -la\n” and nothing. The socket was hung. Looking back at tcpdump, and I saw there wasn’t as many \x20‘s as there should have been. Weird.

Then, I realized it was 10:00pm EST time. Quals was over. I missed fully landing Pwtent Pwnables 500 by seconds…

Below is the Ruby that I used. If you were one of the teams who snagged a copy of the actual pp500 binary when you were shelled in during pp200, please send me a copy. I’d love to complete the feeling of accomplishment by getting a shell through it.

require ‘socket’

mysocket =, port)

mysocket.print “\x61\x6e\x74\x61\x67\x6f\x6e\x69\x73\x74\x0a\x64″+

#[read back 10 megs]
# I was lazy & entered the following 10 times

# The following assumes the key is in the same directory
# and that it is named key. I don’t know for sure.
mysocket.print “cat key\n”
response =  mysocket.recv(1024).chomp
puts response



%d bloggers like this: