Skip to content

Commit 87237c8

Browse files
committed
1 parent 340e250 commit 87237c8

9 files changed

Lines changed: 70 additions & 77 deletions

File tree

lib/core/common.py

Lines changed: 28 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@
9898
from lib.core.exception import SqlmapValueException
9999
from lib.core.log import LOGGER_HANDLER
100100
from lib.core.optiondict import optDict
101-
from lib.core.settings import BANNER, CHUNKED_KEYWORDS
101+
from lib.core.settings import BANNER
102102
from lib.core.settings import BOLD_PATTERNS
103103
from lib.core.settings import BOUNDED_INJECTION_MARKER
104104
from lib.core.settings import BRUTE_DOC_ROOT_PREFIXES
@@ -126,6 +126,7 @@
126126
from lib.core.settings import GOOGLE_ANALYTICS_COOKIE_PREFIX
127127
from lib.core.settings import HASHDB_MILESTONE_VALUE
128128
from lib.core.settings import HOST_ALIASES
129+
from lib.core.settings import HTTP_CHUNKED_SPLIT_KEYWORDS
129130
from lib.core.settings import IGNORE_SAVE_OPTIONS
130131
from lib.core.settings import INFERENCE_UNKNOWN_CHAR
131132
from lib.core.settings import INVALID_UNICODE_CHAR_FORMAT
@@ -4896,49 +4897,35 @@ def firstNotNone(*args):
48964897

48974898
return retVal
48984899

4899-
def generateChunkDdata(data):
4900+
def chunkSplitPostData(data):
4901+
"""
4902+
Convert POST data to chunked transfer-encoded data (Note: splitting done by SQL keywords)
49004903
"""
4901-
Convert post data to chunked format data. If the keyword is in a block, the keyword will be cut.
49024904

4903-
>>> generateChunkDdata('select 1,2,3,4 from admin')
4904-
4;AZdYz
4905-
sele
4906-
2;fJS4D
4907-
ct
4908-
5;qbCOT
4909-
1,2,
4910-
7;KItpi
4911-
3,4 fro
4912-
2;pFu1R
4913-
m
4914-
5;uRoYZ
4915-
admin
4916-
0
4905+
length = len(data)
4906+
retVal = ""
4907+
index = 0
49174908

4909+
while index < length:
4910+
chunkSize = randomInt(1)
49184911

