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

Skip to content

Commit 21e8182

Browse files
committed
Fixes #1305
1 parent a7c4400 commit 21e8182

6 files changed

Lines changed: 150 additions & 142 deletions

File tree

lib/controller/checks.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1249,10 +1249,10 @@ def checkNullConnection():
12491249
infoMsg = "testing NULL connection to the target URL"
12501250
logger.info(infoMsg)
12511251

1252-
pushValue(kb.pageCompress)
1253-
kb.pageCompress = False
1254-
12551252
try:
1253+
pushValue(kb.pageCompress)
1254+
kb.pageCompress = False
1255+
12561256
page, headers, _ = Request.getPage(method=HTTPMETHOD.HEAD)
12571257

12581258
if not page and HTTP_HEADER.CONTENT_LENGTH in (headers or {}):
@@ -1282,7 +1282,8 @@ def checkNullConnection():
12821282
errMsg = getUnicode(errMsg)
12831283
raise SqlmapConnectionException(errMsg)
12841284

1285-
kb.pageCompress = popValue()
1285+
finally:
1286+
kb.pageCompress = popValue()
12861287

12871288
return kb.nullConnection is not None
12881289

lib/controller/controller.py

Lines changed: 34 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -501,47 +501,49 @@ def start():
501501
kb.testedParams.add(paramKey)
502502

503503
if testSqlInj:
504-
if place == PLACE.COOKIE:
505-
pushValue(kb.mergeCookies)
506-
kb.mergeCookies = False
504+
try:
505+
if place == PLACE.COOKIE:
506+
pushValue(kb.mergeCookies)
507+
kb.mergeCookies = False
507508

508-
check = heuristicCheckSqlInjection(place, parameter)
509+
check = heuristicCheckSqlInjection(place, parameter)
509510

510-
if check != HEURISTIC_TEST.POSITIVE:
511-
if conf.smart or (kb.ignoreCasted and check == HEURISTIC_TEST.CASTED):
512-
infoMsg = "skipping %s parameter '%s'" % (paramType, parameter)
513-
logger.info(infoMsg)
514-
continue
511+
if check != HEURISTIC_TEST.POSITIVE:
512+
if conf.smart or (kb.ignoreCasted and check == HEURISTIC_TEST.CASTED):
513+
infoMsg = "skipping %s parameter '%s'" % (paramType, parameter)
514+
logger.info(infoMsg)
515+
continue
515516

516-
infoMsg = "testing for SQL injection on %s " % paramType
517-
infoMsg += "parameter '%s'" % parameter
518-
logger.info(infoMsg)
517+
infoMsg = "testing for SQL injection on %s " % paramType
518+
infoMsg += "parameter '%s'" % parameter
519+
logger.info(infoMsg)
519520

520-
injection = checkSqlInjection(place, parameter, value)
521-
proceed = not kb.endDetection
521+
injection = checkSqlInjection(place, parameter, value)
522+
proceed = not kb.endDetection
522523

523-
if injection is not None and injection.place is not None:
524-
kb.injections.append(injection)
524+
if injection is not None and injection.place is not None:
525+
kb.injections.append(injection)
525526

526-
# In case when user wants to end detection phase (Ctrl+C)
527-
if not proceed:
528-
break
527+
# In case when user wants to end detection phase (Ctrl+C)
528+
if not proceed:
529+
break
529530

530-
msg = "%s parameter '%s' " % (injection.place, injection.parameter)
531-
msg += "is vulnerable. Do you want to keep testing the others (if any)? [y/N] "
532-
test = readInput(msg, default="N")
531+
msg = "%s parameter '%s' " % (injection.place, injection.parameter)
532+
msg += "is vulnerable. Do you want to keep testing the others (if any)? [y/N] "
533+
test = readInput(msg, default="N")
533534

534-
if test[0] not in ("y", "Y"):
535-
proceed = False
536-
paramKey = (conf.hostname, conf.path, None, None)
537-
kb.testedParams.add(paramKey)
538-
else:
539-
warnMsg = "%s parameter '%s' is not " % (paramType, parameter)
540-
warnMsg += "injectable"
541-
logger.warn(warnMsg)
535+
if test[0] not in ("y", "Y"):
536+
proceed = False
537+
paramKey = (conf.hostname, conf.path, None, None)
538+
kb.testedParams.add(paramKey)
539+
else:
540+
warnMsg = "%s parameter '%s' is not " % (paramType, parameter)
541+
warnMsg += "injectable"
542+
logger.warn(warnMsg)
542543

