Upon reaching the factory door, you physically open the RFID lock and find a flash memory chip inside. The chip's package has the word W25Q128 written on it. Your task is to uncover the secret encryption keys stored within so the team can generate valid credentials to gain access to the facility.
Information Gathering
This challenge provided a Python file and a Netcat server.
import socketimport jsondefexchange(hex_list,value=0):# Configure according to your setup host ='127.0.0.1'# The server's hostname or IP address port =1337# The port used by the server cs=0# /CS on A*BUS3 (range: A*BUS3 to A*BUS7) usb_device_url ='ftdi://ftdi:2232h/1'# Convert hex list to strings and prepare the command data command_data ={"tool":"pyftdi","cs_pin": cs,"url": usb_device_url,"data_out":[hex(x)for x in hex_list],# Convert hex numbers to hex strings"readlen": value}with socket.socket(socket.AF_INET, socket.SOCK_STREAM)as s: s.connect((host, port))# Serialize data to JSON and send s.sendall(json.dumps(command_data).encode('utf-8'))# Receive and process response data =b''whileTrue: data += s.recv(1024)if data.endswith(b']'):break response = json.loads(data.decode('utf-8'))#print(f"Received: {response}")return response# Example commandjedec_id =exchange([0x9F],3)print(jedec_id)
It looks like this code will connect to the server and execute commands using the hex list that the user will provide to output information about the device/hardware. Also, this is using the intermediary layer to communicate with the device/hardware.
PyFtdi aims at providing a user-space driver for popular FTDI devices, implemented in pure Python language. From PyFtdi Documentation.
I did some research on the W25Q128 device, and I found the datasheet containing information about this hardware.
The W25Q128FV (128M-bit) Serial Flash memory provides a storage solution for systems with limited space, pins and power. From W25Q128FV Datasheet
Winbond W25Q128FV
Going back to the Python code, the default hex list stored in a list is 0x9F, which is to read the JEDEC ID that contains the manufacturer ID of the hardware.
W25Q128FV datasheet 8.2.29
So I try to connect to the server (change the host and port) and see what the output of 0x9 is, and this is the raw output in decimal form.
result in raw value
I had to modify the script to convert the raw output into hex form,
result with hex value
I found this table on GitHub, and the hex we got matches the JEDEC ID; indeed, it is a Winbond W25Q128,
Winbond devices JEDEC ID
Solution
So, I decided to read all of the information about this device, such as the device ID, security register, SFDP, and unique ID, but had no luck at all. Until I saw the data instruction 0x03,
W25Q128FV datasheet 8.2.6
Again, I modify the script for me to run commands easily (as args) and I added hex to string conversion to output the characters in readable form,
I run the Python script with 0x03 to read data and 49 (it depends, but the length of the flag is 49 characters) as the length of the returned data by the server.
hexd = [hex(num) for num in jedec_id]
print("Hex value: ", hexd, '\n')
import socket
import json
import sys
def exchange(hex_list, value=0):
# Configure according to your setup
host = '<SERVER_IP>' # The server's hostname or IP address
port = <SERVER_PORT> # The port used by the server
cs=0 # /CS on A*BUS3 (range: A*BUS3 to A*BUS7)
usb_device_url = 'ftdi://ftdi:2232h/1'
# Convert hex list to strings and prepare the command data
command_data = {
"tool": "pyftdi",
"cs_pin": cs,
"url": usb_device_url,
"data_out": [hex(x) for x in hex_list], # Convert hex numbers to hex strings
"readlen": value
}
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.connect((host, port))
# Serialize data to JSON and send
s.sendall(json.dumps(command_data).encode('utf-8'))
# Receive and process response
data = b''
while True:
data += s.recv(1024)
if data.endswith(b']'):
break
response = json.loads(data.decode('utf-8'))
#print(f"Received: {response}")
return response
# Example command
value = exchange([int(sys.argv[1], 16)], int(sys.argv[2]))
hexd = [hex(num) for num in value]
string = ''.join([chr(int(hex_str[2:], 16)) for hex_str in hexd])
print("Raw value: ", value, '\n')
print("Hex value: ", hexd, '\n')
print("String value: ", string, '\n')