Write-up Flag Submission Server (angstromctf)
User1
In soviet Russia @ch4nnel1 subscribes to you
Content:
Analysis

By quickly looking at the ASM code of the issued server, you can understand the following:
- the server runs on port 21450
- the function responsible for reading data from the client (recv) is called in only one place and stores the received data in rbp-0x120
- the flag is read from the file and stored in rbp-0x160
Having traced the progress of the program after receiving data from the client, we note an interesting piece of code 0x14f5-0x1929. It shows that the server processes data in packets of 22 (0x16) bytes, and performs a series of checks, at the end of which there is a check with one of the flag charms.
Let's start the server under the debugger. When we connect to him, he gives us some 13 bytes.

For now, ignore them, send it 22 different bytes to understand where the server is using which parts of the packet. Since the flag comparison is the most interesting part, let's start with it. After debugging and exploring the stack, we will understand that the flag char is compared with the 9th byte of the packet, we will try to pass this check for at least the first char. We put 9 byte of packet "a" (flag format = actf{...}) and ... The server terminates the connection, yippee! Now we know the first letter of the flag (if 9 bytes != "a", then the server does not break the connection). Again, looking at the ASM code, you can understand that the disconnect occurred due to the fact that the value of rbp-0x380358==0.
Now let's look at the checks before checking using the flag, there are 2 of them, they make *(rbp-0x380358)=0. Let's explore the first one (0x15c4-0x1646), it takes 13 bytes of the packet starting from 10 and compares them one by one with some values. These values are a xor of a certain constant array ([0xde, 0xad, 0xbe, 0xef, 0xfe, 0xed, 0xca, 0xfe, 0x13,0x37,0xab, 0xcd, 0xef]) with those 13 bytes that we get when we connect to the server.
The second check (0x164c-0x16b2) compares the first 8 bytes of the packet with the value of a certain function, the input of which is a constant = 0x13371337. Although the function contains rand(), the seed for it is precisely specified by its argument, so it will return the same value for the same arguments.
This results in the following package structure:
[second_check_val][data][first_check_val]
{1..............8}{9..9}{10...........22}
Having sent the first packet with different data, you can come to the following conclusion. The server returns 0x0D if the flag letter does not match the data, and returns 0x37 and some 4 bytes (again, forget about them for now) if the flag letter matches. And after trying to send 2 packet with the same check values as the first, the server disconnected me => some of the first two checks do not work as we think. Having debugged, you can understand that the second check does not pass because another value is passed to the function arguments, not 0x13371337. And having carefully looked at it (or, like normal people, after reading the asm), we will understand that this is the 32-bit value that the server returns to us when the letter of the flag is correctly guessed.
As a result, the validation pseudocode looks something like this:
flag="actf{some_c000ll_t3xt}"
some_check_val=[0xde, 0xad, 0xbe, 0xef, 0xfe, 0xed, 0xca, 0xfe, 0x13, 0x37, 0xab, 0xcd, 0xef]
buf=get_arr_13char()
send(buf)
for i in range(13):
some_check_val[i]^=buf[i]
arg=0x13371337
pac=[] #like pointer
counter=0
while 1==1:
check=1
for i in range(22):
pac[i]=recv(1)
for i in range(9, 22):
if(pac[i]!=some_check_val[i-9]):
check=0
if(int(pac[0:8])!=get_other_check_val(arg)):
check=0
if(pac[8]==flag[counter]):
if(check==0):
break
else:
send(0x37)
counter+=1
arg=some_new_int()
send(arg)
else:
send(0x0D)
And then by writing such a script for the flag brute (bytes for the first check I xored myself, and the values for the second check I get by passing the required values to the local server function), we get the flag.
Solution
Solution:
- Find out that the server is running at 21450
- Find 2 package checks and find out the package structure
- Write a "client" that can sign packages
- Add the brute of the flag for the client
Example of solution script
Epilogue
And now I understand why there are so few solutions on this task

A cool way to deal with idaphils, radar rules!
