remove context from all scripts

This commit is contained in:
Maximilian Hils 2016-07-07 18:37:33 -07:00
parent 7a5b21556b
commit c048ae1d5b
33 changed files with 137 additions and 112 deletions

View File

@ -1,2 +1,2 @@
def response(context, flow):
def response(flow):
flow.response.headers["newheader"] = "foo"

View File

@ -14,7 +14,7 @@ def proxy_address(flow):
return ("localhost", 8081)
def request(context, flow):
def request(flow):
if flow.request.method == "CONNECT":
# If the decision is done by domain, one could also modify the server address here.
# We do it after CONNECT here to have the request data available as well.

View File

@ -62,9 +62,9 @@ class ViewPigLatin(contentviews.View):
pig_view = ViewPigLatin()
def start(context):
context.add_contentview(pig_view)
def start():
contentviews.add(pig_view)
def done(context):
context.remove_contentview(pig_view)
def done():
contentviews.remove(pig_view)

View File

@ -28,7 +28,7 @@ import re
parse_host_header = re.compile(r"^(?P<host>[^:]+|\[.+\])(?::(?P<port>\d+))?$")
def request(context, flow):
def request(flow):
if flow.client_conn.ssl_established:
flow.request.scheme = "https"
sni = flow.client_conn.connection.get_servername()

View File

@ -1,4 +1,7 @@
def request(context, flow):
f = context.duplicate_flow(flow)
from mitmproxy import master
def request(flow):
f = master.duplicate_flow(flow)
f.request.path = "/changed"
context.replay_request(f)
master.replay_request(f, block=True, run_scripthooks=False)

View File

@ -1,3 +1,3 @@
def response(context, flow):
def response(flow):
flow.response.status_code = 500
flow.response.content = b""

View File

@ -3,14 +3,16 @@
import sys
from mitmproxy import filt
state = {}
def start(context):
def start():
if len(sys.argv) != 2:
raise ValueError("Usage: -s 'filt.py FILTER'")
context.filter = filt.parse(sys.argv[1])
state["filter"] = filt.parse(sys.argv[1])
def response(context, flow):
if flow.match(context.filter):
def response(flow):
if flow.match(state["filter"]):
print("Flow matches filter:")
print(flow)

View File

@ -3,8 +3,10 @@ import sys
from mitmproxy.flow import FlowWriter
state = {}
def start(context):
def start():
if len(sys.argv) != 2:
raise ValueError('Usage: -s "flowriter.py filename"')
@ -12,9 +14,9 @@ def start(context):
f = sys.stdout
else:
f = open(sys.argv[1], "wb")
context.flow_writer = FlowWriter(f)
state["flow_writer"] = FlowWriter(f)
def response(context, flow):
def response(flow):
if random.choice([True, False]):
context.flow_writer.add(flow)
state["flow_writer"].add(flow)

View File

@ -54,7 +54,13 @@ class _HARLog(HAR.log):
return self.__page_list__
def start(context):
class Context(object):
pass
context = Context()
def start():
"""
On start we create a HARLog instance. You will have to adapt this to
suit your actual needs of HAR generation. As it will probably be
@ -79,7 +85,7 @@ def start(context):
context.seen_server = set()
def response(context, flow):
def response(flow):
"""
Called when a server response has been received. At the time of this
message both a request and a response are present and completely done.
@ -201,7 +207,7 @@ def response(context, flow):
context.HARLog.add(entry)
def done(context):
def done():
"""
Called once on script shutdown, after any other events.
"""

View File

@ -4,25 +4,27 @@ import sys
from bs4 import BeautifulSoup
from mitmproxy.models import decoded
iframe_url = None
def start(context):
def start():
if len(sys.argv) != 2:
raise ValueError('Usage: -s "iframe_injector.py url"')
context.iframe_url = sys.argv[1]
global iframe_url
iframe_url = sys.argv[1]
def response(context, flow):
if flow.request.host in context.iframe_url:
def response(flow):
if flow.request.host in iframe_url:
return
with decoded(flow.response): # Remove content encoding (gzip, ...)
html = BeautifulSoup(flow.response.content, "lxml")
if html.body:
iframe = html.new_tag(
"iframe",
src=context.iframe_url,
src=iframe_url,
frameborder=0,
height=0,
width=0)
html.body.insert(0, iframe)
flow.response.content = str(html).encode("utf8")
context.log("Iframe inserted.")

