Compare commits

...
117 Commits
Author SHA1 Message Date
Miroslav Stampar aee2bee856 Fixes #4664 2021-05-01 11:39:42 +02:00
Miroslav Stampar cfa7b3c3bd Implements #4656 2021-04-28 18:06:15 +02:00
Miroslav Stampar 76b310cc43 Fixes #4650 2021-04-25 20:36:19 +02:00
Miroslav Stampar 9a6acd2054 Fixes #4637 2021-04-13 17:55:54 +02:00
Miroslav Stampar 387020ece8 Better yet for #4633 2021-04-09 11:43:01 +02:00
Miroslav Stampar 732b9670d2 Minor fix related to last commit 2021-04-05 19:00:35 +02:00
Miroslav Stampar 1159c9ccae Fixes #4629 2021-04-05 18:38:47 +02:00
Miroslav Stampar cadbf170f0 Fixes #4630 2021-04-05 18:21:09 +02:00
Miroslav Stampar fc486c8b34 Minor update 2021-04-02 13:55:37 +02:00
Miroslav Stampar cfe43e3f2b Patch for #4626 2021-04-02 12:56:31 +02:00
Miroslav Stampar 6395481aa4 Fixes #4625 2021-04-02 12:47:03 +02:00
Miroslav Stampar 2380ab1e86 Dummy patch for #4623 2021-03-31 10:42:40 +02:00
Miroslav Stampar dd32bfb0cc Minor patch for #4613 2021-03-28 21:41:45 +02:00
Daniel Igarashi b7d90bbe03 Correct a typo (#4619) 2021-03-28 20:01:21 +02:00
Miroslav Stampar 86170e177c Dirty patch for #4618 2021-03-28 19:58:06 +02:00
Miroslav Stampar bce3abc829 Fixes #4612 2021-03-25 17:29:14 +01:00
Miroslav Stampar 8d6125f067 Minor patch 2021-03-22 12:00:32 +01:00
Miroslav Stampar 506e3f0871 Fixes #4611 2021-03-22 11:03:57 +01:00
Miroslav Stampar 6145944dc7 Fixes #4609 2021-03-18 11:40:39 +01:00
Miroslav Stampar 61186b979b Update THANKS.md 2021-03-16 10:11:23 +01:00
Miroslav Stampar 4d4b9a1175 Potential (hide the cause) patch for #4367 2021-03-15 23:02:31 +01:00
Miroslav Stampar 133e2c8c61 Trivial update 2021-03-11 21:31:28 +01:00
Miroslav Stampar 38c341076d Update regarding #4142 (--auth-type bearer) 2021-03-11 20:41:05 +01:00
Miroslav Stampar 40e4422bbd Trivial cosmetics (breaking help into two lines) 2021-03-11 20:14:36 +01:00
Bernardo Damele A. G 98ac1cf9c1 Update FUNDING.yml 2021-03-11 18:11:28 +00:00
Bernardo Damele A. G 56721240fa Update FUNDING.yml 2021-03-11 17:22:58 +00:00
Bernardo Damele A. G c81414cf25 Update FUNDING.yml 2021-03-11 15:41:21 +00:00
Bernardo Damele A. G 2e195a35dc Create FUNDING.yml 2021-03-11 15:38:12 +00:00
Miroslav Stampar 89d25a16ce Trivial patches 2021-03-11 11:11:29 +01:00
Miroslav Stampar 9bc466edac Removing deprecated piece of code 2021-03-11 11:02:23 +01:00
Miroslav Stampar 32b7f3040e Trivial consistency update 2021-03-11 11:00:38 +01:00
Miroslav Stampar f066e215e5 Minor patch 2021-03-11 10:55:09 +01:00
Miroslav Stampar 4e65ff4689 Proper patch for #4591 2021-03-08 15:40:05 +01:00
Miroslav Stampar 1e8bf1c78a Trivial update for #4595 2021-03-07 21:22:17 +01:00
Miroslav Stampar 657c6519ea Graceful fail for --gui (#4601) 2021-03-07 21:15:59 +01:00
Miroslav Stampar 970c7f6a76 Fixes #4599 2021-03-07 20:35:51 +01:00
Miroslav Stampar 105e314ec8 Fixes #4596 2021-03-07 20:31:11 +01:00
Miroslav Stampar dd963a042d Fixes #4591 2021-03-04 08:26:23 +01:00
Miroslav Stampar 0df2592622 Trivial speedup 2021-03-03 23:28:27 +01:00
Miroslav Stampar eeacab0f19 Speedup of caching for char encoding (non-Unicode chars in page) 2021-03-03 23:08:00 +01:00
Miroslav Stampar b3e454d0b1 Trivial update 2021-02-25 12:19:08 +01:00
Miroslav Stampar 99d0031d65 Minor update 2021-02-25 11:39:08 +01:00
Miroslav Stampar 5916bc2d39 Minor update 2021-02-25 11:22:10 +01:00
Miroslav Stampar 2159944de4 Minor update 2021-02-23 12:00:59 +01:00
Miroslav Stampar f87aa83e9b Dirty implementation for #4571 2021-02-21 22:49:57 +01:00
Miroslav Stampar b902cca791 Minor update 2021-02-19 11:38:02 +01:00
Miroslav Stampar 86467e196b Periodical recloak 2021-02-19 11:08:14 +01:00
Miroslav Stampar 30f137699d Trivial bug patch 2021-02-19 11:07:13 +01:00
Miroslav Stampar 7741154383 Fixes #4580 2021-02-16 14:27:02 +01:00
Miroslav Stampar a6262a3aa9 Adding support for Virtuoso DBMS 2021-02-15 14:07:36 +01:00
Miroslav Stampar 1f33b16e01 Fixes #4579 2021-02-14 14:47:28 +01:00
Miroslav Stampar 04396c97e2 Minor refactoring 2021-02-11 13:00:54 +01:00
Miroslav Stampar b1cdbdae61 Minor update of tests 2021-02-11 12:30:21 +01:00
Miroslav Stampar 747951b80b Another patch for #4576 2021-02-10 14:09:13 +01:00
Miroslav Stampar 1bef2f8fda Fixes #4576 2021-02-10 14:02:42 +01:00
Miroslav Stampar b0ac442096 Minor patch of links 2021-02-08 22:42:08 +01:00
Miroslav Stampar 99a5fb243c Trivial update 2021-02-08 21:50:20 +01:00
Miroslav Stampar b2a575482e Proxies dislike non-browser user-agents 2021-02-08 21:47:36 +01:00
Miroslav Stampar 365e08b710 Allowing empty database names in -d 2021-02-08 20:47:37 +01:00
Miroslav Stampar af3b79ff8b Trivial update of doctests 2021-02-08 12:28:24 +01:00
hugoduar 3724a53466 Add spanish common names (#4573) 2021-02-08 11:30:39 +01:00
Miroslav Stampar 01e83cb4a0 Minor patch for ws 2021-02-08 11:18:27 +01:00
Miroslav Stampar cd77cdd1e8 It seems that JSON_GROUP_ARRAY is not available in all Travis CI deployments 2021-02-05 15:15:58 +01:00
Miroslav Stampar 22c421a427 Debugging the testing case 2021-02-05 14:46:23 +01:00
Miroslav Stampar 59fe89f076 Minor update of testing cases 2021-02-05 12:44:39 +01:00
Miroslav Stampar 160011bd87 Couple of bug fixes 2021-02-03 11:52:50 +01:00
Miroslav Stampar 36ee4d68c7 Trivial update 2021-02-01 22:19:20 +01:00
Miroslav Stampar dfc5bc5d87 Minor update of testing cases 2021-02-01 21:58:36 +01:00
Miroslav Stampar d247fda9d3 Fixing HTTP chunking for Python2.6 2021-02-01 21:34:26 +01:00
Miroslav Stampar 78b1c4f072 Trying to fix the mess with content_length between versions 2021-01-31 16:08:02 +01:00
Miroslav Stampar 63e44f9ee9 Trying to debug the Travis CI issue 2021-01-31 14:44:02 +01:00
Miroslav Stampar 08349138ec Bug fix (--chunked failing on TravisCI) 2021-01-31 14:00:44 +01:00
Miroslav Stampar 807d38688f Trivial update 2021-01-29 14:49:08 +01:00
Miroslav Stampar 0975fb1226 Minor update 2021-01-29 14:46:15 +01:00
Miroslav Stampar 71c141ef86 Minor patch 2021-01-29 14:38:13 +01:00
Miroslav Stampar accfbf958e Fixes #4560 2021-01-27 14:01:20 +01:00
Miroslav Stampar c0be1da8b1 Capture deprecations even in nightly Python builds 2021-01-21 10:14:24 +01:00
Miroslav Stampar 4a12493d85 Python3 fix (parsing of headers) 2021-01-20 16:29:52 +01:00
Miroslav Stampar b2c8ba10cd Minor just in case update 2021-01-20 16:06:19 +01:00
Miroslav Stampar 9568ee3c4d Fixes #4548 2021-01-19 12:32:32 +01:00
Miroslav Stampar f3e8039145 Fixes #4549 2021-01-19 12:25:03 +01:00
Miroslav Stampar e5086ef61a Fixes #4545 2021-01-18 12:29:35 +01:00
Miroslav Stampar ed0909fe57 Fixes #4547 2021-01-18 12:04:47 +01:00
Miroslav Stampar 6244850749 More DREI stuff 2021-01-15 10:51:49 +01:00
Miroslav Stampar d78590213b Brrrrr incompatibilities with every new Python minor revision 2021-01-15 09:31:57 +01:00
Miroslav Stampar 4490d55482 Removing leftover 2021-01-15 09:18:21 +01:00
Miroslav Stampar fd137b49ef Fixing Python3.10 incompatibility 2021-01-15 09:17:33 +01:00
Miroslav Stampar 6fa5922fbd Bug fix (error heuristics not working in heavy dynamicity cases) 2021-01-14 22:49:08 +01:00
Miroslav Stampar 42884d3f09 Problems with badge.fury.io 2021-01-13 17:32:57 +01:00
Miroslav Stampar 1a0c533626 Fixes #4541 2021-01-13 13:17:46 +01:00
Miroslav Stampar 5d3bd6ea7a Adding support for YugabyteDB 2021-01-13 11:47:10 +01:00
Miroslav Stampar 29a7646334 Trivial update 2021-01-12 16:55:24 +01:00
shelld3vandMiroslav Stampar fa93f5e099 New translation: Vietnamese (#4509)
* Create README-vi-VN.md

* Update README.md

* Consistency update (same style as in other translations)

Co-authored-by: Miroslav Stampar <[email protected]>
2021-01-12 16:34:17 +01:00
Miroslav Stampar 12238019dd Patch for Python2.6 2021-01-12 16:28:50 +01:00
Miroslav Stampar 0b1b64b682 Thank you Travis CI in discovering of a cluster of f*cks 2021-01-12 16:21:43 +01:00
Miroslav Stampar c8dc375fb5 Update for #4537 2021-01-12 15:58:40 +01:00
Miroslav Stampar a697e6c307 All of a sudden PY2 _configparser doesn't support \tkey = value 2021-01-12 15:57:12 +01:00
Miroslav Stampar 66a3118f81 Adding support for JSON aggregation on SQLite 2021-01-12 15:36:02 +01:00
Miroslav Stampar 3002f92e34 Trivial update 2021-01-12 13:23:08 +01:00
Miroslav Stampar 2ef07c80db Some more refactoring 2021-01-12 13:21:51 +01:00
Miroslav Stampar e3028f195e Support for Raima Database Manager DBMS 2021-01-11 17:36:23 +01:00
Miroslav Stampar 1f39dbd06d Another patch regarding #4530 2021-01-07 14:20:03 +01:00
Miroslav Stampar ccf9e7de54 Another patch regarding #4530 2021-01-07 14:00:10 +01:00
Miroslav Stampar ebd2a940cb Patching profile capabilities 2021-01-07 13:52:38 +01:00
Miroslav Stampar 0d3889730d Another patch for #4530 2021-01-07 11:56:49 +01:00
Miroslav Stampar ccbc3e62f8 First patch for #4530 2021-01-07 11:44:00 +01:00
Miroslav Stampar f84ec1072b Patch related to #4527 (drei) 2021-01-06 16:09:40 +01:00
Miroslav Stampar 779b352f6b Minor cosmetics 2021-01-06 15:47:50 +01:00
Miroslav Stampar 9af2e68b7e Update for #4525 2021-01-06 15:39:51 +01:00
Miroslav Stampar bd59dd4a0f Trivial update 2021-01-06 15:21:33 +01:00
Miroslav Stampar c4e6c3e854 Fixes #4513 2021-01-05 14:50:54 +01:00
Miroslav Stampar 91045aab60 Fixes #4510 2021-01-05 13:36:04 +01:00
Miroslav Stampar b36d8248a4 More fine-tuning for #4505 (in case of --no-escape) 2021-01-04 13:51:51 +01:00
Miroslav Stampar 091678b9d4 Some fine tuning (#4505 - in case of --no-escape) 2021-01-04 13:45:38 +01:00
Miroslav Stampar 0c3d8c9bd1 Fixes #4505 2021-01-04 13:25:29 +01:00
Miroslav Stampar f5b6b0eb4b Fixes #4504 2021-01-03 16:56:35 +01:00
Miroslav Stampar e8048a3cf0 First 2021 dev commit 2021-01-03 15:28:40 +01:00
132 changed files with 1354 additions and 5622 deletions
+1
View File
@@ -0,0 +1 @@
custom: 'https://www.paypal.com/donate?hosted_button_id=A34GMDLKA2V7G'
+3 -2
View File
@@ -1,6 +1,6 @@
# sqlmap ![](https://i.imgur.com/fe85aVR.png)
[![Build Status](https://api.travis-ci.org/sqlmapproject/sqlmap.svg?branch=master)](https://travis-ci.org/sqlmapproject/sqlmap) [![Python 2.6|2.7|3.x](https://img.shields.io/badge/python-2.6|2.7|3.x-yellow.svg)](https://www.python.org/) [![License](https://img.shields.io/badge/license-GPLv2-red.svg)](https://raw.githubusercontent.com/sqlmapproject/sqlmap/master/LICENSE) [![PyPI version](https://badge.fury.io/py/sqlmap.svg)](https://badge.fury.io/py/sqlmap) [![GitHub closed issues](https://img.shields.io/github/issues-closed-raw/sqlmapproject/sqlmap.svg?colorB=ff69b4)](https://github.com/sqlmapproject/sqlmap/issues?q=is%3Aissue+is%3Aclosed) [![Twitter](https://img.shields.io/badge/[email protected])](https://twitter.com/sqlmap)
[![Build Status](https://api.travis-ci.org/sqlmapproject/sqlmap.svg?branch=master)](https://travis-ci.org/sqlmapproject/sqlmap) [![Python 2.6|2.7|3.x](https://img.shields.io/badge/python-2.6|2.7|3.x-yellow.svg)](https://www.python.org/) [![License](https://img.shields.io/badge/license-GPLv2-red.svg)](https://raw.githubusercontent.com/sqlmapproject/sqlmap/master/LICENSE) [![GitHub closed issues](https://img.shields.io/github/issues-closed-raw/sqlmapproject/sqlmap.svg?colorB=ff69b4)](https://github.com/sqlmapproject/sqlmap/issues?q=is%3Aissue+is%3Aclosed) [![Twitter](https://img.shields.io/badge/[email protected])](https://twitter.com/sqlmap)
sqlmap is an open source penetration testing tool that automates the process of detecting and exploiting SQL injection flaws and taking over of database servers. It comes with a powerful detection engine, many niche features for the ultimate penetration tester, and a broad range of switches including database fingerprinting, over data fetching from the database, accessing the underlying file system, and executing commands on the operating system via out-of-band connections.
@@ -16,7 +16,7 @@ You can visit the [collection of screenshots](https://github.com/sqlmapproject/s
Installation
----
You can download the latest tarball by clicking [here](https://github.com/sqlmapproject/sqlmap/tarball/master) or latest zipball by clicking [here](https://github.com/sqlmapproject/sqlmap/zipball/master).
You can download the latest tarball by clicking [here](https://github.com/sqlmapproject/sqlmap/tarball/master) or latest zipball by clicking [here](https://github.com/sqlmapproject/sqlmap/zipball/master).
Preferably, you can download sqlmap by cloning the [Git](https://github.com/sqlmapproject/sqlmap) repository:
@@ -71,3 +71,4 @@ Translations
* [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)
* [Ukrainian](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-uk-UA.md)
* [Vietnamese](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-vi-VN.md)
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+2
View File
@@ -485,6 +485,8 @@ llave
chaveta
tono
cuna
correo
contrasenia
# german
+4
View File
@@ -3223,6 +3223,10 @@ nuke_gallery_pictures_newpicture
Books
grupo
facturas
aclaraciones
preguntas
personas
estadisticas
# site:cn
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+15 -1
View File
@@ -42,7 +42,7 @@
<error regexp="\bSQL Server[^&lt;&quot;]+Driver"/>
<error regexp="Warning.*?\W(mssql|sqlsrv)_"/>
<error regexp="\bSQL Server[^&lt;&quot;]+[0-9a-fA-F]{8}"/>
<error regexp="System\.Data\.SqlClient\.SqlException"/>
<error regexp="System\.Data\.SqlClient\.(SqlException|SqlConnection\.OnError)"/>
<error regexp="(?s)Exception.*?\bRoadhouse\.Cms\."/>
<error regexp="Microsoft SQL Native Client error '[0-9a-fA-F]{8}"/>
<error regexp="\[SQL Server\]"/>
@@ -55,6 +55,7 @@
<error regexp="com\.microsoft\.sqlserver\.jdbc"/>
<error regexp="Pdo[./_\\](Mssql|SqlSrv)"/>
<error regexp="SQL(Srv|Server)Exception"/>
<error regexp="Unclosed quotation mark after the character string"/>
</dbms>
<dbms value="Microsoft Access">
@@ -217,4 +218,17 @@
<error regexp="encountered after end of query"/>
<error regexp="A comparison operator is required here"/>
</dbms>
<dbms value="Raima Database Manager">
<error regexp="-10048: Syntax error"/>
<error regexp="rdmStmtPrepare\(.+?\) returned"/>
</dbms>
<dbms value="Virtuoso">
<error regexp="SQ074: Line \d+:"/>
<error regexp="SR185: Undefined procedure"/>
<error regexp="SQ200: No table "/>
<error regexp="Virtuoso S0002 Error"/>
<error regexp="\[(Virtuoso Driver|Virtuoso iODBC Driver)\]\[Virtuoso Server\]"/>
</dbms>
</root>
+90
View File
@@ -1626,4 +1626,94 @@
<blind query="SELECT &quot;schema_name&quot; FROM INFORMATION_SCHEMA.COLUMNS,INFORMATION_SCHEMA.TABLES,INFORMATION_SCHEMA.SCHEMATA WHERE INFORMATION_SCHEMA.COLUMNS.table_pk=INFORMATION_SCHEMA.TABLES.table_pk AND INFORMATION_SCHEMA.TABLES.schema_pk=INFORMATION_SCHEMA.SCHEMATA.schema_pk AND %s" query2="SELECT &quot;table_name&quot; FROM INFORMATION_SCHEMA.COLUMNS,INFORMATION_SCHEMA.TABLES,INFORMATION_SCHEMA.SCHEMATA WHERE INFORMATION_SCHEMA.COLUMNS.table_pk=INFORMATION_SCHEMA.TABLES.table_pk AND INFORMATION_SCHEMA.TABLES.schema_pk=INFORMATION_SCHEMA.SCHEMATA.schema_pk AND &quot;schema_name&quot;='%s'" count="SELECT COUNT(&quot;schema_name&quot;) FROM INFORMATION_SCHEMA.COLUMNS,INFORMATION_SCHEMA.TABLES,INFORMATION_SCHEMA.SCHEMATA WHERE INFORMATION_SCHEMA.COLUMNS.table_pk=INFORMATION_SCHEMA.TABLES.table_pk AND INFORMATION_SCHEMA.TABLES.schema_pk=INFORMATION_SCHEMA.SCHEMATA.schema_pk AND %s" count2="SELECT COUNT(&quot;table_name&quot;) FROM INFORMATION_SCHEMA.COLUMNS,INFORMATION_SCHEMA.TABLES,INFORMATION_SCHEMA.SCHEMATA WHERE INFORMATION_SCHEMA.COLUMNS.table_pk=INFORMATION_SCHEMA.TABLES.table_pk AND INFORMATION_SCHEMA.TABLES.schema_pk=INFORMATION_SCHEMA.SCHEMATA.schema_pk AND &quot;schema_name&quot;='%s'" condition="&quot;column_name&quot;" condition2="&quot;schema_name&quot;" condition3="&quot;table_name&quot;"/>
</search_column>
</dbms>
<dbms value="Raima Database Manager">
<cast query="CONVERT(%s,CHAR)"/>
<length query="LENGTH(%s)"/>
<isnull query="IFNULL(%s,' ')"/>
<delimiter query="||"/>
<limit/>
<limitregexp/>
<limitgroupstart/>
<limitgroupstop/>
<limitstring/>
<order query="ORDER BY %s ASC"/>
<count query="COUNT(%s)"/>
<comment query="/*"/>
<concatenate query="%s||%s"/>
<case query="SELECT (IF(%s,1,0))"/>
<inference query="UNICODE(SUBSTRING((%s),%d,1))>%d"/>
<banner/>
<current_user/>
<current_db/>
<hostname/>
<table_comment/>
<column_comment/>
<is_dba/>
<dbs/>
<tables/>
<dump_table>
<inband query="SELECT %s FROM %s"/>
<!-- NOTE: Raima does not like escaping of LIKE strings (e.g. ...LIKE CHAR(32)) -->
<blind query="SELECT MIN(%s) FROM %s WHERE CONVERT(%s,CHAR)>'%s'" query2="SELECT MAX(%s) FROM %s WHERE CONVERT(%s,CHAR) LIKE [SINGLE_QUOTE]%s[SINGLE_QUOTE]" count="SELECT COUNT(*) FROM %s" count2="SELECT COUNT(DISTINCT(%s)) FROM %s"/>
</dump_table>
<users/>
<privileges/>
<roles/>
<statements/>
<search_db/>
<search_table/>
<search_column/>
</dbms>
<dbms value="Virtuoso">
<cast query="CAST(%s AS NCHAR)"/>
<length query="LENGTH(%s)"/>
<isnull query="__MAX_NOTNULL(%s,' ')"/>
<delimiter query="||"/>
<limit query="TOP (%d,%d)"/>
<limitregexp query="\s+TOP\s*\(([\d]+)\s*\,\s*([\d]+)\)" query2="\s+TOP\s+([\d]+)"/>
<limitgroupstart query="1"/>
<limitgroupstop query="2"/>
<limitstring query=" TOP "/>
<order query="ORDER BY %s ASC"/>
<count query="COUNT(%s)"/>
<comment query="-- -" query2="/*"/>
<concatenate query="%s||%s"/>
<case query="SELECT (CASE WHEN (%s) THEN 1 ELSE 0 END)"/>
<inference query="ASCII(SUBSTRING((%s),%d,1))>%d"/>
<banner query="sys_stat('st_dbms_name')||' - '||sys_stat('st_dbms_ver')"/>
<current_user query="USERNAME()"/>
<current_db query="UPPER(USERNAME())"/>
<hostname query="sys_stat('st_host_name')"/>
<table_comment/>
<column_comment/>
<is_dba query="USERNAME()='dba'"/>
<dbs>
<inband query="SELECT schema_name FROM INFORMATION_SCHEMA.SCHEMATA"/>
<blind query="SELECT DISTINCT TOP (%d,1) schema_name FROM INFORMATION_SCHEMA.SCHEMATA ORDER BY 1" count="SELECT COUNT(DISTINCT(schema_name)) FROM INFORMATION_SCHEMA.SCHEMATA"/>
</dbs>
<tables>
<inband query="SELECT table_schema,table_name FROM INFORMATION_SCHEMA.TABLES" condition="table_schema"/>
<blind query="SELECT TOP (%d,1) table_name FROM INFORMATION_SCHEMA.TABLES WHERE table_schema='%s' ORDER BY 1" count="SELECT COUNT(table_name) FROM INFORMATION_SCHEMA.TABLES WHERE table_schema='%s'"/>
</tables>
<columns>
<inband query="SELECT column_name,data_type FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name='%s' AND table_schema='%s'" condition="column_name"/>
<blind query="SELECT column_name FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name='%s' AND table_schema='%s'" query2="SELECT data_type FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name='%s' AND column_name='%s' AND table_schema='%s'" count="SELECT COUNT(column_name) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name='%s' AND table_schema='%s'" condition="column_name"/>
</columns>
<dump_table>
<inband query="SELECT %s FROM %s.%s ORDER BY %s"/>
<blind query="SELECT TOP (%d,1) %s FROM %s.%s ORDER BY %s" count="SELECT COUNT(*) FROM %s.%s"/>
</dump_table>
<users>
<inband query="SELECT u_name FROM SYS_USERS WHERE U_IS_ROLE=0 ORDER BY 1"/>
<blind query="SELECT TOP (%d,1) u_name FROM SYS_USERS WHERE U_IS_ROLE=0 ORDER BY 1" count="SELECT COUNT(DISTINCT(u_name)) FROM SYS_USERS"/>
</users>
<privileges/>
<roles/>
<statements/>
<search_db/>
<search_table/>
<search_column/>
</dbms>
</root>
+3 -5
View File
@@ -151,11 +151,6 @@ Giorgio Fedon, <giorgio.fedon(at)gmail.com>
Kasper Fons, <thefeds(at)mail.dk>
* for reporting several bugs
Jose Fonseca, <jose.r.fonseca(at)gmail.com>
* for his Gprof2Dot utility for converting profiler output to dot graph(s) and for his XDot utility to render nicely dot graph(s), both included in sqlmap tree inside extra folder. These libraries are used for sqlmap development purposes only
http://code.google.com/p/jrfonseca/wiki/Gprof2Dot
http://code.google.com/p/jrfonseca/wiki/XDot
Alan Franzoni, <alan.franzoni(at)gmail.com>
* for helping out with Python subprocess library
@@ -739,6 +734,9 @@ rmillet, <rmillet42(at)gmail.com>
Rub3nCT, <rub3nct(at)gmail.com>
* for reporting a minor bug
sapra, <amanistaken(at)gmail.com>
* for helping out with Python multiprocessing library on MacOS
shiftzwei, <shiftzwei(at)gmail.com>
* for reporting a couple of bugs
-4
View File
@@ -48,14 +48,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* The `Chardet` library located under `thirdparty/chardet/`.
Copyright (C) 2008, Mark Pilgrim.
* The `Gprof2dot` library located under `thirdparty/gprof2dot/`.
Copyright (C) 2008-2009, Jose Fonseca.
* The `KeepAlive` library located under `thirdparty/keepalive/`.
Copyright (C) 2002-2003, Michael D. Stenner.
* The `MultipartPost` library located under `thirdparty/multipart/`.
Copyright (C) 2006, Will Holcomb.
* The `XDot` library located under `thirdparty/xdot/`
Copyright (C) 2008, Jose Fonseca.
* The `icmpsh` tool located under `extra/icmpsh/`.
Copyright (C) 2010, Nico Leidecker, Bernardo Damele.
+53
View File
@@ -0,0 +1,53 @@
# sqlmap ![](https://i.imgur.com/fe85aVR.png)
[![Build Status](https://api.travis-ci.org/sqlmapproject/sqlmap.svg?branch=master)](https://travis-ci.org/sqlmapproject/sqlmap) [![Python 2.6|2.7|3.x](https://img.shields.io/badge/python-2.6|2.7|3.x-yellow.svg)](https://www.python.org/) [![License](https://img.shields.io/badge/license-GPLv2-red.svg)](https://raw.githubusercontent.com/sqlmapproject/sqlmap/master/LICENSE) [![PyPI version](https://badge.fury.io/py/sqlmap.svg)](https://badge.fury.io/py/sqlmap) [![GitHub closed issues](https://img.shields.io/github/issues-closed-raw/sqlmapproject/sqlmap.svg?colorB=ff69b4)](https://github.com/sqlmapproject/sqlmap/issues?q=is%3Aissue+is%3Aclosed) [![Twitter](https://img.shields.io/badge/[email protected])](https://twitter.com/sqlmap)
sqlmap là một công cụ kiểm tra thâm nhập mã nguồn mở, nhằm tự động hóa quá trình phát hiện, khai thác lỗ hổng tiêm SQL và tiếp quản các máy chủ cơ sở dữ liệu. Nó đi kèm với
một hệ thống phát hiện mạnh mẽ, nhiều tính năng thích hợp cho người kiểm tra thâm nhập và một loạt các tùy chọn bao gồm lấy dấu cơ sở dữ liệu, truy xuất dữ liệu từ cơ sở dữ
liệu, truy cập tệp của hệ thống và thực hiện các lệnh trên hệ điều hành thông qua kết nối ngoài.
Ảnh chụp màn hình
----
![Screenshot](https://raw.github.com/wiki/sqlmapproject/sqlmap/images/sqlmap_screenshot.png)
Bạn có thể truy cập vào [bộ sưu tập ảnh chụp màn hình](https://github.com/sqlmapproject/sqlmap/wiki/Screenshots), chúng trình bày một số tính năng trên wiki.
Cài đặt
----
Bạn có thể tải xuống tập tin nén tar mới nhất bằng cách nhấp vào [đây](https://github.com/sqlmapproject/sqlmap/tarball/master) hoặc tập tin nén zip mới nhất bằng cách nhấp vào [đây](https://github.com/sqlmapproject/sqlmap/zipball/master).
Tốt hơn là bạn có thể tải xuống sqlmap bằng cách clone với [Git](https://github.com/sqlmapproject/sqlmap):
git clone --depth 1 https://github.com/sqlmapproject/sqlmap.git sqlmap-dev
sqlmap hoạt động hiệu quả với [Python](http://www.python.org/download/) phiên bản **2.6**, **2.7** và **3.x** trên bất kì nền tảng nào.
Sử dụng
----
Để có được danh sách các tùy chọn cơ bản, hãy sử dụng:
python sqlmap.py -h
Để có được danh sách tất cả các tùy chọn, hãy sử dụng:
python sqlmap.py -hh
Bạn có thể tìm thấy video chạy mẫu [tại đây](https://asciinema.org/a/46601).
Để có cái nhìn tổng quan về các khả năng của sqlmap, danh sách các tính năng được hỗ trợ và mô tả về tất cả các tùy chọn, cùng với các ví dụ, bạn nên tham khảo [hướng dẫn sử dụng](https://github.com/sqlmapproject/sqlmap/wiki/Usage) (Tiếng Anh).
Liên kết
----
* Trang chủ: http://sqlmap.org
* Tải xuống: [.tar.gz](https://github.com/sqlmapproject/sqlmap/tarball/master) hoặc [.zip](https://github.com/sqlmapproject/sqlmap/zipball/master)
* Lịch sử thay nguồn đổi cấp dữ liệu RSS: https://github.com/sqlmapproject/sqlmap/commits/master.atom
* Theo dõi vấn đề: https://github.com/sqlmapproject/sqlmap/issues
* Hướng dẫn sử dụng: https://github.com/sqlmapproject/sqlmap/wiki
* Các câu hỏi thường gặp (FAQ): https://github.com/sqlmapproject/sqlmap/wiki/FAQ
* Twitter: [@sqlmap](https://twitter.com/sqlmap)
* Demo: [http://www.youtube.com/user/inquisb/videos](http://www.youtube.com/user/inquisb/videos)
* Ảnh chụp màn hình: https://github.com/sqlmapproject/sqlmap/wiki/Screenshots
+1 -1
View File
@@ -2,7 +2,7 @@
[![Build Status](https://api.travis-ci.org/sqlmapproject/sqlmap.svg?branch=master)](https://travis-ci.org/sqlmapproject/sqlmap) [![Python 2.6|2.7|3.x](https://img.shields.io/badge/python-2.6|2.7|3.x-yellow.svg)](https://www.python.org/) [![License](https://img.shields.io/badge/license-GPLv2-red.svg)](https://raw.githubusercontent.com/sqlmapproject/sqlmap/master/LICENSE) [![PyPI version](https://badge.fury.io/py/sqlmap.svg)](https://badge.fury.io/py/sqlmap) [![GitHub closed issues](https://img.shields.io/github/issues-closed-raw/sqlmapproject/sqlmap.svg?colorB=ff69b4)](https://github.com/sqlmapproject/sqlmap/issues?q=is%3Aissue+is%3Aclosed) [![Twitter](https://img.shields.io/badge/[email protected])](https://twitter.com/sqlmap)
sqlmap 是一个开源的渗透测试工具,可以用来自动化的检测,利用SQL注入漏洞,获取数据库服务器的权限。它具有功能强大的检测引擎,针对各种不同类型数据库的渗透测试的功能选项,包括获取数据库中存储的数据,访问操作系统文件甚至可以通过外带数据连接的方式执行操作系统命令。
sqlmap 是一个开源的渗透测试工具,可以用来自动化的检测,利用SQL注入漏洞,获取数据库服务器的权限。它具有功能强大的检测引擎,针对各种不同类型数据库的渗透测试的功能选项,包括获取数据库中存储的数据,访问操作系统文件甚至可以通过带外数据连接的方式执行操作系统命令。
演示截图
----
+1 -1
View File
@@ -21,7 +21,7 @@ if sys.version_info >= (3, 0):
xrange = range
ord = lambda _: _
KEY = b"cwRAopWDYixMeqs3"
KEY = b"ENWsCymUeJcXqSbD"
def xor(message, key):
return b"".join(struct.pack('B', ord(message[i]) ^ ord(key[i % len(key)])) for i in range(len(message)))
Binary file not shown.
Binary file not shown.
Binary file not shown.
+20 -14
View File
@@ -98,6 +98,7 @@ class ReqHandler(BaseHTTPRequestHandler):
if "<script>" in unquote_plus(query):
self.send_response(INTERNAL_SERVER_ERROR)
self.send_header("X-Powered-By", "Express")
self.send_header("Connection", "close")
self.end_headers()
self.wfile.write("CLOUDFLARE_ERROR_500S_BOX".encode(UNICODE_ENCODING))
@@ -128,7 +129,6 @@ class ReqHandler(BaseHTTPRequestHandler):
self.url, self.params = path, params
if self.url == '/':
if not any(_ in self.params for _ in ("id", "query")):
self.send_response(OK)
self.send_header("Content-type", "text/html; charset=%s" % UNICODE_ENCODING)
@@ -139,10 +139,12 @@ class ReqHandler(BaseHTTPRequestHandler):
code, output = OK, ""
try:
if self.params.get("echo", ""):
output += "%s<br>" % self.params["echo"]
if self.params.get("reflect", ""):
output += "%s<br>" % self.params.get("id")
with _lock:
if "query" in self.params:
_cursor.execute(self.params["query"])
@@ -155,18 +157,22 @@ class ReqHandler(BaseHTTPRequestHandler):
output += "<b>SQL results:</b><br>\n"
if results:
output += "<table border=\"1\">\n"
for row in results:
output += "<tr>"
for value in row:
output += "<td>%s</td>" % value
output += "</tr>\n"
output += "</table>\n"
if self.params.get("code", ""):
if not results:
code = INTERNAL_SERVER_ERROR
else:
output += "no results found"
if results:
output += "<table border=\"1\">\n"
for row in results:
output += "<tr>"
for value in row:
output += "<td>%s</td>" % value
output += "</tr>\n"
output += "</table>\n"
else:
output += "no results found"
output += "</body></html>"
except Exception as ex:
@@ -193,7 +199,7 @@ class ReqHandler(BaseHTTPRequestHandler):
self.do_REQUEST()
def do_PUT(self):
self.do_REQUEST()
self.do_POST()
def do_HEAD(self):
self.do_REQUEST()
+15 -14
View File
@@ -157,6 +157,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):
msg = "it looks like the back-end DBMS is '%s'. " % (Format.getErrorParsedDBMSes() or kb.heuristicDbms or joinValue(injection.dbms, '/'))
msg += "Do you want to skip test payloads specific for other DBMSes? [Y/n]"
@@ -528,7 +529,7 @@ def checkSqlInjection(place, parameter, value):
truePage, trueHeaders, trueCode = threadData.lastComparisonPage or "", threadData.lastComparisonHeaders, threadData.lastComparisonCode
trueRawResponse = "%s%s" % (trueHeaders, truePage)
if trueResult and not(truePage == falsePage and not kb.nullConnection):
if trueResult and not(truePage == falsePage and not any((kb.nullConnection, conf.code))):
# Perform the test's False request
falseResult = Request.queryPage(genCmpPayload(), place, raise404=False)
@@ -990,7 +991,7 @@ def checkSuhosinPatch(injection):
Checks for existence of Suhosin-patch (and alike) protection mechanism(s)
"""
if injection.place == PLACE.GET:
if injection.place in (PLACE.GET, PLACE.URI):
debugMsg = "checking for parameter length "
debugMsg += "constraining mechanisms"
logger.debug(debugMsg)
@@ -1041,11 +1042,6 @@ def heuristicCheckSqlInjection(place, parameter):
if conf.skipHeuristics:
return None
if kb.heavilyDynamic:
debugMsg = "heuristic check skipped because of heavy dynamicity"
logger.debug(debugMsg)
return None
origValue = conf.paramDict[place][parameter]
paramType = conf.method if conf.method not in (None, HTTPMETHOD.GET, HTTPMETHOD.POST) else place
@@ -1082,7 +1078,7 @@ def heuristicCheckSqlInjection(place, parameter):
casting = _(page) and not _(kb.originalPage)
if not casting and not result and kb.dynamicParameter and origValue.isdigit():
if not casting and not result and kb.dynamicParameter and origValue.isdigit() and not kb.heavilyDynamic:
randInt = int(randomInt())
payload = "%s%s%s" % (prefix, "%d-%d" % (int(origValue) + randInt, randInt), suffix)
payload = agent.payload(place, parameter, newValue=payload, where=PAYLOAD.WHERE.REPLACE)
@@ -1096,6 +1092,11 @@ def heuristicCheckSqlInjection(place, parameter):
kb.heuristicTest = HEURISTIC_TEST.CASTED if casting else HEURISTIC_TEST.NEGATIVE if not result else HEURISTIC_TEST.POSITIVE
if kb.heavilyDynamic:
debugMsg = "heuristic check stopped because of heavy dynamicity"
logger.debug(debugMsg)
return kb.heuristicTest
if casting:
errMsg = "possible %s casting detected (e.g. '" % ("integer" if origValue.isdigit() else "type")
@@ -1167,7 +1168,7 @@ def checkDynParam(place, parameter, value):
dynamicity might depend on another parameter.
"""
if kb.redirectChoice:
if kb.choices.redirect:
return None
kb.matchRatio = None
@@ -1268,7 +1269,7 @@ def checkStability():
secondPage, _, _ = Request.queryPage(content=True, noteResponseTime=False, raise404=False)
if kb.redirectChoice:
if kb.choices.redirect:
return None
kb.pageStable = (firstPage == secondPage)
@@ -1415,11 +1416,11 @@ def checkWaf():
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.choices.redirect)
pushValue(kb.resendPostOnRedirect)
pushValue(conf.timeout)
kb.redirectChoice = REDIRECTION.YES
kb.choices.redirect = REDIRECTION.YES
kb.resendPostOnRedirect = False
conf.timeout = IPS_WAF_CHECK_TIMEOUT
@@ -1432,7 +1433,7 @@ def checkWaf():
conf.timeout = popValue()
kb.resendPostOnRedirect = popValue()
kb.redirectChoice = popValue()
kb.choices.redirect = popValue()
hashDBWrite(HASHDB_KEYS.CHECK_WAF_RESULT, retVal, True)
@@ -1565,7 +1566,7 @@ def checkConnection(suppressOutput=False):
else:
kb.errorIsNone = True
if kb.redirectChoice == REDIRECTION.YES and threadData.lastRedirectURL and threadData.lastRedirectURL[0] == threadData.lastRequestUID:
if kb.choices.redirect == REDIRECTION.YES and threadData.lastRedirectURL and threadData.lastRedirectURL[0] == threadData.lastRequestUID:
if (threadData.lastRedirectURL[1] or "").startswith("https://") and conf.hostname in getUnicode(threadData.lastRedirectURL[1]):
conf.url = re.sub(r"https?://", "https://", conf.url)
match = re.search(r":(\d+)", threadData.lastRedirectURL[1])
+8
View File
@@ -33,9 +33,11 @@ from lib.core.settings import MYSQL_ALIASES
from lib.core.settings import ORACLE_ALIASES
from lib.core.settings import PGSQL_ALIASES
from lib.core.settings import PRESTO_ALIASES
from lib.core.settings import RAIMA_ALIASES
from lib.core.settings import SQLITE_ALIASES
from lib.core.settings import SYBASE_ALIASES
from lib.core.settings import VERTICA_ALIASES
from lib.core.settings import VIRTUOSO_ALIASES
from lib.utils.sqlalchemy import SQLAlchemy
from plugins.dbms.access.connector import Connector as AccessConn
@@ -82,12 +84,16 @@ from plugins.dbms.postgresql.connector import Connector as PostgreSQLConn
from plugins.dbms.postgresql import PostgreSQLMap
from plugins.dbms.presto.connector import Connector as PrestoConn
from plugins.dbms.presto import PrestoMap
from plugins.dbms.raima.connector import Connector as RaimaConn
from plugins.dbms.raima import RaimaMap
from plugins.dbms.sqlite.connector import Connector as SQLiteConn
from plugins.dbms.sqlite import SQLiteMap
from plugins.dbms.sybase.connector import Connector as SybaseConn
from plugins.dbms.sybase import SybaseMap
from plugins.dbms.vertica.connector import Connector as VerticaConn
from plugins.dbms.vertica import VerticaMap
from plugins.dbms.virtuoso.connector import Connector as VirtuosoConn
from plugins.dbms.virtuoso import VirtuosoMap
def setHandler():
"""
@@ -121,6 +127,8 @@ def setHandler():
(DBMS.CACHE, CACHE_ALIASES, CacheMap, CacheConn),
(DBMS.EXTREMEDB, EXTREMEDB_ALIASES, ExtremeDBMap, ExtremeDBConn),
(DBMS.FRONTBASE, FRONTBASE_ALIASES, FrontBaseMap, FrontBaseConn),
(DBMS.RAIMA, RAIMA_ALIASES, RaimaMap, RaimaConn),
(DBMS.VIRTUOSO, VIRTUOSO_ALIASES, VirtuosoMap, VirtuosoConn),
]
_ = max(_ if (conf.get("dbms") or Backend.getIdentifiedDbms() or kb.heuristicExtendedDbms or "").lower() in _[1] else () for _ in items)
+7 -4
View File
@@ -487,7 +487,10 @@ class Agent(object):
else:
if not (Backend.isDbms(DBMS.SQLITE) and not isDBMSVersionAtLeast('3')):
nulledCastedField = rootQuery.cast.query % field
if Backend.getIdentifiedDbms() in (DBMS.ACCESS, DBMS.MCKOI):
if re.search(r"COUNT\(", field) and Backend.getIdentifiedDbms() in (DBMS.RAIMA,):
pass
elif Backend.getIdentifiedDbms() in (DBMS.ACCESS, DBMS.MCKOI):
nulledCastedField = rootQuery.isnull.query % (nulledCastedField, nulledCastedField)
else:
nulledCastedField = rootQuery.isnull.query % nulledCastedField
@@ -696,7 +699,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, DBMS.H2, DBMS.MONETDB, DBMS.DERBY, DBMS.VERTICA, DBMS.MCKOI, DBMS.PRESTO, DBMS.ALTIBASE, DBMS.MIMERSQL, DBMS.CRATEDB, DBMS.CUBRID, DBMS.CACHE, DBMS.EXTREMEDB, DBMS.FRONTBASE):
elif Backend.getIdentifiedDbms() in (DBMS.PGSQL, DBMS.ORACLE, DBMS.SQLITE, DBMS.DB2, DBMS.FIREBIRD, DBMS.HSQLDB, DBMS.H2, DBMS.MONETDB, DBMS.DERBY, DBMS.VERTICA, DBMS.MCKOI, DBMS.PRESTO, DBMS.ALTIBASE, DBMS.MIMERSQL, DBMS.CRATEDB, DBMS.CUBRID, DBMS.CACHE, DBMS.EXTREMEDB, DBMS.FRONTBASE, DBMS.RAIMA, DBMS.VIRTUOSO):
if fieldsExists:
concatenatedQuery = concatenatedQuery.replace("SELECT ", "'%s'||" % kb.chars.start, 1)
concatenatedQuery += "||'%s'" % kb.chars.stop
@@ -1006,7 +1009,7 @@ class Agent(object):
fromFrom = limitedQuery[fromIndex + 1:]
orderBy = None
if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.SQLITE, DBMS.H2, DBMS.VERTICA, DBMS.PRESTO, DBMS.MIMERSQL, DBMS.CUBRID, DBMS.EXTREMEDB):
if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.SQLITE, DBMS.H2, DBMS.VERTICA, DBMS.PRESTO, DBMS.MIMERSQL, DBMS.CUBRID, DBMS.EXTREMEDB, DBMS.RAIMA):
limitStr = queries[Backend.getIdentifiedDbms()].limit.query % (num, 1)
limitedQuery += " %s" % limitStr
@@ -1018,7 +1021,7 @@ class Agent(object):
limitStr = queries[Backend.getIdentifiedDbms()].limit.query % (1, num)
limitedQuery += " %s" % limitStr
elif Backend.getIdentifiedDbms() in (DBMS.FRONTBASE,):
elif Backend.getIdentifiedDbms() in (DBMS.FRONTBASE, DBMS.VIRTUOSO):
limitStr = queries[Backend.getIdentifiedDbms()].limit.query % (num, 1)
if query.startswith("SELECT "):
limitedQuery = query.replace("SELECT ", "SELECT %s " % limitStr, 1)
+41 -31
View File
@@ -9,7 +9,6 @@ from __future__ import division
import binascii
import codecs
import collections
import contextlib
import copy
import distutils.version
@@ -194,6 +193,7 @@ from thirdparty.colorama.initialise import init as coloramainit
from thirdparty.magic import magic
from thirdparty.odict import OrderedDict
from thirdparty.six import unichr as _unichr
from thirdparty.six.moves import collections_abc as _collections
from thirdparty.six.moves import configparser as _configparser
from thirdparty.six.moves import http_client as _http_client
from thirdparty.six.moves import input as _input
@@ -216,7 +216,7 @@ class UnicodeRawConfigParser(_configparser.RawConfigParser):
fp.write("[%s]\n" % _configparser.DEFAULTSECT)
for (key, value) in self._defaults.items():
fp.write("\t%s = %s" % (key, getUnicode(value, UNICODE_ENCODING)))
fp.write("%s = %s" % (key, getUnicode(value, UNICODE_ENCODING)))
fp.write("\n")
@@ -226,9 +226,9 @@ class UnicodeRawConfigParser(_configparser.RawConfigParser):
for (key, value) in self._sections[section].items():
if key != "__name__":
if value is None:
fp.write("\t%s\n" % (key))
fp.write("%s\n" % (key))
elif not isListLike(value):
fp.write("\t%s = %s\n" % (key, getUnicode(value, UNICODE_ENCODING)))
fp.write("%s = %s\n" % (key, getUnicode(value, UNICODE_ENCODING)))
fp.write("\n")
@@ -974,7 +974,7 @@ def setColor(message, color=None, bold=False, level=None, istty=None):
level = getattr(logging, level, None)
except:
level = None
retVal = LOGGER_HANDLER.colorize(message, level)
retVal = LOGGER_HANDLER.colorize(message, level, True)
else:
match = re.search(r"\(([^)]*)\s*fork\)", message)
if match:
@@ -1059,7 +1059,8 @@ def dataToDumpFile(dumpFile, data):
errMsg = "permission denied when flushing dump data"
logger.error(errMsg)
else:
raise
errMsg = "error occurred when writing dump data to file ('%s')" % getUnicode(ex)
logger.error(errMsg)
def dataToOutFile(filename, data):
"""
@@ -1270,6 +1271,8 @@ def sanitizeStr(value):
>>> sanitizeStr('foo\\n\\rbar') == 'foo bar'
True
>>> sanitizeStr(None) == 'None'
True
"""
return getUnicode(value).replace("\n", " ").replace("\r", "")
@@ -1528,7 +1531,7 @@ def parseTargetDirect():
remote = False
for dbms in SUPPORTED_DBMS:
details = re.search(r"^(?P<dbms>%s)://(?P<credentials>(?P<user>.*?)\:(?P<pass>.*)\@)?(?P<remote>(?P<hostname>[\w.-]+?)\:(?P<port>[\d]+)\/)?(?P<db>[\w\d\ \:\.\_\-\/\\]+?)$" % dbms, conf.direct, re.I)
details = re.search(r"^(?P<dbms>%s)://(?P<credentials>(?P<user>.*?)\:(?P<pass>.*)\@)?(?P<remote>(?P<hostname>[\w.-]+?)\:(?P<port>[\d]+)\/)?(?P<db>[\w\d\ \:\.\_\-\/\\]*)$" % dbms, conf.direct, re.I)
if details:
conf.dbms = details.group("dbms")
@@ -1829,6 +1832,9 @@ def getLimitRange(count, plusOne=False):
def parseUnionPage(page):
"""
Returns resulting items from UNION query inside provided page content
>>> parseUnionPage("%sfoo%s%sbar%s" % (kb.chars.start, kb.chars.stop, kb.chars.start, kb.chars.stop))
['foo', 'bar']
"""
if page is None:
@@ -2062,6 +2068,9 @@ def safeFilepathEncode(filepath):
def safeExpandUser(filepath):
"""
Patch for a Python Issue18171 (http://bugs.python.org/issue18171)
>>> os.path.basename(__file__) in safeExpandUser(__file__)
True
"""
retVal = filepath
@@ -2873,33 +2882,31 @@ def urldecode(value, encoding=None, unsafe="%%?&=;+%s" % CUSTOM_INJECTION_MARK_C
True
>>> urldecode('AND%201%3E%282%2B3%29%23', convall=False) == 'AND 1>(2%2B3)#'
True
>>> urldecode(b'AND%201%3E%282%2B3%29%23', convall=False) == 'AND 1>(2%2B3)#'
True
"""
result = value
if value:
try:
# for cases like T%C3%BCrk%C3%A7e
value = str(value)
except ValueError:
pass
finally:
if convall:
result = _urllib.parse.unquote_plus(value) if spaceplus else _urllib.parse.unquote(value)
else:
result = value
charset = set(string.printable) - set(unsafe)
value = getUnicode(value)
def _(match):
char = decodeHex(match.group(1), binary=False)
return char if char in charset else match.group(0)
if convall:
result = _urllib.parse.unquote_plus(value) if spaceplus else _urllib.parse.unquote(value)
else:
result = value
charset = set(string.printable) - set(unsafe)
if spaceplus:
result = result.replace('+', ' ') # plus sign has a special meaning in URL encoded data (hence the usage of _urllib.parse.unquote_plus in convall case)
def _(match):
char = decodeHex(match.group(1), binary=False)
return char if char in charset else match.group(0)
result = re.sub(r"%([0-9a-fA-F]{2})", _, result)
if spaceplus:
result = result.replace('+', ' ') # plus sign has a special meaning in URL encoded data (hence the usage of _urllib.parse.unquote_plus in convall case)
result = getUnicode(result, encoding or UNICODE_ENCODING)
result = re.sub(r"%([0-9a-fA-F]{2})", _, result)
result = getUnicode(result, encoding or UNICODE_ENCODING)
return result
@@ -3017,6 +3024,8 @@ def getPublicTypeMembers(type_, onlyValues=False):
>>> [_ for _ in getPublicTypeMembers(OS, True)]
['Linux', 'Windows']
>>> [_ for _ in getPublicTypeMembers(PAYLOAD.TECHNIQUE, True)]
[1, 2, 3, 4, 5, 6]
"""
retVal = []
@@ -3259,7 +3268,7 @@ def filterNone(values):
retVal = values
if isinstance(values, collections.Iterable):
if isinstance(values, _collections.Iterable):
retVal = [_ for _ in values if _]
return retVal
@@ -3550,7 +3559,7 @@ def arrayizeValue(value):
['1']
"""
if isinstance(value, collections.KeysView):
if isinstance(value, _collections.KeysView):
value = [_ for _ in value]
elif not isListLike(value):
value = [value]
@@ -4191,7 +4200,7 @@ def safeSQLIdentificatorNaming(name, isTable=False):
if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.ACCESS, DBMS.CUBRID, DBMS.SQLITE): # Note: in SQLite double-quotes are treated as string if column/identifier is non-existent (e.g. SELECT "foobar" FROM users)
retVal = "`%s`" % retVal
elif Backend.getIdentifiedDbms() in (DBMS.PGSQL, DBMS.DB2, DBMS.HSQLDB, DBMS.H2, DBMS.INFORMIX, DBMS.MONETDB, DBMS.VERTICA, DBMS.MCKOI, DBMS.PRESTO, DBMS.CRATEDB, DBMS.CACHE, DBMS.EXTREMEDB, DBMS.FRONTBASE):
elif Backend.getIdentifiedDbms() in (DBMS.PGSQL, DBMS.DB2, DBMS.HSQLDB, DBMS.H2, DBMS.INFORMIX, DBMS.MONETDB, DBMS.VERTICA, DBMS.MCKOI, DBMS.PRESTO, DBMS.CRATEDB, DBMS.CACHE, DBMS.EXTREMEDB, DBMS.FRONTBASE, DBMS.RAIMA, DBMS.VIRTUOSO):
retVal = "\"%s\"" % retVal
elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.ALTIBASE, DBMS.MIMERSQL):
retVal = "\"%s\"" % retVal.upper()
@@ -4229,7 +4238,7 @@ def unsafeSQLIdentificatorNaming(name):
if isinstance(name, six.string_types):
if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.ACCESS, DBMS.CUBRID, DBMS.SQLITE):
retVal = name.replace("`", "")
elif Backend.getIdentifiedDbms() in (DBMS.PGSQL, DBMS.DB2, DBMS.HSQLDB, DBMS.H2, DBMS.INFORMIX, DBMS.MONETDB, DBMS.VERTICA, DBMS.MCKOI, DBMS.PRESTO, DBMS.CRATEDB, DBMS.CACHE, DBMS.EXTREMEDB, DBMS.FRONTBASE):
elif Backend.getIdentifiedDbms() in (DBMS.PGSQL, DBMS.DB2, DBMS.HSQLDB, DBMS.H2, DBMS.INFORMIX, DBMS.MONETDB, DBMS.VERTICA, DBMS.MCKOI, DBMS.PRESTO, DBMS.CRATEDB, DBMS.CACHE, DBMS.EXTREMEDB, DBMS.FRONTBASE, DBMS.RAIMA, DBMS.VIRTUOSO):
retVal = name.replace("\"", "")
elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.ALTIBASE, DBMS.MIMERSQL):
retVal = name.replace("\"", "").upper()
@@ -4595,7 +4604,7 @@ def findPageForms(content, url, raise_=False, addToTargets=False):
if filtered and filtered != content:
try:
forms = ParseResponse(filtered, backwards_compat=False)
except ParseError:
except:
errMsg = "no success"
if raise_:
raise SqlmapGenericException(errMsg)
@@ -5241,7 +5250,8 @@ def parseRequestFile(reqFile, checkParams=True):
continue
if re.search(r"^[\n]*%s.*?\.(%s)\sHTTP\/" % (HTTPMETHOD.GET, "|".join(CRAWL_EXCLUDE_EXTENSIONS)), request, re.I | re.M):
continue
if not re.search(r"^[\n]*%s[^\n]*\*[^\n]*\sHTTP\/" % HTTPMETHOD.GET, request, re.I | re.M):
continue
getPostReq = False
url = None
+4 -2
View File
@@ -13,7 +13,6 @@ except:
import base64
import binascii
import codecs
import collections
import json
import re
import sys
@@ -31,6 +30,7 @@ from lib.core.settings import SAFE_HEX_MARKER
from lib.core.settings import UNICODE_ENCODING
from thirdparty import six
from thirdparty.six import unichr as _unichr
from thirdparty.six.moves import collections_abc as _collections
try:
from html import escape as htmlEscape
@@ -106,7 +106,7 @@ def singleTimeWarnMessage(message): # Cross-referenced function
sys.stdout.flush()
def filterNone(values): # Cross-referenced function
return [_ for _ in values if _] if isinstance(values, collections.Iterable) else values
return [_ for _ in values if _] if isinstance(values, _collections.Iterable) else values
def isListLike(value): # Cross-referenced function
return isinstance(value, (list, tuple, set, BigArray))
@@ -330,6 +330,8 @@ def getUnicode(value, encoding=None, noneToNull=False):
True
>>> getUnicode(1) == u'1'
True
>>> getUnicode(None) == 'None'
True
"""
if noneToNull and value is None:
+8 -4
View File
@@ -5,11 +5,11 @@ Copyright (c) 2006-2021 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
import collections
import copy
import types
from thirdparty.odict import OrderedDict
from thirdparty.six.moves import collections_abc as _collections
class AttribDict(dict):
"""
@@ -21,13 +21,14 @@ class AttribDict(dict):
1
"""
def __init__(self, indict=None, attribute=None):
def __init__(self, indict=None, attribute=None, keycheck=True):
if indict is None:
indict = {}
# Set any attributes here - before initialisation
# these remain as normal attributes
self.attribute = attribute
self.keycheck = keycheck
dict.__init__(self, indict)
self.__initialised = True
@@ -43,7 +44,10 @@ class AttribDict(dict):
try:
return self.__getitem__(item)
except KeyError:
raise AttributeError("unable to access item '%s'" % item)
if self.keycheck:
raise AttributeError("unable to access item '%s'" % item)
else:
return None
def __setattr__(self, item, value):
"""
@@ -155,7 +159,7 @@ class LRUDict(object):
return self.cache.keys()
# Reference: https://code.activestate.com/recipes/576694/
class OrderedSet(collections.MutableSet):
class OrderedSet(_collections.MutableSet):
"""
This class defines the set with ordered (as added) items
+2
View File
@@ -25,6 +25,8 @@ def cachedmethod(f):
>>> __ = cachedmethod(lambda _: _)
>>> __(1)
1
>>> __(1)
1
>>> __ = cachedmethod(lambda *args, **kwargs: args[0])
>>> __(2)
2
+11 -3
View File
@@ -33,9 +33,11 @@ from lib.core.settings import NULL
from lib.core.settings import ORACLE_ALIASES
from lib.core.settings import PGSQL_ALIASES
from lib.core.settings import PRESTO_ALIASES
from lib.core.settings import RAIMA_ALIASES
from lib.core.settings import SQLITE_ALIASES
from lib.core.settings import SYBASE_ALIASES
from lib.core.settings import VERTICA_ALIASES
from lib.core.settings import VIRTUOSO_ALIASES
FIREBIRD_TYPES = {
261: "BLOB",
@@ -221,9 +223,9 @@ 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/PyMySQL/PyMySQL", "mysql"),
DBMS.PGSQL: (PGSQL_ALIASES, "python-psycopg2", "http://initd.org/psycopg/", "postgresql"),
DBMS.PGSQL: (PGSQL_ALIASES, "python-psycopg2", "https://github.com/psycopg/psycopg2", "postgresql"),
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.SQLITE: (SQLITE_ALIASES, "python-sqlite", "https://docs.python.org/3/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"),
@@ -244,6 +246,8 @@ DBMS_DICT = {
DBMS.CACHE: (CACHE_ALIASES, "python jaydebeapi & python-jpype", "https://pypi.python.org/pypi/JayDeBeApi/ & http://jpype.sourceforge.net/", None),
DBMS.EXTREMEDB: (EXTREMEDB_ALIASES, None, None, None),
DBMS.FRONTBASE: (FRONTBASE_ALIASES, None, None, None),
DBMS.RAIMA: (RAIMA_ALIASES, None, None, None),
DBMS.VIRTUOSO: (VIRTUOSO_ALIASES, None, None, None),
}
# Reference: https://blog.jooq.org/tag/sysibm-sysdummy1/
@@ -280,6 +284,8 @@ HEURISTIC_NULL_EVAL = {
DBMS.CUBRID: "(NULL SETEQ NULL)",
DBMS.CACHE: "%SQLUPPER NULL",
DBMS.EXTREMEDB: "NULLIFZERO(hashcode(NULL))",
DBMS.RAIMA: "IF(ROWNUMBER()>0,CONVERT(NULL,TINYINT),NULL))",
DBMS.VIRTUOSO: "__MAX_NOTNULL(NULL)",
}
SQL_STATEMENTS = {
@@ -360,6 +366,7 @@ OBSOLETE_OPTIONS = {
"--ignore-401": "use '--ignore-code' instead",
"--second-order": "use '--second-url' instead",
"--purge-output": "use '--purge' instead",
"--sqlmap-shell": "use '--shell' instead",
"--check-payload": None,
"--check-waf": None,
"--pickled-options": "use '--api -c ...' instead",
@@ -376,7 +383,7 @@ DUMP_DATA_PREPROCESS = {
DEFAULT_DOC_ROOTS = {
OS.WINDOWS: ("C:/xampp/htdocs/", "C:/wamp/www/", "C:/Inetpub/wwwroot/"),
OS.LINUX: ("/var/www/", "/var/www/html", "/var/www/htdocs", "/usr/local/apache2/htdocs", "/usr/local/www/data", "/var/apache2/htdocs", "/var/www/nginx-default", "/srv/www/htdocs") # Reference: https://wiki.apache.org/httpd/DistrosDefaultLayout
OS.LINUX: ("/var/www/", "/var/www/html", "/var/www/htdocs", "/usr/local/apache2/htdocs", "/usr/local/www/data", "/var/apache2/htdocs", "/var/www/nginx-default", "/srv/www/htdocs", "/usr/local/var/www") # Reference: https://wiki.apache.org/httpd/DistrosDefaultLayout
}
PART_RUN_CONTENT_TYPES = {
@@ -412,6 +419,7 @@ PART_RUN_CONTENT_TYPES = {
HTML_ENTITIES = {
"quot": 34,
"amp": 38,
"apos": 39,
"lt": 60,
"gt": 62,
"nbsp": 160,
+9 -7
View File
@@ -16,9 +16,11 @@ from lib.core.common import Backend
from lib.core.common import checkFile
from lib.core.common import dataToDumpFile
from lib.core.common import dataToStdout
from lib.core.common import filterNone
from lib.core.common import getSafeExString
from lib.core.common import isListLike
from lib.core.common import isMultiThreadMode
from lib.core.common import isNoneValue
from lib.core.common import normalizeUnicode
from lib.core.common import openFile
from lib.core.common import prioritySortColumns
@@ -166,7 +168,7 @@ class Dump(object):
def currentDb(self, data):
if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2, DBMS.MONETDB, DBMS.VERTICA, DBMS.CRATEDB, DBMS.CACHE, DBMS.FRONTBASE):
self.string("current database (equivalent to schema on %s)" % Backend.getIdentifiedDbms(), data, content_type=CONTENT_TYPE.CURRENT_DB)
elif Backend.getIdentifiedDbms() in (DBMS.ALTIBASE, DBMS.DB2, DBMS.MIMERSQL, DBMS.MAXDB):
elif Backend.getIdentifiedDbms() in (DBMS.ALTIBASE, DBMS.DB2, DBMS.MIMERSQL, DBMS.MAXDB, DBMS.VIRTUOSO):
self.string("current database (equivalent to owner on %s)" % Backend.getIdentifiedDbms(), data, content_type=CONTENT_TYPE.CURRENT_DB)
else:
self.string("current database", data, content_type=CONTENT_TYPE.CURRENT_DB)
@@ -200,9 +202,9 @@ class Dump(object):
self._write("%s:" % header)
for user in users:
settings = userSettings[user]
settings = filterNone(userSettings[user])
if settings is None:
if isNoneValue(settings):
stringSettings = ""
else:
stringSettings = " [%d]:" % len(settings)
@@ -243,7 +245,7 @@ class Dump(object):
for db, tables in dbTables.items():
tables = sorted(filter(None, tables))
self._write("Database: %s" % unsafeSQLIdentificatorNaming(db) if db else "Current database")
self._write("Database: %s" % unsafeSQLIdentificatorNaming(db) if db and METADB_SUFFIX not in db else "<current>")
if len(tables) == 1:
self._write("[1 table]")
@@ -298,7 +300,7 @@ class Dump(object):
maxlength2 = max(maxlength2, len("TYPE"))
lines2 = "-" * (maxlength2 + 2)
self._write("Database: %s\nTable: %s" % (unsafeSQLIdentificatorNaming(db) if db else "Current database", unsafeSQLIdentificatorNaming(table)))
self._write("Database: %s\nTable: %s" % (unsafeSQLIdentificatorNaming(db) if db and METADB_SUFFIX not in db else "<current>", unsafeSQLIdentificatorNaming(table)))
if len(columns) == 1:
self._write("[1 column]")
@@ -353,7 +355,7 @@ class Dump(object):
maxlength1 = max(maxlength1, getConsoleLength(getUnicode(table)))
for db, counts in dbTables.items():
self._write("Database: %s" % unsafeSQLIdentificatorNaming(db) if db else "Current database")
self._write("Database: %s" % unsafeSQLIdentificatorNaming(db) if db and METADB_SUFFIX not in db else "<current>")
lines1 = "-" * (maxlength1 + 2)
blank1 = " " * (maxlength1 - len("Table"))
@@ -479,7 +481,7 @@ class Dump(object):
separator += "+%s" % lines
separator += "+"
self._write("Database: %s\nTable: %s" % (unsafeSQLIdentificatorNaming(db) if db else "Current database", unsafeSQLIdentificatorNaming(table)))
self._write("Database: %s\nTable: %s" % (unsafeSQLIdentificatorNaming(db) if db and METADB_SUFFIX not in db else "<current>", unsafeSQLIdentificatorNaming(table)))
if conf.dumpFormat == DUMP_FORMAT.SQLITE:
cols = []
+61
View File
@@ -57,6 +57,8 @@ class DBMS(object):
CACHE = "InterSystems Cache"
EXTREMEDB = "eXtremeDB"
FRONTBASE = "FrontBase"
RAIMA = "Raima Database Manager"
VIRTUOSO = "Virtuoso"
class DBMS_DIRECTORY_NAME(object):
ACCESS = "access"
@@ -84,6 +86,8 @@ class DBMS_DIRECTORY_NAME(object):
CACHE = "cache"
EXTREMEDB = "extremedb"
FRONTBASE = "frontbase"
RAIMA = "raima"
VIRTUOSO = "virtuoso"
class FORK(object):
MARIADB = "MariaDB"
@@ -99,6 +103,7 @@ class FORK(object):
ENTERPRISEDB = "EnterpriseDB"
YELLOWBRICK = "Yellowbrick"
IRIS = "Iris"
YUGABYTEDB = "YugabyteDB"
class CUSTOM_LOGGING(object):
PAYLOAD = 9
@@ -397,6 +402,7 @@ class CONTENT_STATUS(object):
class AUTH_TYPE(object):
BASIC = "basic"
DIGEST = "digest"
BEARER = "bearer"
NTLM = "ntlm"
PKI = "pki"
@@ -434,3 +440,58 @@ class FUZZ_UNION_COLUMN:
STRING = "<string>"
INTEGER = "<integer>"
NULL = "NULL"
class COLOR:
BLUE = "\033[34m"
BOLD_MAGENTA = "\033[35;1m"
BOLD_GREEN = "\033[32;1m"
BOLD_LIGHT_MAGENTA = "\033[95;1m"
LIGHT_GRAY = "\033[37m"
BOLD_RED = "\033[31;1m"
BOLD_LIGHT_GRAY = "\033[37;1m"
YELLOW = "\033[33m"
DARK_GRAY = "\033[90m"
BOLD_CYAN = "\033[36;1m"
LIGHT_RED = "\033[91m"
CYAN = "\033[36m"
MAGENTA = "\033[35m"
LIGHT_MAGENTA = "\033[95m"
LIGHT_GREEN = "\033[92m"
RESET = "\033[0m"
BOLD_DARK_GRAY = "\033[90;1m"
BOLD_LIGHT_YELLOW = "\033[93;1m"
BOLD_LIGHT_RED = "\033[91;1m"
BOLD_LIGHT_GREEN = "\033[92;1m"
LIGHT_YELLOW = "\033[93m"
BOLD_LIGHT_BLUE = "\033[94;1m"
BOLD_LIGHT_CYAN = "\033[96;1m"
LIGHT_BLUE = "\033[94m"
BOLD_WHITE = "\033[97;1m"
LIGHT_CYAN = "\033[96m"
BLACK = "\033[30m"
BOLD_YELLOW = "\033[33;1m"
BOLD_BLUE = "\033[34;1m"
GREEN = "\033[32m"
WHITE = "\033[97m"
BOLD_BLACK = "\033[30;1m"
RED = "\033[31m"
UNDERLINE = "\033[4m"
class BACKGROUND:
BLUE = "\033[44m"
LIGHT_GRAY = "\033[47m"
YELLOW = "\033[43m"
DARK_GRAY = "\033[100m"
LIGHT_RED = "\033[101m"
CYAN = "\033[46m"
MAGENTA = "\033[45m"
LIGHT_MAGENTA = "\033[105m"
LIGHT_GREEN = "\033[102m"
RESET = "\033[0m"
LIGHT_YELLOW = "\033[103m"
LIGHT_BLUE = "\033[104m"
LIGHT_CYAN = "\033[106m"
BLACK = "\033[40m"
GREEN = "\033[42m"
WHITE = "\033[107m"
RED = "\033[41m"
+7 -1
View File
@@ -20,6 +20,7 @@ from lib.core.data import paths
from lib.core.defaults import defaults
from lib.core.enums import MKSTEMP_PREFIX
from lib.core.exception import SqlmapMissingDependence
from lib.core.exception import SqlmapSystemException
from lib.core.settings import DEV_EMAIL_ADDRESS
from lib.core.settings import IS_WIN
from lib.core.settings import ISSUES_PAGE
@@ -72,7 +73,12 @@ def runGui(parser):
tab = event.widget.nametowidget(event.widget.select())
event.widget.configure(height=tab.winfo_reqheight())
window = _tkinter.Tk()
try:
window = _tkinter.Tk()
except Exception as ex:
errMsg = "unable to create GUI window ('%s')" % getSafeExString(ex)
raise SqlmapSystemException(errMsg)
window.title(VERSION_STRING)
# Reference: https://www.holadevs.com/pregunta/64750/change-selected-tab-color-in-ttknotebook
+2 -2
View File
@@ -22,8 +22,8 @@ try:
from thirdparty.ansistrm.ansistrm import ColorizingStreamHandler
class _ColorizingStreamHandler(ColorizingStreamHandler):
def colorize(self, message, levelno):
if levelno in self.level_map and self.is_tty:
def colorize(self, message, levelno, force=False):
if levelno in self.level_map and (self.is_tty or force):
bg, fg, bold = self.level_map[levelno]
params = []
+33 -14
View File
@@ -8,7 +8,6 @@ See the file 'LICENSE' for copying permission
from __future__ import division
import codecs
import collections
import functools
import glob
import inspect
@@ -77,6 +76,7 @@ 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 DUMP_FORMAT
from lib.core.enums import FORK
from lib.core.enums import HTTP_HEADER
from lib.core.enums import HTTPMETHOD
from lib.core.enums import MKSTEMP_PREFIX
@@ -154,6 +154,7 @@ from lib.utils.search import search
from thirdparty import six
from thirdparty.keepalive import keepalive
from thirdparty.multipart import multipartpost
from thirdparty.six.moves import collections_abc as _collections
from thirdparty.six.moves import http_client as _http_client
from thirdparty.six.moves import http_cookiejar as _http_cookiejar
from thirdparty.six.moves import urllib as _urllib
@@ -415,7 +416,7 @@ def _doSearch():
conf.googlePage += 1
def _setStdinPipeTargets():
if isinstance(conf.stdinPipe, collections.Iterable):
if isinstance(conf.stdinPipe, _collections.Iterable):
infoMsg = "using 'STDIN' for parsing targets list"
logger.info(infoMsg)
@@ -727,7 +728,7 @@ def _setDBMS():
if conf.dbms not in SUPPORTED_DBMS:
errMsg = "you provided an unsupported back-end database management "
errMsg += "system. Supported DBMSes are as follows: %s. " % ', '.join(sorted(_ for _ in DBMS_DICT))
errMsg += "system. Supported DBMSes are as follows: %s. " % ', '.join(sorted((_ for _ in (list(DBMS_DICT) + getPublicTypeMembers(FORK, True))), key=str.lower))
errMsg += "If you do not know the back-end DBMS, do not provide "
errMsg += "it and sqlmap will fingerprint it for you."
raise SqlmapUnsupportedDBMSException(errMsg)
@@ -1310,7 +1311,7 @@ def _setAuthCred():
def _setHTTPAuthentication():
"""
Check and set the HTTP(s) authentication method (Basic, Digest, NTLM or PKI),
Check and set the HTTP(s) authentication method (Basic, Digest, Bearer, NTLM or PKI),
username and password for first three methods, or PEM private key file for
PKI authentication
"""
@@ -1333,9 +1334,9 @@ def _setHTTPAuthentication():
errMsg += "but did not provide the type (e.g. --auth-type=\"basic\")"
raise SqlmapSyntaxException(errMsg)
elif (conf.authType or "").lower() not in (AUTH_TYPE.BASIC, AUTH_TYPE.DIGEST, AUTH_TYPE.NTLM, AUTH_TYPE.PKI):
elif (conf.authType or "").lower() not in (AUTH_TYPE.BASIC, AUTH_TYPE.DIGEST, AUTH_TYPE.BEARER, AUTH_TYPE.NTLM, AUTH_TYPE.PKI):
errMsg = "HTTP authentication type value must be "
errMsg += "Basic, Digest, NTLM or PKI"
errMsg += "Basic, Digest, Bearer, NTLM or PKI"
raise SqlmapSyntaxException(errMsg)
if not conf.authFile:
@@ -1348,6 +1349,9 @@ def _setHTTPAuthentication():
regExp = "^(.*?):(.*?)$"
errMsg = "HTTP %s authentication credentials " % authType
errMsg += "value must be in format 'username:password'"
elif authType == AUTH_TYPE.BEARER:
conf.httpHeaders.append((HTTP_HEADER.AUTHORIZATION, "Bearer %s" % conf.authCred.strip()))
return
elif authType == AUTH_TYPE.NTLM:
regExp = "^(.*\\\\.*):(.*?)$"
errMsg = "HTTP NTLM authentication credentials value must "
@@ -1916,7 +1920,7 @@ def _cleanupOptions():
def _cleanupEnvironment():
"""
Cleanup environment (e.g. from leftovers after --sqlmap-shell).
Cleanup environment (e.g. from leftovers after --shell).
"""
if issubclass(_http_client.socket.socket, socks.socksocket):
@@ -1997,6 +2001,7 @@ def _setKnowledgeBaseAttributes(flushAll=True):
kb.cache = AttribDict()
kb.cache.addrinfo = {}
kb.cache.content = {}
kb.cache.comparison = {}
kb.cache.encoding = {}
kb.cache.alphaBoundaries = None
kb.cache.hashRegex = None
@@ -2013,12 +2018,10 @@ def _setKnowledgeBaseAttributes(flushAll=True):
kb.chars.stop = "%s%s%s" % (KB_CHARS_BOUNDARY_CHAR, randomStr(length=3, alphabet=KB_CHARS_LOW_FREQUENCY_ALPHABET), KB_CHARS_BOUNDARY_CHAR)
kb.chars.at, kb.chars.space, kb.chars.dollar, kb.chars.hash_ = ("%s%s%s" % (KB_CHARS_BOUNDARY_CHAR, _, KB_CHARS_BOUNDARY_CHAR) for _ in randomStr(length=4, lowercase=True))
kb.choices = AttribDict(keycheck=False)
kb.codePage = None
kb.columnExistsChoice = None
kb.commonOutputs = None
kb.connErrorChoice = None
kb.connErrorCounter = 0
kb.cookieEncodeChoice = None
kb.copyExecTest = None
kb.counters = {}
kb.customInjectionMark = CUSTOM_INJECTION_MARK_CHAR
@@ -2122,7 +2125,6 @@ def _setKnowledgeBaseAttributes(flushAll=True):
kb.proxyAuthHeader = None
kb.queryCounter = 0
kb.randomPool = {}
kb.redirectChoice = None
kb.reflectiveMechanism = True
kb.reflectiveCounters = {REFLECTIVE_COUNTER.MISS: 0, REFLECTIVE_COUNTER.HIT: 0}
kb.requestCounter = 0
@@ -2142,9 +2144,7 @@ def _setKnowledgeBaseAttributes(flushAll=True):
kb.reduceTests = None
kb.sslSuccess = False
kb.stickyDBMS = False
kb.storeHashesChoice = None
kb.suppressResumeInfo = False
kb.tableExistsChoice = None
kb.tableFrom = None
kb.technique = None
kb.tempDir = None
@@ -2482,7 +2482,17 @@ def _setTorSocksProxySettings():
def _setHttpChunked():
if conf.chunked and conf.data:
_http_client.HTTPConnection._set_content_length = lambda self, a, b: None
if hasattr(_http_client.HTTPConnection, "_set_content_length"):
_http_client.HTTPConnection._set_content_length = lambda self, *args, **kwargs: None
else:
def putheader(self, header, *values):
if header != HTTP_HEADER.CONTENT_LENGTH:
self._putheader(header, *values)
if not hasattr(_http_client.HTTPConnection, "_putheader"):
_http_client.HTTPConnection._putheader = _http_client.HTTPConnection.putheader
_http_client.HTTPConnection.putheader = putheader
def _checkWebSocket():
if conf.url and (conf.url.startswith("ws:/") or conf.url.startswith("wss:/")):
@@ -2539,10 +2549,19 @@ def _basicOptionValidation():
errMsg = "value for option '--first' (firstChar) must be smaller than or equal to value for --last (lastChar) option"
raise SqlmapSyntaxException(errMsg)
if conf.proxyFile and not any((conf.randomAgent, conf.mobile, conf.agent, conf.requestFile)):
warnMsg = "usage of switch '--random-agent' is strongly recommended when "
warnMsg += "using option '--proxy-file'"
logger.warn(warnMsg)
if conf.textOnly and conf.nullConnection:
errMsg = "switch '--text-only' is incompatible with switch '--null-connection'"
raise SqlmapSyntaxException(errMsg)
if conf.base64Parameter and conf.tamper:
errMsg = "option '--base64' is incompatible with option '--tamper'"
raise SqlmapSyntaxException(errMsg)
if conf.eta and conf.verbose > defaults.verbose:
errMsg = "switch '--eta' is incompatible with option '-v'"
raise SqlmapSyntaxException(errMsg)
+2 -72
View File
@@ -5,95 +5,25 @@ Copyright (c) 2006-2021 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
import codecs
import cProfile
import os
from lib.core.common import getSafeExString
from lib.core.data import logger
from lib.core.data import paths
from lib.core.settings import UNICODE_ENCODING
def profile(profileOutputFile=None, dotOutputFile=None, imageOutputFile=None):
def profile(profileOutputFile=None):
"""
This will run the program and present profiling data in a nice looking graph
"""
try:
__import__("gobject")
from thirdparty.gprof2dot import gprof2dot
from thirdparty.xdot import xdot
import gtk
import pydot
except ImportError as ex:
errMsg = "profiling requires third-party libraries ('%s') " % getSafeExString(ex)
errMsg += "(Hint: 'sudo apt install python-pydot python-pyparsing python-profiler graphviz')"
logger.error(errMsg)
return
if profileOutputFile is None:
profileOutputFile = os.path.join(paths.SQLMAP_OUTPUT_PATH, "sqlmap_profile.raw")
if dotOutputFile is None:
dotOutputFile = os.path.join(paths.SQLMAP_OUTPUT_PATH, "sqlmap_profile.dot")
if imageOutputFile is None:
imageOutputFile = os.path.join(paths.SQLMAP_OUTPUT_PATH, "sqlmap_profile.png")
if os.path.exists(profileOutputFile):
os.remove(profileOutputFile)
if os.path.exists(dotOutputFile):
os.remove(dotOutputFile)
if os.path.exists(imageOutputFile):
os.remove(imageOutputFile)
infoMsg = "profiling the execution into file '%s'" % profileOutputFile
logger.info(infoMsg)
# Start sqlmap main function and generate a raw profile file
cProfile.run("start()", profileOutputFile)
infoMsg = "converting profile data into a dot file '%s'" % dotOutputFile
infoMsg = "execution profiled and stored into file '%s' (e.g. 'gprof2dot -f pstats %s | dot -Tpng -o /tmp/sqlmap_profile.png')" % (profileOutputFile, profileOutputFile)
logger.info(infoMsg)
# Create dot file by using extra/gprof2dot/gprof2dot.py
# http://code.google.com/p/jrfonseca/wiki/Gprof2Dot
dotFilePointer = codecs.open(dotOutputFile, 'wt', UNICODE_ENCODING)
parser = gprof2dot.PstatsParser(profileOutputFile)
profile = parser.parse()
profile.prune(0.5 / 100.0, 0.1 / 100.0)
dot = gprof2dot.DotWriter(dotFilePointer)
dot.graph(profile, gprof2dot.TEMPERATURE_COLORMAP)
dotFilePointer.close()
infoMsg = "converting dot file into a graph image '%s'" % imageOutputFile
logger.info(infoMsg)
# Create graph image (png) by using pydot (python-pydot)
# http://code.google.com/p/pydot/
pydotGraph = pydot.graph_from_dot_file(dotOutputFile)
# Reference: http://stackoverflow.com/questions/38176472/graph-write-pdfiris-pdf-attributeerror-list-object-has-no-attribute-writ
if isinstance(pydotGraph, list):
pydotGraph = pydotGraph[0]
try:
pydotGraph.write_png(imageOutputFile)
except OSError:
errMsg = "profiling requires graphviz installed "
errMsg += "(Hint: 'sudo apt install graphviz')"
logger.error(errMsg)
else:
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()
+30 -13
View File
@@ -11,6 +11,7 @@ import random
import re
import string
import sys
import time
from lib.core.enums import DBMS
from lib.core.enums import DBMS_DIRECTORY_NAME
@@ -18,7 +19,7 @@ from lib.core.enums import OS
from thirdparty.six import unichr as _unichr
# sqlmap version (<major>.<minor>.<month>.<monthly commit>)
VERSION = "1.5"
VERSION = "1.5.5.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)
@@ -125,6 +126,9 @@ MAX_MURPHY_SLEEP_TIME = 3
# Regular expression used for extracting results from Google search
GOOGLE_REGEX = r"webcache\.googleusercontent\.com/search\?q=cache:[^:]+:([^+]+)\+&amp;cd=|url\?\w+=((?![^>]+webcache\.googleusercontent\.com)http[^>]+)&(sa=U|rct=j)"
# Google Search consent cookie
GOOGLE_CONSENT_COOKIE = "CONSENT=YES+shp.gws-%s-0-RC1.%s+FX+740" % (time.strftime("%Y%m%d"), "".join(random.sample(string.ascii_lowercase, 2)))
# Regular expression used for extracting results from DuckDuckGo search
DUCKDUCKGO_REGEX = r'<a class="result__url" href="(htt[^"]+)'
@@ -282,20 +286,22 @@ CUBRID_SYSTEM_DBS = ("DBA",)
CACHE_SYSTEM_DBS = ("%Dictionary", "INFORMATION_SCHEMA", "%SYS")
EXTREMEDB_SYSTEM_DBS = ("",)
FRONTBASE_SYSTEM_DBS = ("DEFINITION_SCHEMA", "INFORMATION_SCHEMA")
RAIMA_SYSTEM_DBS = ("",)
VIRTUOSO_SYSTEM_DBS = ("",)
# Note: (<regular>) + (<forks>)
MSSQL_ALIASES = ("microsoft sql server", "mssqlserver", "mssql", "ms")
MYSQL_ALIASES = ("mysql", "my") + ("mariadb", "maria", "memsql", "tidb", "percona")
PGSQL_ALIASES = ("postgresql", "postgres", "pgsql", "psql", "pg") + ("cockroach", "cockroachdb", "redshift", "greenplum", "yellowbrick", "enterprisedb", "aurora")
MYSQL_ALIASES = ("mysql", "my") + ("mariadb", "maria", "memsql", "tidb", "percona", "drizzle")
PGSQL_ALIASES = ("postgresql", "postgres", "pgsql", "psql", "pg") + ("cockroach", "cockroachdb", "amazon redshift", "redshift", "greenplum", "yellowbrick", "enterprisedb", "yugabyte", "yugabytedb")
ORACLE_ALIASES = ("oracle", "orcl", "ora", "or")
SQLITE_ALIASES = ("sqlite", "sqlite3")
ACCESS_ALIASES = ("msaccess", "access", "jet", "microsoft access")
ACCESS_ALIASES = ("microsoft access", "msaccess", "access", "jet")
FIREBIRD_ALIASES = ("firebird", "mozilla firebird", "interbase", "ibase", "fb")
MAXDB_ALIASES = ("max", "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",)
H2_ALIASES = ("h2",) + ("ignite", "apache ignite")
INFORMIX_ALIASES = ("informix", "ibm informix", "ibminformix")
MONETDB_ALIASES = ("monet", "monetdb",)
DERBY_ALIASES = ("derby", "apache derby",)
@@ -306,16 +312,18 @@ ALTIBASE_ALIASES = ("altibase",)
MIMERSQL_ALIASES = ("mimersql", "mimer")
CRATEDB_ALIASES = ("cratedb", "crate")
CUBRID_ALIASES = ("cubrid",)
CACHE_ALIASES = ("intersystems cache", "cachedb", "cache")
CACHE_ALIASES = ("intersystems cache", "cachedb", "cache", "iris")
EXTREMEDB_ALIASES = ("extremedb", "extreme")
FRONTBASE_ALIASES = ("frontbase",)
RAIMA_ALIASES = ("raima database manager", "raima", "raimadb", "raimadm", "rdm", "rds", "velocis")
VIRTUOSO_ALIASES = ("virtuoso", "openlink virtuoso")
DBMS_DIRECTORY_DICT = dict((getattr(DBMS, _), getattr(DBMS_DIRECTORY_NAME, _)) for _ in dir(DBMS) if not _.startswith("_"))
SUPPORTED_DBMS = set(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 + MONETDB_ALIASES + DERBY_ALIASES + VERTICA_ALIASES + MCKOI_ALIASES + PRESTO_ALIASES + ALTIBASE_ALIASES + MIMERSQL_ALIASES + CRATEDB_ALIASES + CUBRID_ALIASES + CACHE_ALIASES + EXTREMEDB_ALIASES)
SUPPORTED_DBMS = set(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 + MONETDB_ALIASES + DERBY_ALIASES + VERTICA_ALIASES + MCKOI_ALIASES + PRESTO_ALIASES + ALTIBASE_ALIASES + MIMERSQL_ALIASES + CRATEDB_ALIASES + CUBRID_ALIASES + CACHE_ALIASES + EXTREMEDB_ALIASES + RAIMA_ALIASES + VIRTUOSO_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.H2, H2_ALIASES), (DBMS.INFORMIX, INFORMIX_ALIASES), (DBMS.MONETDB, MONETDB_ALIASES), (DBMS.DERBY, DERBY_ALIASES), (DBMS.VERTICA, VERTICA_ALIASES), (DBMS.MCKOI, MCKOI_ALIASES), (DBMS.PRESTO, PRESTO_ALIASES), (DBMS.ALTIBASE, ALTIBASE_ALIASES), (DBMS.MIMERSQL, MIMERSQL_ALIASES), (DBMS.CRATEDB, CRATEDB_ALIASES), (DBMS.CUBRID, CUBRID_ALIASES), (DBMS.CACHE, CACHE_ALIASES), (DBMS.EXTREMEDB, EXTREMEDB_ALIASES), (DBMS.FRONTBASE, FRONTBASE_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), (DBMS.MONETDB, MONETDB_ALIASES), (DBMS.DERBY, DERBY_ALIASES), (DBMS.VERTICA, VERTICA_ALIASES), (DBMS.MCKOI, MCKOI_ALIASES), (DBMS.PRESTO, PRESTO_ALIASES), (DBMS.ALTIBASE, ALTIBASE_ALIASES), (DBMS.MIMERSQL, MIMERSQL_ALIASES), (DBMS.CRATEDB, CRATEDB_ALIASES), (DBMS.CUBRID, CUBRID_ALIASES), (DBMS.CACHE, CACHE_ALIASES), (DBMS.EXTREMEDB, EXTREMEDB_ALIASES), (DBMS.FRONTBASE, FRONTBASE_ALIASES), (DBMS.RAIMA, RAIMA_ALIASES), (DBMS.VIRTUOSO, VIRTUOSO_ALIASES))
USER_AGENT_ALIASES = ("ua", "useragent", "user-agent")
REFERER_ALIASES = ("ref", "referer", "referrer")
@@ -397,14 +405,14 @@ FILE_PATH_REGEXES = (r"<b>(?P<result>[^<>]+?)</b> on line \d+", r"\bin (?P<resul
# 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>[^<]+)",
r"(?m)^\s*(fatal|error|warning|exception):?\s*(?P<result>[^\n]+?)$",
r"<b>[^<]{0,100}(fatal|error|warning|exception)[^<]*</b>:?\s*(?P<result>[^<]+)",
r"(?m)^\s{0,100}(fatal|error|warning|exception):?\s*(?P<result>[^\n]+?)$",
r"(sql|dbc)[^>'\"]{0,32}(fatal|error|warning|exception)(</b>)?:\s*(?P<result>[^<>]+)",
r"(?P<result>[^\n>]*SQL Syntax[^\n<]+)",
r"(?P<result>[^\n>]{0,100}SQL Syntax[^\n<]+)",
r"(?s)<li>Error Type:<br>(?P<result>.+?)</li>",
r"CDbCommand (?P<result>[^<>\n]*SQL[^<>\n]+)",
r"error '[0-9a-f]{8}'((<[^>]+>)|\s)+(?P<result>[^<>]+)",
r"\[[^\n\]]+(ODBC|JDBC)[^\n\]]+\](\[[^\]]+\])?(?P<result>[^\n]+(in query expression|\(SQL| at /[^ ]+pdo)[^\n<]+)",
r"\[[^\n\]]{1,100}(ODBC|JDBC)[^\n\]]+\](\[[^\]]+\])?(?P<result>[^\n]+(in query expression|\(SQL| at /[^ ]+pdo)[^\n<]+)",
r"(?P<result>query error: SELECT[^<>]+)"
)
@@ -490,7 +498,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"[^\n]{1,100}"
REFLECTED_REPLACEMENT_REGEX = r"[^\n]{1,168}"
# Maximum time (in seconds) spent per reflective value(s) replacement
REFLECTED_REPLACEMENT_TIMEOUT = 3
@@ -501,6 +509,9 @@ REFLECTED_MAX_REGEX_PARTS = 10
# Chars which can be used as a failsafe values in case of too long URL encoding value
URLENCODE_FAILSAFE_CHARS = "()|,"
# Factor used for yuge page multiplication
YUGE_FACTOR = 1000
# Maximum length of URL encoded value after which failsafe procedure takes away
URLENCODE_CHAR_LIMIT = 2000
@@ -757,6 +768,9 @@ 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
# Page size threshold used in heuristic checks (e.g. getHeuristicCharEncoding(), identYwaf, htmlParser, etc.)
HEURISTIC_PAGE_SIZE_THRESHOLD = 64 * 1024
# Maximum (multi-threaded) length of entry in bisection algorithm
MAX_BISECTION_LENGTH = 50 * 1024 * 1024
@@ -808,6 +822,9 @@ RESTAPI_DEFAULT_ADDRESS = "127.0.0.1"
# Default REST-JSON API server listen port
RESTAPI_DEFAULT_PORT = 8775
# Unsupported options by REST-JSON API server
RESTAPI_UNSUPPORTED_OPTIONS = ("sqlShell", "wizard")
# Use "Supplementary Private Use Area-A"
INVALID_UNICODE_PRIVATE_AREA = False
+4 -1
View File
@@ -659,7 +659,7 @@ def _createTargetDirs():
try:
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(getUnicode(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))
if conf.data:
@@ -672,6 +672,9 @@ def _createTargetDirs():
errMsg += "to write to the output directory '%s' (%s)" % (paths.SQLMAP_OUTPUT_PATH, getSafeExString(ex))
raise SqlmapMissingPrivileges(errMsg)
except UnicodeError as ex:
warnMsg = "something went wrong while saving target data ('%s')" % getSafeExString(ex)
logger.warn(warnMsg)
_createDumpDir()
_createFilesDir()
+34 -120
View File
@@ -39,29 +39,33 @@ def vulnTest():
TESTS = (
("-h", ("to see full list of options run with '-hh'",)),
("--dependencies", ("sqlmap requires", "third-party library")),
("-u <url> --flush-session --wizard", ("Please choose:", "back-end DBMS: SQLite", "current user is DBA: True", "banner: '3.")),
(u"-c <config> --flush-session --roles --statements --hostname --privileges --sql-query=\"SELECT '\u0161u\u0107uraj'\" --technique=U", (u": '\u0161u\u0107uraj'", "on SQLite it is not possible")),
("--dependencies --deprecations", ("sqlmap requires", "third-party library", "~DeprecationWarning:")),
("-u <url> --data='reflect=1' --flush-session --wizard --disable-coloring", ("Please choose:", "back-end DBMS: SQLite", "current user is DBA: True", "banner: '3.")),
("-u <url> --data='code=1' --code=200 --technique=B --banner --no-cast --flush-session", ("back-end DBMS: SQLite", "banner: '3.", "~COALESCE(CAST(")),
(u"-c <config> --flush-session --output-dir=\"<tmpdir>\" --smart --roles --statements --hostname --privileges --sql-query=\"SELECT '\u0161u\u0107uraj'\" --technique=U", (u": '\u0161u\u0107uraj'", "on SQLite it is not possible", "as the output directory")),
(u"-u <url> --flush-session --sql-query=\"SELECT '\u0161u\u0107uraj'\" --technique=B --no-escape --string=luther --unstable", (u": '\u0161u\u0107uraj'",)),
("-m <multiple> --flush-session --technique=B --banner", ("URL 3:", "back-end DBMS: SQLite", "banner: '3.")),
("--dummy", ("all tested parameters do not appear to be injectable", "does not seem to be injectable", "there is not at least one", "~might be injectable")),
("-u '<url>&id2=1' -p id2 -v 5 --flush-session --level=5 --test-filter='AND boolean-based blind - WHERE or HAVING clause (MySQL comment)'", ("~1AND",)),
("-u '<url>&id2=1' -p id2 -v 5 --flush-session --level=5 --text-only --test-filter='AND boolean-based blind - WHERE or HAVING clause (MySQL comment)'", ("~1AND",)),
("--list-tampers", ("between", "MySQL", "xforwardedfor")),
("-r <request> --flush-session -v 5 --test-skip='heavy' --save=<tmp>", ("CloudFlare", "possible DBMS: 'SQLite'", "User-agent: foobar", "~Type: time-based blind")),
("-r <request> --flush-session -v 5 --test-skip='heavy' --save=<config>", ("CloudFlare", "web application technology: Express", "possible DBMS: 'SQLite'", "User-agent: foobar", "~Type: time-based blind", "saved command line options to the configuration file")),
("-c <config>", ("CloudFlare", "possible DBMS: 'SQLite'", "User-agent: foobar", "~Type: time-based blind")),
("<piped> -r <request> -l <log> --flush-session --banner --technique=B", ("banner: '3.", "STDIN")),
("-l <log> --flush-session --keep-alive --skip-waf -v 5 --technique=U --union-from=users --banner --parse-errors", ("banner: '3.", "ORDER BY term out of range", "~xp_cmdshell", "Connection: keep-alive")),
("-l <log> --flush-session --keep-alive --skip-waf -vvvvv --technique=U --union-from=users --banner --parse-errors", ("banner: '3.", "ORDER BY term out of range", "~xp_cmdshell", "Connection: keep-alive")),
("-l <log> --offline --banner -v 5", ("banner: '3.", "~[TRAFFIC OUT]")),
("-u <base> --flush-session --data='id=1&_=Eewef6oh' --chunked --randomize=_ --random-agent --banner", ("fetched random HTTP User-Agent header value", "Parameter: id (POST)", "Type: boolean-based blind", "Type: time-based blind", "Type: UNION query", "banner: '3.")),
("-u <base64> -p id --base64=id --data='base64=true' --flush-session --banner --technique=B", ("banner: '3.",)),
("-u <base64> -p id --base64=id --data='base64=true' --flush-session --tables --technique=U", (" users ",)),
("-u <url> --flush-session --banner --technique=B --not-string 'no results'", ("banner: '3.",)),
("-u <url> --flush-session --banner --technique=B --first=1 --last=2", ("banner: '3.'",)),
("-u <url> --flush-session --banner --technique=B --disable-precon --not-string 'no results'", ("banner: '3.",)),
("-u <url> --flush-session --encoding=gbk --banner --technique=B --first=1 --last=2", ("banner: '3.'",)),
("-u <url> --flush-session --encoding=ascii --forms --crawl=2 --threads=2 --banner", ("total of 2 targets", "might be injectable", "Type: UNION query", "banner: '3.")),
("-u <url> --flush-session --data='{\"id\": 1}' --banner", ("might be injectable", "3 columns", "Payload: {\"id\"", "Type: boolean-based blind", "Type: time-based blind", "Type: UNION query", "banner: '3.")),
("-u <url> --flush-session -H 'Foo: Bar' -H 'Sna: Fu' --data='<root><param name=\"id\" value=\"1*\"/></root>' --union-char=1 --mobile --answers='smartphone=3' --banner --smart -v 5", ("might be injectable", "Payload: <root><param name=\"id\" value=\"1", "Type: boolean-based blind", "Type: time-based blind", "Type: UNION query", "banner: '3.", "Nexus", "Sna: Fu", "Foo: Bar")),
("-u <url> --flush-session --method=PUT --data='a=1&b=2&c=3&id=1' --skip-static --har=<tmp> --dump -T users --start=1 --stop=2", ("might be injectable", "Parameter: id (PUT)", "Type: boolean-based blind", "Type: time-based blind", "Type: UNION query", "2 entries")),
("-u <url> --flush-session -H 'id: 1*' --tables -t <tmp>", ("might be injectable", "Parameter: id #1* ((custom) HEADER)", "Type: boolean-based blind", "Type: time-based blind", "Type: UNION query", " users ")),
("-u <base> --flush-session --data='{\"id\": 1}' --banner", ("might be injectable", "3 columns", "Payload: {\"id\"", "Type: boolean-based blind", "Type: time-based blind", "Type: UNION query", "banner: '3.")),
("-u <base> --flush-session -H 'Foo: Bar' -H 'Sna: Fu' --data='<root><param name=\"id\" value=\"1*\"/></root>' --union-char=1 --mobile --answers='smartphone=3' --banner --smart -v 5", ("might be injectable", "Payload: <root><param name=\"id\" value=\"1", "Type: boolean-based blind", "Type: time-based blind", "Type: UNION query", "banner: '3.", "Nexus", "Sna: Fu", "Foo: Bar")),
("-u <base> --flush-session --method=PUT --data='a=1;id=1;b=2' --param-del=';' --skip-static --har=<tmpfile> --dump -T users --start=1 --stop=2", ("might be injectable", "Parameter: id (PUT)", "Type: boolean-based blind", "Type: time-based blind", "Type: UNION query", "2 entries")),
("-u <url> --flush-session -H 'id: 1*' --tables -t <tmpfile>", ("might be injectable", "Parameter: id #1* ((custom) HEADER)", "Type: boolean-based blind", "Type: time-based blind", "Type: UNION query", " users ")),
("-u <url> --flush-session --banner --invalid-logical --technique=B --predict-output --test-filter='OR boolean' --tamper=space2dash", ("banner: '3.", " LIKE ")),
("-u <url> --flush-session --cookie=\"PHPSESSID=d41d8cd98f00b204e9800998ecf8427e; id=1*; id2=2\" --tables --union-cols=3", ("might be injectable", "Cookie #1* ((custom) HEADER)", "Type: boolean-based blind", "Type: time-based blind", "Type: UNION query", " users ")),
("-u <url> --flush-session --null-connection --technique=B --tamper=between,randomcase --banner", ("NULL connection is supported with HEAD method", "banner: '3.")),
("-u <url> --flush-session --null-connection --technique=B --tamper=between,randomcase --banner --count -T users", ("NULL connection is supported with HEAD method", "banner: '3.", "users | 5")),
("-u <url> --flush-session --parse-errors --test-filter=\"subquery\" --eval=\"import hashlib; id2=2; id3=hashlib.md5(id.encode()).hexdigest()\" --referer=\"localhost\"", ("might be injectable", ": syntax error", "back-end DBMS: SQLite", "WHERE or HAVING clause (subquery")),
("-u <url> --banner --schema --dump -T users --binary-fields=surname --where \"id>3\"", ("banner: '3.", "INTEGER", "TEXT", "id", "name", "surname", "2 entries", "6E616D6569736E756C6C")),
("-u <url> --technique=U --fresh-queries --force-partial --dump -T users --dump-format=HTML --answers=\"crack=n\" -v 3", ("performed 6 queries", "nameisnull", "~using default dictionary", "dumped to HTML file")),
@@ -114,30 +118,37 @@ def vulnTest():
handle, log = tempfile.mkstemp(suffix=".log")
os.close(handle)
handle, multiple = tempfile.mkstemp(suffix=".lst")
os.close(handle)
content = "POST / HTTP/1.0\nUser-agent: foobar\nHost: %s:%s\n\nid=1\n" % (address, port)
open(request, "w+").write(content)
open(log, "w+").write('<port>%d</port><request base64="true"><![CDATA[%s]]></request>' % (port, encodeBase64(content, binary=False)))
url = "http://%s:%d/?id=1" % (address, port)
base = "http://%s:%d/" % (address, port)
url = "%s?id=1" % base
direct = "sqlite3://%s" % database
tmpdir = tempfile.mkdtemp()
content = open(os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "sqlmap.conf"))).read().replace("url =", "url = %s" % url)
open(config, "w+").write(content)
open(multiple, "w+").write("%s?%s=%d\n%s?%s=%d\n%s&%s=1" % (base, randomStr(), randomInt(), base, randomStr(), randomInt(), url, randomStr()))
for options, checks in TESTS:
status = '%d/%d (%d%%) ' % (count, len(TESTS), round(100.0 * count / len(TESTS)))
dataToStdout("\r[%s] [INFO] complete: %s" % (time.strftime("%X"), status))
for tag, value in (("<url>", url), ("<direct>", direct), ("<request>", request), ("<log>", log), ("<config>", config), ("<base64>", url.replace("id=1", "id=MZ=%3d"))):
for tag, value in (("<url>", url), ("<base>", base), ("<direct>", direct), ("<tmpdir>", tmpdir), ("<request>", request), ("<log>", log), ("<multiple>", multiple), ("<config>", config), ("<base64>", url.replace("id=1", "id=MZ=%3d"))):
options = options.replace(tag, value)
cmd = "%s %s %s --batch --non-interactive" % (sys.executable, os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "sqlmap.py")), options)
cmd = "%s \"%s\" %s --batch --non-interactive --debug" % (sys.executable, os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "sqlmap.py")), options)
if "<tmp>" in cmd:
if "<tmpfile>" in cmd:
handle, tmp = tempfile.mkstemp()
os.close(handle)
cmd = cmd.replace("<tmp>", tmp)
cmd = cmd.replace("<tmpfile>", tmp)
if "<piped>" in cmd:
cmd = re.sub(r"<piped>\s*", "", cmd)
@@ -160,107 +171,6 @@ def vulnTest():
return retVal
def bedTest():
"""
Runs the testing against 'testbed'
"""
TESTS = (
# MaxDB
("-u 'http://testbed/maxdb/get_int.php?id=1' --flush-session --technique=B --is-dba --threads=4 --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("Kernel____7.9.10___Build_003-123-265-343", "Database: DBADMIN", "Table: TESTUSERS", "5 entries", "ID", "NAME", "SURNAME", "luther", "blisset", "NULL", "Payload: id=1 AND ", "it looks like the back-end DBMS is 'SAP MaxDB'", "the back-end DBMS is SAP MaxDB", "current user is DBA: True", ": 'foobar'")),
("-u 'http://testbed/maxdb/get_int.php?id=1' --flush-session --technique=U --is-dba --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("Kernel____7.9.10___Build_003-123-265-343", "Database: DBADMIN", "Table: TESTUSERS", "5 entries", "ID", "NAME", "SURNAME", "luther", "blisset", "NULL", "Title: Generic UNION query (NULL) - 3 columns", "the back-end DBMS is SAP MaxDB", "appears to have 3 columns", "current user is DBA: True", ": 'foobar'")),
("-u 'http://testbed/maxdb/get_int.php?id=1' --flush-session --technique=U --hex --banner --current-user --current-db --search -C surname --answers='dump=n'", ("Kernel____7.9.10___Build_003-123-265-343", "current database (equivalent to owner on SAP MaxDB): 'SYS'", "current user: 'DBADMIN'", "[1 column]", "| SURNAME | VARCHAR |")),
# Informix
("-u 'http://testbed/informix/get_int.php?id=1' --flush-session --technique=B --is-dba --threads=4 --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("retrieved: 47", "IBM Informix Dynamic Server Version 14.10.FC2DE", "Database: testdb", "Table: users", "5 entries", "id", "name", "surname", "luther", "blisset", "NULL", "Payload: id=1 AND ", "back-end DBMS could be 'Informix'", "the back-end DBMS is Informix", "current user is DBA: True", ": 'foobar'")),
("-u 'http://testbed/informix/get_int.php?id=1' --flush-session --hex --banner --current-user --current-db --search -C surname --answers='dump=n'", ("IBM Informix Dynamic Server Version 14.10.FC2DE", "current database: 'testdb'", "current user: 'testuser'", "[1 column]", "| surname | varchar |")),
# Altibase
("-u 'http://testbed/altibase/get_int.php?id=1' --flush-session --technique=B --is-dba --threads=4 --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("x86_64-unknown-linux-gnu", "Database: SYS", "Table: TESTUSERS", "5 entries", "ID", "NAME", "SURNAME", "luther", "blisset", "NULL", "Payload: id=1 AND ", "back-end DBMS could be 'Altibase'", "the back-end DBMS is Altibase", "current user is DBA: True", ": 'foobar'")),
("-u 'http://testbed/altibase/get_int.php?id=1' --flush-session --technique=U --is-dba --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("x86_64-unknown-linux-gnu", "Database: SYS", "Table: TESTUSERS", "5 entries", "ID", "NAME", "SURNAME", "luther", "blisset", "NULL", "Title: Generic UNION query (NULL) - 3 columns", "the back-end DBMS is Altibase", "appears to have 3 columns", "current user is DBA: True", ": 'foobar'")),
("-u 'http://testbed/altibase/get_int.php?id=1' --flush-session --technique=U --hex --banner --current-user --current-db --search -C surname --answers='dump=n'", ("x86_64-unknown-linux-gnu", "current database (equivalent to owner on Altibase): 'SYS'", "current user: 'SYS'", "[1 column]", "| SURNAME | VARCHAR |")),
# CockroachDB
("-u 'http://testbed/cockroachdb/get_int.php?id=1' --flush-session --technique=B --is-dba --threads=4 --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("x86_64-unknown-linux-gnu", "CockroachDB fork", "Database: public", "Table: testusers", "5 entries", "id", "name", "surname", "luther", "blisset", "NULL", "Payload: id=1 AND ", "back-end DBMS could be 'PostgreSQL'", "the back-end DBMS is PostgreSQL", "current user is DBA: True", ": 'foobar'")),
("-u 'http://testbed/cockroachdb/get_int.php?id=1' --flush-session --technique=U --is-dba --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("x86_64-unknown-linux-gnu", "CockroachDB fork", "Database: public", "Table: testusers", "5 entries", "id", "name", "surname", "luther", "blisset", "NULL", "Title: Generic UNION query (NULL) - 3 columns", "the back-end DBMS is PostgreSQL", "appears to have 3 columns", "current user is DBA: True", ": 'foobar'")),
("-u 'http://testbed/cockroachdb/get_int.php?id=1' --flush-session --technique=E --is-dba --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("x86_64-unknown-linux-gnu", "CockroachDB fork", "Database: public", "Table: testusers", "5 entries", "id", "name", "surname", "luther", "blisset", "NULL", "Title: PostgreSQL AND error-based", "the back-end DBMS is PostgreSQL", "current user is DBA: True", ": 'foobar'")),
("-u 'http://testbed/cockroachdb/get_int.php?id=1' --flush-session --hex --banner --current-user --current-db --search -C surname --answers='dump=n'", ("Title: AND boolean-based blind", "Title: PostgreSQL AND error-based", "Title: PostgreSQL > 8.1 stacked queries", "Title: PostgreSQL > 8.1 AND time-based blind", "Title: Generic UNION query (NULL) - 3 columns", "x86_64-unknown-linux-gnu", "current database (equivalent to schema on PostgreSQL): 'public'", "current user: 'root'", "[1 column]", "| surname | varchar |")),
# CrateDB
("-u 'http://testbed/cratedb/get_int.php?id=1' --flush-session --technique=B --is-dba --threads=4 --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("4.0.10", "Database: doc", "Table: testusers", "5 entries", "id", "name", "surname", "luther", "blisset", "NULL", "Payload: id=1 AND ", "back-end DBMS could be 'CrateDB'", "the back-end DBMS is CrateDB", "current user is DBA: True", ": 'foobar'")),
("-u 'http://testbed/cratedb/get_int.php?id=1' --flush-session --technique=B --hex --banner --current-user --current-db --search -C surname --answers='dump=n'", ("4.0.10", "current database (equivalent to schema on CrateDB): 'doc'", "current user: 'crate'", "[1 column]", "| surname |")),
# Drizzle
("-u 'http://testbed/drizzle/get_int.php?id=1' --flush-session --technique=B --is-dba --threads=4 --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("7.1.36-stable", "Drizzle fork", "Database: testdb", "Table: testusers", "5 entries", "id", "name", "surname", "luther", "blisset", "NULL", "Payload: id=1 AND ", "it looks like the back-end DBMS is 'MySQL'", "the back-end DBMS is MySQL", "current user is DBA: True", ": 'foobar'")),
("-u 'http://testbed/drizzle/get_int.php?id=1' --flush-session --technique=U --is-dba --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("7.1.36-stable", "Drizzle fork", "Database: testdb", "Table: testusers", "5 entries", "id", "name", "surname", "luther", "blisset", "NULL", "Title: Generic UNION query (NULL) - 3 columns", "the back-end DBMS is MySQL", "appears to have 3 columns", "current user is DBA: True", ": 'foobar'")),
("-u 'http://testbed/drizzle/get_int.php?id=1' --flush-session --hex --banner --current-user --current-db --search -C surname --answers='dump=n'", ("Title: AND boolean-based blind", "Title: MySQL >= 5.0.12 AND time-based blind", "Title: Generic UNION query (NULL) - 3 columns", "7.1.36-stable", "current database: 'testdb'", "current user: 'root'", "[1 column]", "| surname | VARCHAR |")),
# Firebird
("-u 'http://testbed/firebird/get_int.php?id=1' --flush-session --technique=B --is-dba --threads=4 --dump --banner --sql-query=\"SELECT 'foobar'\"", ("banner: '2.5", "Table: USERS", "5 entries", "ID", "NAME", "SURNAME", "luther", "blisset", "NULL", "Payload: id=1 AND ", "possible DBMS: 'Firebird'", "the back-end DBMS is Firebird", "current user is DBA: True", ": 'foobar'")),
("-u 'http://testbed/firebird/get_int.php?id=1' --flush-session --technique=U --is-dba --dump --banner --sql-query=\"SELECT 'foobar'\"", ("banner: '2.5", "Table: USERS", "5 entries", "ID", "NAME", "SURNAME", "luther", "blisset", "NULL", "Title: Generic UNION query (NULL) - 3 columns", "the back-end DBMS is Firebird", "appears to have 3 columns", "current user is DBA: True", ": 'foobar'")),
("-u 'http://testbed/firebird/get_int.php?id=1' --flush-session --technique=U --hex --banner --current-user --search -C surname --answers='dump=n'", ("banner: '2.5", "current user: 'SYSDBA'", "[1 column]", "| SURNAME | VARCHAR |")),
# H2
("-u 'http://testbed/h2/get_int.php?id=1' --flush-session --technique=B --is-dba --threads=4 --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("1.4.192", "Database: PUBLIC", "Table: TESTUSERS", "5 entries", "ID", "NAME", "SURNAME", "luther", "blisset", "NULL", "Payload: id=1 AND ", "back-end DBMS could be 'H2'", "the back-end DBMS is H2", "current user is DBA: True", ": 'foobar'")),
("-u 'http://testbed/h2/get_int.php?id=1' --flush-session --technique=U --is-dba --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("1.4.192", "Database: PUBLIC", "Table: TESTUSERS", "5 entries", "ID", "NAME", "SURNAME", "luther", "blisset", "NULL", "Title: Generic UNION query (NULL) - 3 columns", "the back-end DBMS is H2", "appears to have 3 columns", "current user is DBA: True", ": 'foobar'")),
("-u 'http://testbed/h2/get_int.php?id=1' --flush-session --hex --banner --current-user --current-db --search -C surname --answers='dump=n'", ("Title: AND boolean-based blind", "Title: Generic inline queries", "Title: Generic UNION query (NULL) - 3 columns", "1.4.192", "current database (equivalent to schema on H2): 'PUBLIC'", "current user: 'SA'", "[1 column]", "| SURNAME | VARCHAR |")),
# HSQLDB
("-u 'http://testbed/hsqldb/get_int.php?id=1' --flush-session --technique=B --is-dba --threads=4 --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("2.3.4", "Database: PUBLIC", "Table: TESTUSERS", "5 entries", "ID", "NAME", "SURNAME", "luther", "blisset", "NULL", "Payload: id=1 AND ", "it looks like the back-end DBMS is 'HSQLDB'", "the back-end DBMS is HSQLDB", "current user is DBA: True", ": 'foobar'")),
("-u 'http://testbed/hsqldb/get_int.php?id=1' --flush-session --technique=U --is-dba --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("2.3.4", "Database: PUBLIC", "Table: TESTUSERS", "5 entries", "ID", "NAME", "SURNAME", "luther", "blisset", "NULL", "Title: Generic UNION query (NULL) - 3 columns", "the back-end DBMS is HSQLDB", "appears to have 3 columns", "current user is DBA: True", ": 'foobar'")),
("-u 'http://testbed/hsqldb/get_int.php?id=1' --flush-session --hex --banner --current-user --current-db --search -C surname --answers='dump=n'", ("Title: AND boolean-based blind", "Title: HSQLDB > 2.0 AND time-based blind (heavy query)", "Title: Generic UNION query (NULL) - 3 columns", "2.3.4", "current database (equivalent to schema on HSQLDB): 'PUBLIC'", "current user: 'SA'", "[1 column]", "| SURNAME | VARCHAR |")),
# IBM DB2
("-u 'http://testbed/db2/get_int.php?id=1' --flush-session --technique=B --is-dba --threads=4 --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("banner: 'DB2 v", "Database: DB2INST1", "Table: USERS", "5 entries", "ID", "NAME", "SURNAME", "luther", "blisset", "NULL", "Payload: id=1 AND ", "it looks like the back-end DBMS is 'IBM DB2'", "the back-end DBMS is IBM DB2", "current user is DBA: True", ": 'foobar'")),
("-u 'http://testbed/db2/get_int.php?id=1' --flush-session --technique=U --is-dba --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("banner: 'DB2 v", "Database: DB2INST1", "Table: USERS", "5 entries", "ID", "NAME", "SURNAME", "luther", "blisset", "NULL", "Title: Generic UNION query (NULL) - 3 columns", "the back-end DBMS is IBM DB2", "appears to have 3 columns", "current user is DBA: True", ": 'foobar'")),
("-u 'http://testbed/db2/get_int.php?id=1' --flush-session --technique=U --hex --banner --current-user --current-db --search -C surname --answers='dump=n'", ("banner: 'DB2 v", "current database (equivalent to owner on IBM DB2): 'DB2INST1'", "current user: 'DB2INST1'", "[1 column]", "| SURNAME | VARCHAR(1000) |")),
# MariaDB
("-u 'http://testbed/mariadb/get_int.php?id=1' --flush-session --technique=B --is-dba --threads=4 --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("10.4.12-MariaDB-1:10.4.12+maria~bionic", "MariaDB fork", "Database: testdb", "Table: testusers", "5 entries", "id", "name", "surname", "luther", "blisset", "NULL", "Payload: id=1 AND ", "it looks like the back-end DBMS is 'MySQL'", "the back-end DBMS is MySQL", "current user is DBA: True", ": 'foobar'")),
("-u 'http://testbed/mariadb/get_int.php?id=1' --flush-session --technique=U --is-dba --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("10.4.12-MariaDB-1:10.4.12+maria~bionic", "MariaDB fork", "Database: testdb", "Table: testusers", "5 entries", "id", "name", "surname", "luther", "blisset", "NULL", "Title: Generic UNION query (NULL) - 3 columns", "the back-end DBMS is MySQL", "appears to have 3 columns", "current user is DBA: True", ": 'foobar'")),
("-u 'http://testbed/mariadb/get_int.php?id=1' --flush-session --technique=E --is-dba --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("10.4.12-MariaDB-1:10.4.12+maria~bionic", "MariaDB fork", "Database: testdb", "Table: testusers", "5 entries", "id", "name", "surname", "luther", "blisset", "NULL", "Title: MySQL >= 5.0 AND error-based", "the back-end DBMS is MySQL", "current user is DBA: True", ": 'foobar'")),
("-u 'http://testbed/mariadb/get_int.php?id=1' --flush-session --hex --banner --current-user --current-db --search -C surname --answers='dump=n'", ("Title: AND boolean-based blind", "Title: MySQL >= 5.0 AND error-based", "Title: MySQL >= 5.0.12 AND time-based blind", "Title: Generic UNION query (NULL) - 3 columns", "10.4.12-MariaDB-1:10.4.12+maria~bionic", "current database: 'testdb'", "current user: 'root@%'", "[1 column]", "| surname | varchar(1000) |")),
# MySQL
("-u 'http://testbed/mysql/get_int.php?id=1' --flush-session --technique=B --is-dba --threads=4 --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("8.0.19", "Database: testdb", "Table: testusers", "5 entries", "id", "name", "surname", "luther", "blisset", "NULL", "Payload: id=1 AND ", "it looks like the back-end DBMS is 'MySQL'", "the back-end DBMS is MySQL", "current user is DBA: True", ": 'foobar'")),
("-u 'http://testbed/mysql/get_int.php?id=1' --flush-session --technique=U --is-dba --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("8.0.19", "Database: testdb", "Table: testusers", "5 entries", "id", "name", "surname", "luther", "blisset", "NULL", "Title: Generic UNION query (NULL) - 3 columns", "the back-end DBMS is MySQL", "appears to have 3 columns", "current user is DBA: True", ": 'foobar'")),
("-u 'http://testbed/mysql/get_int.php?id=1' --flush-session --technique=E --is-dba --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("8.0.19", "Database: testdb", "Table: testusers", "5 entries", "id", "name", "surname", "luther", "blisset", "NULL", "Title: MySQL >= 5.0 AND error-based", "the back-end DBMS is MySQL", "current user is DBA: True", ": 'foobar'")),
("-u 'http://testbed/mysql/get_int.php?id=1' --flush-session --hex --banner --current-user --current-db --search -C surname --answers='dump=n'", ("Title: AND boolean-based blind", "Title: MySQL >= 5.1 AND error-based", "Title: MySQL >= 5.0.12 AND time-based blind", "Title: Generic UNION query (NULL) - 3 columns", "8.0.19", "current database: 'testdb'", "current user: 'root@%'", "[1 column]", "| surname | varchar(1000) |")),
# PostgreSQL
("-u 'http://testbed/postgresql/get_int.php?id=1' --flush-session --technique=B --is-dba --threads=4 --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("x86_64-pc-linux-gnu", "Database: public", "Table: testusers", "5 entries", "id", "name", "surname", "luther", "blisset", "NULL", "Payload: id=1 AND ", "it looks like the back-end DBMS is 'PostgreSQL'", "the back-end DBMS is PostgreSQL", "current user is DBA: False", ": 'foobar'")),
("-u 'http://testbed/postgresql/get_int.php?id=1' --flush-session --technique=U --is-dba --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("x86_64-pc-linux-gnu", "Database: public", "Table: testusers", "5 entries", "id", "name", "surname", "luther", "blisset", "NULL", "Title: Generic UNION query (NULL) - 3 columns", "the back-end DBMS is PostgreSQL", "appears to have 3 columns", "current user is DBA: False", ": 'foobar'")),
("-u 'http://testbed/postgresql/get_int.php?id=1' --flush-session --hex --banner --current-user --current-db --search -C surname --answers='dump=n'", ("Title: AND boolean-based blind", "Title: PostgreSQL AND error-based", "Title: PostgreSQL > 8.1 stacked queries", "Title: PostgreSQL > 8.1 AND time-based blind", "Title: Generic UNION query (NULL) - 3 columns", "x86_64-pc-linux-gnu", "current database (equivalent to schema on PostgreSQL): 'public'", "current user: 'testuser'", "[1 column]", "| surname | varchar |")),
)
retVal = True
count = 0
for options, checks in TESTS:
status = '%d/%d (%d%%) ' % (count, len(TESTS), round(100.0 * count / len(TESTS)))
dataToStdout("\r[%s] [INFO] complete: %s" % (time.strftime("%X"), status))
cmd = "%s %s %s --batch" % (sys.executable, os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "sqlmap.py")), options)
output = shellExec(cmd)
if not all((check in output if not check.startswith('~') else check[1:] not in output) for check in checks):
for check in checks:
if check not in output:
print(cmd, check)
dataToStdout("---\n\n$ %s\n" % cmd)
dataToStdout("%s---\n" % output, coloring=False)
retVal = False
count += 1
clearConsoleLine()
if retVal:
logger.info("bed test final result: PASSED")
else:
logger.error("best test final result: FAILED")
return retVal
def fuzzTest():
count = 0
address, port = "127.0.0.10", random.randint(1025, 65535)
@@ -298,11 +208,15 @@ def fuzzTest():
if any(_ in lines[j] for _ in ("googleDork",)):
continue
if re.search(r"= (True|False)", lines[j]):
lines[j] = lines[j].replace(" = False", " = True")
continue
if lines[j].strip().endswith('='):
lines[j] += random.sample(("True", "False", randomStr(), str(randomInt())), 1)[0]
k = random.randint(0, len(lines) - 1)
if '=' in lines[k]:
if '=' in lines[k] and not re.search(r"= (True|False)", lines[k]):
lines[k] += chr(random.randint(0, 255))
open(config, "w+").write("\n".join(lines))
+1 -1
View File
@@ -161,7 +161,7 @@ def update():
if IS_WIN:
infoMsg = "for Windows platform it's recommended "
infoMsg += "to use a GitHub for Windows client for updating "
infoMsg += "purposes (http://windows.github.com/) or just "
infoMsg += "purposes (https://desktop.github.com/) or just "
infoMsg += "download the latest snapshot from "
infoMsg += "https://github.com/sqlmapproject/sqlmap/downloads"
else:
+2 -2
View File
@@ -26,7 +26,7 @@ class MSSQLBannerHandler(ContentHandler):
def __init__(self, banner, info):
ContentHandler.__init__(self)
self._banner = sanitizeStr(banner)
self._banner = sanitizeStr(banner or "")
self._inVersion = False
self._inServicePack = False
self._release = None
@@ -62,7 +62,7 @@ class MSSQLBannerHandler(ContentHandler):
def endElement(self, name):
if name == "signature":
for version in (self._version, self._versionAlt):
if version and re.search(r" %s[\.\ ]+" % re.escape(version), self._banner):
if version and self._banner and re.search(r" %s[\.\ ]+" % re.escape(version), self._banner):
self._feedInfo("dbmsRelease", self._release)
self._feedInfo("dbmsVersion", self._version)
self._feedInfo("dbmsServicePack", self._servicePack)
+26 -14
View File
@@ -193,7 +193,7 @@ def cmdLineParser(argv=None):
help="Extra headers (e.g. \"Accept-Language: fr\\nETag: 123\")")
request.add_argument("--auth-type", dest="authType",
help="HTTP authentication type (Basic, Digest, NTLM or PKI)")
help="HTTP authentication type (Basic, Digest, Bearer, ...)")
request.add_argument("--auth-cred", dest="authCred",
help="HTTP authentication credentials (name:password)")
@@ -704,7 +704,7 @@ def cmdLineParser(argv=None):
help="Regexp for filtering targets")
general.add_argument("--skip-heuristics", dest="skipHeuristics", action="store_true",
help="Skip heuristic detection of SQLi/XSS vulnerabilities")
help="Skip heuristic detection of vulnerabilities")
general.add_argument("--skip-waf", dest="skipWaf", action="store_true",
help="Skip heuristic detection of WAF/IPS protection")
@@ -731,7 +731,7 @@ def cmdLineParser(argv=None):
help="Run host OS command(s) when SQL injection is found")
miscellaneous.add_argument("--beep", dest="beep", action="store_true",
help="Beep on question and/or when SQLi/XSS/FI is found")
help="Beep on question and/or when vulnerability is found")
miscellaneous.add_argument("--dependencies", dest="dependencies", action="store_true",
help="Check for missing (optional) sqlmap dependencies")
@@ -751,7 +751,7 @@ def cmdLineParser(argv=None):
miscellaneous.add_argument("--results-file", dest="resultsFile",
help="Location of CSV results file in multiple targets mode")
miscellaneous.add_argument("--sqlmap-shell", dest="sqlmapShell", action="store_true",
miscellaneous.add_argument("--shell", dest="shell", action="store_true",
help="Prompt for an interactive sqlmap shell")
miscellaneous.add_argument("--tmp-dir", dest="tmpDir",
@@ -773,12 +773,18 @@ def cmdLineParser(argv=None):
parser.add_argument("--dummy", dest="dummy", action="store_true",
help=SUPPRESS)
parser.add_argument("--yuge", dest="yuge", action="store_true",
help=SUPPRESS)
parser.add_argument("--murphy-rate", dest="murphyRate", type=int,
help=SUPPRESS)
parser.add_argument("--debug", dest="debug", action="store_true",
help=SUPPRESS)
parser.add_argument("--deprecations", dest="deprecations", action="store_true",
help=SUPPRESS)
parser.add_argument("--disable-multi", dest="disableMulti", action="store_true",
help=SUPPRESS)
@@ -791,6 +797,9 @@ def cmdLineParser(argv=None):
parser.add_argument("--profile", dest="profile", action="store_true",
help=SUPPRESS)
parser.add_argument("--localhost", dest="localhost", action="store_true",
help=SUPPRESS)
parser.add_argument("--force-dbms", dest="forceDbms",
help=SUPPRESS)
@@ -815,9 +824,6 @@ def cmdLineParser(argv=None):
parser.add_argument("--vuln-test", dest="vulnTest", action="store_true",
help=SUPPRESS)
parser.add_argument("--bed-test", dest="bedTest", action="store_true",
help=SUPPRESS)
parser.add_argument("--fuzz-test", dest="fuzzTest", action="store_true",
help=SUPPRESS)
@@ -891,7 +897,7 @@ def cmdLineParser(argv=None):
raise SqlmapSilentQuitException
elif "--sqlmap-shell" in argv:
elif "--shell" in argv:
_createHomeDirectories()
parser.usage = ""
@@ -904,14 +910,17 @@ def cmdLineParser(argv=None):
while True:
command = None
prompt = "sqlmap > "
try:
# Note: in Python2 command should not be converted to Unicode before passing to shlex (Reference: https://bugs.python.org/issue1170)
command = _input("sqlmap-shell> ").strip()
command = _input(prompt).strip()
except (KeyboardInterrupt, EOFError):
print()
raise SqlmapShellQuitException
command = re.sub(r"(?i)\Anew\s+", "", command or "")
if not command:
continue
elif command.lower() == "clear":
@@ -921,8 +930,9 @@ def cmdLineParser(argv=None):
elif command.lower() in ("x", "q", "exit", "quit"):
raise SqlmapShellQuitException
elif command[0] != '-':
dataToStdout("[!] invalid option(s) provided\n")
dataToStdout("[i] proper example: '-u http://www.site.com/vuln.php?id=1 --banner'\n")
if not re.search(r"(?i)\A(\?|help)\Z", command):
dataToStdout("[!] invalid option(s) provided\n")
dataToStdout("[i] valid example: '-u http://www.site.com/vuln.php?id=1 --banner'\n")
else:
saveHistory(AUTOCOMPLETE_TYPE.SQLMAP)
loadHistory(AUTOCOMPLETE_TYPE.SQLMAP)
@@ -966,6 +976,8 @@ def cmdLineParser(argv=None):
argv[i] = ""
elif argv[i].startswith("--data-raw"):
argv[i] = argv[i].replace("--data-raw", "--data", 1)
elif argv[i].startswith("--auth-creds"):
argv[i] = argv[i].replace("--auth-creds", "--auth-cred", 1)
elif argv[i].startswith("--drop-cookie"):
argv[i] = argv[i].replace("--drop-cookie", "--drop-set-cookie", 1)
elif any(argv[i].startswith(_) for _ in ("--tamper", "--ignore-code", "--skip")):
@@ -1053,8 +1065,8 @@ def cmdLineParser(argv=None):
else:
args.stdinPipe = None
if not any((args.direct, args.url, args.logFile, args.bulkFile, args.googleDork, args.configFile, args.requestFile, args.updateAll, args.smokeTest, args.vulnTest, args.bedTest, args.fuzzTest, args.wizard, args.dependencies, args.purge, args.listTampers, args.hashFile, args.stdinPipe)):
errMsg = "missing a mandatory option (-d, -u, -l, -m, -r, -g, -c, --list-tampers, --wizard, --update, --purge or --dependencies). "
if not any((args.direct, args.url, args.logFile, args.bulkFile, args.googleDork, args.configFile, args.requestFile, args.updateAll, args.smokeTest, args.vulnTest, args.fuzzTest, args.wizard, args.dependencies, args.purge, args.listTampers, args.hashFile, args.stdinPipe)):
errMsg = "missing a mandatory option (-d, -u, -l, -m, -r, -g, -c, --wizard, --shell, --update, --purge, --list-tampers or --dependencies). "
errMsg += "Use -h for basic and -hh for advanced help\n"
parser.error(errMsg)
@@ -1065,7 +1077,7 @@ def cmdLineParser(argv=None):
except SystemExit:
# Protection against Windows dummy double clicking
if IS_WIN:
if IS_WIN and "--non-interactive" not in sys.argv:
dataToStdout("\nPress Enter to continue...")
_input()
raise
+5 -5
View File
@@ -20,7 +20,7 @@ class FingerprintHandler(ContentHandler):
def __init__(self, banner, info):
ContentHandler.__init__(self)
self._banner = sanitizeStr(banner)
self._banner = sanitizeStr(banner or "")
self._regexp = None
self._match = None
self._dbmsVersion = None
@@ -30,7 +30,7 @@ class FingerprintHandler(ContentHandler):
def _feedInfo(self, key, value):
value = sanitizeStr(value)
if value in (None, "None"):
if value in (None, "None", ""):
return
if key == "dbmsVersion":
@@ -47,7 +47,7 @@ class FingerprintHandler(ContentHandler):
self._regexp = sanitizeStr(attrs.get("value"))
_ = re.match(r"\A[A-Za-z0-9]+", self._regexp) # minor trick avoiding compiling of large amount of regexes
if _ and _.group(0).lower() in self._banner.lower() or not _:
if _ and self._banner and _.group(0).lower() in self._banner.lower() or not _:
self._match = re.search(self._regexp, self._banner, re.I | re.M)
else:
self._match = None
@@ -62,10 +62,10 @@ class FingerprintHandler(ContentHandler):
self._techVersion = sanitizeStr(attrs.get("tech_version"))
self._sp = sanitizeStr(attrs.get("sp"))
if self._dbmsVersion.isdigit():
if self._dbmsVersion and self._dbmsVersion.isdigit():
self._feedInfo("dbmsVersion", self._match.group(int(self._dbmsVersion)))
if self._techVersion.isdigit():
if self._techVersion and self._techVersion.isdigit():
self._feedInfo("technology", "%s %s" % (attrs.get("technology"), self._match.group(int(self._techVersion))))
else:
self._feedInfo("technology", attrs.get("technology"))
+1 -2
View File
@@ -11,7 +11,6 @@ from lib.core.common import parseXmlFile
from lib.core.data import kb
from lib.core.data import paths
from lib.parse.handler import FingerprintHandler
from thirdparty.six.moves import filter as _filter
def headersParser(headers):
"""
@@ -30,7 +29,7 @@ def headersParser(headers):
"x-powered-by": os.path.join(paths.SQLMAP_XML_BANNER_PATH, "x-powered-by.xml"),
}
for header in _filter(lambda _: _ in kb.headerPaths, headers):
for header in (_.lower() for _ in headers if _.lower() in kb.headerPaths):
value = headers[header]
xmlfile = kb.headerPaths[header]
handler = FingerprintHandler(value, kb.headersFp)
+3
View File
@@ -13,6 +13,7 @@ from lib.core.common import urldecode
from lib.core.common import parseXmlFile
from lib.core.data import kb
from lib.core.data import paths
from lib.core.settings import HEURISTIC_PAGE_SIZE_THRESHOLD
from lib.core.threads import getCurrentThreadData
class HTMLHandler(ContentHandler):
@@ -69,6 +70,8 @@ def htmlParser(page):
>>> threadData.lastErrorPage = None
"""
page = page[:HEURISTIC_PAGE_SIZE_THRESHOLD]
xmlfile = paths.ERRORS_XML
handler = HTMLHandler(page)
key = hash(page)
+4 -3
View File
@@ -43,6 +43,7 @@ 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 EVENTVALIDATION_REGEX
from lib.core.settings import HEURISTIC_PAGE_SIZE_THRESHOLD
from lib.core.settings import IDENTYWAF_PARSE_LIMIT
from lib.core.settings import MAX_CONNECTION_TOTAL_SIZE
from lib.core.settings import META_CHARSET_REGEX
@@ -258,7 +259,7 @@ def getHeuristicCharEncoding(page):
"""
key = hash(page)
retVal = kb.cache.encoding.get(key) or detect(page)["encoding"]
retVal = kb.cache.encoding[key] if key in kb.cache.encoding else detect(page[:HEURISTIC_PAGE_SIZE_THRESHOLD])["encoding"]
kb.cache.encoding[key] = retVal
if retVal and retVal.lower().replace('-', "") == UNICODE_ENCODING.lower().replace('-', ""):
@@ -303,7 +304,7 @@ def decodePage(page, contentEncoding, contentType, percentDecode=True):
page = data.read()
except Exception as ex:
if "<html" not in page: # in some cases, invalid "Content-Encoding" appears for plain HTML (should be ignored)
if b"<html" not in page: # in some cases, invalid "Content-Encoding" appears for plain HTML (should be ignored)
errMsg = "detected invalid data for declared content "
errMsg += "encoding '%s' ('%s')" % (contentEncoding, getSafeExString(ex))
singleTimeLogMessage(errMsg, logging.ERROR)
@@ -395,7 +396,7 @@ def processResponse(page, responseHeaders, code=None, status=None):
logger.warning("parsed DBMS error message: '%s'" % msg.rstrip('.'))
if not conf.skipWaf and kb.processResponseCounter < IDENTYWAF_PARSE_LIMIT:
rawResponse = "%s %s %s\n%s\n%s" % (_http_client.HTTPConnection._http_vsn_str, code or "", status or "", "".join(getUnicode(responseHeaders.headers if responseHeaders else [])), page)
rawResponse = "%s %s %s\n%s\n%s" % (_http_client.HTTPConnection._http_vsn_str, code or "", status or "", "".join(getUnicode(responseHeaders.headers if responseHeaders else [])), page[:HEURISTIC_PAGE_SIZE_THRESHOLD])
identYwaf.non_blind.clear()
if identYwaf.non_blind_check(rawResponse, silent=True):
+11 -1
View File
@@ -151,10 +151,20 @@ def _comparison(page, headers, code, getRatioValue, pageLength):
seq1 = seq1.split("\n")
seq2 = seq2.split("\n")
key = None
else:
key = (hash(seq1), hash(seq2))
seqMatcher.set_seq1(seq1)
seqMatcher.set_seq2(seq2)
ratio = round(seqMatcher.quick_ratio() if not kb.heavilyDynamic else seqMatcher.ratio(), 3)
if key in kb.cache.comparison:
ratio = kb.cache.comparison[key]
else:
ratio = round(seqMatcher.quick_ratio() if not kb.heavilyDynamic else seqMatcher.ratio(), 3)
if key:
kb.cache.comparison[key] = ratio
# If the url is stable and we did not set yet the match ratio and the
# current injected value changes the url page content
+45 -18
View File
@@ -6,6 +6,7 @@ See the file 'LICENSE' for copying permission
"""
import binascii
import inspect
import logging
import os
import random
@@ -13,6 +14,7 @@ import re
import socket
import string
import struct
import sys
import time
import traceback
@@ -124,6 +126,7 @@ from lib.core.settings import UNICODE_ENCODING
from lib.core.settings import URI_HTTP_HEADER
from lib.core.settings import WARN_TIME_STDEV
from lib.core.settings import WEBSOCKET_INITIAL_TIMEOUT
from lib.core.settings import YUGE_FACTOR
from lib.request.basic import decodePage
from lib.request.basic import forgeHeaders
from lib.request.basic import processResponse
@@ -145,6 +148,10 @@ class Connect(object):
@staticmethod
def _getPageProxy(**kwargs):
if (len(inspect.stack()) > sys.getrecursionlimit() // 2): # Note: https://github.com/sqlmapproject/sqlmap/issues/4525
warnMsg = "unable to connect to the target URL"
raise SqlmapConnectionException(warnMsg)
try:
return Connect.getPage(**kwargs)
except RuntimeError:
@@ -182,16 +189,23 @@ class Connect(object):
warnMsg += "you could successfully use "
warnMsg += "switch '--tor' "
if IS_WIN:
warnMsg += "(e.g. 'https://www.torproject.org/download/download.html.en')"
warnMsg += "(e.g. 'https://www.torproject.org/download/')"
else:
warnMsg += "(e.g. 'https://help.ubuntu.com/community/Tor')"
else:
warnMsg = "if the problem persists please check that the provided "
warnMsg += "target URL is reachable. In case that it is, "
warnMsg += "you can try to rerun with "
warnMsg += "target URL is reachable"
items = []
if not conf.randomAgent:
warnMsg += "switch '--random-agent' and/or "
warnMsg += "proxy switches ('--ignore-proxy', '--proxy',...)"
items.append("switch '--random-agent'")
if not any((conf.proxy, conf.proxyFile, conf.tor)):
items.append("proxy switches ('--proxy', '--proxy-file'...)")
if items:
warnMsg += ". In case that it is, "
warnMsg += "you can try to rerun with "
warnMsg += " and/or ".join(items)
singleTimeWarnMessage(warnMsg)
elif conf.threads > 1:
@@ -228,7 +242,7 @@ class Connect(object):
if len(part) == MAX_CONNECTION_READ_SIZE:
warnMsg = "large response detected. This could take a while"
singleTimeWarnMessage(warnMsg)
part = re.sub(r"(?si)%s.+?%s" % (kb.chars.stop, kb.chars.start), "%s%s%s" % (kb.chars.stop, LARGE_READ_TRIM_MARKER, kb.chars.start), part)
part = re.sub(getBytes(r"(?si)%s.+?%s" % (kb.chars.stop, kb.chars.start)), getBytes("%s%s%s" % (kb.chars.stop, LARGE_READ_TRIM_MARKER, kb.chars.start)), part)
retVal += part
else:
retVal += part
@@ -239,6 +253,9 @@ class Connect(object):
singleTimeWarnMessage(warnMsg)
break
if conf.yuge:
retVal = YUGE_FACTOR * retVal
return retVal
@staticmethod
@@ -475,6 +492,9 @@ class Connect(object):
header, value = line.split(':', 1)
headers[header] = value
if conf.localhost:
headers[HTTP_HEADER.HOST] = "localhost"
for key, value in list(headers.items()):
del headers[key]
if isinstance(value, six.string_types):
@@ -485,8 +505,6 @@ class Connect(object):
if six.PY2:
url = getBytes(url) # Note: Python3 requires text while Python2 has problems when mixing text with binary POST
post = getBytes(post)
if webSocket:
ws = websocket.WebSocket()
ws.settimeout(WEBSOCKET_INITIAL_TIMEOUT if kb.webSocketRecvCount is None else timeout)
@@ -530,6 +548,8 @@ class Connect(object):
logger.log(CUSTOM_LOGGING.TRAFFIC_OUT, requestMsg)
else:
post = getBytes(post)
if target and cmdLineOptions.method or method and method not in (HTTPMETHOD.GET, HTTPMETHOD.POST):
req = MethodRequest(url, post, headers)
req.set_method(cmdLineOptions.method or method)
@@ -597,8 +617,8 @@ 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
skipLogTraffic = kb.redirectChoice == REDIRECTION.NO
page = (threadData.lastRedirectMsg[1] if kb.choices.redirect == REDIRECTION.NO else Connect._connReadProxy(conn)) if not skipRead else None
skipLogTraffic = kb.choices.redirect == REDIRECTION.NO
code = conn.redcode if not finalCode else code
else:
page = Connect._connReadProxy(conn) if not skipRead else None
@@ -734,7 +754,9 @@ class Connect(object):
if ex.code not in (conf.ignoreCode or []):
if ex.code == _http_client.UNAUTHORIZED:
errMsg = "not authorized, try to provide right HTTP "
errMsg += "authentication type and valid credentials (%d)" % code
errMsg += "authentication type and valid credentials (%d). " % code
errMsg += "If this is intended, try to rerun by providing "
errMsg += "a valid value for option '--ignore-code'"
raise SqlmapConnectionException(errMsg)
elif chunked and ex.code in (_http_client.METHOD_NOT_ALLOWED, _http_client.LENGTH_REQUIRED):
warnMsg = "turning off HTTP chunked transfer encoding "
@@ -767,7 +789,7 @@ class Connect(object):
debugMsg = "got HTTP error code: %d ('%s')" % (code, status)
logger.debug(debugMsg)
except (_urllib.error.URLError, socket.error, socket.timeout, _http_client.HTTPException, struct.error, binascii.Error, ProxyError, SqlmapCompressionException, WebSocketException, TypeError, ValueError, OverflowError):
except (_urllib.error.URLError, socket.error, socket.timeout, _http_client.HTTPException, struct.error, binascii.Error, ProxyError, SqlmapCompressionException, WebSocketException, TypeError, ValueError, OverflowError, AttributeError):
tbMsg = traceback.format_exc()
if conf.debug:
@@ -775,6 +797,11 @@ class Connect(object):
if checking:
return None, None, None
elif "AttributeError:" in tbMsg:
if "WSAECONNREFUSED" in tbMsg:
return None, None, None
else:
raise
elif "no host given" in tbMsg:
warnMsg = "invalid URL address used (%s)" % repr(url)
raise SqlmapSyntaxException(warnMsg)
@@ -831,13 +858,13 @@ class Connect(object):
with kb.locks.connError:
kb.connErrorCounter += 1
if kb.connErrorCounter >= MAX_CONSECUTIVE_CONNECTION_ERRORS and kb.connErrorChoice is None:
if kb.connErrorCounter >= MAX_CONSECUTIVE_CONNECTION_ERRORS and kb.choices.connError is None:
message = "there seems to be a continuous problem with connection to the target. "
message += "Are you sure that you want to continue? [y/N] "
kb.connErrorChoice = readInput(message, default='N', boolean=True)
kb.choices.connError = readInput(message, default='N', boolean=True)
if kb.connErrorChoice is False:
if kb.choices.connError is False:
raise SqlmapSkipTargetException
if "forcibly closed" in tbMsg:
@@ -1012,10 +1039,10 @@ class Connect(object):
skip = False
if place == PLACE.COOKIE or place == PLACE.CUSTOM_HEADER and value.split(',')[0].upper() == HTTP_HEADER.COOKIE.upper():
if kb.cookieEncodeChoice is None:
if kb.choices.cookieEncode 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)
if not kb.cookieEncodeChoice:
kb.choices.cookieEncode = readInput(msg, default='Y' if not conf.url.endswith(".aspx") else 'N', boolean=True)
if not kb.choices.cookieEncode:
skip = True
if not skip:
+2 -2
View File
@@ -113,7 +113,7 @@ def _goInference(payload, expression, charsetType=None, firstChar=None, lastChar
else:
expression = "SELECT %s FROM (%s)" % (field, expression)
if field and conf.hexConvert or conf.binaryFields and field in conf.binaryFields:
if field and conf.hexConvert or conf.binaryFields and field in conf.binaryFields or Backend.getIdentifiedDbms() in (DBMS.RAIMA,):
nulledCastedField = agent.nullAndCastField(field)
injExpression = expression.replace(field, nulledCastedField, 1)
else:
@@ -198,7 +198,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) and hasattr(queries[Backend.getIdentifiedDbms()].limitregexp, "query"):
expression, limitCond, topLimit, startLimit, stopLimit = agent.limitCondition(expression)
if limitCond:
+4 -4
View File
@@ -48,13 +48,13 @@ class SmartRedirectHandler(_urllib.request.HTTPRedirectHandler):
def _ask_redirect_choice(self, redcode, redurl, method):
with kb.locks.redirect:
if kb.redirectChoice is None:
if kb.choices.redirect is None:
msg = "got a %d redirect to " % redcode
msg += "'%s'. Do you want to follow? [Y/n] " % redurl
kb.redirectChoice = REDIRECTION.YES if readInput(msg, default='Y', boolean=True) else REDIRECTION.NO
kb.choices.redirect = REDIRECTION.YES if readInput(msg, default='Y', boolean=True) else REDIRECTION.NO
if kb.redirectChoice == REDIRECTION.YES and method == HTTPMETHOD.POST and kb.resendPostOnRedirect is None:
if kb.choices.redirect == REDIRECTION.YES and method == HTTPMETHOD.POST and kb.resendPostOnRedirect is None:
msg = "redirect is a result of a "
msg += "POST request. Do you want to "
msg += "resend original POST data to a new "
@@ -116,7 +116,7 @@ class SmartRedirectHandler(_urllib.request.HTTPRedirectHandler):
redurl = None
result = fp
if redurl and kb.redirectChoice == REDIRECTION.YES:
if redurl and kb.choices.redirect == REDIRECTION.YES:
parseResponse(content, headers)
req.headers[HTTP_HEADER.HOST] = getHostHeader(redurl)
+1 -1
View File
@@ -130,7 +130,7 @@ class UDF(object):
errMsg = "udfSetLocalPaths() method must be defined within the plugin"
raise SqlmapUnsupportedFeatureException(errMsg)
def udfCreateFromSharedLib(self, udf=None, inpRet=None):
def udfCreateFromSharedLib(self, udf, inpRet):
errMsg = "udfCreateFromSharedLib() method must be defined within the plugin"
raise SqlmapUnsupportedFeatureException(errMsg)
+5 -2
View File
@@ -166,9 +166,12 @@ class XP_cmdshell(object):
# Obfuscate the command to execute, also useful to bypass filters
# on single-quotes
self._randStr = randomStr(lowercase=True)
self._cmd = "0x%s" % encodeHex(cmd, binary=False)
self._forgedCmd = "DECLARE @%s VARCHAR(8000);" % self._randStr
self._forgedCmd += "SET @%s=%s;" % (self._randStr, self._cmd)
try:
self._forgedCmd += "SET @%s=%s;" % (self._randStr, "0x%s" % encodeHex(cmd, binary=False))
except UnicodeError:
self._forgedCmd += "SET @%s='%s';" % (self._randStr, cmd)
# Insert the command standard output into a support table,
# 'sqlmapoutput', except when DBMS credentials are provided because
+6 -1
View File
@@ -26,6 +26,7 @@ from lib.core.common import goGoodSamaritan
from lib.core.common import hashDBRetrieve
from lib.core.common import hashDBWrite
from lib.core.common import incrementCounter
from lib.core.common import isListLike
from lib.core.common import safeStringFormat
from lib.core.common import singleTimeWarnMessage
from lib.core.data import conf
@@ -217,7 +218,7 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
markingValue = "'%s'" % CHAR_INFERENCE_MARK
unescapedCharValue = unescaper.escape("'%s'" % decodeIntToUnicode(posValue))
forgedPayload = agent.extractPayload(payload)
forgedPayload = agent.extractPayload(payload) or ""
forgedPayload = safeStringFormat(forgedPayload.replace(INFERENCE_GREATER_CHAR, INFERENCE_EQUALS_CHAR), (expressionUnescaped, idx, posValue)).replace(markingValue, unescapedCharValue)
result = Request.queryPage(agent.replacePayload(payload, forgedPayload), timeBasedCompare=timeBasedCompare, raise404=False)
incrementCounter(getTechnique())
@@ -504,6 +505,10 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
else:
break
# NOTE: https://github.com/sqlmapproject/sqlmap/issues/4629
if not isListLike(threadData.shared.value):
break
with kb.locks.value:
threadData.shared.value[currentCharIndex - 1 - firstChar] = val
currentValue = list(threadData.shared.value)
+3
View File
@@ -104,6 +104,7 @@ def _findUnionCharCount(comment, place, parameter, value, prefix, suffix, where=
if kb.orderByColumns is None and (lowerCount == 1 or conf.uCols): # Note: ORDER BY is not bullet-proof
found = _orderByTechnique(lowerCount, upperCount) if conf.uCols else _orderByTechnique()
if found:
kb.orderByColumns = found
infoMsg = "target URL appears to have %d column%s in query" % (found, 's' if found > 1 else "")
@@ -122,8 +123,10 @@ def _findUnionCharCount(comment, place, parameter, value, prefix, suffix, where=
query = agent.forgeUnionQuery('', -1, count, comment, prefix, suffix, kb.uChar, where)
payload = agent.payload(place=place, parameter=parameter, newValue=query, where=where)
page, headers, code = Request.queryPage(payload, place=place, content=True, raise404=False)
if not isNullValue(kb.uChar):
pages[count] = page
ratio = comparison(page, headers, code, getRatioValue=True) or MIN_RATIO
ratios.append(ratio)
min_, max_ = min(min_, ratio), max(max_, ratio)
+18 -14
View File
@@ -25,6 +25,7 @@ from lib.core.common import hashDBRetrieve
from lib.core.common import hashDBWrite
from lib.core.common import incrementCounter
from lib.core.common import initTechnique
from lib.core.common import isDigit
from lib.core.common import isListLike
from lib.core.common import isNoneValue
from lib.core.common import isNumPosStrValue
@@ -85,8 +86,9 @@ def _oneShotUnionUse(expression, unpack=True, limited=False):
query = agent.forgeUnionQuery(injExpression, vector[0], vector[1], vector[2], vector[3], vector[4], vector[5], vector[6], None, limited)
where = PAYLOAD.WHERE.NEGATIVE if conf.limitStart or conf.limitStop else vector[6]
else:
injExpression = unescaper.escape(expression)
where = vector[6]
query = agent.forgeUnionQuery(expression, vector[0], vector[1], vector[2], vector[3], vector[4], vector[5], vector[6], None, False)
query = agent.forgeUnionQuery(injExpression, vector[0], vector[1], vector[2], vector[3], vector[4], vector[5], vector[6], None, False)
payload = agent.payload(newValue=query, where=where)
@@ -97,7 +99,7 @@ def _oneShotUnionUse(expression, unpack=True, limited=False):
if kb.jsonAggMode:
if Backend.isDbms(DBMS.MSSQL):
output = extractRegexResult(r"%s(?P<result>.*)%s" % (kb.chars.start, kb.chars.stop), page or "")
output = extractRegexResult(r"%s(?P<result>.*)%s" % (kb.chars.start, kb.chars.stop), removeReflectiveValues(page or "", payload))
if output:
try:
retVal = ""
@@ -109,11 +111,11 @@ def _oneShotUnionUse(expression, unpack=True, limited=False):
else:
retVal = getUnicode(retVal)
elif Backend.isDbms(DBMS.PGSQL):
output = extractRegexResult(r"(?P<result>%s.*%s)" % (kb.chars.start, kb.chars.stop), page or "")
output = extractRegexResult(r"(?P<result>%s.*%s)" % (kb.chars.start, kb.chars.stop), removeReflectiveValues(page or "", payload))
if output:
retVal = output
else:
output = extractRegexResult(r"%s(?P<result>.*?)%s" % (kb.chars.start, kb.chars.stop), page or "")
output = extractRegexResult(r"%s(?P<result>.*?)%s" % (kb.chars.start, kb.chars.stop), removeReflectiveValues(page or "", payload))
if output:
try:
retVal = ""
@@ -185,25 +187,25 @@ def configUnion(char=None, columns=None):
kb.uChar = char
if conf.uChar is not None:
kb.uChar = char.replace("[CHAR]", conf.uChar if conf.uChar.isdigit() else "'%s'" % conf.uChar.strip("'"))
kb.uChar = char.replace("[CHAR]", conf.uChar if isDigit(conf.uChar) else "'%s'" % conf.uChar.strip("'"))
def _configUnionCols(columns):
if not isinstance(columns, six.string_types):
return
columns = columns.replace(" ", "")
if "-" in columns:
colsStart, colsStop = columns.split("-")
columns = columns.replace(' ', "")
if '-' in columns:
colsStart, colsStop = columns.split('-')
else:
colsStart, colsStop = columns, columns
if not colsStart.isdigit() or not colsStop.isdigit():
if not isDigit(colsStart) or not isDigit(colsStop):
raise SqlmapSyntaxException("--union-cols must be a range of integers")
conf.uColsStart, conf.uColsStop = int(colsStart), int(colsStop)
if conf.uColsStart > conf.uColsStop:
errMsg = "--union-cols range has to be from lower to "
errMsg = "--union-cols range has to represent lower to "
errMsg += "higher number of columns"
raise SqlmapSyntaxException(errMsg)
@@ -241,14 +243,16 @@ def unionUse(expression, unpack=True, dump=False):
debugMsg += "it does not play well with UNION query SQL injection"
singleTimeDebugMessage(debugMsg)
if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.ORACLE, DBMS.PGSQL, DBMS.MSSQL) and expressionFields and not conf.binaryFields:
if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.ORACLE, DBMS.PGSQL, DBMS.MSSQL, DBMS.SQLITE) and expressionFields and not any((conf.binaryFields, conf.limitStart, conf.limitStop, conf.forcePartial)):
match = re.search(r"SELECT\s*(.+?)\bFROM", expression, re.I)
if match and not (Backend.isDbms(DBMS.ORACLE) and FROM_DUMMY_TABLE[DBMS.ORACLE] in expression):
if match and not (Backend.isDbms(DBMS.ORACLE) and FROM_DUMMY_TABLE[DBMS.ORACLE] in expression) and not re.search(r"\b(MIN|MAX|COUNT)\(", expression):
kb.jsonAggMode = True
if Backend.isDbms(DBMS.MYSQL):
query = expression.replace(expressionFields, "CONCAT('%s',JSON_ARRAYAGG(CONCAT_WS('%s',%s)),'%s')" % (kb.chars.start, kb.chars.delimiter, expressionFields, kb.chars.stop), 1)
elif Backend.isDbms(DBMS.ORACLE):
query = expression.replace(expressionFields, "'%s'||JSON_ARRAYAGG(%s)||'%s'" % (kb.chars.start, ("||'%s'||" % kb.chars.delimiter).join(expressionFieldsList), kb.chars.stop), 1)
elif Backend.isDbms(DBMS.SQLITE):
query = expression.replace(expressionFields, "'%s'||JSON_GROUP_ARRAY(%s)||'%s'" % (kb.chars.start, ("||'%s'||" % kb.chars.delimiter).join("COALESCE(%s,' ')" % field for field in expressionFieldsList), kb.chars.stop), 1)
elif Backend.isDbms(DBMS.PGSQL): # Note: ARRAY_AGG does CSV alike output, thus enclosing start/end inside each item
query = expression.replace(expressionFields, "ARRAY_AGG('%s'||%s||'%s')::text" % (kb.chars.start, ("||'%s'||" % kb.chars.delimiter).join("COALESCE(%s::text,' ')" % field for field in expressionFieldsList), kb.chars.stop), 1)
elif Backend.isDbms(DBMS.MSSQL):
@@ -326,8 +330,8 @@ def unionUse(expression, unpack=True, dump=False):
if stopLimit > TURN_OFF_RESUME_INFO_LIMIT:
kb.suppressResumeInfo = True
debugMsg = "suppressing possible resume console info because of "
debugMsg += "large number of rows. It might take too long"
debugMsg = "suppressing possible resume console info for "
debugMsg += "large number of rows as it might take too long"
logger.debug(debugMsg)
try:
+8 -2
View File
@@ -49,6 +49,7 @@ from lib.core.settings import IS_WIN
from lib.core.settings import RESTAPI_DEFAULT_ADAPTER
from lib.core.settings import RESTAPI_DEFAULT_ADDRESS
from lib.core.settings import RESTAPI_DEFAULT_PORT
from lib.core.settings import RESTAPI_UNSUPPORTED_OPTIONS
from lib.core.settings import VERSION_STRING
from lib.core.shell import autoCompletion
from lib.core.subprocessng import Popen
@@ -502,6 +503,11 @@ def scan_start(taskid):
logger.warning("[%s] Invalid JSON options provided to scan_start()" % taskid)
return jsonize({"success": False, "message": "Invalid JSON options"})
for key in request.json:
if key in RESTAPI_UNSUPPORTED_OPTIONS:
logger.warning("[%s] Unsupported option '%s' provided to scan_start()" % (taskid, key))
return jsonize({"success": False, "message": "Unsupported option '%s'" % key})
# Initialize sqlmap engine's options with user's provided options, if any
for option, value in request.json.items():
DataStore.tasks[taskid].set_option(option, value)
@@ -836,7 +842,7 @@ def client(host=RESTAPI_DEFAULT_ADDRESS, port=RESTAPI_DEFAULT_PORT, username=Non
raw = _client("%s/task/new" % addr)
res = dejsonize(raw)
if not res["success"]:
logger.error("Failed to create new task")
logger.error("Failed to create new task ('%s')" % res.get("message", ""))
continue
taskid = res["taskid"]
logger.info("New task ID is '%s'" % taskid)
@@ -844,7 +850,7 @@ def client(host=RESTAPI_DEFAULT_ADDRESS, port=RESTAPI_DEFAULT_PORT, username=Non
raw = _client("%s/scan/%s/start" % (addr, taskid), cmdLineOptions)
res = dejsonize(raw)
if not res["success"]:
logger.error("Failed to start scan")
logger.error("Failed to start scan ('%s')" % res.get("message", ""))
continue
logger.info("Scanning started")
+7 -7
View File
@@ -63,15 +63,15 @@ def _addPageTextWords():
@stackedmethod
def tableExists(tableFile, regex=None):
if kb.tableExistsChoice is None and not any(_ for _ in kb.injection.data if _ not in (PAYLOAD.TECHNIQUE.TIME, PAYLOAD.TECHNIQUE.STACKED)) and not conf.direct:
if kb.choices.tableExists is None and not any(_ for _ in kb.injection.data if _ not in (PAYLOAD.TECHNIQUE.TIME, PAYLOAD.TECHNIQUE.STACKED)) and not conf.direct:
warnMsg = "it's not recommended to use '%s' and/or '%s' " % (PAYLOAD.SQLINJECTION[PAYLOAD.TECHNIQUE.TIME], PAYLOAD.SQLINJECTION[PAYLOAD.TECHNIQUE.STACKED])
warnMsg += "for common table existence check"
logger.warn(warnMsg)
message = "are you sure you want to continue? [y/N] "
kb.tableExistsChoice = readInput(message, default='N', boolean=True)
kb.choices.tableExists = readInput(message, default='N', boolean=True)
if not kb.tableExistsChoice:
if not kb.choices.tableExists:
return None
result = inject.checkBooleanExpression("%s" % safeStringFormat(BRUTE_TABLE_EXISTS_TEMPLATE, (randomInt(1), randomStr())))
@@ -104,7 +104,7 @@ def tableExists(tableFile, regex=None):
tables = filterListValue(tables, regex)
for conf.db in (conf.db.split(',') if conf.db else [conf.db]):
if conf.db:
if conf.db and METADB_SUFFIX not in conf.db:
infoMsg = "checking database '%s'" % conf.db
logger.info(infoMsg)
@@ -187,15 +187,15 @@ def tableExists(tableFile, regex=None):
return kb.data.cachedTables
def columnExists(columnFile, regex=None):
if kb.columnExistsChoice is None and not any(_ for _ in kb.injection.data if _ not in (PAYLOAD.TECHNIQUE.TIME, PAYLOAD.TECHNIQUE.STACKED)) and not conf.direct:
if kb.choices.columnExists is None and not any(_ for _ in kb.injection.data if _ not in (PAYLOAD.TECHNIQUE.TIME, PAYLOAD.TECHNIQUE.STACKED)) and not conf.direct:
warnMsg = "it's not recommended to use '%s' and/or '%s' " % (PAYLOAD.SQLINJECTION[PAYLOAD.TECHNIQUE.TIME], PAYLOAD.SQLINJECTION[PAYLOAD.TECHNIQUE.STACKED])
warnMsg += "for common column existence check"
logger.warn(warnMsg)
message = "are you sure you want to continue? [y/N] "
kb.columnExistsChoice = readInput(message, default='N', boolean=True)
kb.choices.columnExists = readInput(message, default='N', boolean=True)
if not kb.columnExistsChoice:
if not kb.choices.columnExists:
return None
if not conf.tbl:
+22 -20
View File
@@ -13,22 +13,6 @@ except: # removed ImportError because of https://github.com/sqlmapproject/sqlma
from thirdparty.fcrypt.fcrypt import crypt
_multiprocessing = None
try:
import multiprocessing
# problems on FreeBSD (Reference: https://web.archive.org/web/20110710041353/http://www.eggheadcafe.com/microsoft/Python/35880259/multiprocessing-on-freebsd.aspx)
_ = multiprocessing.Queue()
# problems with ctypes (Reference: https://github.com/sqlmapproject/sqlmap/issues/2952)
_ = multiprocessing.Value('i')
except (ImportError, OSError, AttributeError):
pass
else:
try:
if multiprocessing.cpu_count() > 1:
_multiprocessing = multiprocessing
except NotImplementedError:
pass
import base64
import binascii
@@ -637,13 +621,13 @@ def storeHashesToFile(attack_dict):
if item and item not in items:
items.add(item)
if kb.storeHashesChoice is None:
if kb.choices.storeHashes is None:
message = "do you want to store hashes to a temporary file "
message += "for eventual further processing with other tools [y/N] "
kb.storeHashesChoice = readInput(message, default='N', boolean=True)
kb.choices.storeHashes = readInput(message, default='N', boolean=True)
if items and kb.storeHashesChoice:
if items and kb.choices.storeHashes:
handle, filename = tempfile.mkstemp(prefix=MKSTEMP_PREFIX.HASHES, suffix=".txt")
os.close(handle)
@@ -983,6 +967,24 @@ def dictionaryAttack(attack_dict):
if conf.disableMulti:
_multiprocessing = None
else:
# Note: https://github.com/sqlmapproject/sqlmap/issues/4367
try:
import multiprocessing
# problems on FreeBSD (Reference: https://web.archive.org/web/20110710041353/http://www.eggheadcafe.com/microsoft/Python/35880259/multiprocessing-on-freebsd.aspx)
_ = multiprocessing.Queue()
# problems with ctypes (Reference: https://github.com/sqlmapproject/sqlmap/issues/2952)
_ = multiprocessing.Value('i')
except (ImportError, OSError, AttributeError):
pass
else:
try:
if multiprocessing.cpu_count() > 1:
_multiprocessing = multiprocessing
except NotImplementedError:
pass
for (_, hashes) in attack_dict.items():
for hash_ in hashes:
@@ -1133,7 +1135,7 @@ def dictionaryAttack(attack_dict):
custom_wordlist.append(normalizeUnicode(user))
# Algorithms without extra arguments (e.g. salt and/or username)
if hash_regex in (HASH.MYSQL, HASH.MYSQL_OLD, HASH.MD5_GENERIC, HASH.SHA1_GENERIC, HASH.SHA224_GENERIC, HASH.SHA256_GENERIC, HASH.SHA384_GENERIC, HASH.SHA512_GENERIC, HASH.APACHE_SHA1, HASH.VBULLETIN, HASH.VBULLETIN_OLD):
if hash_regex in (HASH.MYSQL, HASH.MYSQL_OLD, HASH.MD5_GENERIC, HASH.SHA1_GENERIC, HASH.SHA224_GENERIC, HASH.SHA256_GENERIC, HASH.SHA384_GENERIC, HASH.SHA512_GENERIC, HASH.APACHE_SHA1):
for suffix in suffix_list:
if not attack_info or processException:
break
+2 -1
View File
@@ -30,6 +30,7 @@ from lib.core.exception import SqlmapConnectionException
from lib.core.exception import SqlmapNoneDataException
from lib.core.settings import MAX_INT
from lib.core.settings import NULL
from lib.core.settings import SINGLE_QUOTE_MARKER
from lib.core.unescaper import unescaper
from lib.request import inject
from lib.utils.safe2bin import safechardecode
@@ -128,7 +129,7 @@ def pivotDumpTable(table, colList, count=None, blind=True, alias=None):
if column == colList[0]:
query = dumpNode.query.replace("'%s'" if unescaper.escape(pivotValue, False) != pivotValue else "%s", "%s") % (agent.preprocessField(table, column), table, agent.preprocessField(table, column), unescaper.escape(pivotValue, False))
else:
query = dumpNode.query2.replace("'%s'" if unescaper.escape(pivotValue, False) != pivotValue else "%s", "%s") % (agent.preprocessField(table, column), table, agent.preprocessField(table, colList[0]), unescaper.escape(pivotValue, False))
query = dumpNode.query2.replace("'%s'" if unescaper.escape(pivotValue, False) != pivotValue else "%s", "%s") % (agent.preprocessField(table, column), table, agent.preprocessField(table, colList[0]), unescaper.escape(pivotValue, False) if SINGLE_QUOTE_MARKER not in dumpNode.query2 else pivotValue)
query = agent.whereQuery(query)
return unArrayizeValue(inject.getValue(query, blind=blind, time=blind, union=not blind, error=not blind))
+6 -4
View File
@@ -28,6 +28,7 @@ from lib.core.exception import SqlmapUserQuitException
from lib.core.settings import BING_REGEX
from lib.core.settings import DUCKDUCKGO_REGEX
from lib.core.settings import DUMMY_SEARCH_USER_AGENT
from lib.core.settings import GOOGLE_CONSENT_COOKIE
from lib.core.settings import GOOGLE_REGEX
from lib.core.settings import HTTP_ACCEPT_ENCODING_HEADER_VALUE
from lib.core.settings import UNICODE_ENCODING
@@ -52,6 +53,7 @@ def _search(dork):
requestHeaders[HTTP_HEADER.USER_AGENT] = dict(conf.httpHeaders).get(HTTP_HEADER.USER_AGENT, DUMMY_SEARCH_USER_AGENT)
requestHeaders[HTTP_HEADER.ACCEPT_ENCODING] = HTTP_ACCEPT_ENCODING_HEADER_VALUE
requestHeaders[HTTP_HEADER.COOKIE] = GOOGLE_CONSENT_COOKIE
try:
req = _urllib.request.Request("https://www.google.com/ncr", headers=requestHeaders)
@@ -63,7 +65,7 @@ def _search(dork):
gpage = conf.googlePage if conf.googlePage > 1 else 1
logger.info("using search result page #%d" % gpage)
url = "https://www.google.com/search?"
url = "https://www.google.com/search?" # NOTE: if consent fails, try to use the "http://"
url += "q=%s&" % urlencode(dork, convall=True)
url += "num=100&hl=en&complete=0&safe=off&filter=0&btnG=Search"
url += "&start=%d" % ((gpage - 1) * 100)
@@ -184,8 +186,8 @@ def _search(dork):
@stackedmethod
def search(dork):
pushValue(kb.redirectChoice)
kb.redirectChoice = REDIRECTION.YES
pushValue(kb.choices.redirect)
kb.choices.redirect = REDIRECTION.YES
try:
return _search(dork)
@@ -203,7 +205,7 @@ def search(dork):
else:
raise
finally:
kb.redirectChoice = popValue()
kb.choices.redirect = popValue()
def setHTTPHandlers(): # Cross-referenced function
raise NotImplementedError
+11 -2
View File
@@ -101,13 +101,22 @@ class SQLAlchemy(GenericConnector):
return None
def execute(self, query):
retVal = False
try:
self.cursor = self.connector.execute(query)
retVal = True
except (_sqlalchemy.exc.OperationalError, _sqlalchemy.exc.ProgrammingError) as ex:
logger.log(logging.WARN if conf.dbmsHandler else logging.DEBUG, "(remote) %s" % getSafeExString(ex))
except _sqlalchemy.exc.InternalError as ex:
raise SqlmapConnectionException(getSafeExString(ex))
return retVal
def select(self, query):
self.execute(query)
return self.fetchall()
retVal = None
if self.execute(query):
retVal = self.fetchall()
return retVal
+4 -3
View File
@@ -8,6 +8,7 @@ See the file 'LICENSE' for copying permission
import ntpath
import os
from lib.core.common import checkFile
from lib.core.common import getLimitRange
from lib.core.common import isNumPosStrValue
from lib.core.common import isTechniqueAvailable
@@ -384,13 +385,13 @@ class Filesystem(GenericFilesystem):
# procedure to write a file on the back-end Microsoft SQL Server
# file system
self.initEnv()
self.getRemoteTempPath()
tmpPath = posixToNtSlashes(conf.tmpPath)
remoteFile = posixToNtSlashes(remoteFile)
with open(localFile, "rb") as f:
localFileContent = f.read()
checkFile(localFile)
localFileContent = open(localFile, "rb").read()
self._stackedWriteFilePS(tmpPath, localFileContent, remoteFile, fileType)
written = self.askCheckWrittenFile(localFile, remoteFile, forceCheck)
+2 -1
View File
@@ -150,7 +150,8 @@ class Fingerprint(GenericFingerprint):
"Vista or 2008": ("6.0", (2, 1)),
"7 or 2008 R2": ("6.1", (1, 0)),
"8 or 2012": ("6.2", (0,)),
"8.1 or 2012 R2": ("6.3", (0,))
"8.1 or 2012 R2": ("6.3", (0,)),
"10 or 2016 or 2019": ("10.0", (0,))
}
# Get back-end DBMS underlying operating system version
+1 -1
View File
@@ -38,7 +38,7 @@ class Takeover(GenericTakeover):
banVer = kb.bannerFp["dbmsVersion"]
if distutils.version.LooseVersion(banVer) >= distutils.version.LooseVersion("5.0.67"):
if banVer and distutils.version.LooseVersion(banVer) >= distutils.version.LooseVersion("5.0.67"):
if self.__plugindir is None:
logger.info("retrieving MySQL plugin directory absolute path")
self.__plugindir = unArrayizeValue(inject.getValue("SELECT @@plugin_dir"))
+2
View File
@@ -39,6 +39,8 @@ class Fingerprint(GenericFingerprint):
fork = FORK.YELLOWBRICK
elif inject.checkBooleanExpression("VERSION() LIKE '%EnterpriseDB%'"): # Reference: https://www.enterprisedb.com/edb-docs/d/edb-postgres-advanced-server/user-guides/user-guide/11/EDB_Postgres_Advanced_Server_Guide.1.087.html
fork = FORK.ENTERPRISEDB
elif inject.checkBooleanExpression("VERSION() LIKE '%YB-%'"): # Reference: https://github.com/yugabyte/yugabyte-db/issues/2447#issue-499562926
fork = FORK.YUGABYTEDB
elif inject.checkBooleanExpression("AURORA_VERSION() LIKE '%'"): # Reference: https://aws.amazon.com/premiumsupport/knowledge-center/aurora-version-number/
fork = FORK.AURORA
else:
+4 -1
View File
@@ -51,7 +51,10 @@ class Takeover(GenericTakeover):
banVer = kb.bannerFp["dbmsVersion"]
if distutils.version.LooseVersion(banVer) >= distutils.version.LooseVersion("10"):
if not banVer:
errMsg = "unsupported feature on unknown version of PostgreSQL"
raise SqlmapUnsupportedFeatureException(errMsg)
elif distutils.version.LooseVersion(banVer) >= distutils.version.LooseVersion("10"):
majorVer = banVer.split('.')[0]
elif distutils.version.LooseVersion(banVer) >= distutils.version.LooseVersion("8.2") and '.' in banVer:
majorVer = '.'.join(banVer.split('.')[:2])

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