4919-
"""
4920-
dl = len(data)
4921-
ret = ""
4922-
keywords = CHUNKED_KEYWORDS
4923-
index = 0
4924-
while index < dl:
4925-
chunk_size = random.randint(1, 9)
4926-
if index + chunk_size >= dl:
4927-
chunk_size = dl - index
4928-
salt = ''.join(random.sample(string.ascii_letters + string.digits, 5))
4929-
while 1:
4930-
tmp_chunk = data[index:index + chunk_size]
4931-
tmp_bool = True
4932-
for k in keywords:
4933-
if k in tmp_chunk:
4934-
chunk_size -= 1
4935-
tmp_bool = False
4936-
break
4937-
if tmp_bool:
4912+
if index + chunkSize >= length:
4913+
chunkSize = length - index
4914+
4915+
salt = randomStr(5, alphabet=string.ascii_letters + string.digits)
4916+
4917+
while chunkSize:
4918+
candidate = data[index:index + chunkSize]
4919+
4920+
if re.search(r"\b%s\b" % '|'.join(HTTP_CHUNKED_SPLIT_KEYWORDS), candidate, re.I):
4921+
chunkSize -= 1
4922+
else:
49384923
break
4939-
index += chunk_size
4940-
ret += "%s;%s\r\n" % (hex(chunk_size)[2:], salt)
4941-
ret += "%s\r\n" % tmp_chunk
49424924

4943-
ret += "0\r\n\r\n"
4944-
return ret
4925+
index += chunkSize
4926+
retVal += "%x;%s\r\n" % (chunkSize, salt)
4927+
retVal += "%s\r\n" % candidate
4928+
4929+
retVal += "0\r\n\r\n"
4930+
4931+
return retVal

lib/core/option.py

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@
140140
from lib.request.connect import Connect as Request
141141
from lib.request.dns import DNSServer
142142
from lib.request.basicauthhandler import SmartHTTPBasicAuthHandler
143-
from lib.request.httphandler import HTTPHandler
143+
from lib.request.chunkedhandler import ChunkedHandler
144144
from lib.request.httpshandler import HTTPSHandler
145145
from lib.request.pkihandler import HTTPSPKIAuthHandler
146146
from lib.request.rangehandler import HTTPRangeHandler
@@ -158,7 +158,7 @@
158158
from xml.etree.ElementTree import ElementTree
159159

160160
authHandler = urllib2.BaseHandler()
161-
httpHandler = HTTPHandler()
161+
chunkedHandler = ChunkedHandler()
162162
httpsHandler = HTTPSHandler()
163163
keepAliveHandler = keepalive.HTTPHandler()
164164
proxyHandler = urllib2.ProxyHandler()
@@ -1109,7 +1109,7 @@ def _setHTTPHandlers():
11091109
debugMsg = "creating HTTP requests opener object"
11101110
logger.debug(debugMsg)
11111111

1112-
handlers = filter(None, [multipartPostHandler, proxyHandler if proxyHandler.proxies else None, authHandler, redirectHandler, rangeHandler, httpHandler, httpsHandler])
1112+
handlers = filter(None, [multipartPostHandler, proxyHandler if proxyHandler.proxies else None, authHandler, redirectHandler, rangeHandler, chunkedHandler if conf.chunked else None, httpsHandler])
11131113

11141114
if not conf.dropSetCookie:
11151115
if not conf.loadCookies:
@@ -2314,6 +2314,10 @@ def _setTorSocksProxySettings():
23142314
socks.setdefaultproxy(socks.PROXY_TYPE_SOCKS5 if conf.torType == PROXY_TYPE.SOCKS5 else socks.PROXY_TYPE_SOCKS4, LOCALHOST, port)
23152315
socks.wrapmodule(urllib2)
23162316

2317+
def _setHttpChunked():
2318+
if conf.chunked and conf.data:
2319+
httplib.HTTPConnection._set_content_length = lambda self, a, b: None
2320+
23172321
def _checkWebSocket():
23182322
if conf.url and (conf.url.startswith("ws:/") or conf.url.startswith("wss:/")):
23192323
try:
@@ -2401,6 +2405,10 @@ def _basicOptionValidation():
24012405
errMsg = "switch '--dump' is incompatible with switch '--search'"
24022406
raise SqlmapSyntaxException(errMsg)
24032407

2408+
if conf.chunked and not any((conf.data, conf.requestFile)):
2409+
errMsg = "switch '--chunked' requires usage of option '--data' or '-r'"
2410+
raise SqlmapSyntaxException(errMsg)
2411+
24042412
if conf.api and not conf.configFile:
24052413
errMsg = "switch '--api' requires usage of option '-c'"
24062414
raise SqlmapSyntaxException(errMsg)
@@ -2605,15 +2613,6 @@ def initOptions(inputOptions=AttribDict(), overrideOptions=False):
26052613
_setKnowledgeBaseAttributes()
26062614
_mergeOptions(inputOptions, overrideOptions)
26072615

2608-
def _setHttpChunked():
2609-
conf.chunk = conf.chunk and conf.data
2610-
if conf.chunk:
2611-
def hook(self, a, b):
2612-
pass
2613-
2614-
httplib.HTTPConnection._set_content_length = hook
2615-
2616-
26172616
def init():
26182617
"""
26192618
Set attributes into both configuration and knowledge base singletons
@@ -2639,11 +2638,11 @@ def init():
26392638
_listTamperingFunctions()
26402639
_setTamperingFunctions()
26412640
_setPreprocessFunctions()
2642-
_setHttpChunked()
26432641
_setWafFunctions()
26442642
_setTrafficOutputFP()
26452643
_setupHTTPCollector()
26462644
_resolveCrossReferences()
2645+
_setHttpChunked()
26472646
_checkWebSocket()
26482647

26492648
parseTargetDirect()

lib/core/optiondict.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@
6161
"csrfToken": "string",
6262
"csrfUrl": "string",
6363
"forceSSL": "boolean",
64+
"chunked": "boolean",
6465
"hpp": "boolean",
6566
"evalCode": "string",
6667
},

lib/core/settings.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
from lib.core.enums import OS
2020

2121
# sqlmap version (<major>.<minor>.<month>.<monthly commit>)
22-
VERSION = "1.3.3.31"
22+
VERSION = "1.3.3.32"
2323
TYPE = "dev" if VERSION.count('.') > 2 and VERSION.split('.')[-1] != '0' else "stable"
2424
TYPE_COLORS = {"dev": 33, "stable": 90, "pip": 34}
2525
VERSION_STRING = "sqlmap/%s#%s" % ('.'.join(VERSION.split('.')[:-1]) if VERSION.count('.') > 2 and VERSION.split('.')[-1] == '0' else VERSION, TYPE)
@@ -794,8 +794,8 @@
794794
# Letters of lower frequency used in kb.chars
795795
KB_CHARS_LOW_FREQUENCY_ALPHABET = "zqxjkvbp"
796796

