diff --git a/README.md b/README.md index a620dc945..8115c5dd5 100644 --- a/README.md +++ b/README.md @@ -55,5 +55,8 @@ Links Translations ---- -* [Portuguese](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-pt-BR.md) +* [Chinese](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-zh-CN.md) +* [Croatian](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-hr-HR.md) +* [Greek](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-gr-GR.md) * [Indonesian](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-id-ID.md) +* [Portuguese](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-pt-BR.md) diff --git a/doc/COPYING b/doc/COPYING index 38a61d291..a8ccaaa4d 100644 --- a/doc/COPYING +++ b/doc/COPYING @@ -1,7 +1,7 @@ COPYING -- Describes the terms under which sqlmap is distributed. A copy of the GNU General Public License (GPL) is appended to this file. -sqlmap is (C) 2006-2013 Bernardo Damele Assumpcao Guimaraes, Miroslav Stampar. +sqlmap is (C) 2006-2014 Bernardo Damele Assumpcao Guimaraes, Miroslav Stampar. This program is free software; you may redistribute and/or modify it under the terms of the GNU General Public License as published by the Free diff --git a/doc/THANKS.md b/doc/THANKS.md index e90ff7f88..97335723c 100644 --- a/doc/THANKS.md +++ b/doc/THANKS.md @@ -1,777 +1,786 @@ # Individuals -Andres Tarasco Acuna, +Andres Tarasco Acuna, * for suggesting a feature -Santiago Accurso, +Santiago Accurso, * for reporting a bug -Syed Afzal, +Syed Afzal, * for contributing a WAF script varnish.py -Zaki Akhmad, +Zaki Akhmad, * for suggesting a couple of features -Olu Akindeinde, +Olu Akindeinde, * for reporting a couple of bugs -David Alvarez, +David Alvarez, * for reporting a bug -Sergio Alves, +Sergio Alves, * for reporting a bug -Thomas Anderson, +Thomas Anderson, * for reporting a bug -Chip Andrews, +Chip Andrews, * for his excellent work maintaining the SQL Server versions database at SQLSecurity.com and permission to implement the update feature taking data from his site -Smith Andy, +Smith Andy, * for suggesting a feature -Otavio Augusto, +Otavio Augusto, * for reporting a minor bug -Simon Baker, +Simon Baker, * for reporting some bugs -Ryan Barnett, +Ryan Barnett, * for organizing the ModSecurity SQL injection challenge, http://modsecurity.org/demo/challenge.html -Emiliano Bazaes, +Emiliano Bazaes, * for reporting a minor bug -Daniele Bellucci, +Daniele Bellucci, * for starting sqlmap project and developing it between July and August 2006 -Sebastian Bittig, and the rest of the team at r-tec IT Systeme GmbH +Sebastian Bittig, and the rest of the team at r-tec IT Systeme GmbH * for contributing the DB2 support initial patch: fingerprint and enumeration -Anthony Boynes, +Anthony Boynes, * for reporting several bugs Marcelo Toscani Brandao * for reporting a bug -Velky Brat, +Velky Brat, * for suggesting a minor enhancement to the bisection algorithm -James Briggs, +James Briggs, * for suggesting a minor enhancement -Gianluca Brindisi, +Gianluca Brindisi, * for reporting a couple of bugs -Jack Butler, +Jack Butler, * for contributing the sqlmap site favicon -Ulisses Castro, +Ulisses Castro, * for reporting a bug -Roberto Castrogiovanni, +Roberto Castrogiovanni, * for reporting a minor bug -Cesar Cerrudo, +Cesar Cerrudo, * for his Windows access token kidnapping tool Churrasco included in sqlmap tree as a contrib library and used to run the stand-alone payload stager on the target Windows machine as SYSTEM user if the user wants to perform a privilege escalation attack, http://www.argeniss.com/research/TokenKidnapping.pdf -Karl Chen, +Karl Chen, * for contributing the initial multi-threading patch for the inference algorithm -Y P Chien, +Y P Chien, * for reporting a minor bug -Pierre Chifflier, and Mark Hymers, +Pierre Chifflier, and Mark Hymers, * for uploading and accepting the sqlmap Debian package to the official Debian project repository -Hysia Chow +Hysia Chow * for contributing a couple of WAF scripts -Chris Clements, +Chris Clements, * for reporting a couple of bugs -John Cobb, +John Cobb, * for reporting a minor bug -Andreas Constantinides, +Andreas Constantinides, * for reporting a minor bug -Andre Costa, +Andre Costa, * for reporting a minor bug * for suggesting a minor enhancement -Ulises U. Cune, +Ulises U. Cune, * for reporting a bug -Alessandro Curio, +Alessandro Curio, * for reporting a minor bug -Alessio Dalla Piazza, +Alessio Dalla Piazza, * for reporting a couple of bugs -Sherif El-Deeb, +Sherif El-Deeb, * for reporting a minor bug -Stefano Di Paola, +Stefano Di Paola, * for suggesting good features -Mosk Dmitri, +Mosk Dmitri, * for reporting a minor bug -Meng Dong, +Meng Dong, * for contributing a code for Waffit integration -Carey Evans, +Carey Evans, * for his fcrypt module that allows crypt(3) support on Windows platforms -Shawn Evans, +Shawn Evans, * for suggesting an idea for one tamper script, greatest.py -Adam Faheem, +Adam Faheem, * for reporting a few bugs -James Fisher, +James Fisher, * for contributing two very good feature requests * for his great tool too brute force directories and files names on web/application servers, DirBuster, http://tinyurl.com/dirbuster -Jim Forster, +Jim Forster, * for reporting a bug -Rong-En Fan, +Rong-En Fan, * for commiting the sqlmap 0.5 port to the official FreeBSD project repository -Giorgio Fedon, +Giorgio Fedon, * for suggesting a speed improvement for bisection algorithm * for reporting a bug when running against Microsoft SQL Server 2005 -Kasper Fons, +Kasper Fons, * for reporting several bugs -Jose Fonseca, +Jose Fonseca, * for his Gprof2Dot utility for converting profiler output to dot graph(s) and for his XDot utility to render nicely dot graph(s), both included in sqlmap tree inside extra folder. These libraries are used for sqlmap development purposes only http://code.google.com/p/jrfonseca/wiki/Gprof2Dot http://code.google.com/p/jrfonseca/wiki/XDot -Alan Franzoni, +Alan Franzoni, * for helping me out with Python subprocess library -Harold Fry, +Harold Fry, * for suggesting a minor enhancement -Daniel G. Gamonal, +Daniel G. Gamonal, * for reporting a minor bug -Marcos Mateos Garcia, +Marcos Mateos Garcia, * for reporting a minor bug -Andrew Gecse, +Andrew Gecse, * for reporting a minor issue -Ivan Giacomelli, +Ivan Giacomelli, * for reporting a bug * for suggesting a minor enhancement * for reviewing the documentation -Nico Golde, +Nico Golde, * for reporting a couple of bugs -Oliver Gruskovnjak, +Oliver Gruskovnjak, * for reporting a bug * for contributing a minor patch -Davide Guerri, +Davide Guerri, * for suggesting an enhancement -Dan Guido, +Dan Guido, * for promoting sqlmap in the context of the Penetration Testing and Vulnerability Analysis class at the Polytechnic University of New York, http://isisblogs.poly.edu/courses/pentest/ -David Guimaraes, +David Guimaraes, * for reporting considerable amount of bugs * for suggesting several features -Chris Hall, +Chris Hall, * for coding the prettyprint.py library -Tate Hansen, +Tate Hansen, * for donating to sqlmap development -Mario Heiderich, -Christian Matthies, -Lars H. Strojny, +Mario Heiderich, +Christian Matthies, +Lars H. Strojny, * for their great tool PHPIDS included in sqlmap tree as a set of rules for testing payloads against IDS detection, http://php-ids.org -Kristian Erik Hermansen, +Kristian Erik Hermansen, * for reporting a bug * for donating to sqlmap development -Alexander Hagenah, +Alexander Hagenah, * for reporting a minor bug -Dennis Hecken, +Dennis Hecken, * for reporting a minor bug -Choi Ho, +Choi Ho, * for reporting a minor bug -Jorge Hoya, +Jorge Hoya, * for suggesting a minor enhancement -Will Holcomb, +Will Holcomb, * for his MultipartPostHandler class to handle multipart POST forms and permission to include it within sqlmap source code -Daniel Huckmann, +Daniel Huckmann, * for reporting a couple of bugs -Daliev Ilya, +Daliev Ilya, * for reporting a bug -Jovon Itwaru, +Mehmet İnce, +* for contributing a tamper script xforwardedfor.py + +Jovon Itwaru, * for reporting a minor bug -Prashant Jadhav, +Prashant Jadhav, * for reporting a bug -Dirk Jagdmann, +Dirk Jagdmann, * for reporting a typo in the documentation -Luke Jahnke, +Luke Jahnke, * for reporting a bug when running against MySQL < 5.0 -Andrew Kitis +Andrew Kitis * for contributing a tamper script lowercase.py -David Klein, +David Klein, * for reporting a minor code improvement -Sven Klemm, +Sven Klemm, * for reporting two minor bugs with PostgreSQL -Anant Kochhar, +Anant Kochhar, * for providing with feedback on the user's manual -Dmitriy Kononov, +Dmitriy Kononov, * for reporting a minor bug -Alexander Kornbrust, +Alexander Kornbrust, * for reporting a couple of bugs -Krzysztof Kotowicz, +Krzysztof Kotowicz, * for reporting a minor bug -Nicolas Krassas, +Nicolas Krassas, * for reporting a couple of bugs -Oliver Kuckertz, +Oliver Kuckertz, * for contributing a minor patch -Alex Landa, +Alex Landa, * for contributing a patch adding beta support for XML output -Guido Landi, +Guido Landi, * for reporting a couple of bugs * for the great technical discussions * for Microsoft SQL Server 2000 and Microsoft SQL Server 2005 'sp_replwritetovarbin' stored procedure heap-based buffer overflow (MS09-004) exploit development * for presenting with me at SOURCE Conference 2009 in Barcelona (Spain) on September 21, 2009 and at CONfidence 2009 in Warsaw (Poland) on November 20, 2009 -Lee Lawson, +Lee Lawson, * for reporting a minor bug -John J. Lee, and others +John J. Lee, and others * for developing the clientform Python library used by sqlmap to parse forms when --forms switch is specified -Nico Leidecker, +Nico Leidecker, * for providing with feedback on a few features * for reporting a couple of bugs * for his great tool icmpsh included in sqlmap tree to get a command prompt via an out-of-band tunnel over ICMP, http://leidecker.info/downloads/icmpsh.zip -Gabriel Lima, +Gabriel Lima, * for reporting a couple of bugs -Svyatoslav Lisin, +Svyatoslav Lisin, * for suggesting a minor feature -Miguel Lopes, +Miguel Lopes, * for reporting a minor bug -Truong Duc Luong, +Truong Duc Luong, * for reporting a minor bug -Pavol Luptak, +Pavol Luptak, * for reporting a bug when injecting on a POST data parameter -Till Maas, +Till Maas, * for suggesting a minor feature -Michael Majchrowicz, +Michael Majchrowicz, * for extensively beta-testing sqlmap on various MySQL DBMS * for providing really appreciated feedback * for suggesting a lot of ideas and features -Vinícius Henrique Marangoni, +Vinícius Henrique Marangoni, * for contributing a Portuguese translation of README.md -Ahmad Maulana, +Ahmad Maulana, * for contributing a tamper script halfversionedmorekeywords.py -Ferruh Mavituna, +Ferruh Mavituna, * for exchanging ideas on the implementation of a couple of features -David McNab, +David McNab, * for his XMLObject module that allows XML files to be operated on like Python objects -Spencer J. McIntyre, +Spencer J. McIntyre, * for reporting a minor bug * for contributing a patch for OS fingerprinting on DB2 -Brad Merrell, +Brad Merrell, * for reporting a minor bug -Michael Meyer, +Michael Meyer, * for suggesting a minor feature -Enrico Milanese, +Enrico Milanese, * for reporting a minor bug * for sharing some ideas for the PHP backdoor -Liran Mimoni, +Liran Mimoni, * for reporting a minor bug -Marco Mirandola, +Marco Mirandola, * for reporting a minor bug -Devon Mitchell, +Devon Mitchell, * for reporting a minor bug -Anton Mogilin, +Anton Mogilin, * for reporting a few bugs -Sergio Molina, +Sergio Molina, * for reporting a minor bug -Anastasios Monachos, +Anastasios Monachos, * for providing some useful data * for suggesting a feature * for reporting a couple of bugs -Kirill Morozov, +Kirill Morozov, * for reporting a bug * for suggesting a feature -Alejo Murillo Moya, +Alejo Murillo Moya, * for reporting a minor bug * for suggesting a few features -Yonny Mutai, +Yonny Mutai, * for reporting a minor bug -Roberto Nemirovsky, +Roberto Nemirovsky, * for pointing me out some enhancements -Simone Onofri, +Simone Onofri, * for patching the PHP web backdoor to make it work properly also on Windows -Michele Orru, +Michele Orru, * for reporting a couple of bug * for suggesting ideas on how to implement the RESTful API -Shaohua Pan, +Shaohua Pan, * for reporting several bugs * for suggesting a few features -Antonio Parata, +Antonio Parata, * for sharing some ideas for the PHP backdoor -Adrian Pastor, +Adrian Pastor, * for donating to sqlmap development -Christopher Patten, +Christopher Patten, * for reporting a bug in the blind SQL injection bisection algorithm -Zack Payton, +Zack Payton, * for reporting a minor bug -Jaime Penalba, +Jaime Penalba, * for contributing a patch for INSERT/UPDATE generic boundaries -Pedrito Perez, <0ark1ang3l@gmail.com> +Pedrito Perez, <0ark1ang3l(at)gmail.com> * for reporting a couple of bugs -Brandon Perry, +Brandon Perry, * for reporting a couple of bugs -Travis Phillips, +Travis Phillips, * for suggesting a minor enhancement -Mark Pilgrim, +Mark Pilgrim, * for porting chardet package (Universal Encoding Detector) to Python -Steve Pinkham, +Steve Pinkham, * for suggesting a feature * for contributing a new SQL injection vector (MSSQL time-based blind) * for donating to sqlmap development -Adam Pridgen, +Adam Pridgen, * for suggesting some features -Luka Pusic, +Luka Pusic, * for reporting a couple of bugs -Ole Rasmussen, +Ole Rasmussen, * for reporting a bug * for suggesting a feature -Alberto Revelli, +Alberto Revelli, * for inspiring me to write sqlmap user's manual in SGML * for his great Microsoft SQL Server take over tool, sqlninja, http://sqlninja.sourceforge.net -David Rhoades, +David Rhoades, * for reporting a bug -Andres Riancho, +Andres Riancho, * for beta-testing sqlmap * for reporting a bug and suggesting some features * for including sqlmap in his great web application audit and attack framework, w3af, http://w3af.sourceforge.net * for suggesting a way for handling DNS caching -Jamie Riden, +Jamie Riden, * for reporting a minor bug -Alexander Rigbo, +Alexander Rigbo, * for contributing a minor patch -Antonio Riva, +Antonio Riva, * for reporting a bug when running with python 2.5 -Ethan Robish, +Ethan Robish, * for reporting a bug -Levente Rog, +Levente Rog, * for reporting a minor bug -Andrea Rossi, +Andrea Rossi, * for reporting a minor bug * for suggesting a feature -Frederic Roy, +Frederic Roy, * for reporting a couple of bugs -Vladimir Rutsky, +Vladimir Rutsky, * for suggesting a couple of minor enhancements -Richard Safran, +Richard Safran, * for donating the sqlmap.org domain -Tomoyuki Sakurai, +Tomoyuki Sakurai, * for submitting to the FreeBSD project the sqlmap 0.5 port -Roberto Salgado, +Roberto Salgado, * for contributing considerable amount of tamper scripts -Pedro Jacques Santos Santiago, +Pedro Jacques Santos Santiago, * for reporting considerable amount of bugs -Marek Sarvas, +Marek Sarvas, * for reporting several bugs -Philippe A. R. Schaeffer, +Philippe A. R. Schaeffer, * for reporting a minor bug -Mohd Zamiri Sanin, +Mohd Zamiri Sanin, * for reporting a minor bug -Jorge Santos, +Jorge Santos, * for reporting a minor bug -Sven Schluter, +Sven Schluter, * for contributing a patch * for waiting a number of seconds between each HTTP request -Ryan Sears, +Ryan Sears, * for suggesting a couple of enhancements * for donating to sqlmap development -Uemit Seren, +Uemit Seren, * for reporting a minor adjustment when running with python 2.6 -Shane Sewell, +Shane Sewell, * for suggesting a feature -Ahmed Shawky, +Ahmed Shawky, * for reporting a major bug with improper handling of parameter values * for reporting a bug -Brian Shura, +Brian Shura, * for reporting a bug -Sumit Siddharth, +Sumit Siddharth, * for sharing ideas on the implementation of a couple of features -Andre Silva, +Andre Silva, * for reporting a bug -Benjamin Silva H. +Benjamin Silva H. * for reporting a bug -Duarte Silva +Duarte Silva * for reporting a couple of bugs -M Simkin, +M Simkin, * for suggesting a feature -Konrads Smelkovs, +Konrads Smelkovs, * for reporting a few bugs in --sql-shell and --sql-query on Microsoft SQL Server -Chris Spencer, +Chris Spencer, * for reviewing the user's manual grammar -Michael D. Stenner, +Michael D. Stenner, * for his keepalive module that allows handling of persistent HTTP 1.1 keep-alive connections -Marek Stiefenhofer, +Marek Stiefenhofer, * for reporting a few bugs -Jason Swan, +Jason Swan, * for reporting a bug when enumerating columns on Microsoft SQL Server * for suggesting a couple of improvements -Chilik Tamir, +Chilik Tamir, * for contributing a patch for initial support SOAP requests -Alessandro Tanasi, +Alessandro Tanasi, * for extensively beta-testing sqlmap * for suggesting many features and reporting some bugs * for reviewing the documentation -Andres Tarasco, +Andres Tarasco, * for contributing good feedback -Tom Thumb, +Tom Thumb, * for reporting a major bug -Kazim Bugra Tombul, +Kazim Bugra Tombul, * for reporting a minor bug -Efrain Torres, +Efrain Torres, * for helping me out to improve the Metasploit Framework sqlmap auxiliary module and for commiting it on the Metasploit official subversion repository * for his great Metasploit WMAP Framework -Sandro Tosi, +Sandro Tosi, * for helping to create sqlmap Debian package correctly -Jacco van Tuijl, +Jacco van Tuijl, * for reporting several bugs -Vitaly Turenko, +Vitaly Turenko, * for reporting a bug -Augusto Urbieta, +Augusto Urbieta, * for reporting a minor bug -Bedirhan Urgun, +Bedirhan Urgun, * for reporting a few bugs * for suggesting some features and improvements * for benchmarking sqlmap in the context of his SQL injection benchmark project, OWASP SQLiBench, http://code.google.com/p/sqlibench -Kyprianos Vasilopoulos, +Kyprianos Vasilopoulos, * for reporting a couple of minor bugs -Vlado Velichkovski, +Vlado Velichkovski, * for reporting considerable amount of bugs * for suggesting an enhancement -Johnny Venter, +Johnny Venter, * for reporting a couple of bugs -Carlos Gabriel Vergara, +Carlos Gabriel Vergara, * for suggesting couple of good features -Patrick Webster, +Patrick Webster, * for suggesting an enhancement -Ed Williams, +Ed Williams, * for suggesting a minor enhancement -Anthony Zboralski, +Anthony Zboralski, * for providing with detailed feedback * for reporting a few minor bugs * for donating to sqlmap development -Thierry Zoller, +Thierry Zoller, * for reporting a couple of major bugs -Zhen Zhou, +Zhen Zhou, * for suggesting a feature --insane-, +-insane-, * for reporting a minor bug -1ndr4 joe, +1ndr4 joe, * for reporting a couple of bugs -abc abc, +abc abc, * for reporting a minor bug -Abuse 007, +Abuse 007, * for reporting a bug -Alex, +Alex, * for reporting a minor bug -anonymous anonymous, +anonymous anonymous, * for reporting a couple of bugs -bamboo, +bamboo, * for reporting a couple of bugs -Brandon E., +Brandon E., * for reporting a bug -black zero, +black zero, * for reporting a minor bug -blueBoy, +blueBoy, * for reporting a bug -buawig, +buawig, * for reporting considerable amount of bugs -Bugtrace, +Bugtrace, * for reporting several bugs -cats, +cats, * for reporting a couple of bugs -Christian S, +Christian S, * for reporting a minor bug -clav, +clav, * for reporting a minor bug -dragoun dash, +dragoun dash, * for reporting a minor bug -fufuh, +fufuh, * for reporting a bug when running on Windows -Hans Wurst, +Hans Wurst, * for reporting a couple of bugs -james, +Hysia, +* for contributing a Chinese translation of README.md + +james, * for reporting a bug -Joe "Pragmatk", +Joe "Pragmatk", * for reporting a few bugs -John Smith, +John Smith, * for reporting several bugs * for suggesting some features -m4l1c3, +m4l1c3, * for reporting considerable amount of bugs -mariano, +mariano, * for reporting a bug -mitchell, +mitchell, * for reporting a few bugs -Nadzree, +Nadzree, * for reporting a minor bug -nightman, +nightman, * for reporting considerable amount of bugs -Oso Dog osodog123@yahoo.com +Oso Dog osodog123(at)yahoo.com * for reporting a minor bug -pacman730, +pacman730, * for reporting a bug -pentestmonkey, +pentestmonkey, * for reporting several bugs * for suggesting a few minor enhancements -Phat R., +Phat R., * for reporting a few bugs -Phil P, <@superevr> +Phil P, <(at)superevr> * for suggesting a minor enhancement -ragos, +ragos, * for reporting a minor bug -rmillet, +rmillet, * for reporting a bug -Rub3nCT, +Rub3nCT, * for reporting a minor bug -shiftzwei, +shiftzwei, * for reporting a couple of bugs -smith, +smith, * for reporting a minor bug -Soma Cruz, +Soma Cruz, * for reporting a minor bug -Stuffe, +Spiros94, +* for contributing a Greek translation of README.md + +Stuffe, * for reporting a minor bug and a feature request -Sylphid, +Sylphid, * for suggesting some features -syssecurity.info, +syssecurity.info, * for reporting a minor bug -This LittlePiggy, +This LittlePiggy, * for reporting a minor bug -ToR, +ToR, * for reporting considerable amount of bugs * for suggesting a feature -ultramegaman, +ultramegaman, * for reporting a minor bug -Vinicius, +Vinicius, * for reporting a minor bug -wanglei, +wanglei, * for reporting a minor bug -warninggp, +warninggp, * for reporting a few minor bugs -x, +x, * for reporting a bug -zhouhx, +zhouhx, * for contributing a minor patch # Organizations -Black Hat team, +Black Hat team, * for the opportunity to present my research titled 'Advanced SQL injection to operating system full control' at Black Hat Europe 2009 Briefings on April 16, 2009 in Amsterdam (NL). I unveiled and demonstrated some of the sqlmap 0.7 release candidate version new features during my presentation * Homepage: http://goo.gl/BKfs7 * Slides: http://goo.gl/Dh65t * White paper: http://goo.gl/spX3N -SOURCE Conference team, +SOURCE Conference team, * for the opportunity to present my research titled 'Expanding the control over the operating system from the database' at SOURCE Conference 2009 on September 21, 2009 in Barcelona (ES). I unveiled and demonstrated some of the sqlmap 0.8 release candidate version new features during my presentation * Homepage: http://goo.gl/IeXV4 * Slides: http://goo.gl/OKnfj -AthCon Conference team, +AthCon Conference team, * for the opportunity to present my research titled 'Got database access? Own the network!' at AthCon Conference 2010 on June 3, 2010 in Athens (GR). I unveiled and demonstrated some of the sqlmap 0.8 version features during my presentation * Homepage: http://goo.gl/Fs71I * Slides: http://goo.gl/QMfjO -Metasploit Framework development team, +Metasploit Framework development team, * for their powerful tool Metasploit Framework, used by sqlmap, among others things, to create the shellcode and establish an out-of-band connection between sqlmap and the database server * Homepage: http://www.metasploit.com -OWASP Board, +OWASP Board, * for sponsoring part of the sqlmap development in the context of OWASP Spring of Code 2007 * Homepage: http://www.owasp.org diff --git a/doc/THIRD-PARTY.md b/doc/THIRD-PARTY.md index 5debfe274..f2479b31a 100644 --- a/doc/THIRD-PARTY.md +++ b/doc/THIRD-PARTY.md @@ -20,6 +20,8 @@ This file lists bundled packages and their associated licensing terms. * The Oset library located under thirdparty/oset/. Copyright (C) 2010, BlueDynamics Alliance, Austria. Copyright (C) 2009, Raymond Hettinger, and others. +* The PrettyPrint library located under thirdparty/prettyprint/. + Copyright (C) 2010, Chris Hall. * The SocksiPy library located under thirdparty/socks/. Copyright (C) 2006, Dan-Haim. @@ -55,7 +57,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Copyright (C) 2008-2009, Jose Fonseca. * The KeepAlive library located under thirdparty/keepalive/. Copyright (C) 2002-2003, Michael D. Stenner. -* The MultipartPost library located under thirdparty/multipartpost/. +* The MultipartPost library located under thirdparty/multipart/. Copyright (C) 2006, Will Holcomb. * The XDot library located under thirdparty/xdot/. Copyright (C) 2008, Jose Fonseca. @@ -281,8 +283,6 @@ be bound by the terms and conditions of this License Agreement. Copyright (C) 2012, Marcel Hellkamp. * The PageRank library located under thirdparty/pagerank/. Copyright (C) 2010, Corey Goldberg. -* The PrettyPrint library located under thirdparty/prettyprint/. - Copyright (C) 2010, Chris Hall. * The Termcolor library located under thirdparty/termcolor/. Copyright (C) 2008-2011, Volvox Development Team. diff --git a/doc/translations/README-gr-GR.md b/doc/translations/README-gr-GR.md new file mode 100644 index 000000000..8b09ba653 --- /dev/null +++ b/doc/translations/README-gr-GR.md @@ -0,0 +1,53 @@ +sqlmap +== + + +Το sqlmap είναι πρόγραμμα ανοιχτού κώδικα, που αυτοματοποιεί την εύρεση και εκμετάλλευση ευπαθειών τύπου SQL Injection σε βάσεις δεδομένων. Έρχεται με μια δυνατή μηχανή αναγνώρισης ευπαθειών, πολλά εξειδικευμένα χαρακτηριστικά για τον απόλυτο penetration tester όπως και με ένα μεγάλο εύρος επιλογών αρχίζοντας από την αναγνώριση της βάσης δεδομένων, κατέβασμα δεδομένων της βάσης, μέχρι και πρόσβαση στο βαθύτερο σύστημα αρχείων και εκτέλεση εντολών στο απευθείας στο λειτουργικό μέσω εκτός ζώνης συνδέσεων. + +Εικόνες +---- + +![Screenshot](https://raw.github.com/wiki/sqlmapproject/sqlmap/images/sqlmap_screenshot.png) + +Μπορείτε να επισκεφτείτε τη [συλλογή από εικόνες](https://github.com/sqlmapproject/sqlmap/wiki/Screenshots) που επιδεικνύουν κάποια από τα χαρακτηριστικά. + +Εγκατάσταση +---- + +Έχετε τη δυνατότητα να κατεβάσετε την τελευταία tarball πατώντας [εδώ](https://github.com/sqlmapproject/sqlmap/tarball/master) ή την τελευταία zipball πατώντας [εδώ](https://github.com/sqlmapproject/sqlmap/zipball/master). + +Κατά προτίμηση, μπορείτε να κατεβάσετε το sqlmap κάνοντας κλώνο το [Git](https://github.com/sqlmapproject/sqlmap) αποθετήριο: + + git clone https://github.com/sqlmapproject/sqlmap.git sqlmap-dev + +Το sqlmap λειτουργεί χωρίς περαιτέρω κόπο με την [Python](http://www.python.org/download/) έκδοσης **2.6.x** και **2.7.x** σε όποια πλατφόρμα. + +Χρήση +---- + +Για να δείτε μια βασική λίστα από επιλογές πατήστε: + + python sqlmap.py -h + +Για να πάρετε μια λίστα από όλες τις επιλογές πατήστε: + + python sqlmap.py -hh + +Μπορείτε να δείτε ένα δείγμα λειτουργίας του προγράμματος [εδώ](https://gist.github.com/stamparm/5335217). +Για μια γενικότερη άποψη των δυνατοτήτων του sqlmap, μια λίστα των υποστηριζόμενων χαρακτηριστικών και περιγραφή για όλες τις επιλογές, μαζί με παραδείγματα, καλείστε να συμβουλευτείτε το [εγχειρίδιο χρήστη](https://github.com/sqlmapproject/sqlmap/wiki). + +Σύνδεσμοι +---- + +* Αρχική σελίδα: http://sqlmap.org +* Λήψεις: [.tar.gz](https://github.com/sqlmapproject/sqlmap/tarball/master) ή [.zip](https://github.com/sqlmapproject/sqlmap/zipball/master) +* Commits RSS feed: https://github.com/sqlmapproject/sqlmap/commits/master.atom +* Προβλήματα: https://github.com/sqlmapproject/sqlmap/issues +* Εγχειρίδιο Χρήστη: https://github.com/sqlmapproject/sqlmap/wiki +* Συχνές Ερωτήσεις (FAQ): https://github.com/sqlmapproject/sqlmap/wiki/FAQ +* Εγγραφή σε Mailing list: https://lists.sourceforge.net/lists/listinfo/sqlmap-users +* Mailing list RSS feed: http://rss.gmane.org/messages/complete/gmane.comp.security.sqlmap +* Mailing list αρχείο: http://news.gmane.org/gmane.comp.security.sqlmap +* Twitter: [@sqlmap](https://twitter.com/sqlmap) +* Demos: [http://www.youtube.com/user/inquisb/videos](http://www.youtube.com/user/inquisb/videos) +* Εικόνες: https://github.com/sqlmapproject/sqlmap/wiki/Screenshots diff --git a/doc/translations/README-hr-HR.md b/doc/translations/README-hr-HR.md new file mode 100644 index 000000000..69e2d531d --- /dev/null +++ b/doc/translations/README-hr-HR.md @@ -0,0 +1,53 @@ +sqlmap +== + + +sqlmap je alat namijenjen za penetracijsko testiranje koji automatizira proces detekcije i eksploatacije sigurnosnih propusta SQL injekcije te preuzimanje poslužitelja baze podataka. Dolazi s moćnim mehanizmom za detekciju, mnoštvom korisnih opcija za napredno penetracijsko testiranje te široki spektar opcija od onih za prepoznavanja baze podataka, preko dohvaćanja podataka iz baze, do pristupa zahvaćenom datotečnom sustavu i izvršavanja komandi na operacijskom sustavu korištenjem tzv. "out-of-band" veza. + +Slike zaslona +---- + +![Slika zaslona](https://raw.github.com/wiki/sqlmapproject/sqlmap/images/sqlmap_screenshot.png) + +Možete posjetiti [kolekciju slika zaslona](https://github.com/sqlmapproject/sqlmap/wiki/Screenshots) gdje se demonstriraju neke od značajki na wiki stranicama. + +Instalacija +---- + +Možete preuzeti zadnji tarball klikom [ovdje](https://github.com/sqlmapproject/sqlmap/tarball/master) ili zadnji zipball klikom [ovdje](https://github.com/sqlmapproject/sqlmap/zipball/master). + +Po mogućnosti, možete preuzeti sqlmap kloniranjem [Git](https://github.com/sqlmapproject/sqlmap) repozitorija: + + git clone https://github.com/sqlmapproject/sqlmap.git sqlmap-dev + +sqlmap radi bez posebnih zahtjeva korištenjem [Python](http://www.python.org/download/) verzije **2.6.x** i/ili **2.7.x** na bilo kojoj platformi. + +Korištenje +---- + +Kako biste dobili listu osnovnih opcija i prekidača koristite: + + python sqlmap.py -h + +Kako biste dobili listu svih opcija i prekidača koristite: + + python sqlmap.py -hh + +Možete pronaći primjer izvršavanja [ovdje](https://gist.github.com/stamparm/5335217). +Kako biste dobili pregled mogućnosti sqlmap-a, liste podržanih značajki te opis svih opcija i prekidača, zajedno s primjerima, preporučen je uvid u [korisnički priručnik](https://github.com/sqlmapproject/sqlmap/wiki). + +Poveznice +---- + +* Početna stranica: http://sqlmap.org +* Preuzimanje: [.tar.gz](https://github.com/sqlmapproject/sqlmap/tarball/master) ili [.zip](https://github.com/sqlmapproject/sqlmap/zipball/master) +* RSS feed promjena u kodu: https://github.com/sqlmapproject/sqlmap/commits/master.atom +* Prijava problema: https://github.com/sqlmapproject/sqlmap/issues +* Korisnički priručnik: https://github.com/sqlmapproject/sqlmap/wiki +* Najčešće postavljena pitanja (FAQ): https://github.com/sqlmapproject/sqlmap/wiki/FAQ +* Pretplata na mailing listu: https://lists.sourceforge.net/lists/listinfo/sqlmap-users +* RSS feed mailing liste: http://rss.gmane.org/messages/complete/gmane.comp.security.sqlmap +* Arhiva mailing liste: http://news.gmane.org/gmane.comp.security.sqlmap +* Twitter: [@sqlmap](https://twitter.com/sqlmap) +* Demo: [http://www.youtube.com/user/inquisb/videos](http://www.youtube.com/user/inquisb/videos) +* Slike zaslona: https://github.com/sqlmapproject/sqlmap/wiki/Screenshots diff --git a/doc/translations/README-zh-CN.md b/doc/translations/README-zh-CN.md new file mode 100644 index 000000000..c3b8b2941 --- /dev/null +++ b/doc/translations/README-zh-CN.md @@ -0,0 +1,52 @@ +sqlmap +== + + +sqlmap 是一个开源的渗透测试工具,可以用来自动化的检测,利用SQL注入漏洞,获取数据库服务器的权限。它具有功能强大的检测引擎,针对各种不同类型数据库的渗透测试的功能选项,包括获取数据库中存储的数据,访问操作系统文件甚至可以通过外带数据连接的方式执行操作系统命令。 + +演示截图 +---- + +![截图](https://raw.github.com/wiki/sqlmapproject/sqlmap/images/sqlmap_screenshot.png) + +你可以访问 wiki上的 [截图](https://github.com/sqlmapproject/sqlmap/wiki/Screenshots) 查看各种用法的演示 + +安装方法 +---- + +你可以点击 [这里](https://github.com/sqlmapproject/sqlmap/tarball/master) 下载最新的 `tar` 打包的源代码 或者点击 [这里](https://github.com/sqlmapproject/sqlmap/zipball/master)下载最新的 `zip` 打包的源代码. + +推荐你从 [Git](https://github.com/sqlmapproject/sqlmap) 仓库获取最新的源代码: + + git clone https://github.com/sqlmapproject/sqlmap.git sqlmap-dev + +sqlmap 可以运行在 [Python](http://www.python.org/download/) **2.6.x** 和 **2.7.x** 版本的任何平台上 + +使用方法 +---- + +通过如下命令可以查看基本的用法及命令行参数: + + python sqlmap.py -h + +通过如下的命令可以查看所有的用法及命令行参数: + + python sqlmap.py -hh + +你可以从 [这里](https://gist.github.com/stamparm/5335217) 看到一个sqlmap 的使用样例。除此以外,你还可以查看 [使用手册](https://github.com/sqlmapproject/sqlmap/wiki)。获取sqlmap所有支持的特性、参数、命令行选项开关及说明的使用帮助。 + +链接 +---- + +* 项目主页: http://sqlmap.org +* 源代码下载: [.tar.gz](https://github.com/sqlmapproject/sqlmap/tarball/master) or [.zip](https://github.com/sqlmapproject/sqlmap/zipball/master) +* RSS 订阅: https://github.com/sqlmapproject/sqlmap/commits/master.atom +* Issue tracker: https://github.com/sqlmapproject/sqlmap/issues +* 使用手册: https://github.com/sqlmapproject/sqlmap/wiki +* 常见问题 (FAQ): https://github.com/sqlmapproject/sqlmap/wiki/FAQ +* 邮件讨论列表: https://lists.sourceforge.net/lists/listinfo/sqlmap-users +* 邮件列表 RSS 订阅: http://rss.gmane.org/messages/complete/gmane.comp.security.sqlmap +* 邮件列表归档: http://news.gmane.org/gmane.comp.security.sqlmap +* Twitter: [@sqlmap](https://twitter.com/sqlmap) +* 教程: [http://www.youtube.com/user/inquisb/videos](http://www.youtube.com/user/inquisb/videos) +* 截图: https://github.com/sqlmapproject/sqlmap/wiki/Screenshots diff --git a/lib/controller/checks.py b/lib/controller/checks.py index d19a32d31..29f4ffda3 100644 --- a/lib/controller/checks.py +++ b/lib/controller/checks.py @@ -58,6 +58,7 @@ from lib.core.exception import SqlmapConnectionException from lib.core.exception import SqlmapNoneDataException from lib.core.exception import SqlmapSilentQuitException from lib.core.exception import SqlmapUserQuitException +from lib.core.settings import DUMMY_XSS_CHECK_APPENDIX from lib.core.settings import FORMAT_EXCEPTION_STRINGS from lib.core.settings import HEURISTIC_CHECK_ALPHABET from lib.core.settings import SUHOSIN_MAX_VALUE_LENGTH @@ -84,7 +85,13 @@ def checkSqlInjection(place, parameter, value): # Set the flag for SQL injection test mode kb.testMode = True - for test in getSortedInjectionTests(): + paramType = conf.method if conf.method not in (None, HTTPMETHOD.GET, HTTPMETHOD.POST) else place + + tests = getSortedInjectionTests() + + while tests: + test = tests.pop(0) + try: if kb.endDetection: break @@ -398,7 +405,7 @@ def checkSqlInjection(place, parameter, value): # Perform the test's False request if not falseResult: - infoMsg = "%s parameter '%s' seems to be '%s' injectable " % (place, parameter, title) + infoMsg = "%s parameter '%s' seems to be '%s' injectable " % (paramType, parameter, title) logger.info(infoMsg) injectable = True @@ -409,7 +416,7 @@ def checkSqlInjection(place, parameter, value): candidates = filter(None, (_.strip() if _.strip() in (kb.pageTemplate or "") and _.strip() not in falsePage and _.strip() not in threadData.lastComparisonHeaders else None for _ in (trueSet - falseSet))) if candidates: conf.string = candidates[0] - infoMsg = "%s parameter '%s' seems to be '%s' injectable (with --string=\"%s\")" % (place, parameter, title, repr(conf.string).lstrip('u').strip("'")) + infoMsg = "%s parameter '%s' seems to be '%s' injectable (with --string=\"%s\")" % (paramType, parameter, title, repr(conf.string).lstrip('u').strip("'")) logger.info(infoMsg) injectable = True @@ -432,7 +439,7 @@ def checkSqlInjection(place, parameter, value): result = output == "1" if result: - infoMsg = "%s parameter '%s' is '%s' injectable " % (place, parameter, title) + infoMsg = "%s parameter '%s' is '%s' injectable " % (paramType, parameter, title) logger.info(infoMsg) injectable = True @@ -454,7 +461,7 @@ def checkSqlInjection(place, parameter, value): trueResult = Request.queryPage(reqPayload, place, timeBasedCompare=True, raise404=False) if trueResult: - infoMsg = "%s parameter '%s' seems to be '%s' injectable " % (place, parameter, title) + infoMsg = "%s parameter '%s' seems to be '%s' injectable " % (paramType, parameter, title) logger.info(infoMsg) injectable = True @@ -490,7 +497,7 @@ def checkSqlInjection(place, parameter, value): reqPayload, vector = unionTest(comment, place, parameter, value, prefix, suffix) if isinstance(reqPayload, basestring): - infoMsg = "%s parameter '%s' is '%s' injectable" % (place, parameter, title) + infoMsg = "%s parameter '%s' is '%s' injectable" % (paramType, parameter, title) logger.info(infoMsg) injectable = True @@ -596,6 +603,7 @@ def checkSqlInjection(place, parameter, value): choice = readInput(msg, default=str(conf.verbose), checkBatch=False).strip() conf.verbose = int(choice) setVerbosity() + tests.insert(0, test) elif choice[0] in ("n", "N"): return None elif choice[0] in ("e", "E"): @@ -781,6 +789,8 @@ def heuristicCheckSqlInjection(place, parameter): origValue = conf.paramDict[place][parameter] + paramType = conf.method if conf.method not in (None, HTTPMETHOD.GET, HTTPMETHOD.POST) else place + prefix = "" suffix = "" @@ -806,8 +816,8 @@ def heuristicCheckSqlInjection(place, parameter): parseFilePaths(page) result = wasLastResponseDBMSError() - infoMsg = "heuristic (basic) test shows that %s " % place - infoMsg += "parameter '%s' might " % parameter + infoMsg = "heuristic (basic) test shows that %s parameter " % paramType + infoMsg += "'%s' might " % parameter def _(page): return any(_ in (page or "") for _ in FORMAT_EXCEPTION_STRINGS) @@ -848,6 +858,23 @@ def heuristicCheckSqlInjection(place, parameter): infoMsg += "not be injectable" logger.warn(infoMsg) + kb.heuristicMode = True + + value = "%s%s%s" % (randomStr(), DUMMY_XSS_CHECK_APPENDIX, randomStr()) + payload = "%s%s%s" % (prefix, "'%s" % value, suffix) + payload = agent.payload(place, parameter, newValue=payload) + page, _ = Request.queryPage(payload, place, content=True, raise404=False) + + paramType = conf.method if conf.method not in (None, HTTPMETHOD.GET, HTTPMETHOD.POST) else place + + if value in (page or ""): + infoMsg = "heuristic (XSS) test shows that %s parameter " % paramType + infoMsg += "'%s' might " % parameter + infoMsg += "be vulnerable to XSS attacks" + logger.info(infoMsg) + + kb.heuristicMode = False + return kb.heuristicTest def checkDynParam(place, parameter, value): @@ -864,7 +891,9 @@ def checkDynParam(place, parameter, value): dynResult = None randInt = randomInt() - infoMsg = "testing if %s parameter '%s' is dynamic" % (place, parameter) + paramType = conf.method if conf.method not in (None, HTTPMETHOD.GET, HTTPMETHOD.POST) else place + + infoMsg = "testing if %s parameter '%s' is dynamic" % (paramType, parameter) logger.info(infoMsg) try: @@ -872,7 +901,7 @@ def checkDynParam(place, parameter, value): dynResult = Request.queryPage(payload, place, raise404=False) if not dynResult: - infoMsg = "confirming that %s parameter '%s' is dynamic" % (place, parameter) + infoMsg = "confirming that %s parameter '%s' is dynamic" % (paramType, parameter) logger.info(infoMsg) randInt = randomInt() diff --git a/lib/controller/controller.py b/lib/controller/controller.py index e57330d96..37dcc6e25 100644 --- a/lib/controller/controller.py +++ b/lib/controller/controller.py @@ -126,8 +126,8 @@ def _selectInjection(): kb.injection = kb.injections[index] def _formatInjection(inj): - data = "Place: %s\n" % inj.place - data += "Parameter: %s\n" % inj.parameter + paramType = conf.method if conf.method not in (None, HTTPMETHOD.GET, HTTPMETHOD.POST) else inj.place + data = "Parameter: %s (%s)\n" % (inj.parameter, paramType) for stype, sdata in inj.data.items(): title = sdata.title @@ -146,7 +146,7 @@ def _formatInjection(inj): vector = "%s%s" % (vector, comment) data += " Type: %s\n" % PAYLOAD.SQLINJECTION[stype] data += " Title: %s\n" % title - data += " Payload: %s\n" % urldecode(payload, unsafe="&", plusspace=(inj.place == PLACE.POST and kb.postSpaceToPlus)) + data += " Payload: %s\n" % urldecode(payload, unsafe="&", plusspace=(inj.place != PLACE.GET and kb.postSpaceToPlus)) data += " Vector: %s\n\n" % vector if conf.verbose > 1 else "\n" return data @@ -251,7 +251,7 @@ def start(): return True if conf.url and not any((conf.forms, conf.crawlDepth)): - kb.targets.add((conf.url, conf.method, conf.data, conf.cookie)) + kb.targets.add((conf.url, conf.method, conf.data, conf.cookie, None)) if conf.configFile and not kb.targets: errMsg = "you did not edit the configuration file properly, set " @@ -264,13 +264,16 @@ def start(): logger.info(infoMsg) hostCount = 0 + initialHeaders = list(conf.httpHeaders) - for targetUrl, targetMethod, targetData, targetCookie in kb.targets: + for targetUrl, targetMethod, targetData, targetCookie, targetHeaders in kb.targets: try: conf.url = targetUrl - conf.method = targetMethod + conf.method = targetMethod.upper() if targetMethod else targetMethod conf.data = targetData conf.cookie = targetCookie + conf.httpHeaders = list(initialHeaders) + conf.httpHeaders.extend(targetHeaders or []) initTargetEnv() parseTargetUrl() @@ -308,13 +311,13 @@ def start(): if conf.forms: message = "[#%d] form:\n%s %s" % (hostCount, conf.method or HTTPMETHOD.GET, targetUrl) else: - message = "URL %d:\n%s %s%s" % (hostCount, conf.method or HTTPMETHOD.GET, targetUrl, " (PageRank: %s)" % get_pagerank(targetUrl) if conf.googleDork and conf.pageRank else "") + message = "URL %d:\n%s %s%s" % (hostCount, HTTPMETHOD.GET, targetUrl, " (PageRank: %s)" % get_pagerank(targetUrl) if conf.googleDork and conf.pageRank else "") if conf.cookie: message += "\nCookie: %s" % conf.cookie if conf.data is not None: - message += "\nPOST data: %s" % urlencode(conf.data) if conf.data else "" + message += "\n%s data: %s" % ((conf.method if conf.method != HTTPMETHOD.GET else conf.method) or HTTPMETHOD.POST, urlencode(conf.data) if conf.data else "") if conf.forms: if conf.method == HTTPMETHOD.GET and targetUrl.find("?") == -1: @@ -324,13 +327,13 @@ def start(): test = readInput(message, default="Y") if not test or test[0] in ("y", "Y"): - if conf.method == HTTPMETHOD.POST: - message = "Edit POST data [default: %s]%s: " % (urlencode(conf.data) if conf.data else "None", " (Warning: blank fields detected)" if conf.data and extractRegexResult(EMPTY_FORM_FIELDS_REGEX, conf.data) else "") + if conf.method != HTTPMETHOD.GET: + message = "Edit %s data [default: %s]%s: " % (conf.method, urlencode(conf.data) if conf.data else "None", " (Warning: blank fields detected)" if conf.data and extractRegexResult(EMPTY_FORM_FIELDS_REGEX, conf.data) else "") conf.data = readInput(message, default=conf.data) conf.data = _randomFillBlankFields(conf.data) conf.data = urldecode(conf.data) if conf.data and urlencode(DEFAULT_GET_POST_DELIMITER, None) not in conf.data else conf.data - elif conf.method == HTTPMETHOD.GET: + else: if targetUrl.find("?") > -1: firstPart = targetUrl[:targetUrl.find("?")] secondPart = targetUrl[targetUrl.find("?") + 1:] @@ -425,6 +428,8 @@ def start(): paramDict = conf.paramDict[place] + paramType = conf.method if conf.method not in (None, HTTPMETHOD.GET, HTTPMETHOD.POST) else place + for parameter, value in paramDict.items(): if not proceed: break @@ -436,7 +441,7 @@ def start(): if paramKey in kb.testedParams: testSqlInj = False - infoMsg = "skipping previously processed %s parameter '%s'" % (place, parameter) + infoMsg = "skipping previously processed %s parameter '%s'" % (paramType, parameter) logger.info(infoMsg) elif parameter in conf.testParameter: @@ -445,31 +450,37 @@ def start(): elif parameter == conf.rParam: testSqlInj = False - infoMsg = "skipping randomizing %s parameter '%s'" % (place, parameter) + infoMsg = "skipping randomizing %s parameter '%s'" % (paramType, parameter) logger.info(infoMsg) elif parameter in conf.skip: testSqlInj = False - infoMsg = "skipping %s parameter '%s'" % (place, parameter) + infoMsg = "skipping %s parameter '%s'" % (paramType, parameter) + logger.info(infoMsg) + + elif parameter == conf.csrfToken: + testSqlInj = False + + infoMsg = "skipping anti-CSRF token parameter '%s'" % parameter logger.info(infoMsg) # Ignore session-like parameters for --level < 4 elif conf.level < 4 and (parameter.upper() in IGNORE_PARAMETERS or parameter.upper().startswith(GOOGLE_ANALYTICS_COOKIE_PREFIX)): testSqlInj = False - infoMsg = "ignoring %s parameter '%s'" % (place, parameter) + infoMsg = "ignoring %s parameter '%s'" % (paramType, parameter) logger.info(infoMsg) elif PAYLOAD.TECHNIQUE.BOOLEAN in conf.tech: check = checkDynParam(place, parameter, value) if not check: - warnMsg = "%s parameter '%s' does not appear dynamic" % (place, parameter) + warnMsg = "%s parameter '%s' does not appear dynamic" % (paramType, parameter) logger.warn(warnMsg) else: - infoMsg = "%s parameter '%s' is dynamic" % (place, parameter) + infoMsg = "%s parameter '%s' is dynamic" % (paramType, parameter) logger.info(infoMsg) kb.testedParams.add(paramKey) @@ -479,11 +490,11 @@ def start(): if check != HEURISTIC_TEST.POSITIVE: if conf.smart or (kb.ignoreCasted and check == HEURISTIC_TEST.CASTED): - infoMsg = "skipping %s parameter '%s'" % (place, parameter) + infoMsg = "skipping %s parameter '%s'" % (paramType, parameter) logger.info(infoMsg) continue - infoMsg = "testing for SQL injection on %s " % place + infoMsg = "testing for SQL injection on %s " % paramType infoMsg += "parameter '%s'" % parameter logger.info(infoMsg) @@ -506,7 +517,7 @@ def start(): paramKey = (conf.hostname, conf.path, None, None) kb.testedParams.add(paramKey) else: - warnMsg = "%s parameter '%s' is not " % (place, parameter) + warnMsg = "%s parameter '%s' is not " % (paramType, parameter) warnMsg += "injectable" logger.warn(warnMsg) diff --git a/lib/core/agent.py b/lib/core/agent.py index 923677b15..4c35c9152 100644 --- a/lib/core/agent.py +++ b/lib/core/agent.py @@ -10,6 +10,7 @@ import re from lib.core.common import Backend from lib.core.common import extractRegexResult from lib.core.common import getSQLSnippet +from lib.core.common import getUnicode from lib.core.common import isDBMSVersionAtLeast from lib.core.common import isNumber from lib.core.common import isTechniqueAvailable @@ -32,6 +33,8 @@ from lib.core.enums import PLACE from lib.core.enums import POST_HINT from lib.core.exception import SqlmapNoneDataException from lib.core.settings import CUSTOM_INJECTION_MARK_CHAR +from lib.core.settings import DEFAULT_COOKIE_DELIMITER +from lib.core.settings import DEFAULT_GET_POST_DELIMITER from lib.core.settings import GENERIC_SQL_COMMENT from lib.core.settings import PAYLOAD_DELIMITER from lib.core.settings import REPLACEMENT_MARKER @@ -85,7 +88,7 @@ class Agent(object): paramString = conf.parameters[place] paramDict = conf.paramDict[place] - origValue = paramDict[parameter] + origValue = getUnicode(paramDict[parameter]) if place == PLACE.URI: paramString = origValue @@ -99,10 +102,8 @@ class Agent(object): origValue = origValue.split(CUSTOM_INJECTION_MARK_CHAR)[0] if kb.postHint in (POST_HINT.SOAP, POST_HINT.XML): origValue = origValue.split('>')[-1] - elif kb.postHint == POST_HINT.JSON: - origValue = extractRegexResult(r"(?s)\"\s*:\s*(?P\d+\Z)", origValue) or extractRegexResult(r'(?s)(?P[^"]+\Z)', origValue) - elif kb.postHint == POST_HINT.JSON_LIKE: - origValue = extractRegexResult(r'(?s)\'\s*:\s*(?P\d+\Z)', origValue) or extractRegexResult(r"(?s)(?P[^']+\Z)", origValue) + elif kb.postHint in (POST_HINT.JSON, POST_HINT.JSON_LIKE): + origValue = extractRegexResult(r"(?s)\"\s*:\s*(?P\d+\Z)", origValue) or extractRegexResult(r'(?s)\s*(?P[^"\[,]+\Z)', origValue) else: _ = extractRegexResult(r"(?s)(?P[^\s<>{}();'\"&]+\Z)", origValue) or "" origValue = _.split('=', 1)[1] if '=' in _ else "" @@ -110,6 +111,9 @@ class Agent(object): paramString = origValue origValue = origValue.split(CUSTOM_INJECTION_MARK_CHAR)[0] origValue = origValue[origValue.index(',') + 1:] + match = re.search(r"([^;]+)=(?P[^;]+);?\Z", origValue) + if match: + origValue = match.group("value") if conf.prefix: value = origValue @@ -153,9 +157,27 @@ class Agent(object): elif place in (PLACE.USER_AGENT, PLACE.REFERER, PLACE.HOST): retVal = paramString.replace(origValue, self.addPayloadDelimiters(newValue)) else: - retVal = re.sub(r"(\A|\b)%s=%s" % (re.escape(parameter), re.escape(origValue)), "%s=%s" % (parameter, self.addPayloadDelimiters(newValue.replace("\\", "\\\\"))), paramString) + def _(pattern, repl, string): + retVal = string + match = None + for match in re.finditer(pattern, string): + pass + if match: + while True: + _ = re.search(r"\\g<([^>]+)>", repl) + if _: + repl = repl.replace(_.group(0), match.group(int(_.group(1)) if _.group(1).isdigit() else _.group(1))) + else: + break + retVal = string[:match.start()] + repl + string[match.end():] + return retVal + + if origValue: + retVal = _(r"(\A|\b)%s=%s(\Z|\b)" % (re.escape(parameter), re.escape(origValue)), "%s=%s" % (parameter, self.addPayloadDelimiters(newValue.replace("\\", "\\\\"))), paramString) + else: + retVal = _(r"(\A|\b)%s=%s(\Z|%s|%s|\s)" % (re.escape(parameter), re.escape(origValue), DEFAULT_GET_POST_DELIMITER, DEFAULT_COOKIE_DELIMITER), "%s=%s\g<2>" % (parameter, self.addPayloadDelimiters(newValue.replace("\\", "\\\\"))), paramString) if retVal == paramString and urlencode(parameter) != parameter: - retVal = re.sub(r"(\A|\b)%s=%s" % (re.escape(urlencode(parameter)), re.escape(origValue)), "%s=%s" % (urlencode(parameter), self.addPayloadDelimiters(newValue.replace("\\", "\\\\"))), paramString) + retVal = _(r"(\A|\b)%s=%s" % (re.escape(urlencode(parameter)), re.escape(origValue)), "%s=%s" % (urlencode(parameter), self.addPayloadDelimiters(newValue.replace("\\", "\\\\"))), paramString) return retVal @@ -987,7 +1009,7 @@ class Agent(object): """ _ = re.escape(PAYLOAD_DELIMITER) - return re.sub("(%s.*?%s)" % (_, _), ("%s%s%s" % (PAYLOAD_DELIMITER, payload, PAYLOAD_DELIMITER)).replace("\\", r"\\"), value) if value else value + return re.sub("(?s)(%s.*?%s)" % (_, _), ("%s%s%s" % (PAYLOAD_DELIMITER, payload, PAYLOAD_DELIMITER)).replace("\\", r"\\"), value) if value else value def runAsDBMSUser(self, query): if conf.dbmsCred and "Ad Hoc Distributed Queries" not in query: diff --git a/lib/core/bigarray.py b/lib/core/bigarray.py index 04ef7a691..aaa6d2e56 100644 --- a/lib/core/bigarray.py +++ b/lib/core/bigarray.py @@ -13,6 +13,7 @@ except: import os import tempfile +from lib.core.exception import SqlmapSystemException from lib.core.settings import BIGARRAY_CHUNK_LENGTH class Cache(object): @@ -33,8 +34,9 @@ class BigArray(list): def __init__(self): self.chunks = [[]] self.cache = None - self.length = 0 self.filenames = set() + self.protected = False + self._os_remove = os.remove def append(self, value): self.chunks[-1].append(value) @@ -62,12 +64,17 @@ class BigArray(list): return ValueError, "%s is not in list" % value def _dump(self, value): - handle, filename = tempfile.mkstemp(prefix="sqlmapba-") - self.filenames.add(filename) - os.close(handle) - with open(filename, "w+b") as fp: - pickle.dump(value, fp, pickle.HIGHEST_PROTOCOL) - return filename + try: + handle, filename = tempfile.mkstemp(prefix="sqlmapba-") + self.filenames.add(filename) + os.close(handle) + with open(filename, "w+b") as fp: + pickle.dump(value, fp, pickle.HIGHEST_PROTOCOL) + return filename + except IOError, ex: + errMsg = "exception occurred while storing data " + errMsg += "to a temporary file ('%s')" % ex + raise SqlmapSystemException, errMsg def _checkcache(self, index): if (self.cache and self.cache.index != index and self.cache.dirty): @@ -77,6 +84,14 @@ class BigArray(list): with open(self.chunks[index], "rb") as fp: self.cache = Cache(index, pickle.load(fp), False) + def __getstate__(self): + self.protected = True + return self.chunks, self.filenames, self.protected + + def __setstate__(self, state): + self.__init__() + self.chunks, self.filenames, self.protected = state + def __getslice__(self, i, j): retval = BigArray() i = max(0, len(self) + i if i < 0 else i) @@ -119,8 +134,9 @@ class BigArray(list): return len(self.chunks[-1]) if len(self.chunks) == 1 else (len(self.chunks) - 1) * BIGARRAY_CHUNK_LENGTH + len(self.chunks[-1]) def __del__(self): - for filename in self.filenames: - try: - os.remove(filename) - except: - pass + if not self.protected: + for filename in self.filenames: + try: + self._os_remove(filename) + except: + pass diff --git a/lib/core/common.py b/lib/core/common.py index e99dfa63d..53b425af4 100755 --- a/lib/core/common.py +++ b/lib/core/common.py @@ -9,8 +9,11 @@ import codecs import contextlib import cookielib import copy +import getpass +import hashlib import httplib import inspect +import json import logging import ntpath import os @@ -23,6 +26,7 @@ import sys import tempfile import time import urllib +import urllib2 import urlparse import unicodedata @@ -71,12 +75,12 @@ from lib.core.enums import PAYLOAD from lib.core.enums import REFLECTIVE_COUNTER from lib.core.enums import SORT_ORDER from lib.core.exception import SqlmapDataException -from lib.core.exception import SqlmapFilePathException from lib.core.exception import SqlmapGenericException from lib.core.exception import SqlmapNoneDataException from lib.core.exception import SqlmapMissingDependence from lib.core.exception import SqlmapSilentQuitException from lib.core.exception import SqlmapSyntaxException +from lib.core.exception import SqlmapSystemException from lib.core.exception import SqlmapUserQuitException from lib.core.log import LOGGER_HANDLER from lib.core.optiondict import optDict @@ -98,6 +102,8 @@ from lib.core.settings import ERROR_PARSING_REGEXES from lib.core.settings import FORCE_COOKIE_EXPIRATION_TIME from lib.core.settings import FORM_SEARCH_REGEX from lib.core.settings import GENERIC_DOC_ROOT_DIRECTORY_NAMES +from lib.core.settings import GIT_PAGE +from lib.core.settings import GITHUB_REPORT_OAUTH_TOKEN from lib.core.settings import GOOGLE_ANALYTICS_COOKIE_PREFIX from lib.core.settings import HASHDB_MILESTONE_VALUE from lib.core.settings import HOST_ALIASES @@ -551,6 +557,9 @@ def paramToDict(place, parameters=None): if len(parts) >= 2: parameter = urldecode(parts[0].replace(" ", "")) + if not parameter: + continue + if conf.paramDel and conf.paramDel == '\n': parts[-1] = parts[-1].rstrip() @@ -560,7 +569,7 @@ def paramToDict(place, parameters=None): if condition: testableParameters[parameter] = "=".join(parts[1:]) - if not conf.multipleTargets: + if not conf.multipleTargets and not (conf.csrfToken and parameter == conf.csrfToken): _ = urldecode(testableParameters[parameter], convall=True) if (_.strip(DUMMY_SQL_INJECTION_CHARS) != _\ or re.search(r'\A9{3,}', _) or re.search(DUMMY_USER_INJECTION, _))\ @@ -839,7 +848,7 @@ def dataToTrafficFile(data): except IOError, ex: errMsg = "something went wrong while trying " errMsg += "to write to the traffic file '%s' ('%s')" % (conf.trafficFile, ex) - raise SqlmapGenericException(errMsg) + raise SqlmapSystemException(errMsg) def dataToDumpFile(dumpFile, data): dumpFile.write(data) @@ -851,8 +860,13 @@ def dataToOutFile(filename, data): if data: retVal = os.path.join(conf.filePath, filePathToSafeString(filename)) - with codecs.open(retVal, "wb", UNICODE_ENCODING) as f: - f.write(data) + try: + with codecs.open(retVal, "wb", UNICODE_ENCODING) as f: + f.write(data) + except IOError, ex: + errMsg = "something went wrong while trying to write " + errMsg += "to the output file ('%s')" % ex + raise SqlmapGenericException(errMsg) return retVal @@ -875,7 +889,7 @@ def readInput(message, default=None, checkBatch=True): message = "\n%s" % message kb.prependFlag = False - if conf.answers: + if conf.get("answers"): for item in conf.answers.split(','): question = item.split('=')[0].strip() answer = item.split('=')[1] if len(item.split('=')) > 1 else None @@ -891,7 +905,7 @@ def readInput(message, default=None, checkBatch=True): break if retVal is None: - if checkBatch and conf.batch: + if checkBatch and conf.get("batch"): if isListLike(default): options = ",".join(getUnicode(opt, UNICODE_ENCODING) for opt in default) elif default: @@ -912,7 +926,7 @@ def readInput(message, default=None, checkBatch=True): try: retVal = raw_input() or default - retVal = getUnicode(retVal, system=True) if retVal else retVal + retVal = getUnicode(retVal, encoding=sys.stdin.encoding) if retVal else retVal except: time.sleep(0.05) # Reference: http://www.gossamer-threads.com/lists/python/python/781893 kb.prependFlag = True @@ -981,11 +995,23 @@ def sanitizeStr(value): def checkFile(filename): """ - Checks for file existence + Checks for file existence and readability """ - if not os.path.isfile(filename): - raise SqlmapFilePathException("unable to read file '%s'" % filename) + valid = True + + if filename is None or not os.path.isfile(filename): + valid = False + + if valid: + try: + with open(filename, "rb") as f: + pass + except: + valid = False + + if not valid: + raise SqlmapSystemException("unable to read file '%s'" % filename) def banner(): """ @@ -1053,14 +1079,15 @@ def setPaths(): paths.SQLMAP_XML_BANNER_PATH = os.path.join(paths.SQLMAP_XML_PATH, "banner") _ = os.path.join(os.path.expanduser("~"), ".sqlmap") - paths.SQLMAP_OUTPUT_PATH = getUnicode(paths.get("SQLMAP_OUTPUT_PATH", os.path.join(_, "output")), system=True) + paths.SQLMAP_OUTPUT_PATH = getUnicode(paths.get("SQLMAP_OUTPUT_PATH", os.path.join(_, "output")), encoding=sys.getfilesystemencoding()) paths.SQLMAP_DUMP_PATH = os.path.join(paths.SQLMAP_OUTPUT_PATH, "%s", "dump") paths.SQLMAP_FILES_PATH = os.path.join(paths.SQLMAP_OUTPUT_PATH, "%s", "files") # sqlmap files - paths.SQL_SHELL_HISTORY = os.path.join(_, "sql.hst") paths.OS_SHELL_HISTORY = os.path.join(_, "os.hst") + paths.SQL_SHELL_HISTORY = os.path.join(_, "sql.hst") paths.SQLMAP_SHELL_HISTORY = os.path.join(_, "sqlmap.hst") + paths.GITHUB_HISTORY = os.path.join(_, "github.hst") paths.SQLMAP_CONFIG = os.path.join(paths.SQLMAP_ROOT_PATH, "sqlmap-%s.conf" % randomStr()) paths.COMMON_COLUMNS = os.path.join(paths.SQLMAP_TXT_PATH, "common-columns.txt") paths.COMMON_TABLES = os.path.join(paths.SQLMAP_TXT_PATH, "common-tables.txt") @@ -1071,7 +1098,6 @@ def setPaths(): paths.WORDLIST = os.path.join(paths.SQLMAP_TXT_PATH, "wordlist.zip") paths.ERRORS_XML = os.path.join(paths.SQLMAP_XML_PATH, "errors.xml") paths.PAYLOADS_XML = os.path.join(paths.SQLMAP_XML_PATH, "payloads.xml") - paths.INJECTIONS_XML = os.path.join(paths.SQLMAP_XML_PATH, "injections.xml") paths.LIVE_TESTS_XML = os.path.join(paths.SQLMAP_XML_PATH, "livetests.xml") paths.QUERIES_XML = os.path.join(paths.SQLMAP_XML_PATH, "queries.xml") paths.GENERIC_XML = os.path.join(paths.SQLMAP_XML_BANNER_PATH, "generic.xml") @@ -1080,6 +1106,10 @@ def setPaths(): paths.ORACLE_XML = os.path.join(paths.SQLMAP_XML_BANNER_PATH, "oracle.xml") paths.PGSQL_XML = os.path.join(paths.SQLMAP_XML_BANNER_PATH, "postgresql.xml") + for path in paths.values(): + if any(path.endswith(_) for _ in (".txt", ".xml", ".zip")): + checkFile(path) + def weAreFrozen(): """ Returns whether we are frozen via py2exe. @@ -1210,7 +1240,14 @@ def parseTargetUrl(): if CUSTOM_INJECTION_MARK_CHAR in conf.url: conf.url = conf.url.replace('?', URI_QUESTION_MARKER) - urlSplit = urlparse.urlsplit(conf.url) + try: + urlSplit = urlparse.urlsplit(conf.url) + except ValueError, ex: + errMsg = "invalid URL '%s' has been given ('%s'). " % (conf.url, ex) + errMsg += "Please be sure that you don't have any leftover characters (e.g. '[' or ']') " + errMsg += "in the hostname part" + raise SqlmapGenericException(errMsg) + hostnamePort = urlSplit.netloc.split(":") if not re.search("\[.+\]", urlSplit.netloc) else filter(None, (re.search("\[.+\]", urlSplit.netloc).group(0), re.search("\](:(?P\d+))?", urlSplit.netloc).group("port"))) conf.scheme = urlSplit.scheme.strip().lower() if not conf.forceSSL else "https" @@ -1281,7 +1318,7 @@ def expandAsteriskForColumns(expression): if expression != conf.query: conf.db = db else: - expression = re.sub(r"([^\w])%s" % conf.tbl, "\g<1>%s.%s" % (conf.db, conf.tbl), expression) + expression = re.sub(r"([^\w])%s" % re.escape(conf.tbl), "\g<1>%s.%s" % (conf.db, conf.tbl), expression) else: conf.db = db conf.db = safeSQLIdentificatorNaming(conf.db) @@ -1519,29 +1556,30 @@ def safeStringFormat(format_, params): if format_.count(PAYLOAD_DELIMITER) == 2: _ = format_.split(PAYLOAD_DELIMITER) - _[1] = _[1].replace("%d", "%s") + _[1] = re.sub(r"(\A|[^A-Za-z0-9])(%d)([^A-Za-z0-9]|\Z)", r"\g<1>%s\g<3>", _[1]) retVal = PAYLOAD_DELIMITER.join(_) else: - retVal = format_.replace("%d", "%s") + retVal = re.sub(r"(\A|[^A-Za-z0-9])(%d)([^A-Za-z0-9]|\Z)", r"\g<1>%s\g<3>", format_) if isinstance(params, basestring): retVal = retVal.replace("%s", params, 1) elif not isListLike(params): retVal = retVal.replace("%s", str(params), 1) else: - count, index = 0, 0 - if retVal.count("%s") == len(params): - while index != -1: - index = retVal.find("%s") - if index != -1: - retVal = retVal[:index] + getUnicode(params[count]) + retVal[index + 2:] - count += 1 + start, end = 0, len(retVal) + match = re.search(r"%s(.+)%s" % (PAYLOAD_DELIMITER, PAYLOAD_DELIMITER), retVal) + if match and PAYLOAD_DELIMITER not in match.group(1): + start, end = match.start(), match.end() + if retVal.count("%s", start, end) == len(params): + for param in params: + index = retVal.find("%s", start) + retVal = retVal[:index] + getUnicode(param) + retVal[index + 2:] else: count = 0 while True: match = re.search(r"(\A|[^A-Za-z0-9])(%s)([^A-Za-z0-9]|\Z)", retVal) if match: - if count > len(params): + if count >= len(params): raise Exception("wrong number of parameters during string formatting") else: retVal = re.sub(r"(\A|[^A-Za-z0-9])(%s)([^A-Za-z0-9]|\Z)", r"\g<1>%s\g<3>" % params[count], retVal, 1) @@ -1679,7 +1717,11 @@ def getConsoleWidth(default=80): width = int(os.getenv("COLUMNS")) else: try: - process = execute("stty size", shell=True, stdout=PIPE, stderr=PIPE) + try: + FNULL = open(os.devnull, 'w') + except IOError: + FNULL = None + process = execute("stty size", shell=True, stdout=PIPE, stderr=FNULL or PIPE) stdout, _ = process.communicate() items = stdout.split() @@ -1862,31 +1904,36 @@ def getFileItems(filename, commentPrefix='#', unicode_=True, lowercase=False, un checkFile(filename) - with codecs.open(filename, 'r', UNICODE_ENCODING, errors="ignore") if unicode_ else open(filename, 'r') as f: - for line in (f.readlines() if unicode_ else f.xreadlines()): # xreadlines doesn't return unicode strings when codec.open() is used - if commentPrefix: - if line.find(commentPrefix) != -1: - line = line[:line.find(commentPrefix)] + try: + with codecs.open(filename, 'r', UNICODE_ENCODING, errors="ignore") if unicode_ else open(filename, 'r') as f: + for line in (f.readlines() if unicode_ else f.xreadlines()): # xreadlines doesn't return unicode strings when codec.open() is used + if commentPrefix: + if line.find(commentPrefix) != -1: + line = line[:line.find(commentPrefix)] - line = line.strip() + line = line.strip() - if not unicode_: - try: - line = str.encode(line) - except UnicodeDecodeError: - continue + if not unicode_: + try: + line = str.encode(line) + except UnicodeDecodeError: + continue - if line: - if lowercase: - line = line.lower() + if line: + if lowercase: + line = line.lower() - if unique and line in retVal: - continue + if unique and line in retVal: + continue - if unique: - retVal[line] = True - else: - retVal.append(line) + if unique: + retVal[line] = True + else: + retVal.append(line) + except (IOError, OSError, MemoryError), ex: + errMsg = "something went wrong while trying " + errMsg += "to read the content of file '%s' ('%s')" % (filename, ex) + raise SqlmapSystemException(errMsg) return retVal if not unique else retVal.keys() @@ -1995,7 +2042,7 @@ def getPartRun(alias=True): else: return retVal -def getUnicode(value, encoding=None, system=False, noneToNull=False): +def getUnicode(value, encoding=None, noneToNull=False): """ Return the unicode representation of the supplied value: @@ -2011,28 +2058,22 @@ def getUnicode(value, encoding=None, system=False, noneToNull=False): return NULL if isListLike(value): - value = list(getUnicode(_, encoding, system, noneToNull) for _ in value) + value = list(getUnicode(_, encoding, noneToNull) for _ in value) return value - if not system: - if isinstance(value, unicode): - return value - elif isinstance(value, basestring): - while True: - try: - return unicode(value, encoding or kb.get("pageEncoding") or UNICODE_ENCODING) - except UnicodeDecodeError, ex: - value = value[:ex.start] + "".join(INVALID_UNICODE_CHAR_FORMAT % ord(_) for _ in value[ex.start:ex.end]) + value[ex.end:] - else: + if isinstance(value, unicode): + return value + elif isinstance(value, basestring): + while True: try: - return unicode(value) - except UnicodeDecodeError: - return unicode(str(value), errors="ignore") # encoding ignored for non-basestring instances + return unicode(value, encoding or kb.get("pageEncoding") or UNICODE_ENCODING) + except UnicodeDecodeError, ex: + value = value[:ex.start] + "".join(INVALID_UNICODE_CHAR_FORMAT % ord(_) for _ in value[ex.start:ex.end]) + value[ex.end:] else: try: - return getUnicode(value, sys.getfilesystemencoding() or sys.stdin.encoding) - except: - return getUnicode(value, UNICODE_ENCODING) + return unicode(value) + except UnicodeDecodeError: + return unicode(str(value), errors="ignore") # encoding ignored for non-basestring instances def longestCommonPrefix(*sequences): """ @@ -2498,11 +2539,11 @@ def removeDynamicContent(page): if prefix is None and suffix is None: continue elif prefix is None: - page = re.sub(r'(?s)^.+%s' % suffix, suffix, page) + page = re.sub(r'(?s)^.+%s' % re.escape(suffix), suffix, page) elif suffix is None: - page = re.sub(r'(?s)%s.+$' % prefix, prefix, page) + page = re.sub(r'(?s)%s.+$' % re.escape(prefix), prefix, page) else: - page = re.sub(r'(?s)%s.+%s' % (prefix, suffix), '%s%s' % (prefix, suffix), page) + page = re.sub(r'(?s)%s.+%s' % (re.escape(prefix), re.escape(suffix)), '%s%s' % (prefix, suffix), page) return page @@ -2793,7 +2834,7 @@ def openFile(filename, mode='r'): errMsg += "Please check %s permissions on a file " % ("write" if \ mode and ('w' in mode or 'a' in mode or '+' in mode) else "read") errMsg += "and that it's not locked by another process." - raise SqlmapFilePathException(errMsg) + raise SqlmapSystemException(errMsg) def decodeIntToUnicode(value): """ @@ -2808,14 +2849,11 @@ def decodeIntToUnicode(value): if isinstance(value, int): try: - # http://dev.mysql.com/doc/refman/5.0/en/string-functions.html#function_ord - if Backend.getIdentifiedDbms() in (DBMS.MYSQL,): + if value > 255: _ = "%x" % value if len(_) % 2 == 1: _ = "0%s" % _ - retVal = getUnicode(hexdecode(_)) - elif value > 255: - retVal = unichr(value) + retVal = getUnicode(hexdecode(_), encoding="UTF-16" if Backend.isDbms(DBMS.MSSQL) else None) else: retVal = getUnicode(chr(value)) except: @@ -2828,21 +2866,81 @@ def unhandledExceptionMessage(): Returns detailed message about occurred unhandled exception """ - errMsg = "unhandled exception in %s, retry your " % VERSION_STRING - errMsg += "run with the latest development version from the GitHub " - errMsg += "repository. If the exception persists, please send by e-mail " - errMsg += "to '%s' or open a new issue at '%s' with the following text " % (ML, ISSUES_PAGE) - errMsg += "and any information required to reproduce the bug. The " + errMsg = "unhandled exception occurred in %s. It is recommended to retry your " % VERSION_STRING + errMsg += "run with the latest development version from official GitHub " + errMsg += "repository at '%s'. If the exception persists, please open a new issue " % GIT_PAGE + errMsg += "at '%s' (or less preferably send by e-mail to '%s') " % (ISSUES_PAGE, ML) + errMsg += "with the following text and any other information required to " + errMsg += "reproduce the bug. The " errMsg += "developers will try to reproduce the bug, fix it accordingly " - errMsg += "and get back to you.\n" - errMsg += "sqlmap version: %s%s\n" % (VERSION, "-%s" % REVISION if REVISION else "") + errMsg += "and get back to you\n" + errMsg += "sqlmap version: %s\n" % VERSION_STRING[VERSION_STRING.find('/') + 1:] errMsg += "Python version: %s\n" % PYVERSION errMsg += "Operating system: %s\n" % PLATFORM - errMsg += "Command line: %s\n" % " ".join(sys.argv) + errMsg += "Command line: %s\n" % re.sub(r".+?\bsqlmap.py\b", "sqlmap.py", " ".join(sys.argv)) errMsg += "Technique: %s\n" % (enumValueToNameLookup(PAYLOAD.TECHNIQUE, kb.technique) if kb.get("technique") else ("DIRECT" if conf.get("direct") else None)) errMsg += "Back-end DBMS: %s" % ("%s (fingerprinted)" % Backend.getDbms() if Backend.getDbms() is not None else "%s (identified)" % Backend.getIdentifiedDbms()) - return maskSensitiveData(errMsg) + return errMsg + +def createGithubIssue(errMsg, excMsg): + """ + Automatically create a Github issue with unhandled exception information + """ + + issues = [] + try: + issues = getFileItems(paths.GITHUB_HISTORY, unique=True) + except: + pass + finally: + issues = set(issues) + + _ = re.sub(r"'[^']+'", "''", excMsg) + _ = re.sub(r"\s+line \d+", "", _) + _ = re.sub(r'File ".+?/(\w+\.py)', "\g<1>", _) + key = hashlib.md5(_).hexdigest()[:8] + + if key in issues: + return + + msg = "\ndo you want to automatically create a new (anonymized) issue " + msg += "with the unhandled exception information at " + msg += "the official Github repository? [y/N] " + try: + test = readInput(msg, default="N") + except: + test = None + + if test and test[0] in ("y", "Y"): + ex = None + errMsg = errMsg[errMsg.find("\n"):] + + + data = {"title": "Unhandled exception (#%s)" % key, "body": "```%s\n```\n```\n%s```" % (errMsg, excMsg)} + req = urllib2.Request(url="https://api.github.com/repos/sqlmapproject/sqlmap/issues", data=json.dumps(data), headers={"Authorization": "token %s" % GITHUB_REPORT_OAUTH_TOKEN}) + + try: + f = urllib2.urlopen(req) + content = f.read() + except Exception, ex: + content = None + + issueUrl = re.search(r"https://github.com/sqlmapproject/sqlmap/issues/\d+", content or "") + if issueUrl: + infoMsg = "created Github issue can been found at the address '%s'" % issueUrl.group(0) + logger.info(infoMsg) + + try: + with open(paths.GITHUB_HISTORY, "a+b") as f: + f.write("%s\n" % key) + except: + pass + else: + warnMsg = "something went wrong while creating a Github issue" + if ex: + warnMsg += " ('%s')" % ex + logger.warn(warnMsg) def maskSensitiveData(msg): """ @@ -2857,6 +2955,15 @@ def maskSensitiveData(msg): value = extractRegexResult(regex, retVal) retVal = retVal.replace(value, '*' * len(value)) + if not conf.get("hostname"): + match = re.search(r"(?i)sqlmap.+(-u|--url)\s+([^ ]+)", retVal) + if match: + retVal = retVal.replace(match.group(2), '*' * len(match.group(2))) + + + if getpass.getuser(): + retVal = re.sub(r"(?i)\b%s\b" % re.escape(getpass.getuser()), "*" * len(getpass.getuser()), retVal) + return retVal def listToStrValue(value): @@ -2931,7 +3038,7 @@ def removeReflectiveValues(content, payload, suppressWarning=False): retVal = content - if all([content, payload]) and isinstance(content, unicode) and kb.reflectiveMechanism: + if all([content, payload]) and isinstance(content, unicode) and kb.reflectiveMechanism and not kb.heuristicMode: def _(value): while 2 * REFLECTED_REPLACEMENT_REGEX in value: value = value.replace(2 * REFLECTED_REPLACEMENT_REGEX, REFLECTED_REPLACEMENT_REGEX) @@ -2966,7 +3073,7 @@ def removeReflectiveValues(content, payload, suppressWarning=False): regex = REFLECTED_REPLACEMENT_REGEX.join(parts[1:]) retVal = re.sub(r"(?i)\b%s\b" % regex, REFLECTED_VALUE_MARKER, retVal) - if retVal != content and not kb.heuristicMode: + if retVal != content: kb.reflectiveCounters[REFLECTIVE_COUNTER.HIT] += 1 if not suppressWarning: warnMsg = "reflective value(s) found and filtering out" @@ -3392,8 +3499,17 @@ def findPageForms(content, url, raise_=False, addToTargets=False): logger.debug(debugMsg) continue - target = (url, method, data, conf.cookie) - retVal.add(target) + # flag to know if we are dealing with the same target host + _ = reduce(lambda x, y: x == y, map(lambda x: urlparse.urlparse(x).netloc.split(':')[0], (response.geturl(), url))) + + if conf.scope: + if not re.search(conf.scope, url, re.I): + continue + elif not _: + continue + else: + target = (url, method, data, conf.cookie, None) + retVal.add(target) else: errMsg = "there were no forms found at the given target URL" if raise_: @@ -3403,17 +3519,6 @@ def findPageForms(content, url, raise_=False, addToTargets=False): if addToTargets and retVal: for target in retVal: - url = target[0] - - # flag to know if we are dealing with the same target host - _ = reduce(lambda x, y: x == y, map(lambda x: urlparse.urlparse(x).netloc.split(':')[0], (response.geturl(), url))) - - if conf.scope: - if not re.search(conf.scope, url, re.I): - continue - elif not _: - continue - kb.targets.add(target) return retVal diff --git a/lib/core/convert.py b/lib/core/convert.py index 4f48de409..d0646e21b 100644 --- a/lib/core/convert.py +++ b/lib/core/convert.py @@ -41,6 +41,7 @@ def base64pickle(value): """ retVal = None + try: retVal = base64encode(pickle.dumps(value, pickle.HIGHEST_PROTOCOL)) except: @@ -63,7 +64,14 @@ def base64unpickle(value): 'foobar' """ - return pickle.loads(base64decode(value)) + retVal = None + + try: + retVal = pickle.loads(base64decode(value)) + except TypeError: + retVal = pickle.loads(base64decode(bytes(value))) + + return retVal def hexdecode(value): """ diff --git a/lib/core/dicts.py b/lib/core/dicts.py index c9cd0cd51..0a3d7dabe 100644 --- a/lib/core/dicts.py +++ b/lib/core/dicts.py @@ -207,6 +207,7 @@ POST_HINT_CONTENT_TYPES = { POST_HINT.MULTIPART: "multipart/form-data", POST_HINT.SOAP: "application/soap+xml", POST_HINT.XML: "application/xml", + POST_HINT.ARRAY_LIKE: "application/x-www-form-urlencoded; charset=utf-8", } DEPRECATED_OPTIONS = { diff --git a/lib/core/dump.py b/lib/core/dump.py index ba3123ba9..43a86c740 100644 --- a/lib/core/dump.py +++ b/lib/core/dump.py @@ -66,13 +66,24 @@ class Dump(object): if kb.get("multiThreadMode"): self._lock.acquire() - self._outputFP.write(text) + try: + self._outputFP.write(text) + except IOError, ex: + errMsg = "error occurred while writing to log file ('%s')" % ex + raise SqlmapGenericException(errMsg) if kb.get("multiThreadMode"): self._lock.release() kb.dataOutputFlag = True + def flush(self): + if self._outputFP: + try: + self._outputFP.flush() + except IOError: + pass + def setOutputFile(self): self._outputFile = os.path.join(conf.outputPath, "log") try: @@ -380,7 +391,7 @@ class Dump(object): self._write(tableValues, content_type=CONTENT_TYPE.DUMP_TABLE) return - dumpDbPath = os.path.join(conf.dumpPath, re.sub(r"[^\w]", "_", unsafeSQLIdentificatorNaming(db))) + dumpDbPath = os.path.join(conf.dumpPath, re.sub(r"[^\w]", "_", normalizeUnicode(unsafeSQLIdentificatorNaming(db)))) if conf.dumpFormat == DUMP_FORMAT.SQLITE: replication = Replication(os.path.join(conf.dumpPath, "%s.sqlite3" % unsafeSQLIdentificatorNaming(db))) @@ -388,7 +399,7 @@ class Dump(object): if not os.path.isdir(dumpDbPath): os.makedirs(dumpDbPath, 0755) - dumpFileName = os.path.join(dumpDbPath, "%s.%s" % (unsafeSQLIdentificatorNaming(table), conf.dumpFormat.lower())) + dumpFileName = os.path.join(dumpDbPath, "%s.%s" % (normalizeUnicode(unsafeSQLIdentificatorNaming(table)), conf.dumpFormat.lower())) appendToFile = os.path.isfile(dumpFileName) and any((conf.limitStart, conf.limitStop)) dumpFP = openFile(dumpFileName, "wb" if not appendToFile else "ab") diff --git a/lib/core/enums.py b/lib/core/enums.py index b4f8b809f..80cab9474 100644 --- a/lib/core/enums.py +++ b/lib/core/enums.py @@ -74,6 +74,7 @@ class POST_HINT: JSON_LIKE = "JSON-like" MULTIPART = "MULTIPART" XML = "XML (generic)" + ARRAY_LIKE = "Array-like" class HTTPMETHOD: GET = "GET" diff --git a/lib/core/exception.py b/lib/core/exception.py index 8fe6a7756..eed80e1eb 100644 --- a/lib/core/exception.py +++ b/lib/core/exception.py @@ -23,6 +23,9 @@ class SqlmapFilePathException(SqlmapBaseException): class SqlmapGenericException(SqlmapBaseException): pass +class SqlmapInstallationException(SqlmapBaseException): + pass + class SqlmapMissingDependence(SqlmapBaseException): pass @@ -50,9 +53,15 @@ class SqlmapShellQuitException(SqlmapBaseException): class SqlmapSyntaxException(SqlmapBaseException): pass +class SqlmapSystemException(SqlmapBaseException): + pass + class SqlmapThreadException(SqlmapBaseException): pass +class SqlmapTokenException(SqlmapBaseException): + pass + class SqlmapUndefinedMethod(SqlmapBaseException): pass diff --git a/lib/core/option.py b/lib/core/option.py index fa1029a58..986e1b080 100644 --- a/lib/core/option.py +++ b/lib/core/option.py @@ -84,11 +84,13 @@ from lib.core.enums import WIZARD from lib.core.exception import SqlmapConnectionException from lib.core.exception import SqlmapFilePathException from lib.core.exception import SqlmapGenericException +from lib.core.exception import SqlmapInstallationException from lib.core.exception import SqlmapMissingDependence from lib.core.exception import SqlmapMissingMandatoryOptionException from lib.core.exception import SqlmapMissingPrivileges from lib.core.exception import SqlmapSilentQuitException from lib.core.exception import SqlmapSyntaxException +from lib.core.exception import SqlmapSystemException from lib.core.exception import SqlmapUnsupportedDBMSException from lib.core.exception import SqlmapUserQuitException from lib.core.log import FORMATTER @@ -106,6 +108,7 @@ from lib.core.settings import DUMMY_URL from lib.core.settings import INJECT_HERE_MARK from lib.core.settings import IS_WIN from lib.core.settings import KB_CHARS_BOUNDARY_CHAR +from lib.core.settings import KB_CHARS_LOW_FREQUENCY_ALPHABET from lib.core.settings import LOCALHOST from lib.core.settings import MAX_CONNECT_RETRIES from lib.core.settings import MAX_NUMBER_OF_THREADS @@ -219,7 +222,7 @@ def _feedTargetsDict(reqFile, addedTargetUrls): if not(conf.scope and not re.search(conf.scope, url, re.I)): if not kb.targets or url not in addedTargetUrls: - kb.targets.add((url, method, None, cookie)) + kb.targets.add((url, method, None, cookie, None)) addedTargetUrls.add(url) def _parseBurpLog(content): @@ -233,7 +236,7 @@ def _feedTargetsDict(reqFile, addedTargetUrls): for match in re.finditer(BURP_XML_HISTORY_REGEX, content, re.I | re.S): port, request = match.groups() request = request.decode("base64") - _ = re.search(r"%s:.+" % HTTP_HEADER.HOST, request) + _ = re.search(r"%s:.+" % re.escape(HTTP_HEADER.HOST), request) if _: host = _.group(0).strip() if not re.search(r":\d+\Z", host): @@ -271,6 +274,7 @@ def _feedTargetsDict(reqFile, addedTargetUrls): params = False newline = None lines = request.split('\n') + headers = [] for index in xrange(len(lines)): line = lines[index] @@ -282,7 +286,7 @@ def _feedTargetsDict(reqFile, addedTargetUrls): line = line.strip('\r') match = re.search(r"\A(%s) (.+) HTTP/[\d.]+\Z" % "|".join(getPublicTypeMembers(HTTPMETHOD, True)), line) if not method else None - if len(line) == 0 and method in (HTTPMETHOD.POST, HTTPMETHOD.PUT) and data is None: + if len(line) == 0 and method and method != HTTPMETHOD.GET and data is None: data = "" params = True @@ -320,14 +324,14 @@ def _feedTargetsDict(reqFile, addedTargetUrls): port = filterStringValue(splitValue[1], "[0-9]") # Avoid to add a static content length header to - # conf.httpHeaders and consider the following lines as + # headers and consider the following lines as # POSTed data if key.upper() == HTTP_HEADER.CONTENT_LENGTH.upper(): params = True # Avoid proxy and connection type related headers elif key not in (HTTP_HEADER.PROXY_CONNECTION, HTTP_HEADER.CONNECTION): - conf.httpHeaders.append((getUnicode(key), getUnicode(value))) + headers.append((getUnicode(key), getUnicode(value))) if CUSTOM_INJECTION_MARK_CHAR in re.sub(PROBLEMATIC_CUSTOM_INJECTION_PATTERNS, "", value or ""): params = True @@ -355,12 +359,17 @@ def _feedTargetsDict(reqFile, addedTargetUrls): if not(conf.scope and not re.search(conf.scope, url, re.I)): if not kb.targets or url not in addedTargetUrls: - kb.targets.add((url, method, data, cookie)) + kb.targets.add((url, method, data, cookie, tuple(headers))) addedTargetUrls.add(url) - fp = openFile(reqFile, "rb") - - content = fp.read() + checkFile(reqFile) + try: + with openFile(reqFile, "rb") as f: + content = f.read() + except (IOError, OSError, MemoryError), ex: + errMsg = "something went wrong while trying " + errMsg += "to read the content of file '%s' ('%s')" % (reqFile, ex) + raise SqlmapSystemException(errMsg) if conf.scope: logger.info("using regular expression '%s' for filtering targets" % conf.scope) @@ -400,7 +409,13 @@ def _loadQueries(): return retVal tree = ElementTree() - tree.parse(paths.QUERIES_XML) + try: + tree.parse(paths.QUERIES_XML) + except Exception, ex: + errMsg = "something seems to be wrong with " + errMsg += "the file '%s' ('%s'). Please make " % (paths.QUERIES_XML, ex) + errMsg += "sure that you haven't made any changes to it" + raise SqlmapInstallationException, errMsg for node in tree.findall("*"): queries[node.attrib['value']] = iterate(node) @@ -560,14 +575,14 @@ def _setGoogleDorking(): for link in links: link = urldecode(link) if re.search(r"(.*?)\?(.+)", link): - kb.targets.add((link, conf.method, conf.data, conf.cookie)) + kb.targets.add((link, conf.method, conf.data, conf.cookie, None)) elif re.search(URI_INJECTABLE_REGEX, link, re.I): if kb.data.onlyGETs is None and conf.data is None and not conf.googleDork: message = "do you want to scan only results containing GET parameters? [Y/n] " test = readInput(message, default="Y") kb.data.onlyGETs = test.lower() != 'n' if not kb.data.onlyGETs or conf.googleDork: - kb.targets.add((link, conf.method, conf.data, conf.cookie)) + kb.targets.add((link, conf.method, conf.data, conf.cookie, None)) return links @@ -617,7 +632,7 @@ def _setBulkMultipleTargets(): for line in getFileItems(conf.bulkFile): if re.match(r"[^ ]+\?(.+)", line, re.I) or CUSTOM_INJECTION_MARK_CHAR in line: found = True - kb.targets.add((line.strip(), None, None, None)) + kb.targets.add((line.strip(), None, None, None, None)) if not found and not conf.forms and not conf.crawlDepth: warnMsg = "no usable links found (with GET parameters)" @@ -634,7 +649,7 @@ def _setSitemapTargets(): for item in parseSitemap(conf.sitemapUrl): if re.match(r"[^ ]+\?(.+)", item, re.I): found = True - kb.targets.add((item.strip(), None, None, None)) + kb.targets.add((item.strip(), None, None, None, None)) if not found and not conf.forms and not conf.crawlDepth: warnMsg = "no usable links found (with GET parameters)" @@ -933,13 +948,13 @@ def _setTamperingFunctions(): try: module = __import__(filename[:-3]) - except ImportError, msg: + except (ImportError, SyntaxError), msg: raise SqlmapSyntaxException("cannot import tamper script '%s' (%s)" % (filename[:-3], msg)) priority = PRIORITY.NORMAL if not hasattr(module, '__priority__') else module.__priority__ for name, function in inspect.getmembers(module, inspect.isfunction): - if name == "tamper": + if name == "tamper" and inspect.getargspec(function).args and inspect.getargspec(function).keywords == "kwargs": found = True kb.tamperFunctions.append(function) function.func_name = module.__name__ @@ -998,13 +1013,15 @@ def _setWafFunctions(): sys.path.insert(0, dirname) try: + if filename[:-3] in sys.modules: + del sys.modules[filename[:-3]] module = __import__(filename[:-3]) except ImportError, msg: raise SqlmapSyntaxException("cannot import WAF script '%s' (%s)" % (filename[:-3], msg)) _ = dict(inspect.getmembers(module)) if "detect" not in _: - errMsg = "missing function 'detect(page, headers, code)' " + errMsg = "missing function 'detect(get_page)' " errMsg += "in WAF script '%s'" % found raise SqlmapGenericException(errMsg) else: @@ -1241,16 +1258,6 @@ def _setHTTPAuthentication(): checkFile(key_file) authHandler = HTTPSPKIAuthHandler(key_file) -def _setHTTPMethod(): - """ - Check and set the HTTP method to perform HTTP requests through. - """ - - conf.method = HTTPMETHOD.POST if conf.data is not None else HTTPMETHOD.GET - - debugMsg = "setting the HTTP method to %s" % conf.method - logger.debug(debugMsg) - def _setHTTPExtraHeaders(): if conf.headers: debugMsg = "setting extra HTTP headers" @@ -1640,8 +1647,8 @@ def _setKnowledgeBaseAttributes(flushAll=True): kb.chars = AttribDict() kb.chars.delimiter = randomStr(length=6, lowercase=True) - kb.chars.start = "%s%s%s" % (KB_CHARS_BOUNDARY_CHAR, randomStr(length=3, lowercase=True), KB_CHARS_BOUNDARY_CHAR) - kb.chars.stop = "%s%s%s" % (KB_CHARS_BOUNDARY_CHAR, randomStr(length=3, lowercase=True), KB_CHARS_BOUNDARY_CHAR) + kb.chars.start = "%s%s%s" % (KB_CHARS_BOUNDARY_CHAR, randomStr(length=3, alphabet=KB_CHARS_LOW_FREQUENCY_ALPHABET), KB_CHARS_BOUNDARY_CHAR) + kb.chars.stop = "%s%s%s" % (KB_CHARS_BOUNDARY_CHAR, randomStr(length=3, alphabet=KB_CHARS_LOW_FREQUENCY_ALPHABET), KB_CHARS_BOUNDARY_CHAR) kb.chars.at, kb.chars.space, kb.chars.dollar, kb.chars.hash_ = ("%s%s%s" % (KB_CHARS_BOUNDARY_CHAR, _, KB_CHARS_BOUNDARY_CHAR) for _ in randomStr(length=4, lowercase=True)) kb.columnExistsChoice = None @@ -1736,6 +1743,7 @@ def _setKnowledgeBaseAttributes(flushAll=True): kb.reduceTests = None kb.stickyDBMS = False kb.stickyLevel = None + kb.storeCrawlingChoice = None kb.storeHashesChoice = None kb.suppressResumeInfo = False kb.technique = None @@ -1778,11 +1786,11 @@ def _useWizardInterface(): message = "Please enter full target URL (-u): " conf.url = readInput(message, default=None) - message = "POST data (--data) [Enter for None]: " + message = "%s data (--data) [Enter for None]: " % ((conf.method if conf.method != HTTPMETHOD.GET else conf.method) or HTTPMETHOD.POST) conf.data = readInput(message, default=None) if not (filter(lambda _: '=' in unicode(_), (conf.url, conf.data)) or '*' in conf.url): - warnMsg = "no GET and/or POST parameter(s) found for testing " + warnMsg = "no GET and/or %s parameter(s) found for testing " % ((conf.method if conf.method != HTTPMETHOD.GET else conf.method) or HTTPMETHOD.POST) warnMsg += "(e.g. GET parameter 'id' in 'http://www.site.com/vuln.php?id=1'). " if not conf.crawlDepth and not conf.forms: warnMsg += "Will search for forms" @@ -2176,6 +2184,14 @@ def _basicOptionValidation(): errMsg = "switch '--forms' requires usage of option '-u' ('--url'), '-g', '-m' or '-x'" raise SqlmapSyntaxException(errMsg) + if conf.csrfUrl and not conf.csrfToken: + errMsg = "option '--csrf-url' requires usage of option '--csrf-token'" + raise SqlmapSyntaxException(errMsg) + + if conf.csrfToken and conf.threads > 1: + errMsg = "option '--csrf-url' is incompatible with option '--threads'" + raise SqlmapSyntaxException(errMsg) + if conf.requestFile and conf.url and conf.url != DUMMY_URL: errMsg = "option '-r' is incompatible with option '-u' ('--url')" raise SqlmapSyntaxException(errMsg) @@ -2270,7 +2286,7 @@ def _resolveCrossReferences(): lib.controller.checks.setVerbosity = setVerbosity def initOptions(inputOptions=AttribDict(), overrideOptions=False): - if not inputOptions.disableColoring: + if IS_WIN: coloramainit() _setConfAttributes() @@ -2310,7 +2326,6 @@ def init(): _setHTTPCookies() _setHTTPReferer() _setHTTPUserAgent() - _setHTTPMethod() _setHTTPAuthentication() _setHTTPProxy() _setDNSCache() diff --git a/lib/core/optiondict.py b/lib/core/optiondict.py index cfbd02b67..d637aa817 100644 --- a/lib/core/optiondict.py +++ b/lib/core/optiondict.py @@ -23,6 +23,7 @@ optDict = { }, "Request": { + "method": "string", "data": "string", "paramDel": "string", "cookie": "string", @@ -52,6 +53,8 @@ optDict = { "safUrl": "string", "saFreq": "integer", "skipUrlEncode": "boolean", + "csrfToken": "string", + "csrfUrl": "string", "forceSSL": "boolean", "hpp": "boolean", "evalCode": "string", diff --git a/lib/core/settings.py b/lib/core/settings.py index 4a93fdfa5..4fe7e7447 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -26,6 +26,7 @@ DESCRIPTION = "automatic SQL injection and database takeover tool" SITE = "http://sqlmap.org" ISSUES_PAGE = "https://github.com/sqlmapproject/sqlmap/issues/new" GIT_REPOSITORY = "git://github.com/sqlmapproject/sqlmap.git" +GIT_PAGE = "https://github.com/sqlmapproject/sqlmap" ML = "sqlmap-users@lists.sourceforge.net" # colorful banner @@ -33,7 +34,7 @@ BANNER = """\033[01;33m _ ___ ___| |_____ ___ ___ \033[01;37m{\033[01;%dm%s\033[01;37m}\033[01;33m |_ -| . | | | .'| . | |___|_ |_|_|_|_|__,| _| - |_| |_| \033[0m\033[4m%s\033[0m\n + |_| |_| \033[0m\033[4;37m%s\033[0m\n """ % ((31 + hash(REVISION) % 6) if REVISION else 30, VERSION_STRING.split('/')[-1], SITE) # Minimum distance of ratio from kb.matchRatio to result in True @@ -473,6 +474,9 @@ DEFAULT_COOKIE_DELIMITER = ';' # Unix timestamp used for forcing cookie expiration when provided with --load-cookies FORCE_COOKIE_EXPIRATION_TIME = "9999999999" +# Github OAuth token used for creating an automatic Issue for unhandled exceptions +GITHUB_REPORT_OAUTH_TOKEN = "d6c0c7bf3f2298a7b85f82176c46d2f8d494fcc5" + # Skip unforced HashDB flush requests below the threshold number of cached items HASHDB_FLUSH_THRESHOLD = 32 @@ -509,6 +513,9 @@ DNS_BOUNDARIES_ALPHABET = re.sub("[a-fA-F]", "", string.ascii_letters) # Alphabet used for heuristic checks HEURISTIC_CHECK_ALPHABET = ('"', '\'', ')', '(', '[', ']', ',', '.') +# String used for dummy XSS check of a tested parameter value +DUMMY_XSS_CHECK_APPENDIX = "<'\">" + # Connection chunk size (processing large responses in chunks to avoid MemoryError crashes - e.g. large table dump in full UNION injections) MAX_CONNECTION_CHUNK_SIZE = 10 * 1024 * 1024 @@ -531,7 +538,7 @@ VALID_TIME_CHARS_RUN_THRESHOLD = 100 CHECK_ZERO_COLUMNS_THRESHOLD = 10 # Boldify all logger messages containing these "patterns" -BOLD_PATTERNS = ("' injectable", "might be injectable", "' is vulnerable", "is not injectable", "test failed", "test passed", "live test final result", "test shows that") +BOLD_PATTERNS = ("' injectable", "might be injectable", "' is vulnerable", "is not injectable", "test failed", "test passed", "live test final result", "test shows that", "the back-end DBMS is", "created Github") # Generic www root directory names GENERIC_DOC_ROOT_DIRECTORY_NAMES = ("htdocs", "httpdocs", "public", "wwwroot", "www") @@ -543,7 +550,7 @@ MAX_HELP_OPTION_LENGTH = 18 MAX_CONNECT_RETRIES = 100 # Strings for detecting formatting errors -FORMAT_EXCEPTION_STRINGS = ("Type mismatch", "Error converting", "Failed to convert", "System.FormatException", "java.lang.NumberFormatException") +FORMAT_EXCEPTION_STRINGS = ("Type mismatch", "Error converting", "Failed to convert", "System.FormatException", "java.lang.NumberFormatException", "ValueError: invalid literal") # Regular expression used for extracting ASP.NET view state values VIEWSTATE_REGEX = r'(?i)(?P__VIEWSTATE[^"]*)[^>]+value="(?P[^"]+)' @@ -569,6 +576,9 @@ JSON_LIKE_RECOGNITION_REGEX = r"(?s)\A(\s*\[)*\s*\{.*'[^']+'\s*:\s*('[^']+'|\d+) # Regular expression used for detecting multipart POST data MULTIPART_RECOGNITION_REGEX = r"(?i)Content-Disposition:[^;]+;\s*name=" +# Regular expression used for detecting Array-like POST data +ARRAY_LIKE_RECOGNITION_REGEX = r"(\A|%s)(\w+)\[\]=.+%s\2\[\]=" % (DEFAULT_GET_POST_DELIMITER, DEFAULT_GET_POST_DELIMITER) + # Default POST data content-type DEFAULT_CONTENT_TYPE = "application/x-www-form-urlencoded; charset=utf-8" @@ -596,6 +606,9 @@ METASPLOIT_SESSION_TIMEOUT = 300 # Reference: http://www.cookiecentral.com/faq/#3.5 NETSCAPE_FORMAT_HEADER_COOKIES = "# Netscape HTTP Cookie File." +# Infixes used for automatic recognition of parameters carrying anti-CSRF tokens +CSRF_TOKEN_PARAMETER_INFIXES = ("csrf", "xsrf") + # Prefixes used in brute force search for web server document root BRUTE_DOC_ROOT_PREFIXES = { OS.LINUX: ("/var/www", "/usr/local/apache", "/usr/local/apache2", "/usr/local/www/apache22", "/usr/local/www/apache24", "/usr/local/httpd", "/var/www/nginx-default", "/srv/www", "/var/www/%TARGET%", "/var/www/vhosts/%TARGET%", "/var/www/virtual/%TARGET%", "/var/www/clients/vhosts/%TARGET%", "/var/www/clients/virtual/%TARGET%"), @@ -611,6 +624,9 @@ BRUTE_DOC_ROOT_TARGET_MARK = "%TARGET%" # Character used as a boundary in kb.chars (preferably less frequent letter) KB_CHARS_BOUNDARY_CHAR = 'q' +# Letters of lower frequency used in kb.chars +KB_CHARS_LOW_FREQUENCY_ALPHABET = "zqxjkvbp" + # CSS style used in HTML dump format HTML_DUMP_CSS_STYLE = """