transparent minecraft man-in-the-middle proxy targeting mc 1.8.9 (unlikely to work consistently with other minecraft versions)
tested on Python 3.8
dependencies are requests and cryptography (pip3 install requests cryptography) if you want to do encrypted passthrough (default for the notchian server)
Make a file called auth.json with the following contents:
{
"email": "your_mojang_account@email.com",
"password": "supersecure",
"client_token": "487c8d0040774f6b84af38831801a867"
}To get a client_token, copy your local launcher's token from ~/.minecraft/launcher_accounts.json (mojangClientToken) to use the proxy while staying signed in, or run python3 gen_token.py, which may sign you out from your launcher.
Your credentials are necessary since part of the encryption process mandates the client sends a request to Mojang's session server, which servers will then check for.
Since the encryption is handled as part of the proxy rather than being passed through (thus allowing the proxy to read and write encrypted packets), we need to have an access token to provide as part of the request.
warning warning warning: here be dragons! the API is subject to change without notice; consult the below reference implementation if your code breaks after an update
python3 main.py path_to_auth_json host proxy_target where:
path_to_auth_jsonis the path relative to the current directory whereauth.jsonis stored- both
hostandproxy_targetare in the formatip:port hostis the host the proxy will run onproxy_targetis the host the proxy will connect to
e.g. python3 main.py auth.json 0.0.0.0:25567 localhost:25566 will use auth.json in the current directory to forward connections on all interfaces port 25567 to a minecraft server running on localhost port 25566.
if run like ^, packet information will be printed to the console.
to implement custom behavior when a play packet is received from the client or server, subclass LayerOne.extra.handler.Handler with a class such as this one (ChatModifierHandler from example_handlers/chat_modifier.py):
from LayerOne.extra.handler import Host, PrintFunc, SendFunc, Handler
from LayerOne.network.packet import Packet
from LayerOne.types.string import String
class ChatModifierHandler (Handler):
def __init__ (self, client_address: Host): pass
def ready (self): pass
def client_to_server (self, current_state: dict, print_func: PrintFunc, to_client_func: SendFunc, to_server_func: SendFunc, packet_id: int, packet_data: bytes) -> bool:
if packet_id == 0x01: # Chat Message
chat_message: str = Packet.decode_fields (packet_data, (String,)) [0]
if chat_message.startswith ("/"): return True # pass through commands
chat_message = "SUBSCRIBE TO TECHNOBLADEEEEEEEEee"
out_data = Packet.encode_fields ((chat_message, String))
to_server_func (0x01, out_data) # send modified chat message
print_func ("hacked outgoing chat message")
return False # don't pass through hacked chat message
return True # pass through other c2s packets
def server_to_client (self, current_state: dict, print_func: PrintFunc, to_client_func: SendFunc, to_server_func: SendFunc, packet_id: int, packet_data: bytes) -> bool:
return True # pass through unmodified
def disconnected (self): pass__init__, ready, and disconnected are called when a client connects, completes login, and disconnects, respectively. Only __init__ accepts any arguments (Host is an (ip, port) tuple), and the return value is discarded.
(They're mainly meant for handlers to do any startup/cleanup necessary; disconnected is guaranteed to be called unless the process is killed.)
client_to_server and server_to_client are called when a packet is sent from the client to the server and from the server to the client, respectively, with the following caveats:
current_state: dictcontains information about the current state of the protocol, such as["id"]representing the value of the notchian state enum (0 = handshaking, 1 = status, 2 = login, 3 = play)print_func: PrintFuncis a function that prints the sole argument as a string with fancy formatting, depending on which direction the function is called from. In addition to a single positional argument whichstris called on to form the body of the message, it accepts keyword argumentsgeneric: bool = False(avoid appending extra packet info?) andmeta: bool = False(ifgeneric, add extra emphasis?).to_client_func: SendFunc, to_server_func: SendFuncare functions that send a packet with the given positional packet ID (int) and data (bytes) in the direction indicated by the variable name, handling any necessary compression and/or encryption.packet_idis the packet ID (int) of the incoming packet. See the wiki.vg page below to understand how to interpret this; serverbound and clientbound directions have separate sets of IDs, and the connection state will always be 3 aka Play.packet_datais the data contained in the incoming packet.Packet.decode_fieldsandPacket.encode_fieldsprovide interoperability with Python types and types in protocol format.- The return value, a
bool, indicates whether the packet should be passed through unmodified to the other side. ReturningTrueis helpful inelseblocks if you want special behavior to occur only for specific packets.
Note the example usages of Packet.decode_fields and Packet.encode_fields based on wiki.vg's description of the serverbound Chat Message packet (id 0x01, single String field containing the raw message text)
To start the server with a custom handler class, add another argument with the form package.path:ClassName:
package.pathis the path to the.pyfile containing the class implementation, in Pythonimportformat.ClassNameis the name of the class.
ex. python3 main.py auth.json 0.0.0.0:25567 localhost:25566 example_handlers.chat_modifier:ChatModifierHandler will use the ChatModifierHandler class from example_handlers/chat_modifier.py.
Good luck and happy MITM'ing! If you make a cool handler, open an issue with a link to the source code, and I'll add it to this list of cool handlers:
ChatModifierHandlerby An0nDev: replaces all outgoing global chat messages with the text "SUBSCRIBE TO TECHNOBLADEEEEEEEEee"
https://wiki.vg for all protocol information, most from https://wiki.vg/index.php?title=Protocol&oldid=7368
python requests and cryptography libraries to handle http requests and encryption
many stdlib components, namely zlib for compression