View File

@ -1,4 +1,4 @@
def request(context, flow):
def request(flow):
if flow.request.urlencoded_form:
flow.request.urlencoded_form["mitmproxy"] = "rocks"
else:

View File

@ -1,2 +1,2 @@
def request(context, flow):
def request(flow):
flow.request.query["mitmproxy"] = "rocks"

View File

@ -5,16 +5,20 @@ import sys
from mitmproxy.models import decoded
def start(context):
state = {}
def start():
if len(sys.argv) != 3:
raise ValueError('Usage: -s "modify_response_body.py old new"')
# You may want to use Python's argparse for more sophisticated argument
# parsing.
context.old, context.new = sys.argv[1].encode(), sys.argv[2].encode()
state["old"], state["new"] = sys.argv[1].encode(), sys.argv[2].encode()
def response(context, flow):
def response(flow):
with decoded(flow.response): # automatically decode gzipped responses.
flow.response.content = flow.response.content.replace(
context.old,
context.new)
state["old"],
state["new"]
)

View File

@ -1,9 +1,10 @@
import time
import mitmproxy
from mitmproxy.script import concurrent
@concurrent # Remove this and see what happens
def request(context, flow):
context.log("handle request: %s%s" % (flow.request.host, flow.request.path))
def request(flow):
mitmproxy.log("handle request: %s%s" % (flow.request.host, flow.request.path))
time.sleep(5)
context.log("start request: %s%s" % (flow.request.host, flow.request.path))
mitmproxy.log("start request: %s%s" % (flow.request.host, flow.request.path))

View File