797-
# Keywords that need to be cut in the chunked
798-
CHUNKED_KEYWORDS = ['select', 'update', 'insert', 'from', 'load_file', 'sysdatabases', 'msysaccessobjects', 'msysqueries', 'sysmodules', 'information_schema', 'union']
797+
# SQL keywords used for splitting in HTTP Chunked encoding (switch --chunk)
798+
HTTP_CHUNKED_SPLIT_KEYWORDS = ("SELECT", "UPDATE", "INSERT", "FROM", "LOAD_FILE", "UNION", "information_schema", "sysdatabases", "msysaccessobjects", "msysqueries", "sysmodules")
799799

800800
# CSS style used in HTML dump format
801801
HTML_DUMP_CSS_STYLE = """<style>

lib/parse/cmdline.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -215,14 +215,15 @@ def cmdLineParser(argv=None):
215215
request.add_option("--force-ssl", dest="forceSSL", action="store_true",
216216
help="Force usage of SSL/HTTPS")
217217

218+
request.add_option("--chunked", dest="chunked", action="store_true",
219+
help="Use HTTP Chunked transfer encoding method")
220+
218221
request.add_option("--hpp", dest="hpp", action="store_true",
219222
help="Use HTTP parameter pollution method")
220223

221224
request.add_option("--eval", dest="evalCode",
222225
help="Evaluate provided Python code before the request (e.g. \"import hashlib;id2=hashlib.md5(id).hexdigest()\")")
223-
224-
request.add_option("--chunk", dest="chunk", action="store_true", help="all requests will be added headers with 'Transfer-Encoding: Chunked' and sent by transcoding")
225-
226+
226227
# Optimization options
227228
optimization = OptionGroup(parser, "Optimization", "These options can be used to optimize the performance of sqlmap")
228229

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,15 @@
66
"""
77

88
import urllib2
9-
import httplib
10-
from lib.core.data import conf
119

10+
from lib.core.data import conf
1211

13-
class HTTPHandler(urllib2.HTTPHandler):
12+
class ChunkedHandler(urllib2.HTTPHandler):
1413
"""
15-
The hook http_requests function ensures that the chunk function is working properly.
14+
Ensures that urllib2.HTTPHandler is working properly in case of Chunked Transfer-Encoding
1615
"""
1716

18-
def _hook(self, request):
17+
def _http_request(self, request):
1918
host = request.get_host()
2019
if not host:
2120
raise urllib2.URLError('no host given')
@@ -26,7 +25,7 @@ def _hook(self, request):
2625
request.add_unredirected_header(
2726
'Content-type',
2827
'application/x-www-form-urlencoded')
29-
if not request.has_header('Content-length') and not conf.chunk:
28+
if not request.has_header('Content-length') and not conf.chunked:
3029
request.add_unredirected_header(
3130
'Content-length', '%d' % len(data))
3231

@@ -43,4 +42,4 @@ def _hook(self, request):
4342
request.add_unredirected_header(name, value)
4443
return request
4544

46-
http_request = _hook
45+
http_request = _http_request

lib/request/connect.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ class WebSocketException(Exception):
3131
from lib.core.common import asciifyUrl
3232
from lib.core.common import calculateDeltaSeconds
3333
from lib.core.common import checkSameHost
34+
from lib.core.common import chunkSplitPostData
3435
from lib.core.common import clearConsoleLine
3536
from lib.core.common import dataToStdout
3637
from lib.core.common import escapeJsonValue
@@ -61,7 +62,6 @@ class WebSocketException(Exception):
6162
from lib.core.common import unsafeVariableNaming
6263
from lib.core.common import urldecode
6364
from lib.core.common import urlencode
64-
from lib.core.common import generateChunkDdata
6565
from lib.core.data import conf
6666
from lib.core.data import kb
6767
from lib.core.data import logger
@@ -272,13 +272,14 @@ def getPage(**kwargs):
272272
checking = kwargs.get("checking", False)
273273
skipRead = kwargs.get("skipRead", False)
274274
finalCode = kwargs.get("finalCode", False)
275-
chunked = conf.chunk
275+
chunked = kwargs.get("chunked", False) or conf.chunked
276276

277277
if multipart:
278278
post = multipart
279+
279280
if chunked:
280281
post = urllib.unquote(post)
281-
post = generateChunkDdata(post)
282+
post = chunkSplitPostData(post)
282283

283284
websocket_ = url.lower().startswith("ws")
284285

@@ -403,7 +404,7 @@ def getPage(**kwargs):
403404
headers[HTTP_HEADER.CONNECTION] = "keep-alive"
404405

405406
if chunked:
406-
headers[HTTP_HEADER.TRANSFER_ENCODING] = "Chunked"
407+
headers[HTTP_HEADER.TRANSFER_ENCODING] = "chunked"
407408

408409
if auxHeaders:
409410
headers = forgeHeaders(auxHeaders, headers)