543-
if place == PLACE.COOKIE:
544-
kb.mergeCookies = popValue()
544+
finally:
545+
if place == PLACE.COOKIE:
546+
kb.mergeCookies = popValue()
545547

546548
if len(kb.injections) == 0 or (len(kb.injections) == 1 and kb.injections[0].place is None):
547549
if kb.vainRun and not conf.multipleTargets:

lib/request/connect.py

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1030,23 +1030,24 @@ def _randomizeParameter(paramString, randomParameter):
10301030
if kb.nullConnection and not content and not response and not timeBasedCompare:
10311031
noteResponseTime = False
10321032

1033-
pushValue(kb.pageCompress)
1034-
kb.pageCompress = False
1035-
1036-
if kb.nullConnection == NULLCONNECTION.HEAD:
1037-
method = HTTPMETHOD.HEAD
1038-
elif kb.nullConnection == NULLCONNECTION.RANGE:
1039-
auxHeaders[HTTP_HEADER.RANGE] = "bytes=-1"
1033+
try:
1034+
pushValue(kb.pageCompress)
1035+
kb.pageCompress = False
10401036

1041-
_, headers, code = Connect.getPage(url=uri, get=get, post=post, method=method, cookie=cookie, ua=ua, referer=referer, host=host, silent=silent, auxHeaders=auxHeaders, raise404=raise404, skipRead=(kb.nullConnection == NULLCONNECTION.SKIP_READ))
1037+
if kb.nullConnection == NULLCONNECTION.HEAD:
1038+
method = HTTPMETHOD.HEAD
1039+
elif kb.nullConnection == NULLCONNECTION.RANGE:
1040+
auxHeaders[HTTP_HEADER.RANGE] = "bytes=-1"
10421041

1043-
if headers:
1044-
if kb.nullConnection in (NULLCONNECTION.HEAD, NULLCONNECTION.SKIP_READ) and HTTP_HEADER.CONTENT_LENGTH in headers:
1045-
pageLength = int(headers[HTTP_HEADER.CONTENT_LENGTH])
1046-
elif kb.nullConnection == NULLCONNECTION.RANGE and HTTP_HEADER.CONTENT_RANGE in headers:
1047-
pageLength = int(headers[HTTP_HEADER.CONTENT_RANGE][headers[HTTP_HEADER.CONTENT_RANGE].find('/') + 1:])
1042+
_, headers, code = Connect.getPage(url=uri, get=get, post=post, method=method, cookie=cookie, ua=ua, referer=referer, host=host, silent=silent, auxHeaders=auxHeaders, raise404=raise404, skipRead=(kb.nullConnection == NULLCONNECTION.SKIP_READ))
10481043

1049-
kb.pageCompress = popValue()
1044+
if headers:
1045+
if kb.nullConnection in (NULLCONNECTION.HEAD, NULLCONNECTION.SKIP_READ) and HTTP_HEADER.CONTENT_LENGTH in headers:
1046+
pageLength = int(headers[HTTP_HEADER.CONTENT_LENGTH])
1047+
elif kb.nullConnection == NULLCONNECTION.RANGE and HTTP_HEADER.CONTENT_RANGE in headers:
1048+
pageLength = int(headers[HTTP_HEADER.CONTENT_RANGE][headers[HTTP_HEADER.CONTENT_RANGE].find('/') + 1:])
1049+
finally:
1050+
kb.pageCompress = popValue()
10501051

10511052
if not pageLength:
10521053
try:

