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

Skip to content

Commit fae965f

Browse files
author
Louis-Philippe Huberdeau
committed
Parse and build the response block
1 parent 0d756a8 commit fae965f

1 file changed

Lines changed: 89 additions & 4 deletions

File tree

lib/utils/collect.py

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

88
from BaseHTTPServer import BaseHTTPRequestHandler
9+
from httplib import HTTPResponse
910
from StringIO import StringIO
11+
import base64
12+
import re
1013

1114
from lib.core.data import logger
1215
from lib.core.settings import VERSION
@@ -122,18 +125,68 @@ def toDict(self):
122125

123126
class Response:
124127

125-
def __init__(self):
126-
pass
128+
extract_status = re.compile(r'\((\d{3}) (.*)\)')
129+
130+
def __init__(self, httpVersion, status, statusText, headers, content, raw=None, comment=None):
131+
self.raw = raw
132+
self.httpVersion = httpVersion
133+
self.status = status
134+
self.statusText = statusText
135+
self.headers = headers
136+
self.content = content
137+
self.comment = comment
127138

128139
@classmethod
129140
def parse(cls, raw):
130-
return cls()
141+
altered = raw
142+
comment = None
143+
144+
if altered.startswith("HTTP response ["):
145+
io = StringIO(raw)
146+
first_line = io.readline()
147+
parts = cls.extract_status.search(first_line)
148+
status_line = "HTTP/1.0 %s %s" % (parts.group(1), parts.group(2))
149+
remain = io.read()
150+
altered = status_line + "\n" + remain
151+
comment = first_line
152+
153+
response = HTTPResponse(FakeSocket(altered))
154+
response.begin()
155+
return cls(httpVersion="HTTP/1.1" if response.version == 11 else "HTTP/1.0",
156+
status=response.status,
157+
statusText=response.reason,
158+
headers=response.msg,
159+
content=response.read(-1),
160+
comment=comment,
161+
raw=raw)
131162

132163
def toDict(self):
133164
return {
165+
"httpVersion": self.httpVersion,
166+
"status": self.status,
167+
"statusText": self.statusText,
168+
"headers": [dict(name=key, value=value) for key, value in self.headers.items()],
169+
"content": {
170+
"mimeType": self.headers.get('Content-Type'),
171+
"encoding": "base64",
172+
"text": base64.b64encode(self.content),
173+
},
174+
"comment": self.comment,
175+
"_raw": self.raw,
134176
}
135177

136178

179+
class FakeSocket:
180+
# Original source:
181+
# https://stackoverflow.com/questions/24728088/python-parse-http-response-string
182+
183+
def __init__(self, response_text):
184+
self._file = StringIO(response_text)
185+
186+
def makefile(self, *args, **kwargs):
187+
return self._file
188+
189+
137190
class HTTPRequest(BaseHTTPRequestHandler):
138191
# Original source:
139192
# https://stackoverflow.com/questions/4685217/parse-raw-http-headers
@@ -171,7 +224,7 @@ def test_basic_request(self):
171224
self.assertEqual("HTTP/1.0", req.httpVersion)
172225

