mirror of
https://github.com/sqlmapproject/sqlmap.git
synced 2025-12-07 21:21:33 +00:00
Compare commits
78 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
eeacab0f19 | ||
|
|
b3e454d0b1 | ||
|
|
99d0031d65 | ||
|
|
5916bc2d39 | ||
|
|
2159944de4 | ||
|
|
f87aa83e9b | ||
|
|
b902cca791 | ||
|
|
86467e196b | ||
|
|
30f137699d | ||
|
|
7741154383 | ||
|
|
a6262a3aa9 | ||
|
|
1f33b16e01 | ||
|
|
04396c97e2 | ||
|
|
b1cdbdae61 | ||
|
|
747951b80b | ||
|
|
1bef2f8fda | ||
|
|
b0ac442096 | ||
|
|
99a5fb243c | ||
|
|
b2a575482e | ||
|
|
365e08b710 | ||
|
|
af3b79ff8b | ||
|
|
3724a53466 | ||
|
|
01e83cb4a0 | ||
|
|
cd77cdd1e8 | ||
|
|
22c421a427 | ||
|
|
59fe89f076 | ||
|
|
160011bd87 | ||
|
|
36ee4d68c7 | ||
|
|
dfc5bc5d87 | ||
|
|
d247fda9d3 | ||
|
|
78b1c4f072 | ||
|
|
63e44f9ee9 | ||
|
|
08349138ec | ||
|
|
807d38688f | ||
|
|
0975fb1226 | ||
|
|
71c141ef86 | ||
|
|
accfbf958e | ||
|
|
c0be1da8b1 | ||
|
|
4a12493d85 | ||
|
|
b2c8ba10cd | ||
|
|
9568ee3c4d | ||
|
|
f3e8039145 | ||
|
|
e5086ef61a | ||
|
|
ed0909fe57 | ||
|
|
6244850749 | ||
|
|
d78590213b | ||
|
|
4490d55482 | ||
|
|
fd137b49ef | ||
|
|
6fa5922fbd | ||
|
|
42884d3f09 | ||
|
|
1a0c533626 | ||
|
|
5d3bd6ea7a | ||
|
|
29a7646334 | ||
|
|
fa93f5e099 | ||
|
|
12238019dd | ||
|
|
0b1b64b682 | ||
|
|
c8dc375fb5 | ||
|
|
a697e6c307 | ||
|
|
66a3118f81 | ||
|
|
3002f92e34 | ||
|
|
2ef07c80db | ||
|
|
e3028f195e | ||
|
|
1f39dbd06d | ||
|
|
ccf9e7de54 | ||
|
|
ebd2a940cb | ||
|
|
0d3889730d | ||
|
|
ccbc3e62f8 | ||
|
|
f84ec1072b | ||
|
|
779b352f6b | ||
|
|
9af2e68b7e | ||
|
|
bd59dd4a0f | ||
|
|
c4e6c3e854 | ||
|
|
91045aab60 | ||
|
|
b36d8248a4 | ||
|
|
091678b9d4 | ||
|
|
0c3d8c9bd1 | ||
|
|
f5b6b0eb4b | ||
|
|
e8048a3cf0 |
@@ -1,6 +1,6 @@
|
||||
# sqlmap 
|
||||
|
||||
[](https://travis-ci.org/sqlmapproject/sqlmap) [](https://www.python.org/) [](https://raw.githubusercontent.com/sqlmapproject/sqlmap/master/LICENSE) [](https://badge.fury.io/py/sqlmap) [](https://github.com/sqlmapproject/sqlmap/issues?q=is%3Aissue+is%3Aclosed) [](https://twitter.com/sqlmap)
|
||||
[](https://travis-ci.org/sqlmapproject/sqlmap) [](https://www.python.org/) [](https://raw.githubusercontent.com/sqlmapproject/sqlmap/master/LICENSE) [](https://github.com/sqlmapproject/sqlmap/issues?q=is%3Aissue+is%3Aclosed) [](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.
@@ -485,6 +485,8 @@ llave
|
||||
chaveta
|
||||
tono
|
||||
cuna
|
||||
correo
|
||||
contrasenia
|
||||
|
||||
# german
|
||||
|
||||
|
||||
@@ -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.
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.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
data/udf/postgresql/linux/64/12/lib_postgresqludf_sys.so_
Normal file
BIN
data/udf/postgresql/linux/64/12/lib_postgresqludf_sys.so_
Normal file
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.
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.
@@ -42,7 +42,7 @@
|
||||
<error regexp="\bSQL Server[^<"]+Driver"/>
|
||||
<error regexp="Warning.*?\W(mssql|sqlsrv)_"/>
|
||||
<error regexp="\bSQL Server[^<"]+[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>
|
||||
|
||||
@@ -1626,4 +1626,94 @@
|
||||
<blind query="SELECT "schema_name" 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 "table_name" 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 "schema_name"='%s'" count="SELECT COUNT("schema_name") 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("table_name") 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 "schema_name"='%s'" condition=""column_name"" condition2=""schema_name"" condition3=""table_name""/>
|
||||
</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>
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
doc/translations/README-vi-VN.md
Normal file
53
doc/translations/README-vi-VN.md
Normal file
@@ -0,0 +1,53 @@
|
||||
# sqlmap 
|
||||
|
||||
[](https://travis-ci.org/sqlmapproject/sqlmap) [](https://www.python.org/) [](https://raw.githubusercontent.com/sqlmapproject/sqlmap/master/LICENSE) [](https://badge.fury.io/py/sqlmap) [](https://github.com/sqlmapproject/sqlmap/issues?q=is%3Aissue+is%3Aclosed) [](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
|
||||
----
|
||||
|
||||

|
||||
|
||||
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
|
||||
@@ -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.
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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])
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -25,6 +25,8 @@ def cachedmethod(f):
|
||||
>>> __ = cachedmethod(lambda _: _)
|
||||
>>> __(1)
|
||||
1
|
||||
>>> __(1)
|
||||
1
|
||||
>>> __ = cachedmethod(lambda *args, **kwargs: args[0])
|
||||
>>> __(2)
|
||||
2
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -166,7 +166,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)
|
||||
@@ -243,7 +243,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 +298,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 +353,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 +479,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 = []
|
||||
|
||||
@@ -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
|
||||
@@ -434,3 +439,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"
|
||||
|
||||
@@ -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 = []
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -154,6 +153,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 +415,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)
|
||||
|
||||
@@ -1916,7 +1916,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):
|
||||
@@ -2013,12 +2013,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 +2120,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 +2139,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 +2477,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,6 +2544,11 @@ 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)
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -18,7 +18,7 @@ from lib.core.enums import OS
|
||||
from thirdparty.six import unichr as _unichr
|
||||
|
||||
# sqlmap version (<major>.<minor>.<month>.<monthly commit>)
|
||||
VERSION = "1.5"
|
||||
VERSION = "1.5.3.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)
|
||||
@@ -282,20 +282,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", "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")
|
||||
INFORMIX_ALIASES = ("informix", "ibm informix", "ibminformix")
|
||||
MONETDB_ALIASES = ("monet", "monetdb",)
|
||||
DERBY_ALIASES = ("derby", "apache derby",)
|
||||
@@ -306,16 +308,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 +401,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 +494,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
|
||||
@@ -757,6 +761,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 +815,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
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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=\"<tmdir>\"--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 <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=<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 <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,25 +118,32 @@ 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:
|
||||
handle, tmp = tempfile.mkstemp()
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 SQLi/XSS/FI vulnerabilities")
|
||||
|
||||
general.add_argument("--skip-waf", dest="skipWaf", action="store_true",
|
||||
help="Skip heuristic detection of WAF/IPS protection")
|
||||
@@ -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)
|
||||
|
||||
@@ -891,7 +900,7 @@ def cmdLineParser(argv=None):
|
||||
|
||||
raise SqlmapSilentQuitException
|
||||
|
||||
elif "--sqlmap-shell" in argv:
|
||||
elif "--shell" in argv:
|
||||
_createHomeDirectories()
|
||||
|
||||
parser.usage = ""
|
||||
@@ -904,14 +913,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 +933,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)
|
||||
@@ -1054,7 +1067,7 @@ def cmdLineParser(argv=None):
|
||||
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). "
|
||||
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 +1078,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
|
||||
|
||||
@@ -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"))
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -145,6 +147,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 +188,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 +241,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 +252,9 @@ class Connect(object):
|
||||
singleTimeWarnMessage(warnMsg)
|
||||
break
|
||||
|
||||
if conf.yuge:
|
||||
retVal = 100 * retVal
|
||||
|
||||
return retVal
|
||||
|
||||
@staticmethod
|
||||
@@ -475,6 +491,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 +504,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 +547,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 +616,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 +753,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 "
|
||||
@@ -831,13 +852,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 +1033,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:
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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")
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -637,13 +637,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)
|
||||
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -184,8 +184,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 +203,7 @@ def search(dork):
|
||||
else:
|
||||
raise
|
||||
finally:
|
||||
kb.redirectChoice = popValue()
|
||||
kb.choices.redirect = popValue()
|
||||
|
||||
def setHTTPHandlers(): # Cross-referenced function
|
||||
raise NotImplementedError
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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"))
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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])
|
||||
|
||||
29
plugins/dbms/raima/__init__.py
Normal file
29
plugins/dbms/raima/__init__.py
Normal file
@@ -0,0 +1,29 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
Copyright (c) 2006-2021 sqlmap developers (http://sqlmap.org/)
|
||||
See the file 'LICENSE' for copying permission
|
||||
"""
|
||||
|
||||
from lib.core.enums import DBMS
|
||||
from lib.core.settings import RAIMA_SYSTEM_DBS
|
||||
from lib.core.unescaper import unescaper
|
||||
from plugins.dbms.raima.enumeration import Enumeration
|
||||
from plugins.dbms.raima.filesystem import Filesystem
|
||||
from plugins.dbms.raima.fingerprint import Fingerprint
|
||||
from plugins.dbms.raima.syntax import Syntax
|
||||
from plugins.dbms.raima.takeover import Takeover
|
||||
from plugins.generic.misc import Miscellaneous
|
||||
|
||||
class RaimaMap(Syntax, Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
|
||||
"""
|
||||
This class defines Raima methods
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self.excludeDbsList = RAIMA_SYSTEM_DBS
|
||||
|
||||
for cls in self.__class__.__bases__:
|
||||
cls.__init__(self)
|
||||
|
||||
unescaper[DBMS.RAIMA] = Syntax.escape
|
||||
15
plugins/dbms/raima/connector.py
Normal file
15
plugins/dbms/raima/connector.py
Normal file
@@ -0,0 +1,15 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
Copyright (c) 2006-2021 sqlmap developers (http://sqlmap.org/)
|
||||
See the file 'LICENSE' for copying permission
|
||||
"""
|
||||
|
||||
from lib.core.exception import SqlmapUnsupportedFeatureException
|
||||
from plugins.generic.connector import Connector as GenericConnector
|
||||
|
||||
class Connector(GenericConnector):
|
||||
def connect(self):
|
||||
errMsg = "on Raima Database Manager it is not (currently) possible to establish a "
|
||||
errMsg += "direct connection"
|
||||
raise SqlmapUnsupportedFeatureException(errMsg)
|
||||
84
plugins/dbms/raima/enumeration.py
Normal file
84
plugins/dbms/raima/enumeration.py
Normal file
@@ -0,0 +1,84 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
Copyright (c) 2006-2021 sqlmap developers (http://sqlmap.org/)
|
||||
See the file 'LICENSE' for copying permission
|
||||
"""
|
||||
|
||||
from lib.core.data import logger
|
||||
from plugins.generic.enumeration import Enumeration as GenericEnumeration
|
||||
|
||||
class Enumeration(GenericEnumeration):
|
||||
def getBanner(self):
|
||||
warnMsg = "on Raima Database Manager it is not possible to get the banner"
|
||||
logger.warn(warnMsg)
|
||||
|
||||
return None
|
||||
|
||||
def getCurrentUser(self):
|
||||
warnMsg = "on Raima Database Manager it is not possible to enumerate the current user"
|
||||
logger.warn(warnMsg)
|
||||
|
||||
def getCurrentDb(self):
|
||||
warnMsg = "on Raima Database Manager it is not possible to get name of the current database"
|
||||
logger.warn(warnMsg)
|
||||
|
||||
def isDba(self, user=None):
|
||||
warnMsg = "on Raima Database Manager it is not possible to test if current user is DBA"
|
||||
logger.warn(warnMsg)
|
||||
|
||||
def getUsers(self):
|
||||
warnMsg = "on Raima Database Manager it is not possible to enumerate the users"
|
||||
logger.warn(warnMsg)
|
||||
|
||||
return []
|
||||
|
||||
def getPasswordHashes(self):
|
||||
warnMsg = "on Raima Database Manager it is not possible to enumerate the user password hashes"
|
||||
logger.warn(warnMsg)
|
||||
|
||||
return {}
|
||||
|
||||
def getPrivileges(self, *args, **kwargs):
|
||||
warnMsg = "on Raima Database Manager it is not possible to enumerate the user privileges"
|
||||
logger.warn(warnMsg)
|
||||
|
||||
return {}
|
||||
|
||||
def getDbs(self):
|
||||
warnMsg = "on Raima Database Manager it is not possible to enumerate databases (use only '--tables')"
|
||||
logger.warn(warnMsg)
|
||||
|
||||
return []
|
||||
|
||||
def searchDb(self):
|
||||
warnMsg = "on Raima Database Manager it is not possible to search databases"
|
||||
logger.warn(warnMsg)
|
||||
|
||||
return []
|
||||
|
||||
def searchTable(self):
|
||||
warnMsg = "on Raima Database Manager it is not possible to search tables"
|
||||
logger.warn(warnMsg)
|
||||
|
||||
return []
|
||||
|
||||
def searchColumn(self):
|
||||
warnMsg = "on Raima Database Manager it is not possible to search columns"
|
||||
logger.warn(warnMsg)
|
||||
|
||||
return []
|
||||
|
||||
def search(self):
|
||||
warnMsg = "on Raima Database Manager search option is not available"
|
||||
logger.warn(warnMsg)
|
||||
|
||||
def getHostname(self):
|
||||
warnMsg = "on Raima Database Manager it is not possible to enumerate the hostname"
|
||||
logger.warn(warnMsg)
|
||||
|
||||
def getStatements(self):
|
||||
warnMsg = "on Raima Database Manager it is not possible to enumerate the SQL statements"
|
||||
logger.warn(warnMsg)
|
||||
|
||||
return []
|
||||
18
plugins/dbms/raima/filesystem.py
Normal file
18
plugins/dbms/raima/filesystem.py
Normal file
@@ -0,0 +1,18 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
Copyright (c) 2006-2021 sqlmap developers (http://sqlmap.org/)
|
||||
See the file 'LICENSE' for copying permission
|
||||
"""
|
||||
|
||||
from lib.core.exception import SqlmapUnsupportedFeatureException
|
||||
from plugins.generic.filesystem import Filesystem as GenericFilesystem
|
||||
|
||||
class Filesystem(GenericFilesystem):
|
||||
def readFile(self, remoteFile):
|
||||
errMsg = "on Raima Database Manager it is not possible to read files"
|
||||
raise SqlmapUnsupportedFeatureException(errMsg)
|
||||
|
||||
def writeFile(self, localFile, remoteFile, fileType=None, forceCheck=False):
|
||||
errMsg = "on Raima Database Manager it is not possible to write files"
|
||||
raise SqlmapUnsupportedFeatureException(errMsg)
|
||||
93
plugins/dbms/raima/fingerprint.py
Normal file
93
plugins/dbms/raima/fingerprint.py
Normal file
@@ -0,0 +1,93 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
Copyright (c) 2006-2021 sqlmap developers (http://sqlmap.org/)
|
||||
See the file 'LICENSE' for copying permission
|
||||
"""
|
||||
|
||||
from lib.core.common import Backend
|
||||
from lib.core.common import Format
|
||||
from lib.core.data import conf
|
||||
from lib.core.data import kb
|
||||
from lib.core.data import logger
|
||||
from lib.core.enums import DBMS
|
||||
from lib.core.session import setDbms
|
||||
from lib.core.settings import METADB_SUFFIX
|
||||
from lib.core.settings import RAIMA_ALIASES
|
||||
from lib.request import inject
|
||||
from plugins.generic.fingerprint import Fingerprint as GenericFingerprint
|
||||
|
||||
class Fingerprint(GenericFingerprint):
|
||||
def __init__(self):
|
||||
GenericFingerprint.__init__(self, DBMS.RAIMA)
|
||||
|
||||
def getFingerprint(self):
|
||||
value = ""
|
||||
wsOsFp = Format.getOs("web server", kb.headersFp)
|
||||
|
||||
if wsOsFp:
|
||||
value += "%s\n" % wsOsFp
|
||||
|
||||
if kb.data.banner:
|
||||
dbmsOsFp = Format.getOs("back-end DBMS", kb.bannerFp)
|
||||
|
||||
if dbmsOsFp:
|
||||
value += "%s\n" % dbmsOsFp
|
||||
|
||||
value += "back-end DBMS: "
|
||||
|
||||
if not conf.extensiveFp:
|
||||
value += DBMS.RAIMA
|
||||
return value
|
||||
|
||||
actVer = Format.getDbms()
|
||||
blank = " " * 15
|
||||
value += "active fingerprint: %s" % actVer
|
||||
|
||||
if kb.bannerFp:
|
||||
banVer = kb.bannerFp.get("dbmsVersion")
|
||||
|
||||
if banVer:
|
||||
banVer = Format.getDbms([banVer])
|
||||
value += "\n%sbanner parsing fingerprint: %s" % (blank, banVer)
|
||||
|
||||
htmlErrorFp = Format.getErrorParsedDBMSes()
|
||||
|
||||
if htmlErrorFp:
|
||||
value += "\n%shtml error message fingerprint: %s" % (blank, htmlErrorFp)
|
||||
|
||||
return value
|
||||
|
||||
def checkDbms(self):
|
||||
if not conf.extensiveFp and Backend.isDbmsWithin(RAIMA_ALIASES):
|
||||
setDbms(DBMS.RAIMA)
|
||||
return True
|
||||
|
||||
infoMsg = "testing %s" % DBMS.RAIMA
|
||||
logger.info(infoMsg)
|
||||
|
||||
result = inject.checkBooleanExpression("ROWNUMBER()=ROWNUMBER()")
|
||||
|
||||
if result:
|
||||
infoMsg = "confirming %s" % DBMS.RAIMA
|
||||
logger.info(infoMsg)
|
||||
|
||||
result = inject.checkBooleanExpression("INSSTR('[RANDSTR1]',0,0,'[RANDSTR2]') IS NOT NULL")
|
||||
|
||||
if not result:
|
||||
warnMsg = "the back-end DBMS is not %s" % DBMS.RAIMA
|
||||
logger.warn(warnMsg)
|
||||
|
||||
return False
|
||||
|
||||
setDbms(DBMS.RAIMA)
|
||||
|
||||
return True
|
||||
else:
|
||||
warnMsg = "the back-end DBMS is not %s" % DBMS.RAIMA
|
||||
logger.warn(warnMsg)
|
||||
|
||||
return False
|
||||
|
||||
def forceDbmsEnum(self):
|
||||
conf.db = ("%s%s" % (DBMS.RAIMA, METADB_SUFFIX)).replace(' ', '_')
|
||||
22
plugins/dbms/raima/syntax.py
Normal file
22
plugins/dbms/raima/syntax.py
Normal file
@@ -0,0 +1,22 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
Copyright (c) 2006-2021 sqlmap developers (http://sqlmap.org/)
|
||||
See the file 'LICENSE' for copying permission
|
||||
"""
|
||||
|
||||
from lib.core.convert import getOrds
|
||||
from plugins.generic.syntax import Syntax as GenericSyntax
|
||||
|
||||
class Syntax(GenericSyntax):
|
||||
@staticmethod
|
||||
def escape(expression, quote=True):
|
||||
"""
|
||||
>>> Syntax.escape("SELECT 'abcdefgh' FROM foobar") == "SELECT CHAR(97)||CHAR(98)||CHAR(99)||CHAR(100)||CHAR(101)||CHAR(102)||CHAR(103)||CHAR(104) FROM foobar"
|
||||
True
|
||||
"""
|
||||
|
||||
def escaper(value):
|
||||
return "||".join("CHAR(%d)" % _ for _ in getOrds(value))
|
||||
|
||||
return Syntax._escape(expression, quote, escaper)
|
||||
28
plugins/dbms/raima/takeover.py
Normal file
28
plugins/dbms/raima/takeover.py
Normal file
@@ -0,0 +1,28 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
Copyright (c) 2006-2021 sqlmap developers (http://sqlmap.org/)
|
||||
See the file 'LICENSE' for copying permission
|
||||
"""
|
||||
|
||||
from lib.core.exception import SqlmapUnsupportedFeatureException
|
||||
from plugins.generic.takeover import Takeover as GenericTakeover
|
||||
|
||||
class Takeover(GenericTakeover):
|
||||
def osCmd(self):
|
||||
errMsg = "on Raima Database Manager it is not possible to execute commands"
|
||||
raise SqlmapUnsupportedFeatureException(errMsg)
|
||||
|
||||
def osShell(self):
|
||||
errMsg = "on Raima Database Manager it is not possible to execute commands"
|
||||
raise SqlmapUnsupportedFeatureException(errMsg)
|
||||
|
||||
def osPwn(self):
|
||||
errMsg = "on Raima Database Manager it is not possible to establish an "
|
||||
errMsg += "out-of-band connection"
|
||||
raise SqlmapUnsupportedFeatureException(errMsg)
|
||||
|
||||
def osSmb(self):
|
||||
errMsg = "on Raima Database Manager it is not possible to establish an "
|
||||
errMsg += "out-of-band connection"
|
||||
raise SqlmapUnsupportedFeatureException(errMsg)
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user