lib/request/inject.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -391,11 +391,13 @@ def getValue(expression, blind=True, union=True, error=True, time=True, fromUser
391391
warnMsg += ". Falling back to partial UNION technique"
392392
singleTimeWarnMessage(warnMsg)
393393

394-
pushValue(kb.forcePartialUnion)
395-
kb.forcePartialUnion = True
396-
value = _goUnion(query, unpack, dump)
397-
found = (value is not None) or (value is None and expectingNone)
398-
kb.forcePartialUnion = popValue()
394+
try:
395+
pushValue(kb.forcePartialUnion)
396+
kb.forcePartialUnion = True
397+
value = _goUnion(query, unpack, dump)
398+
found = (value is not None) or (value is None and expectingNone)
399+
finally:
400+
kb.forcePartialUnion = popValue()
399401
else:
400402
singleTimeWarnMessage(warnMsg)
401403

lib/techniques/union/test.py

Lines changed: 66 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -81,73 +81,74 @@ def _orderByTest(cols):
8181

8282
return found
8383

84-
pushValue(kb.errorIsNone)
85-
items, ratios = [], []
86-
kb.errorIsNone = False
87-
lowerCount, upperCount = conf.uColsStart, conf.uColsStop
88-
89-
if lowerCount == 1:
90-
found = kb.orderByColumns or _orderByTechnique()
91-
if found:
92-
kb.orderByColumns = found
93-
infoMsg = "target URL appears to have %d column%s in query" % (found, 's' if found > 1 else "")
94-
singleTimeLogMessage(infoMsg)
95-
return found
96-
97-
if abs(upperCount - lowerCount) < MIN_UNION_RESPONSES:
98-
upperCount = lowerCount + MIN_UNION_RESPONSES
99-
100-
min_, max_ = MAX_RATIO, MIN_RATIO
101-
pages = {}
84+
try:
85+
pushValue(kb.errorIsNone)
86+
items, ratios = [], []
87+
kb.errorIsNone = False
88+
lowerCount, upperCount = conf.uColsStart, conf.uColsStop
89+
90+
if lowerCount == 1:
91+
found = kb.orderByColumns or _orderByTechnique()
92+
if found:
93+
kb.orderByColumns = found
94+
infoMsg = "target URL appears to have %d column%s in query" % (found, 's' if found > 1 else "")
95+
singleTimeLogMessage(infoMsg)
96+
return found
97+
98+
if abs(upperCount - lowerCount) < MIN_UNION_RESPONSES:
99+
upperCount = lowerCount + MIN_UNION_RESPONSES
100+
101+
min_, max_ = MAX_RATIO, MIN_RATIO
102+
pages = {}
103+
104+
for count in xrange(lowerCount, upperCount + 1):
105+
query = agent.forgeUnionQuery('', -1, count, comment, prefix, suffix, kb.uChar, where)
106+
payload = agent.payload(place=place, parameter=parameter, newValue=query, where=where)
107+
page, headers = Request.queryPage(payload, place=place, content=True, raise404=False)
108+
if not isNullValue(kb.uChar):
109+
pages[count] = page
110+
ratio = comparison(page, headers, getRatioValue=True) or MIN_RATIO
111+
ratios.append(ratio)
112+
min_, max_ = min(min_, ratio), max(max_, ratio)
113+
items.append((count, ratio))
102114

103-
for count in xrange(lowerCount, upperCount + 1):
104-
query = agent.forgeUnionQuery('', -1, count, comment, prefix, suffix, kb.uChar, where)
105-
payload = agent.payload(place=place, parameter=parameter, newValue=query, where=where)
106-
page, headers = Request.queryPage(payload, place=place, content=True, raise404=False)
107115
if not isNullValue(kb.uChar):
108-
pages[count] = page
109-
ratio = comparison(page, headers, getRatioValue=True) or MIN_RATIO
110-
ratios.append(ratio)
111-
min_, max_ = min(min_, ratio), max(max_, ratio)
112-
items.append((count, ratio))
113-
114-
if not isNullValue(kb.uChar):
115-
for regex in (kb.uChar, r'>\s*%s\s*<' % kb.uChar):
116-
contains = [(count, re.search(regex, page or "", re.IGNORECASE) is not None) for count, page in pages.items()]
117-
if len(filter(lambda x: x[1], contains)) == 1:
118-
retVal = filter(lambda x: x[1], contains)[0][0]
119-
break
120-
121-
if not retVal:
122-
ratios.pop(ratios.index(min_))
123-
ratios.pop(ratios.index(max_))
124-
125-
minItem, maxItem = None, None
126-
127-
for item in items:
128-
if item[1] == min_:
129-
minItem = item
130-
elif item[1] == max_:
131-
maxItem = item
132-
133-
if all(map(lambda x: x == min_ and x != max_, ratios)):
134-
retVal = maxItem[0]
135-
136-
elif all(map(lambda x: x != min_ and x == max_, ratios)):
137-
retVal = minItem[0]
138-
139-
elif abs(max_ - min_) >= MIN_STATISTICAL_RANGE:
140-
deviation = stdev(ratios)
141-
lower, upper = average(ratios) - UNION_STDEV_COEFF * deviation, average(ratios) + UNION_STDEV_COEFF * deviation
142-
143-
if min_ < lower:
144-
retVal = minItem[0]
145-
146-
if max_ > upper:
147-
if retVal is None or abs(max_ - upper) > abs(min_ - lower):
148-
retVal = maxItem[0]
149-
150-
kb.errorIsNone = popValue()
116+
for regex in (kb.uChar, r'>\s*%s\s*<' % kb.uChar):
117+
contains = [(count, re.search(regex, page or "", re.IGNORECASE) is not None) for count, page in pages.items()]
118+
if len(filter(lambda x: x[1], contains)) == 1:
119+
retVal = filter(lambda x: x[1], contains)[0][0]
120+
break
121+
122+
if not retVal:
123+
ratios.pop(ratios.index(min_))
124+
ratios.pop(ratios.index(max_))
125+
126+
minItem, maxItem = None, None
127+
128+
for item in items:
129+
if item[1] == min_:
130+
minItem = item
131+
elif item[1] == max_:
132+
maxItem = item
133+
134+
if all(map(lambda x: x == min_ and x != max_, ratios)):
135+
retVal = maxItem[0]
136+
137+
elif all(map(lambda x: x != min_ and x == max_, ratios)):
138+
retVal = minItem[0]
139+
140+
elif abs(max_ - min_) >= MIN_STATISTICAL_RANGE:
141+
deviation = stdev(ratios)
142+
lower, upper = average(ratios) - UNION_STDEV_COEFF * deviation, average(ratios) + UNION_STDEV_COEFF * deviation
143+
144+
if min_ < lower:
145+
retVal = minItem[0]
146+
147+
if max_ > upper:
148+
if retVal is None or abs(max_ - upper) > abs(min_ - lower):
149+
retVal = maxItem[0]
150+
finally:
151+
kb.errorIsNone = popValue()
151152

152153
if retVal:
153154
infoMsg = "target URL appears to be UNION injectable with %d columns" % retVal

plugins/generic/databases.py

Lines changed: 23 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -742,32 +742,33 @@ def getSchema(self):
742742
infoMsg = "enumerating database management system schema"
743743
logger.info(infoMsg)
744744

745-
pushValue(conf.db)
746-
pushValue(conf.tbl)
747-
pushValue(conf.col)
745+
try:
746+
pushValue(conf.db)
747+
pushValue(conf.tbl)
748+
pushValue(conf.col)
748749

749-
kb.data.cachedTables = {}
750-
kb.data.cachedColumns = {}
751-
752-
self.getTables()
753-
754-
infoMsg = "fetched tables: "
755-
infoMsg += ", ".join(["%s" % ", ".join("%s%s%s" % (unsafeSQLIdentificatorNaming(db), ".." if \
756-
Backend.isDbms(DBMS.MSSQL) or Backend.isDbms(DBMS.SYBASE) \
757-
else ".", unsafeSQLIdentificatorNaming(t)) for t in tbl) for db, tbl in \
758-
kb.data.cachedTables.items()])
759-
logger.info(infoMsg)
750+
kb.data.cachedTables = {}
751+
kb.data.cachedColumns = {}
760752

761-
for db, tables in kb.data.cachedTables.items():
762-
for tbl in tables:
763-
conf.db = db
764-
conf.tbl = tbl
753+
self.getTables()
765754

766-
self.getColumns()
755+
infoMsg = "fetched tables: "
756+
infoMsg += ", ".join(["%s" % ", ".join("%s%s%s" % (unsafeSQLIdentificatorNaming(db), ".." if \
757+
Backend.isDbms(DBMS.MSSQL) or Backend.isDbms(DBMS.SYBASE) \
758+
else ".", unsafeSQLIdentificatorNaming(t)) for t in tbl) for db, tbl in \
759+
kb.data.cachedTables.items()])
760+
logger.info(infoMsg)
767761

768-
conf.col = popValue()
769-
conf.tbl = popValue()
770-
conf.db = popValue()
762+
for db, tables in kb.data.cachedTables.items():
763+
for tbl in tables:
764+
conf.db = db
765+
conf.tbl = tbl
766+
767+
self.getColumns()
768+
finally:
769+
conf.col = popValue()
770+
conf.tbl = popValue()
771+
conf.db = popValue()
771772

772773
return kb.data.cachedColumns
773774

0 commit comments

Comments
 (0)