@ -4,6 +4,7 @@ instance, we're using the Flask framework (http://flask.pocoo.org/) to expose
a single simplest-possible page.
"""
from flask import Flask
import mitmproxy
app = Flask("proxapp")
@ -15,10 +16,10 @@ def hello_world():
# Register the app using the magic domain "proxapp" on port 80. Requests to
# this domain and port combination will now be routed to the WSGI app instance.
def start(context):
context.app_registry.add(app, "proxapp", 80)
def start():
mitmproxy.master.apps.add(app, "proxapp", 80)
# SSL works too, but the magic domain needs to be resolvable from the mitmproxy machine due to mitmproxy's design.
# mitmproxy will connect to said domain and use serve its certificate (unless --no-upstream-cert is set)
# but won't send any data.
context.app_registry.add(app, "example.com", 443)
mitmproxy.master.apps.add(app, "example.com", 443)

View File

@ -5,7 +5,7 @@ from mitmproxy.models import HTTPResponse
from netlib.http import Headers
def request(context, flow):
def request(flow):
# pretty_host takes the "Host" header of the request into account,
# which is useful in transparent mode where we usually only have the IP
# otherwise.

View File

@ -2,23 +2,21 @@ from netlib.http import decoded
import re
from six.moves import urllib
def start(context):
# set of SSL/TLS capable hosts
context.secure_hosts = set()
secure_hosts = set()
def request(context, flow):
def request(flow):
flow.request.headers.pop('If-Modified-Since', None)
flow.request.headers.pop('Cache-Control', None)
# proxy connections to SSL-enabled hosts
if flow.request.pretty_host in context.secure_hosts:
if flow.request.pretty_host in secure_hosts:
flow.request.scheme = 'https'
flow.request.port = 443
def response(context, flow):
def response(flow):
with decoded(flow.response):
flow.request.headers.pop('Strict-Transport-Security', None)
flow.request.headers.pop('Public-Key-Pins', None)
@ -31,7 +29,7 @@ def response(context, flow):
location = flow.response.headers['Location']
hostname = urllib.parse.urlparse(location).hostname
if hostname:
context.secure_hosts.add(hostname)
secure_hosts.add(hostname)
flow.response.headers['Location'] = location.replace('https://', 'http://', 1)
# strip secure flag from 'Set-Cookie' headers

View File

@ -1,4 +1,4 @@
def responseheaders(context, flow):
def responseheaders(flow):
"""
Enables streaming for all responses.
"""

View File

@ -16,5 +16,5 @@ def modify(chunks):
yield chunk.replace("foo", "bar")
def responseheaders(context, flow):
def responseheaders(flow):
flow.response.stream = modify

View File

@ -1,79 +1,80 @@
import mitmproxy
"""
This is a script stub, with definitions for all events.
"""
def start(context):
def start():
"""
Called once on script startup, before any other events.
"""
context.log("start")
mitmproxy.log("start")
def clientconnect(context, root_layer):
def clientconnect(root_layer):
"""
Called when a client initiates a connection to the proxy. Note that a
connection can correspond to multiple HTTP requests
"""
context.log("clientconnect")
mitmproxy.log("clientconnect")
def request(context, flow):
def request(flow):
"""
Called when a client request has been received.
"""
context.log("request")
mitmproxy.log("request")
def serverconnect(context, server_conn):
def serverconnect(server_conn):
"""
Called when the proxy initiates a connection to the target server. Note that a
connection can correspond to multiple HTTP requests
"""
context.log("serverconnect")
mitmproxy.log("serverconnect")
def responseheaders(context, flow):
def responseheaders(flow):
"""
Called when the response headers for a server response have been received,
but the response body has not been processed yet. Can be used to tell mitmproxy
to stream the response.
"""
context.log("responseheaders")
mitmproxy.log("responseheaders")
def response(context, flow):
def response(flow):
"""
Called when a server response has been received.
"""
context.log("response")
mitmproxy.log("response")
def error(context, flow):
def error(flow):
"""
Called when a flow error has occured, e.g. invalid server responses, or
interrupted connections. This is distinct from a valid server HTTP error
response, which is simply a response with an HTTP error code.
"""
context.log("error")
mitmproxy.log("error")
def serverdisconnect(context, server_conn):
def serverdisconnect(server_conn):
"""
Called when the proxy closes the connection to the target server.
"""
context.log("serverdisconnect")
mitmproxy.log("serverdisconnect")
def clientdisconnect(context, root_layer):
def clientdisconnect(root_layer):
"""
Called when a client disconnects from the proxy.
"""
context.log("clientdisconnect")
mitmproxy.log("clientdisconnect")
def done(context):
def done():
"""
Called once on script shutdown, after any other events.
"""
context.log("done")
mitmproxy.log("done")

View File

@ -11,7 +11,7 @@ mitmdump -T --host --tcp ".*" -q -s examples/tcp_message.py
from netlib import strutils
def tcp_message(ctx, tcp_msg):
def tcp_message(tcp_msg):
modified_msg = tcp_msg.message.replace("foo", "bar")
is_modified = False if modified_msg == tcp_msg.message else True

View File

@ -20,13 +20,14 @@ Example:
Authors: Maximilian Hils, Matthew Tuusberg
"""
from __future__ import (absolute_import, print_function, division)
from __future__ import absolute_import, print_function, division
import collections
import random
import sys
from enum import Enum
import mitmproxy
from mitmproxy.exceptions import TlsProtocolException
from mitmproxy.protocol import TlsLayer, RawTCPLayer
@ -97,7 +98,6 @@ class TlsFeedback(TlsLayer):
def _establish_tls_with_client(self):
server_address = self.server_conn.address
tls_strategy = self.script_context.tls_strategy
try:
super(TlsFeedback, self)._establish_tls_with_client()
@ -110,15 +110,18 @@ class TlsFeedback(TlsLayer):
# inline script hooks below.
tls_strategy = None
def start(context):
def start():
global tls_strategy
if len(sys.argv) == 2:
context.tls_strategy = ProbabilisticStrategy(float(sys.argv[1]))
tls_strategy = ProbabilisticStrategy(float(sys.argv[1]))
else:
context.tls_strategy = ConservativeStrategy()
tls_strategy = ConservativeStrategy()
def next_layer(context, next_layer):
def next_layer(next_layer):
"""
This hook does the actual magic - if the next layer is planned to be a TLS layer,
we check if we want to enter pass-through mode instead.
@ -126,14 +129,13 @@ def next_layer(context, next_layer):
if isinstance(next_layer, TlsLayer) and next_layer._client_tls:
server_address = next_layer.server_conn.address
if context.tls_strategy.should_intercept(server_address):
if tls_strategy.should_intercept(server_address):
# We try to intercept.
# Monkey-Patch the layer to get feedback from the TLSLayer if interception worked.
next_layer.__class__ = TlsFeedback
next_layer.script_context = context
else:
# We don't intercept - reply with a pass-through layer and add a "skipped" entry.
context.log("TLS passthrough for %s" % repr(next_layer.server_conn.address), "info")
next_layer_replacement = RawTCPLayer(next_layer.ctx, logging=False)
mitmproxy.log("TLS passthrough for %s" % repr(next_layer.server_conn.address), "info")
next_layer_replacement = RawTCPLayer(next_layer.ctx, ignore=True)
next_layer.reply.send(next_layer_replacement)
context.tls_strategy.record_skipped(server_address)
tls_strategy.record_skipped(server_address)

View File

@ -3,7 +3,7 @@ from PIL import Image
from mitmproxy.models import decoded
def response(context, flow):
def response(flow):
if flow.response.headers.get("content-type", "").startswith("image"):
with decoded(flow.response): # automatically decode gzipped responses.
try:

View File

@ -5,12 +5,12 @@ from a_helper import parser
var = 0
def start(ctx):
def start():
global var
var = parser.parse_args(sys.argv[1:]).var
def here(ctx):
def here():
global var
var += 1
return var

View File

@ -1,36 +1,37 @@
import mitmproxy
log = []
def clientconnect(ctx, cc):
ctx.log("XCLIENTCONNECT")
def clientconnect(cc):
mitmproxy.log("XCLIENTCONNECT")
log.append("clientconnect")
def serverconnect(ctx, cc):
ctx.log("XSERVERCONNECT")
def serverconnect(cc):
mitmproxy.log("XSERVERCONNECT")
log.append("serverconnect")
def request(ctx, f):
ctx.log("XREQUEST")
def request(f):
mitmproxy.log("XREQUEST")
log.append("request")
def response(ctx, f):
ctx.log("XRESPONSE")
def response(f):
mitmproxy.log("XRESPONSE")
log.append("response")
def responseheaders(ctx, f):
ctx.log("XRESPONSEHEADERS")
def responseheaders(f):
mitmproxy.log("XRESPONSEHEADERS")
log.append("responseheaders")
def clientdisconnect(ctx, cc):
ctx.log("XCLIENTDISCONNECT")
def clientdisconnect(cc):
mitmproxy.log("XCLIENTDISCONNECT")
log.append("clientdisconnect")
def error(ctx, cc):
ctx.log("XERROR")
def error(cc):
mitmproxy.log("XERROR")
log.append("error")

View File

@ -3,5 +3,5 @@ from mitmproxy.script import concurrent
@concurrent
def request(context, flow):
def request(flow):
time.sleep(0.1)

View File

@ -2,5 +2,5 @@ from mitmproxy.script import concurrent
@concurrent
def start(context):
def start():
pass

View File

@ -1,4 +1,6 @@
import mitmproxy
def request(ctx, f):
f = ctx.duplicate_flow(f)
ctx.replay_request(f)
def request(f):
f = mitmproxy.master.duplicate_flow(f)
mitmproxy.master.replay_request(f, block=True, run_scripthooks=False)

View File

@ -1,2 +1,2 @@
def request(ctx, r):
raise ValueError
def request(r):
raise ValueError()

View File

@ -1,3 +1,3 @@
def start(ctx):
def start():
raise ValueError()

View File

@ -3,5 +3,5 @@ def modify(chunks):
yield chunk.replace(b"foo", b"bar")
def responseheaders(context, flow):
def responseheaders(flow):
flow.response.stream = modify

View File

@ -1,4 +1,4 @@
def tcp_message(ctx, flow):
def tcp_message(flow):
message = flow.messages[-1]
if not message.from_client:
message.content = message.content.replace(b"foo", b"bar")

View File

@ -1,2 +1,2 @@
def done(ctx):
def done():
raise RuntimeError()