inject -> inject.tcp/inject.websocket

This commit is contained in:
Maximilian Hils 2021-03-16 15:01:33 +01:00
parent b767b82c86
commit fe6f0d368b
3 changed files with 55 additions and 36 deletions

View File

@ -14,15 +14,16 @@ def websocket_message(flow):
last_message = flow.websocket.messages[-1] last_message = flow.websocket.messages[-1]
if b"secret" in last_message.content: if b"secret" in last_message.content:
last_message.kill() last_message.kill()
ctx.master.commands.call("inject", [flow], not last_message.from_client, "ssssssh") ctx.master.commands.call("inject.websocket", flow, last_message.from_client, "ssssssh")
# Complex example: Schedule a periodic timer # Complex example: Schedule a periodic timer
async def inject_async(flow: http.HTTPFlow): async def inject_async(flow: http.HTTPFlow):
msg = "hello from mitmproxy! " msg = "hello from mitmproxy! "
assert flow.websocket # make type checker happy
while flow.websocket.timestamp_end is None: while flow.websocket.timestamp_end is None:
ctx.master.commands.call("inject", [flow], False, msg) ctx.master.commands.call("inject.websocket", flow, True, msg)
await asyncio.sleep(1) await asyncio.sleep(1)
msg = msg[1:] + msg[:1] msg = msg[1:] + msg[:1]

View File

@ -1,9 +1,9 @@
import asyncio import asyncio
import warnings import warnings
from typing import Dict, Optional, Sequence, Tuple from typing import Dict, Optional, Tuple
from mitmproxy import command, controller, ctx, flow, http, log, master, options, platform, tcp, websocket from mitmproxy import command, controller, ctx, flow, http, log, master, options, platform, tcp, websocket
from mitmproxy.flow import Error from mitmproxy.flow import Error, Flow
from mitmproxy.proxy import commands, events from mitmproxy.proxy import commands, events
from mitmproxy.proxy import server from mitmproxy.proxy import server
from mitmproxy.proxy.layers.tcp import TcpMessageInjected from mitmproxy.proxy.layers.tcp import TcpMessageInjected
@ -147,30 +147,36 @@ class Proxyserver:
finally: finally:
del self._connections[peername] del self._connections[peername]
def inject_event(self, flow: flow.Flow, event: events.Event): def inject_event(self, event: events.MessageInjected):
if flow.client_conn.peername not in self._connections: if event.flow.client_conn.peername not in self._connections:
raise ValueError("Flow is not from a live connection.") raise ValueError("Flow is not from a live connection.")
self._connections[flow.client_conn.peername].server_event(event) self._connections[event.flow.client_conn.peername].server_event(event)
@command.command("inject.websocket")
def inject_websocket(self, flow: Flow, to_client: bool, message: str, is_text: bool = True):
if not isinstance(flow, http.HTTPFlow) or not flow.websocket:
ctx.log.warn("Cannot inject WebSocket messages into non-WebSocket flows.")
@command.command("inject")
def inject(self, flows: Sequence[flow.Flow], from_client: bool, message: str):
message_bytes = strutils.escaped_str_to_bytes(message) message_bytes = strutils.escaped_str_to_bytes(message)
event: events.MessageInjected msg = websocket.WebSocketMessage(
for f in flows: Opcode.TEXT if is_text else Opcode.BINARY,
if isinstance(f, http.HTTPFlow): not to_client,
if f.websocket: message_bytes
msg = websocket.WebSocketMessage(Opcode.TEXT, from_client, message_bytes) )
event = WebSocketMessageInjected(f, msg) event = WebSocketMessageInjected(flow, msg)
else: try:
ctx.log.warn("Cannot inject messages into HTTP connections.") self.inject_event(event)
continue except ValueError as e:
elif isinstance(f, tcp.TCPFlow): ctx.log.warn(str(e))
event = TcpMessageInjected(f, tcp.TCPMessage(from_client, message_bytes))
else: # pragma: no cover
ctx.log.warn(f"Cannot inject message into {f.__class__.__name__}, skipping.")
continue
try: @command.command("inject.tcp")
self.inject_event(f, event) def inject_tcp(self, flow: Flow, to_client: bool, message: str):
except ValueError as e: if not isinstance(flow, tcp.TCPFlow):
ctx.log.warn(str(e)) ctx.log.warn("Cannot inject TCP messages into non-TCP flows.")
message_bytes = strutils.escaped_str_to_bytes(message)
event = TcpMessageInjected(flow, tcp.TCPMessage(not to_client, message_bytes))
try:
self.inject_event(event)
except ValueError as e:
ctx.log.warn(str(e))

View File

@ -110,9 +110,9 @@ async def test_inject():
writer.write(b"a") writer.write(b"a")
assert await reader.read(1) == b"A" assert await reader.read(1) == b"A"
ps.inject(state.flows, True, "b") ps.inject_tcp(state.flows[0], False, "b")
assert await reader.read(1) == b"B" assert await reader.read(1) == b"B"
ps.inject(state.flows, False, "c") ps.inject_tcp(state.flows[0], True, "c")
assert await reader.read(1) == b"c" assert await reader.read(1) == b"c"
@ -120,16 +120,28 @@ async def test_inject():
async def test_inject_fail(): async def test_inject_fail():
ps = Proxyserver() ps = Proxyserver()
with taddons.context(ps) as tctx: with taddons.context(ps) as tctx:
ps.inject( ps.inject_websocket(
[tflow.tflow()], tflow.tflow(),
False, True,
"test" "test"
) )
await tctx.master.await_log("Cannot inject messages into HTTP connections.", level="warn") await tctx.master.await_log("Cannot inject WebSocket messages into non-WebSocket flows.", level="warn")
ps.inject_tcp(
tflow.tflow(),
True,
"test"
)
await tctx.master.await_log("Cannot inject TCP messages into non-TCP flows.", level="warn")
ps.inject( ps.inject_websocket(
[tflow.twebsocketflow()], tflow.twebsocketflow(),
False, True,
"test"
)
await tctx.master.await_log("Flow is not from a live connection.", level="warn")
ps.inject_websocket(
tflow.ttcpflow(),
True,
"test" "test"
) )
await tctx.master.await_log("Flow is not from a live connection.", level="warn") await tctx.master.await_log("Flow is not from a live connection.", level="warn")