From: Jude N Date: Fri, 5 Jul 2019 13:05:15 +0000 (-0400) Subject: Initial push - still in a pretty unusable state. X-Git-Url: https://pwan.org/git/?p=vern.git;a=commitdiff_plain;h=bb462271117f60af0bfbcdebd2809d77f15ba6a1 Initial push - still in a pretty unusable state. --- bb462271117f60af0bfbcdebd2809d77f15ba6a1 diff --git a/README.md b/README.md new file mode 100644 index 0000000..62b2d9a --- /dev/null +++ b/README.md @@ -0,0 +1,11 @@ +- This is still super-alpha code so its pretty useless. + +- TODO: setup.py +- source ./env/bin/activate +- Run mitmproxy +- Collect CA cert from ~/.mitmproxy +- Import the CA as per your distro + - cp mitmproxy-ca-cert.cer to /usr/share/ca-certificates/mitmproxy-ca-cert.crt + - run sudo dpkg-reconfigure ca-certificates + +- mitmdump -s digestauth.py diff --git a/digestauth.py b/digestauth.py new file mode 100644 index 0000000..9c86fb0 --- /dev/null +++ b/digestauth.py @@ -0,0 +1,79 @@ + +from mitmproxy import ctx, exceptions +from requests.auth import HTTPDigestAuth +from requests.utils import parse_dict_header + +import re +import threading +import requests +import typing +import getpass + + +class DigestAuthenticator: + + def __init__(self): + self.lock = threading.Lock() + self.resubmitted_response = None + self._username = None + self._password = None + + def load(self, loader): + ctx.log.info('in load') + loader.add_option( + name = "uname", + typespec = typing.Text, + default = '', + help = "Please enter your user name" + ) + + def configure(self, updates): + ctx.log.info('updates: ' + str(updates)) + ctx.log.info('in configue: ' + str(ctx.options)) + if ctx.options.uname == '': + raise exceptions.OptionsError("Please enter a non-empty value for uname with --set uname=your_username") + else: + self._username = ctx.options.uname + self._password = getpass.getpass("Please enter the password for " + self._username + ": ") + + + def response(self, flow): + + if flow.response.status_code == 401 and 'Authorization' not in flow.request.headers: + + www_authenticate_header = flow.response.headers['WWW-Authenticate'] + + if 'digest' in www_authenticate_header.lower(): + + http_digest_auth = HTTPDigestAuth(self._username, self._password) + http_digest_auth.init_per_thread_state() + pat = re.compile(r'digest ', flags=re.IGNORECASE) + http_digest_auth._thread_local.chal = parse_dict_header(pat.sub('', www_authenticate_header, count=1)) + authorization_header = http_digest_auth.build_digest_header(flow.request.method, flow.request.url) + + resubmitted_headers = {} + resubmitted_headers.update(flow.request.headers) + resubmitted_headers.update({'Authorization': str(authorization_header)}) + if flow.request.method == 'GET': + resubmitted_response = requests.get(flow.request.url, headers=resubmitted_headers, allow_redirects=False) + else: + # TODO: This probably needs a data=payload arg... + resubmitted_response = requests.post(flow.request.url, headers=resubmitted_headers) + + if resubmitted_response.status_code == 301: + ctx.log.info("301 response headers: " + str(resubmitted_response.headers)) + + flow.response.status_code = resubmitted_response.status_code + flow.response.reason = resubmitted_response.reason + flow.response.content = resubmitted_response.text.encode('ascii') + + # TODO: additional response fields (headers and cookies) + + else: + # TODO: switch info to debug eventually + ctx.log("DigestAuthenticator other request: " + str(flow.response.status_code) + "\n\n", "info") + + +addons = [ + DigestAuthenticator() +]