How does U16 function of pwn (CTF) library works?

69 views Asked by At

I am trying to solve uni challenge in Python, the challenge is located in CTF server (using pwn library to connect). I can interact with the server by sending keys, for example: 1-help, 2-read info from array, etc.

After submitting a key, the server asks me to also provide serialised data. For example, for reading info from array, i should submit the following: 0100(01 is key for reading), 0500(5 is row), 0400(4 is column). So, i send 010005000400.

I can see the challenge code, in order to understand how it works in the server. Input goes through the following operation:

data = input(" > Enter serialized data: ").strip() #input
serialized_input = binascii.unhexlify(data.encode()) #unhexlifying

After that, it takes first two bytes of input (0100) and checks if it matches the operation code. (0x0001 for reading)

Ex:

if u16(serialized_input[0:2]) == 0x0001: #u16(b'\x01\x00')
        row = u16(serialized_input[2:4]) #u16(b'\x05\x00')
        col = u16(serialized_input[4:6]) #u16(b'\x04\x00')
        print(f"0x{ram.read(row, col):02x}")  

The u16 function is a common utility function in the context of binary exploitation and CTF challenges. It's typically used to interpret a 2-byte sequence (16 bits) as an unsigned integer.(from ChatGPT)

def u16(data):
    return int.from_bytes(data, byteorder='big') 

This function is not defined in my code, it is a part pf pwn library.

So, I want to perform the operation which will check my work. The code for this operation is 0xcafe. I need to come up with some input, which will pass this if statement:


if u16(serialized_input[0:2]) == 0xcafe:

The problem is that I am not even sure that u16 (unpack function) can return letters. And I have even less idea about what two bytes could be "cafe" after unpack

I tried using 'cafe' as input and got output 65226. I tried 65226 as input, but got 20998 as output. I tried to use 65226 as binary, but since u16 only takes 2 bytes and binary representation of 65226 is longer than 2 bytes, it didn't work out.

input = 'cafe'
    serialized_input = binascii.unhexlify(input.encode())
    result = u16(serialized_input[0:2]) # u16(b'\xca\xfe')
1

There are 1 answers

0
sammo4 On

I copied the code and ran it on my machine and using cafe as input did work for me. This is because its not checking for the string 0xcafe, it's checking for a hexadecimal number.
The result of u16(serialized_input[0:2]) with cafe as input would evaluate to 51966 or 0xcafe in hex

In Python, saying

print("win") if 0xcafe == 51966 else print("L")

this printed win

also entering 0xcafe into python3 terminal would evaluate to 51966

I'm curious why you got 65226 which is feca or little-indian for cafe, so maybe some experimentation with the cafe and feca.

Although entering 51966 would not evaluate to 0xcafe in this program because the input is being unhexified if you go to a decimal to hex whatever u16(serialized_input[0:2]) evaluates to, putting that into a decimal to hex converter would give your original input.