sqlmap.conf

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,10 @@ csrfUrl =
190190
# Valid: True or False
191191
forceSSL = False
192192

193+
# Use HTTP Chunked transfer encoding method.
194+
# Valid: True or False
195+
chunked = False
196+
193197
# Use HTTP parameter pollution.
194198
# Valid: True or False
195199
hpp = False

txt/checksum.md5

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ c1da277517c7ec4c23e953a51b51e203 lib/controller/handler.py
3030
fb6be55d21a70765e35549af2484f762 lib/controller/__init__.py
3131
ed7874be0d2d3802f3d20184f2b280d5 lib/core/agent.py
3232
a932126e7d80e545c5d44af178d0bc0c lib/core/bigarray.py
33-
b096680d917729fd9658f9b75d44bb3b lib/core/common.py
33+
2344f86e7eb59920645bea6d5f40f580 lib/core/common.py
3434
de8d27ae6241163ff9e97aa9e7c51a18 lib/core/convert.py
3535
abcb1121eb56d3401839d14e8ed06b6e lib/core/data.py
3636
f89512ef3ebea85611c5dde6c891b657 lib/core/datatype.py
@@ -42,15 +42,15 @@ f89512ef3ebea85611c5dde6c891b657 lib/core/datatype.py
4242
84ef8f32e4582fcc294dc14e1997131d lib/core/exception.py
4343
fb6be55d21a70765e35549af2484f762 lib/core/__init__.py
4444
18c896b157b03af716542e5fe9233ef9 lib/core/log.py
45-
947f41084e551ff3b7ef7dda2f25ef20 lib/core/optiondict.py
46-
94679a06c134ca5c1db1e435e1cb9fb1 lib/core/option.py
45+
2f474c3c7a56f0c3cf3371838e7e5fd4 lib/core/optiondict.py
46+
e9b27d7328a8da0b48a908f0112c7745 lib/core/option.py
4747
fe370021c6bc99daf44b2bfc0d1effb3 lib/core/patch.py
4848
4b12aa67fbf6c973d12e54cf9cb54ea0 lib/core/profiling.py
4949
d5ef43fe3cdd6c2602d7db45651f9ceb lib/core/readlineng.py
5050
7d8a22c582ad201f65b73225e4456170 lib/core/replication.py
5151
3179d34f371e0295dd4604568fb30bcd lib/core/revision.py
5252
d6269c55789f78cf707e09a0f5b45443 lib/core/session.py
53-
858db5e54ce928b2ae4ed7fe55c25c12 lib/core/settings.py
53+
d89a43c92f2995116fce16b0e00e8aff lib/core/settings.py
5454
4483b4a5b601d8f1c4281071dff21ecc lib/core/shell.py
5555
10fd19b0716ed261e6d04f311f6f527c lib/core/subprocessng.py
5656
10d7e4f7ba2502cce5cf69223c52eddc lib/core/target.py
@@ -61,7 +61,7 @@ d6269c55789f78cf707e09a0f5b45443 lib/core/session.py
6161
5b3f08208be0579356f78ce5805d37b2 lib/core/wordlist.py
6262
fb6be55d21a70765e35549af2484f762 lib/__init__.py
6363
4881480d0c1778053908904e04570dc3 lib/parse/banner.py
64-
fafa321d2bbfc60410a131f68d5203ea lib/parse/cmdline.py
64+
79777f4f934f3b0a436fdd6600f7d3b8 lib/parse/cmdline.py
6565
06ccbccb63255c8f1c35950a4c8a6f6b lib/parse/configfile.py
6666
d34df646508c2dceb25205e1316673d1 lib/parse/handler.py
6767
43deb2400e269e602e916efaec7c0903 lib/parse/headers.py
@@ -71,8 +71,9 @@ adcecd2d6a8667b22872a563eb83eac0 lib/parse/payloads.py
7171
993104046c7d97120613409ef7780c76 lib/parse/sitemap.py
7272
e4ea70bcd461f5176867dcd89d372386 lib/request/basicauthhandler.py
7373
bd4b654767eab19cd4dcd4520a68eed5 lib/request/basic.py
74+
caa52d249fbcf1705cd9208b84d93387 lib/request/chunkedhandler.py
7475
fc25d951217077fe655ed2a3a81552ae lib/request/comparison.py
75-
e6792ea3cdbcbe17a7fa8cf856d2b956 lib/request/connect.py
76+
f44c5d2716317a0dfa024c98ce4865e9 lib/request/connect.py
7677
43005bd6a78e9cf0f3ed2283a1cb122e lib/request/direct.py
7778
2b7509ba38a667c61cefff036ec4ca6f lib/request/dns.py
7879
ceac6b3bf1f726f8ff43c6814e9d7281 lib/request/httpshandler.py

0 commit comments

Comments
 (0)