Given was PlayCAP.pcapng
and app.html
. First checking the PCAP, we see that an USB connection is captured there. In the Response DEVICE
, the vendor Nintendo Co., Ltd
is shown. Later the device name is sent as string: Pro Controller
.
At https://github.com/ToadKing/switch-pro-x/blob/master/switch-pro-x/ProControllerDevice.cpp there is a user-space driver for the Pro Controller for PC.
Now, we extract all data from the PCAP and parse them. In the app.html
, we see that they use the direction buttons for changing the selection, A
to select and X
to reset (set current selection to [0,0]).
Using the Bitmasks from the driver, only reading a button once (by using a state-machine), and using the same functionality as app.html
, we can decode the flag.
Script here:
#!/usr/bin/env python3
b = []
with open("data.txt", "r") as f:
for i in f.read().split("\n"):
if len(i) == 0:
continue
b.append([int(f"{i[j]}{i[j+1]}", 16) for j in range(0, len(i), 2)])
curr_x = 0
curr_y = 0
flag = []
buttons = []
# state is saved because the controller sends a cyclic status message so we get multiple messages with the same state which we can safely ignore
# UP DOWN LEFT RIGHT A X
state = [False, False, False, False, False, False]
for i in b:
type = i[0]
# only use type 30
if type != 0x30:
continue
serial = i[1] # ignored
button_pressed = [
0x02 & i[5] != 0, # UP
0x01 & i[5] != 0, # DOWN
0x08 & i[5] != 0, # LEFT
0x04 & i[5] != 0, # RIGHT
0x08 & i[3] != 0, # A
0x02 & i[3] != 0, # X
]
for i in range(6):
# button is now pressed and wasn't before
if button_pressed[i] and not state[i]:
state[i] = True
if i == 0: # UP
buttons.append("↑")
curr_y = (curr_y - 1 + 6) % 6
if i == 1: # DOWN
buttons.append("↓")
curr_y = (curr_y + 1) % 6
if i == 2: # LEFT
buttons.append("←")
curr_x = (curr_x - 1 + 10) % 10
if i == 3: # RIGHT
buttons.append("→")
curr_x = (curr_x + 1) % 10
if i == 4: # A
flag.append("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.,-=:;{}"[curr_y * 10 + curr_x])
buttons.append("A")
if i == 5: # X
curr_x = 0
curr_y = 0
buttons.append("X")
# button is not longer pressed, but was before
if not button_pressed[i] and state[i]:
state[i] = False
print("Buttons: " + "".join(buttons))
print("Flag: " + "".join(flag))
Buttons: XXX→→→A↓↓↓↓A↑←A→→→→→→→A→→→→→↑↑→→→→A↓↓↓↓A↑↑↑↑←←←←←←←A↓↓←A→→→→→↓A←A↑↑↑→A↓↓→→→←A↑←A↓↓←←←←←←↓A↑↑↑↑↑A→→→→→→A↓↓A→→↓A→→A→↓A↑↑→→→→→A→→→A↓↓↓AX
Flag: DrgnS{LetsPlayAGamepad}
Bonus: Running the challenge on a regular Switch