Parse and build the response block

This commit is contained in:
Louis-Philippe Huberdeau 2017-06-23 13:28:22 -04:00
parent 0d756a8823
commit fae965f8b6

View File

@ -6,7 +6,10 @@ See the file 'doc/COPYING' for copying permission
""" """
from BaseHTTPServer import BaseHTTPRequestHandler from BaseHTTPServer import BaseHTTPRequestHandler
from httplib import HTTPResponse
from StringIO import StringIO from StringIO import StringIO
import base64
import re
from lib.core.data import logger from lib.core.data import logger
from lib.core.settings import VERSION from lib.core.settings import VERSION
@ -122,18 +125,68 @@ class Request:
class Response: class Response:
def __init__(self): extract_status = re.compile(r'\((\d{3}) (.*)\)')
pass
def __init__(self, httpVersion, status, statusText, headers, content, raw=None, comment=None):
self.raw = raw
self.httpVersion = httpVersion
self.status = status
self.statusText = statusText
self.headers = headers
self.content = content
self.comment = comment
@classmethod @classmethod
def parse(cls, raw): def parse(cls, raw):
return cls() altered = raw
comment = None
if altered.startswith("HTTP response ["):
io = StringIO(raw)
first_line = io.readline()
parts = cls.extract_status.search(first_line)
status_line = "HTTP/1.0 %s %s" % (parts.group(1), parts.group(2))
remain = io.read()
altered = status_line + "\n" + remain
comment = first_line
response = HTTPResponse(FakeSocket(altered))
response.begin()
return cls(httpVersion="HTTP/1.1" if response.version == 11 else "HTTP/1.0",
status=response.status,
statusText=response.reason,
headers=response.msg,
content=response.read(-1),
comment=comment,
raw=raw)
def toDict(self): def toDict(self):
return { return {
"httpVersion": self.httpVersion,
"status": self.status,
"statusText": self.statusText,
"headers": [dict(name=key, value=value) for key, value in self.headers.items()],
"content": {
"mimeType": self.headers.get('Content-Type'),
"encoding": "base64",
"text": base64.b64encode(self.content),
},
"comment": self.comment,
"_raw": self.raw,
} }
class FakeSocket:
# Original source:
# https://stackoverflow.com/questions/24728088/python-parse-http-response-string
def __init__(self, response_text):
self._file = StringIO(response_text)
def makefile(self, *args, **kwargs):
return self._file
class HTTPRequest(BaseHTTPRequestHandler): class HTTPRequest(BaseHTTPRequestHandler):
# Original source: # Original source:
# https://stackoverflow.com/questions/4685217/parse-raw-http-headers # https://stackoverflow.com/questions/4685217/parse-raw-http-headers
@ -171,7 +224,7 @@ if __name__ == '__main__':
self.assertEqual("HTTP/1.0", req.httpVersion) self.assertEqual("HTTP/1.0", req.httpVersion)
def test_with_request_as_logged_by_sqlmap(self): def test_with_request_as_logged_by_sqlmap(self):
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 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
req = Request.parse(raw) req = Request.parse(raw)
self.assertEqual("POST", req.method) self.assertEqual("POST", req.method)
self.assertEqual("138", req.headers["Content-Length"]) self.assertEqual("138", req.headers["Content-Length"])
@ -204,4 +257,36 @@ if __name__ == '__main__':
"text": "name=test&csrfmiddlewaretoken=594d26cfa3fad\n", "text": "name=test&csrfmiddlewaretoken=594d26cfa3fad\n",
}) })
class ResponseParseTest(unittest.TestCase):
def test_parse_standard_http_response(self):
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
resp = Response.parse(raw)
self.assertEqual(resp.status, 404)
self.assertEqual(resp.statusText, "Not Found")
def test_parse_response_as_logged_by_sqlmap(self):
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
resp = Response.parse(raw)
self.assertEqual(resp.status, 200)
self.assertEqual(resp.statusText, "OK")
self.assertEqual(resp.headers["Content-Length"], "518")
self.assertIn("Test", resp.content)
self.assertEqual("HTTP response [#74] (200 OK):\n", resp.comment)
class ResponseRenderTest(unittest.TestCase):
def test_simple_page_encoding(self):
resp = Response(status=200, statusText="OK",
httpVersion="HTTP/1.1",
headers={"Content-Type": "text/html"},
content="<html><body>Hello</body></html>\n")
out = resp.toDict()
self.assertEqual(200, out["status"])
self.assertEqual("OK", out["statusText"])
self.assertIn({"name": "Content-Type", "value": "text/html"}, out["headers"])
self.assertEqual(out["content"], {
"mimeType": "text/html",
"encoding": "base64",
"text": "PGh0bWw+PGJvZHk+SGVsbG88L2JvZHk+PC9odG1sPgo=",
})
unittest.main(buffer=False) unittest.main(buffer=False)