1#!/usr/local/bin/perl
2# DotDotPwn - The Directory Traversal Fuzzer
3# Copyright (C) 2012 Christian Navarrete and Alejandro Hernandez H.
4#
5# This program is free software: you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation, either version 3 of the License, or
8# (at your option) any later version.
9#
10# This program is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13# GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with this program.  If not, see <http://www.gnu.org/licenses/>
17#
18# ====================================================================
19#
20#-=[]=--=[]=--=[]=--=[]=--=[]=--=[]=--=[]=--=[]=--=[]=--=[]=--=[]=--=[
21#                                                                  -=[
22#  DotDotPwn - The Directory Traversal Fuzzer                      -=[
23#  is a production of:                                             -=[
24#                                                                  -=[
25#  CubilFelino                                          Chatsubo   -=[
26#  Security Research Lab      and       [(in)Security Dark] Labs   -=[
27#  chr1x.sectester.net                chatsubo-labs.blogspot.com   -=[
28#  http://twitter.com/chr1x         http://twitter.com/nitr0usmx   -=[
29#                                                                  -=[
30#-=[]=--=[]=--=[]=--=[]=--=[]=--=[]=--=[]=--=[]=--=[]=--=[]=--=[]=--=[
31#
32#
33# Changes (Read CHANGELOG.txt for Details):
34#
35# * DotDotPwn v3.0.2: The Directory Traversal Fuzzer
36#   by nitr0us & chr1x & Contributors (AUTHORS.txt)
37#
38# * DotDotPwn v2.1: The Directory Traversal Fuzzer
39#   by chr1x & nitr0us
40#
41# * DotDotPwn v2.0: From checker to Fuzzer
42#   by nitr0us (nitrousenador@gmail.com)
43#   http://chatsubo-labs.blogspot.com
44#
45# * DotDotPwn v1.0 - Teh Directory Traversal Checker
46#   by chr1x@sectester.net
47#   http://chr1x.sectester.net
48#
49
50use lib qw(.);
51
52$| = 1; # forces a flush after every write or print
53$SIG{INT} = \&abort; # When ctrl + C is pressed, the abort function prints useful info
54
55## DotDotPwn Core Modules ##
56use DotDotPwn::TraversalEngine;
57
58## DotDotPwn Protocol Modules ##
59use DotDotPwn::HTTP;
60use DotDotPwn::HTTP_Url;
61use DotDotPwn::FTP;
62use DotDotPwn::TFTP;
63use DotDotPwn::Payload;
64use DotDotPwn::STDOUT;
65
66## DotDotPwn Misc Modules ##
67use DotDotPwn::Fingerprint;
68use DotDotPwn::BisectionAlgorithm;
69
70## Perl modules ##
71use Getopt::Std;
72#use Switch;
73
74my $DotDotPwn  =
75'#################################################################################
76#                                                                               #
77#  CubilFelino                                                       Chatsubo   #
78#  Security Research Lab              and            [(in)Security Dark] Labs   #
79#  chr1x.sectester.net                             chatsubo-labs.blogspot.com   #
80#                                                                               #
81#                               pr0udly present:                                #
82#                                                                               #
83#  ________            __  ________            __  __________                   #
84#  \______ \    ____ _/  |_\______ \    ____ _/  |_\______   \__  _  __ ____    #
85#   |    |  \  /  _ \\\\   __\|    |  \  /  _ \\\\   __\|     ___/\ \/ \/ //    \   #
86#   |    `   \(  <_> )|  |  |    `   \(  <_> )|  |  |    |     \     /|   |  \  #
87#  /_______  / \____/ |__| /_______  / \____/ |__|  |____|      \/\_/ |___|  /  #
88#          \/                      \/                                      \/   #
89#                              - DotDotPwn v3.0.2 -                             #
90#                         The Directory Traversal Fuzzer                        #
91#                         http://dotdotpwn.sectester.net                        #
92#                            dotdotpwn@sectester.net                            #
93#                                                                               #
94#                               by chr1x & nitr0us                              #
95#################################################################################
96
97';
98
99if(@ARGV < 2){ # -m module required
100    print $DotDotPwn; # Banner
101
102    print "Usage: $0 -m <module> -h <host> [OPTIONS]\n";
103    print "\tAvailable options:\n";
104    print "\t-m\tModule [http | http-url | ftp | tftp | payload | stdout]\n";
105    print "\t-h\tHostname\n";
106    print "\t-O\tOperating System detection for intelligent fuzzing (nmap)\n";
107    print "\t-o\tOperating System type if known (\"windows\", \"unix\" or \"generic\")\n";
108    print "\t-s\tService version detection (banner grabber)\n";
109    print "\t-d\tDepth of traversals (e.g. deepness 3 equals to ../../../; default: 6)\n";
110    print "\t-f\tSpecific filename (e.g. /etc/motd; default: according to OS detected, defaults in TraversalEngine.pm)\n";
111    print "\t-E\tAdd \@Extra_files in TraversalEngine.pm (e.g. web.config, httpd.conf, etc.)\n";
112    print "\t-S\tUse SSL for HTTP and Payload module (not needed for http-url, use a https:// url instead)\n";
113    print "\t-u\tURL with the part to be fuzzed marked as TRAVERSAL (e.g. http://foo:8080/id.php?x=TRAVERSAL&y=31337)\n";
114    print "\t-k\tText pattern to match in the response (http-url & payload modules - e.g. \"root:\" if trying /etc/passwd)\n";
115    print "\t-p\tFilename with the payload to be sent and the part to be fuzzed marked with the TRAVERSAL keyword\n";
116    print "\t-x\tPort to connect (default: HTTP=80; FTP=21; TFTP=69)\n";
117    print "\t-t\tTime in milliseconds between each test (default: 300 (.3 second))\n";
118    print "\t-X\tUse the Bisection Algorithm to detect the exact deepness once a vulnerability has been found\n";
119    print "\t-e\tFile extension appended at the end of each fuzz string (e.g. \".php\", \".jpg\", \".inc\")\n";
120    print "\t-U\tUsername (default: 'anonymous')\n";
121    print "\t-P\tPassword (default: 'dot\@dot.pwn')\n";
122    print "\t-M\tHTTP Method to use when using the 'http' module [GET | POST | HEAD | COPY | MOVE] (default: GET)\n";
123    print "\t-r\tReport filename (default: 'HOST_MM-DD-YYYY_HOUR-MIN.txt')\n";
124    print "\t-b\tBreak after the first vulnerability is found\n";
125    print "\t-q\tQuiet mode (doesn't print each attempt)\n";
126    print "\t-C\tContinue if no data was received from host\n";
127
128    exit;
129}
130
131getopts("qXOSsCbEm:h:U:P:f:u:k:d:x:t:p:o:r:M:e:");
132
133our $module  = $opt_m || die "Module is neccesary (-m)\n";
134our $host    = $opt_h || die "Hostname is neccesary (-h)\n" unless ($module eq "http-url" || $module eq "stdout");
135our $user    = $opt_U || 'anonymous';
136our $pass    = $opt_P || 'dot@dot.pwn';
137our $method  = $opt_M || 'GET';
138my  $deep    = $opt_d || 6;
139our $bisdeep = 16; # Deepness used when the Bisection Algorithm is going to be used (-X switch)
140our $quiet   = $opt_q;
141our $break   = $opt_b;
142our $url     = $opt_u;
143my  $ssl     = $opt_S;
144our $pattern = $opt_k;
145my  $file    = $opt_f;
146our $extra_f = $opt_E;
147our $extens  = $opt_e;
148my  $OS      = $opt_O;
149my  $o_type  = $opt_o;
150my  $serv    = $opt_s;
151my  $ping    = $opt_C;
152our $bisect  = $opt_X;
153our $time    = ($opt_t || 300) * 1000; # Time in milliseconds between each test
154our $start_time; # Will hold the time at the beginning of execution
155our $runtime;    # Will hold the difference between the end time and $start_time, so, it's the runtime
156my  $payload_file = $opt_p;
157our $payload; # The content of $payload_file
158my  $proto_url;
159my  $proto;
160our $port;
161our $dot_quiet_mode = 10; # When quiet mode is enabled, print a dot (.) each 10 attempts
162my  $n_travs = 0; # Counter of Traversals found
163our @traversals;  # Traversal strings generated by the Traversal Engine that will be launched against the target
164
165print $DotDotPwn if $module ne "stdout";
166
167
168# Variable asignment and other validations per module
169#switch($module){
170if ($module eq "ftp")  {
171	$port = $opt_x || 21;
172} elsif ($module eq "http") {
173	$port = $ssl ? 443 : 80; $port = $opt_x if $opt_x;
174} elsif ($module eq "tftp") {
175	$port = $opt_x || 69;
176} elsif ($module eq "http-url") {
177	die "URL is neccesary (-u)\n" unless $url;
178
179	# URL Parsing
180	die "Invalid URL format!\n" if $url !~ m|(\w+)://([\w\.\-]+):?(\d*)?/|;
181
182	$port = 80;
183	$proto_url = $1;
184	$port = 443 if ($proto_url eq 'https');
185	$host  = $2;
186	$port = $3 if $3;
187
188	#die "'$proto_url' Protocol not supported\n" if $proto_url ne "http";
189	die "No \"TRAVERSAL\" keyword found in the supplied URL\n" if $url !~ /TRAVERSAL/;
190	die "Pattern string to match is neccesary (-k)\n" unless $pattern;
191} elsif ($module eq "payload") {
192	$port = $opt_x || die "Port number is necessary (-x)\n";
193	die "Payload file is necessary (-p)\n" unless $payload_file;
194	die "Pattern string to match is neccesary (-k)\n" unless $pattern;
195
196	open PAYLOAD_FD, $payload_file or die "Cannot open $payload_file: $!";
197
198	# Undef the end of record character to read the whole file into one scalar variable
199	undef $/;
200
201	$payload = <PAYLOAD_FD>;
202
203	close PAYLOAD_FD;
204
205	$/ = "\n"; # Restore for normal behaviour
206
207	die "No \"TRAVERSAL\" keyword found in the supplied payload file\n" if $payload !~ /TRAVERSAL/;
208} elsif ($module eq "stdout") {
209	@traversals = TraversalEngine(OS_type($o_type), $deep, $file);
210	toSTDOUT();
211	exit;
212} else { print "[-] Invalid Module ($module)!\n"; exit; }
213#}
214
215
216($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime(time);
217
218our $report;
219
220if($opt_r) {
221	$report = "Reports/" . $opt_r;
222} else {
223	$report = sprintf "Reports/%s_%02d-%02d-%d_%02d-%02d.txt", $host, $mon+1, $mday, $year+1900, $hour, $min;
224}
225
226print "[+] Report name: $report\n";
227
228open(REPORT , ">$report");
229
230printf REPORT "\n[+] Date and Time: %02d-%02d-%4d %02d:%02d:%02d\n",$mon+1, $mday, $year+1900, $hour, $min, $sec;
231
232# Target information
233for my $fh (STDOUT, REPORT) {
234	print $fh "\n[========== TARGET INFORMATION ==========]\n";
235	print $fh "[+] Hostname: $host\n";
236}
237
238if($OS){
239	for my $fh (STDOUT, REPORT) { print $fh "[+] Detecting Operating System (nmap) ...\n"; }
240	$target_OS = OS_Detection($host);
241	for my $fh (STDOUT, REPORT) { print $fh "[+] Operating System detected: " . $target_OS . "\n"; }
242}
243
244# Manual definition of OS type if known
245if($o_type) {
246	if( ($o_type eq "unix") || ($o_type eq "windows") || ($o_type eq "generic") ) {
247		$target_OS = $o_type; # Overwrite the previously OS type detected by nmap. It has more importance!
248		for my $fh (STDOUT, REPORT) { print $fh "[+] Setting Operating System type to \"" . $target_OS . "\"\n"; }
249	} else {
250		for my $fh (STDOUT, REPORT) { print "[-] Invalid OS type \"" . $o_type . "\"... Using the previously detected by nmap (if -O enabled)\n"; }
251	}
252}
253
254$proto = $proto_url || ($module eq "payload" ? "N/A" : $module);
255
256for my $fh (STDOUT, REPORT) { print $fh "[+] Protocol: $proto\n"; }
257for my $fh (STDOUT, REPORT) { print $fh "[+] Port: $port\n"; }
258for my $fh (STDOUT, REPORT) { print $fh "[+] Service detected:\n" . Banner_Grabber($host, $port, $proto) if $serv; }
259
260
261#Traversal Engine
262for my $fh (STDOUT, REPORT) { print $fh "\n[=========== TRAVERSAL ENGINE ===========]\n"; }
263@traversals = TraversalEngine(OS_type($target_OS), $deep, $file);
264for my $fh (STDOUT, REPORT) { print $fh "[+] Traversal Engine DONE ! - Total traversal tests created: " . scalar(@traversals) . "\n"; }
265
266
267# Testing
268print  "\n[=========== TESTING RESULTS ============]\n";
269printf "[+] Ready to launch %.2f traversals per second\n", (1000000 / $time);
270print  "[+] Press Enter to start the testing (You can stop it pressing Ctrl + C)\n";
271<STDIN>;
272
273$start_time = time;
274
275# (nitr0us)
276# "use Switch" Added here again to avoid an existing bug in Switch.pm @ Perl 5.8
277# that raises an error in the next switch($module) statement
278#
279# http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=480106
280#use Switch;
281
282#switch($module){
283if ($module eq "ftp")      { $n_travs = FuzzFTP($host, $port, $user, $pass); }
284if ($module eq "http")     { $n_travs = FuzzHTTP($host, $port, $ssl, $method, $ping); }
285if ($module eq "tftp")     { $n_travs = FuzzTFTP($host, $port); }
286if ($module eq "payload")  { $n_travs = FuzzPayload($host, $port, $ssl, $payload); }
287if ($module eq "http-url") { $n_travs = FuzzHTTP_Url($url, $ping); }
288#}
289
290$runtime = time - $start_time;
291for my $fh (STDOUT, REPORT) {
292	printf $fh "\n[+] Fuzz testing finished after %.2f minutes ($runtime seconds)\n", ($runtime / 60);
293	print  $fh "[+] Total Traversals found: $n_travs\n";
294}
295
296print "[+] Report saved: $report\n";
297
298exit 31337;
299
300
301# Handler of Ctrl + C
302sub abort{
303	# Don't know why, but the switch() statement never worked here =/
304
305	if   ($module eq "ftp")      { $n_travs = $DotDotPwn::FTP::n_travs; }
306	elsif($module eq "http")     { $n_travs = $DotDotPwn::HTTP::n_travs; }
307	elsif($module eq "http-url") { $n_travs = $DotDotPwn::HTTP_Url::n_travs; }
308	elsif($module eq "tftp")     { $n_travs = $DotDotPwn::TFTP::n_travs; }
309	elsif($module eq "payload")  { $n_travs = $DotDotPwn::Payload::n_travs; }
310
311	for my $fh (STDOUT, REPORT) {
312		print $fh "\n[+] Total Traversals found: $n_travs\n";
313		print $fh "[-] Fuzz testing aborted\n";
314	}
315
316	print "[+] Report saved: $report\n";
317
318	exit;
319}
320