-
Notifications
You must be signed in to change notification settings - Fork 993
Writing WhatWeb Plugins
Note to New Contributors
Please read this before writing a plugin.
- Check your desired plugins in ./plugins/
- Check them on the Plugin-ToDo page and pending page.
- If you don't find them, write them down on that page so that others can see what you'll be doing
- Start writing your plugins
- Update that page accordingly by removing what you've written
- Test your plugins well against a wide range of targets as many as possible
- Submit your new plugins via email or forking the project or via the Issues page.
To get started modify plugin-template.rb.txt in the my-plugins folder. Rename it to your desired one like my-first-plugin.rb which will be run by WhatWeb without your needing to put it into ./plugins/ folder.
Also read the tutorial on writing WhatWeb plugins at How to develop WhatWeb plugins.
A typical plugin looks like this:
Plugin.define "Plone" do
author "Andrew Horton"
version "0.2"
description "CMS http://plone.org"
examples %w| www.norden.org www.trolltech.com www.plone.net www.smeal.psu.edu|
matches [
{:name=>"meta generator tag",
:regexp=>/<meta name="generator" content="[^>]*http:\/\/plone.org" \/>/},
{:name=>"plone css",
:regexp=>/(@import url|text\/css)[^>]*portal_css\/.*plone.*css(\)|")/}, #"
{:name=>"plone javascript",
:regexp=>/src="[^"]*ploneScripts[0-9]+.js"/}, #"
{:text=>'<div class="visualIcon contenttype-plone-site">'},
{:name=>"div tag, visual-portal-wrapper",
:certainty=>75,
:text=>'<div id="visual-portal-wrapper">'},
]
def passive
m=[]
#X-Caching-Rule-Id: plone-content-types
#X-Cache-Rule: plone-content-types
m << {:name=>"X-Caching-Rule-Id: plone-content-types" } if @meta["x-caching-rule-id"] =~ /plone-content-types/i
m << {:name=>"X-Cache-Rule: plone-content-types" } if @meta["x-cache-rule"] =~ /plone-content-types/i
m
end
endThere are 3 levels to a plugin. Simple matches, passive and aggressive tests. You don’t need to know ruby to write plugins with simple matches. Passive and aggressive tests are written in ruby.
The matches [] array contains a set of ways to match a website to a system.
The methods are:
* :text Matches text within the webpage
* :regexp A regular expression. Append /i for case insensitive matches
* :ghdb Like a google query
* :md5 MD5 hash of the HTML page
* :tagpattern Pattern of HTML tags
* :name This is the name of the match, and is optional.
* :url The URL has to match this. Used for passive and agressive testing
* :certainty Optional, defaults to 100. Values are maybe (25), probably (75) and certain (100).
* :version As a string or number this is a version returned when other methods match
* :version As a regular expression, this extracts the version information from the HTML. Also requires :version_regexp_offset=>1
If you port a GHDB match, use :ghdb. I usually rewrite the GHDB matches with regular expressions, especially if they require inurl:
Example:
# http://johnny.ihackstuff.com/ghdb?function=detail&id=1840
{ :ghdb=>'"Powered by Vsns Lemon" intitle:"Vsns Lemon"' }
Note the GHDB queries are case insensitive, as a Google query is.
Supported GHDB codes are:
* intitle:
* inurl:
* filetype:
Each plugin can access @body, @meta, @status, @base_uri, @md5, @ip and @tagpattern variables.
Passive tests add matches to the m array, each match is a hash containing the name of the match, probability and more. The entire hash is returned with Full output, Brief output returns just the match, :version and :string
To discover the regular expressions to match against, wget about 20-30 examples into the tests/ folder. Be aware that some software can have dramatic variations between versions.
Cookies
If the software uses unique cookies (such as Set-Cookie: PastVisitor=1; expires=Wed, 02-Jun-2010 04:05:29 GMT; path=/) then you can search for more instances of the software on ShodanHQ.
HTTP Headers
If the software uses unique HTTP headers (such as Server:BarracudaHTTP) then you can search for more instances of the software on ShodanHQ.
URL Pattern
If the software uses a unique URL pattern (such as inurl:web.config ext:config "ConnectionString") then you can search for more instances of the software on Google using inurl:
Unique Phrases
If the software uses a unique phrase (such as intitle:"Powered by ABC Software") then you can search for more instances of the software on Google using intext: or intitle:
-
Search ShodanHQ for example software with customer HTTP headers.
-
Search Google for unique phrases, titles or URL structures.
-
Check for demonstration or showcase websites hosted by the vendor.
More than one copy of WhatWeb
If you're editing a plugin and you have more than one copy of WhatWeb you'll need to change the name of the plugin in Plugin.define or else the plugin's output will be overwritten by the other plugin.
Regex matches
When you're matching HTML make sure you make the entire HTML element. For example:
For the href parameter:
/<a[\s]+href=['"]?http:\/\/this\/is\/a\/unique\/path\/to\/fingerprint\/['"]?[^>]*>/i
For the title parameter:
/<a[\s]+title=['"]?http:\/\/this\/is\/a\/unique\/title\/to\/fingerprint\/['"]?[^>]*>/i
Passive Matches
Passive matches in the def passive section require the same regex in both the @body regular expression and the @body.scan regular expression. For example:
# Version Detection # Powered by text
def passive
m=[]
@body =~ /powered by ABC software version ([\d\.]+)/
m << { :version=>@body.scan(/powered by ABC software version ([\d\.]+)/) }
end
m
end
endIf the two regular expressions differ then the plugin will fail.
lrn2regexp
Learn it, Live it, Love it http://www.rubular.com/