173226
def test_with_request_as_logged_by_sqlmap(self):
174-
raw = "HTTP request [#75]:\nPOST /create.php HTTP/1.1\nHost: 240.0.0.2\nAccept-encoding: gzip,deflate\nCache-control: no-cache\nContent-type: application/x-www-form-urlencoded; charset=utf-8\nAccept: */*\nUser-agent: Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.215 Safari/534.10\nCookie: PHPSESSID=65c4a9cfbbe91f2d975d50ce5e8d1026\nContent-length: 138\nConnection: close\n\nname=test%27%29%3BSELECT%20LIKE%28%27ABCDEFG%27%2CUPPER%28HEX%28RANDOMBLOB%28000000000%2F2%29%29%29%29--&csrfmiddlewaretoken=594d26cfa3fad\n" # noqa
227+
raw = "HTTP request [#75]:\nPOST /create.php HTTP/1.1\nHost: 127.0.0.1\nAccept-encoding: gzip,deflate\nCache-control: no-cache\nContent-type: application/x-www-form-urlencoded; charset=utf-8\nAccept: */*\nUser-agent: Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.215 Safari/534.10\nCookie: PHPSESSID=65c4a9cfbbe91f2d975d50ce5e8d1026\nContent-length: 138\nConnection: close\n\nname=test%27%29%3BSELECT%20LIKE%28%27ABCDEFG%27%2CUPPER%28HEX%28RANDOMBLOB%280.0.10000%2F2%29%29%29%29--&csrfmiddlewaretoken=594d26cfa3fad\n" # noqa
175228
req = Request.parse(raw)
176229
self.assertEqual("POST", req.method)
177230
self.assertEqual("138", req.headers["Content-Length"])
@@ -204,4 +257,36 @@ def test_render_with_post_body(self):
204257
"text": "name=test&csrfmiddlewaretoken=594d26cfa3fad\n",
205258
})
206259

260+
class ResponseParseTest(unittest.TestCase):
261+
def test_parse_standard_http_response(self):
262+
raw = "HTTP/1.1 404 Not Found\nContent-length: 518\nX-powered-by: PHP/5.6.30\nContent-encoding: gzip\nExpires: Thu, 19 Nov 1981 08:52:00 GMT\nVary: Accept-Encoding\nUri: http://127.0.0.1/\nServer: Apache/2.4.10 (Debian)\nConnection: close\nPragma: no-cache\nCache-control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0\nDate: Fri, 23 Jun 2017 16:18:17 GMT\nContent-type: text/html; charset=UTF-8\n\n<!doctype html>\n<html>Test</html>\n" # noqa
263+
resp = Response.parse(raw)
264+
self.assertEqual(resp.status, 404)
265+
self.assertEqual(resp.statusText, "Not Found")
266+
267+
def test_parse_response_as_logged_by_sqlmap(self):
268+
raw = "HTTP response [#74] (200 OK):\nContent-length: 518\nX-powered-by: PHP/5.6.30\nContent-encoding: gzip\nExpires: Thu, 19 Nov 1981 08:52:00 GMT\nVary: Accept-Encoding\nUri: http://127.0.0.1/\nServer: Apache/2.4.10 (Debian)\nConnection: close\nPragma: no-cache\nCache-control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0\nDate: Fri, 23 Jun 2017 16:18:17 GMT\nContent-type: text/html; charset=UTF-8\n\n<!doctype html>\n<html>Test</html>\n" # noqa
269+
resp = Response.parse(raw)
270+
self.assertEqual(resp.status, 200)
271+
self.assertEqual(resp.statusText, "OK")
272+
self.assertEqual(resp.headers["Content-Length"], "518")
273+
self.assertIn("Test", resp.content)
274+
self.assertEqual("HTTP response [#74] (200 OK):\n", resp.comment)
275+
276+
class ResponseRenderTest(unittest.TestCase):
277+
def test_simple_page_encoding(self):
278+
resp = Response(status=200, statusText="OK",
279+
httpVersion="HTTP/1.1",
280+
headers={"Content-Type": "text/html"},
281+
content="<html><body>Hello</body></html>\n")
282+
out = resp.toDict()
283+
self.assertEqual(200, out["status"])
284+
self.assertEqual("OK", out["statusText"])
285+
self.assertIn({"name": "Content-Type", "value": "text/html"}, out["headers"])
286+
self.assertEqual(out["content"], {
287+
"mimeType": "text/html",
288+
"encoding": "base64",
289+
"text": "PGh0bWw+PGJvZHk+SGVsbG88L2JvZHk+PC9odG1sPgo=",
290+
})
291+
207292
unittest.main(buffer=False)

0 commit comments

Comments
 (0)