Hello everybody here is our writeup on how we tackled and solved some of the challenges from picoCTF 2024 competition. ![Screenshot 2024-03-13 at 13-47-02 picoCTF - Event](https://hackmd.io/_uploads/SyYD8xk0p.png) ## WEB ### BookMarklet (50 Points) #### Description ![image](https://hackmd.io/_uploads/B1MaiZJA6.png) #### Solution This was fairly very easy! Provided with javascript code when visiting the web application all we do is copy the function and run it through the console to get the flag: ![image](https://hackmd.io/_uploads/S1NMh-JA6.png) ![image](https://hackmd.io/_uploads/Sywrnb1AT.png) FLAG : picoCTF{p@g3_turn3r_cebccdfe} ### IntroToBurp (100 Points) #### Description ![image](https://hackmd.io/_uploads/B14KnbJAp.png) #### Solution ### Unminify (100 Points) #### Description ![image](https://hackmd.io/_uploads/SJqK-GJCa.png) #### Solution First opening the web application and reading the source code through inspection features I get that the HTML code is minified: ![image](https://hackmd.io/_uploads/HJ32bGy0p.png) Copying the code and using https://unminifyall.com/ I was able to un-minify the code and get the flag from it: ![image](https://hackmd.io/_uploads/r1QyGzJAa.png) FLAG : picoCTF{pr3tty_c0d3_b99eb82e} ### Trickster #### Description ![image](https://hackmd.io/_uploads/Hk9-SKkR6.png) #### Solution We are given a web application with a feature to upload PNG images. Quickly I was able to bypass the upload feature and upload a malicious file since it checked for the image extension and the magic byte: ![image](https://hackmd.io/_uploads/SyfsHYkRp.png) Now let's test to see if the file is actually uploaded or not. I just guessed the `/uploads/` folder with an instinct hehe! ![image](https://hackmd.io/_uploads/rkKzLtk0p.png) I then got the flag from the directory before it :-1: ![image](https://hackmd.io/_uploads/By9V8tJ0p.png) FLAG : picoCTF{c3rt!fi3d_Xp3rt_tr1ckst3r_9ae8fb17} #### No Sql Injection #### Description ![Screenshot 2024-03-15 at 03-58-56 picoCTF - picoCTF 2024](https://hackmd.io/_uploads/SyJzlFbCp.png) ### Solution The challenge was all about NoSQL injection, with this challenge we were need to first bypass the login page and then find the encoded base64 flag with burpsuite is easy to find the flag. ![Screenshot 2024-03-15 at 04-02-34 Non-SQL injection](https://hackmd.io/_uploads/r10oeKZCp.png) I used this payload to bypass the login page ``` username:{"$gt": ""} password:{"$gt": ""} ``` With this payload just found myself inside the admin page, time to find the flag. ![Screenshot 2024-03-15 at 04-05-04 Non-SQL injection](https://hackmd.io/_uploads/By7PbKWRT.png) Easy with burp suite to find the encoded base64 flag from the reponse ``` ┌──(alienx㉿alienX)-[~/Desktop/PPP/PICO-2024] └─$ echo "cGljb0NURntqQmhEMnk3WG9OelB2XzFZeFM5RXc1cUwwdUk2cGFzcWxfaW5qZWN0aW9uXzVlMjQ1ZDZlfQ==" | base64 -d picoCTF{jBhD2y7XoNzPv_1YxS9Ew5qL0uI6pasql_injection_5e245d6e} ``` ``` picoCTF{jBhD2y7XoNzPv_1YxS9Ew5qL0uI6pasql_injection_5e245d6e} ``` ## Reverse Engineering ### Packer (100 Points) #### Description ![image](https://hackmd.io/_uploads/HJdXdgyC6.png) #### Solution Provided with an executable, the first thing I check is to see if the binary is packed as the challenge name hints: ![image](https://hackmd.io/_uploads/HyFddxkCT.png) With the command `strings out | tail` I was able to see how the last string looks like and it's actually packed with UPX. What follows next is to decompress the packed binary to an original binary using the command `upx -d out -o original` will decompress the packed binary to a new binary known as "original": ![image](https://hackmd.io/_uploads/r1N4YxyRT.png) As seen above we are able to successfuly decompress the packed binary this will allow us to get a clear output of strings declares in variables and disassembling of the binary. With the command `rabin2 -z original | grep -i "flag"` I was able to get a weird string encoded in hex: ![image](https://hackmd.io/_uploads/Hyv6Yly0p.png) Decoding it will provide us with the flag: ![image](https://hackmd.io/_uploads/BkeZqeJ0a.png) FLAG : picoCTF{U9X_UnP4ck1N6_B1n4Ri3S_1a5a3f39} ### FastCheck (200 Points) #### Description ![image](https://hackmd.io/_uploads/Hy1T5xk0p.png) #### Solution Given the description, I first try to check for the strings available on the file using the command `strings bin`: ![image](https://hackmd.io/_uploads/SkLIjlJ06.png) I then got a partial flag, since it's not complete yet the next thing is to disassemble the binary and have a clear read of how it works since when executed it doesn't give any output ### weirdSnake ### Description ![Screenshot 2024-03-15 at 03-41-29 picoCTF - picoCTF 2024](https://hackmd.io/_uploads/HJ0RiuZRp.png) ### solution With this challenge you were provided with the binary file, with assembly language, downloaded it and it is in ascii form i was able to read it. ``` ┌──(alienx㉿alienX)-[~/Desktop/PPP/PICO-2024] └─$ mv ~/Downloads/snake . ┌──(alienx㉿alienX)-[~/Desktop/PPP/PICO-2024] └─$ file snak.py snak.py: ASCII text ┌──(alienx㉿alienX)-[~/Desktop/PPP/PICO-2024] └─$ cat snake| head 1 0 LOAD_CONST 0 (4) 2 LOAD_CONST 1 (54) 4 LOAD_CONST 2 (41) 6 LOAD_CONST 3 (0) 8 LOAD_CONST 4 (112) 10 LOAD_CONST 5 (32) 12 LOAD_CONST 6 (25) 14 LOAD_CONST 7 (49) 16 LOAD_CONST 8 (33) 18 LOAD_CONST 9 (3) ┌──(alienx㉿alienX)-[~/Desktop/PPP/PICO-2024] └─$ ``` From the snake file, contains assembly code with the assembly code found some constant decimal value being loaded into the memory location 'LOAD_CONST' but also this value are being XOR with the 'key_str' which was 'J_o3t'.There are two ways to do this you can start by writting a script that load the encoded decimal value and XOR it with the key or you can use cyberchef. N/B: but also the key was in a reverse like this. ![Screenshot 2024-03-15 at 03-52-39 From Decimal XOR - CyberChef](https://hackmd.io/_uploads/H1bvAdbR6.png) The first attempt with the key didn't reveal a flag but decided to change it like this. ![Screenshot 2024-03-15 at 03-53-53 From Decimal XOR - CyberChef](https://hackmd.io/_uploads/B19jCO-Aa.png) Another way to know they used in simple encryption its by using the "picoCTF" as we know is part of the flag And from there you can see that key was reverse 't_Jo3' and replace the key with the privious one. ![Screenshot 2024-03-15 at 03-57-30 From Decimal XOR - CyberChef](https://hackmd.io/_uploads/S1EFkK-Ca.png) ``` flag:picoCTF{N0t_sO_coNfus1ng_sn@ke_516dfaee} ``` ## FORENSIC ### Scan Surprise #### Description ![Screenshot 2024-03-13 at 14-06-49 picoCTF - picoCTF 2024](https://hackmd.io/_uploads/HkQlseyR6.png) #### Solution From the above challenge we were given a zip file so we need to unzip the file, no need to start an instance, ![Screenshot from 2024-03-13 14-08-45](https://hackmd.io/_uploads/S12OieyAT.png) As we can see below we are given with a QR code lets use cyberchef to decode this ![Screenshot 2024-03-13 at 14-10-18 Parse QR Code - CyberChef](https://hackmd.io/_uploads/r1iioeJA6.png) ``` picoCTF{p33k_@_b00_d4ca652e} ``` ### CanYouSee #### Description ![Screenshot 2024-03-13 at 14-30-37 picoCTF - picoCTF 2024](https://hackmd.io/_uploads/Sy9qlWyCT.png) #### solution From the above zipped file we just need to unzip the file and use exiftool for viewing metadata of the image ![Screenshot from 2024-03-13 14-30-31](https://hackmd.io/_uploads/ByERlbJRa.png) After viewing the metadata we find that the image has some interesting base64 encoded text we can decrypt them with a terminal also as show above ``` picoCTF{ME74D47A_HIDD3N_3b9209a2} ``` ### Secret of the Polyglot #### Description ![Screenshot 2024-03-13 at 16-39-12 picoCTF - picoCTF 2024](https://hackmd.io/_uploads/HkaaRf1CT.png) ### solution From the avove we have been given a pdf file based and being requiested to find the flag,when you open the file at initially you will find that the file is a pdf based with half of the flag, lemme use a simple way i used to solve this ![Screenshot from 2024-03-13 16-42-23](https://hackmd.io/_uploads/SyqHkQ1Aa.png) So we need to find another flag part,we need to check the file format first before we proceed. ``` ┌──(alienx㉿alienX)-[~/…/PPP/PICO-2024/forensic/home] └─$ file flag2of2-final.pdf flag2of2-final.pdf: PNG image data, 50 x 50, 8-bit/color RGBA, non-interlaced ┌──(alienx㉿alienX)-[~/…/PPP/PICO-2024/forensic/home] └─$ ls ctf-player flag2of2-final.pdf ┌──(alienx㉿alienX)-[~/…/PPP/PICO-2024/forensic/home] └─$ file flag2of2-final.pdf flag2of2-final.pdf: PNG image data, 50 x 50, 8-bit/color RGBA, non-interlaced ┌──(alienx㉿alienX)-[~/…/PPP/PICO-2024/forensic/home] └─$ foremost flag2of2-final.pdf Processing: flag2of2-final.pdf |*| ┌──(alienx㉿alienX)-[~/…/PPP/PICO-2024/forensic/home] └─$ ls -la output/png/ total 12 drwxr-xr-- 2 alienx alienx 4096 Mar 13 16:46 . drwxr-xr-- 3 alienx alienx 4096 Mar 13 16:46 .. -rw-r--r-- 1 alienx alienx 914 Mar 13 16:46 00000000.png ┌──(alienx㉿alienX)-[~/…/PPP/PICO-2024/forensic/home] └─$ open output/png/00000000.png ┌──(alienx㉿alienX)-[~/…/PPP/PICO-2024/forensic/home] └─$ open output ┌──(alienx㉿alienX)-[~/…/PPP/PICO-2024/forensic/home] └─$ open output/png/00000000.png ┌──(alienx㉿alienX)-[~/…/PPP/PICO-2024/forensic/home] └─$ ``` Now we know that were dealing with a pdf with a image data based file,and I decided to use foremost tool to extract some information. ![Screenshot from 2024-03-13 16-48-47](https://hackmd.io/_uploads/Hy7pe710p.png) And if you take a close look u will see the other flag ``` picoCTF{f1u3n7_1n_pn9_&_pdf_90974127} ``` ## GENERAL ### Collaborative Development (75 Points) #### Description ![image](https://hackmd.io/_uploads/ryDufQy0a.png) #### Solution After downloading the zip file, I was able to see that it's a git repo and inside it is a file `flag.py` : ![image](https://hackmd.io/_uploads/SkEVQ7kCT.png) using the command `git show` I was able to look at the previous commits: ![image](https://hackmd.io/_uploads/ry6S77k0p.png) Nothing interesting from here, At first I thought it was a dead end but then I decided to check for other branches using the command `git branch -a`: ![image](https://hackmd.io/_uploads/HJEuXm1Ap.png) Now switching to each branch and reading through the flag.py I was able to retrieve the flag. To switch branch do `git checkout [branch-name]` ![image](https://hackmd.io/_uploads/B11y471Ca.png) Concatenating the strings we have the flags! FLAG : picoCTF{t3@mw0rk_m@k3s_th3_dr3@m_w0rk_2c91ca76} ### Endianness #### Description ![image](https://hackmd.io/_uploads/HJ04OmyAp.png) #### Solution Provided with the source code: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdbool.h> #include <ctype.h> #include <time.h> char *find_little_endian(const char *word) { size_t word_len = strlen(word); char *little_endian = (char *)malloc((2 * word_len + 1) * sizeof(char)); for (size_t i = word_len; i-- > 0;) { snprintf(&little_endian[(word_len - 1 - i) * 2], 3, "%02X", (unsigned char)word[i]); } little_endian[2 * word_len] = '\0'; return little_endian; } char *find_big_endian(const char *word) { size_t length = strlen(word); char *big_endian = (char *)malloc((2 * length + 1) * sizeof(char)); for (size_t i = 0; i < length; i++) { snprintf(&big_endian[i * 2], 3, "%02X", (unsigned char)word[i]); } big_endian[2 * length] = '\0'; return big_endian; } char *generate_random_word() { printf("Welcome to the Endian CTF!\n"); printf("You need to find both the little endian and big endian representations of a word.\n"); printf("If you get both correct, you will receive the flag.\n"); srand(time(NULL)); int word_length = 5; char *word = (char *)malloc((word_length + 1) * sizeof(char)); for (int i = 0; i < word_length; i++) { word[i] = (rand() % 26) + 'a'; } word[word_length] = '\0'; return word; } int main() { char *challenge_word = generate_random_word(); printf("Word: %s\n", challenge_word); fflush(stdout); char *little_endian = find_little_endian(challenge_word); size_t user_little_endian_size = strlen(little_endian); char user_little_endian[user_little_endian_size + 1]; bool correct_flag = false; while (!correct_flag) { printf("Enter the Little Endian representation: "); fflush(stdout); scanf("%10s", user_little_endian); for (size_t i = 0; i < strlen(user_little_endian); i++) { user_little_endian[i] = toupper(user_little_endian[i]); } if (strncmp(user_little_endian, little_endian, user_little_endian_size) == 0) { printf("Correct Little Endian representation!\n"); fflush(stdout); correct_flag = true; } else { printf("Incorrect Little Endian representation. Try again!\n"); fflush(stdout); } } char *big_endian = find_big_endian(challenge_word); size_t user_big_endian_size = strlen(big_endian); char user_big_endian[user_big_endian_size + 1]; bool final_flag = false; while (!final_flag) { printf("Enter the Big Endian representation: "); fflush(stdout); scanf("%10s", user_big_endian); for (size_t i = 0; i < strlen(user_big_endian); i++) { user_big_endian[i] = toupper(user_big_endian[i]); } if (strncmp(user_big_endian, big_endian, user_big_endian_size) == 0) { printf("Correct Big Endian representation!\n"); fflush(stdout); final_flag = true; } else { printf("Incorrect Big Endian representation. Try again!\n"); fflush(stdout); } } FILE *flag = fopen("flag.txt", "r"); if (flag == NULL) { printf("Flag not found. Please run this on the server\n"); fflush(stdout); exit(0); } char flag_content[100]; fgets(flag_content, sizeof(flag_content), flag); printf("Congratulations! You found both endian representations correctly!\n"); fflush(stdout); printf("Your Flag is: %s\n", flag_content); fflush(stdout); exit(0); return 0; } ``` The way the little endian and big endian are generated are all defined from the source code and the result from the generated string's endian should match your answer. Thus this means we need to tweak their own code to give us the output of each random word they generate for us to create the little endian and big endian. Where are I ended up having this C Program: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdbool.h> #include <ctype.h> #include <time.h> char *find_little_endian(const char *word) { size_t word_len = strlen(word); char *little_endian = (char *)malloc((2 * word_len + 1) * sizeof(char)); for (size_t i = word_len; i-- > 0;) { snprintf(&little_endian[(word_len - 1 - i) * 2], 3, "%02X", (unsigned char)word[i]); } little_endian[2 * word_len] = '\0'; return little_endian; } char *find_big_endian(const char *word) { size_t length = strlen(word); char *big_endian = (char *)malloc((2 * length + 1) * sizeof(char)); for (size_t i = 0; i < length; i++) { snprintf(&big_endian[i * 2], 3, "%02X", (unsigned char)word[i]); } big_endian[2 * length] = '\0'; return big_endian; } int main() { char challenge_word[100]; scanf("%s", challenge_word); printf("Word: %s\n", challenge_word); fflush(stdout); char *little_endian = find_little_endian(challenge_word); printf("\n"); printf(little_endian); size_t user_little_endian_size = strlen(little_endian); char user_little_endian[user_little_endian_size + 1]; bool correct_flag = false; char *big_endian = find_big_endian(challenge_word); printf("\n"); printf(big_endian); size_t user_big_endian_size = strlen(big_endian); char user_big_endian[user_big_endian_size + 1]; return 0; } ``` This program allows me to put in the input as the generated word and it'll give me a response with little endian and big endian of the word: ![image](https://hackmd.io/_uploads/HkXvtQ1Rp.png) Now time to use these outputs in the program from the instance : ![image](https://hackmd.io/_uploads/S1aKYQ10p.png) FLAG : picoCTF{3ndi4n_sw4p_su33ess_28329f0a} ### Dont-You-Love-Banners #### Description ![image](https://hackmd.io/_uploads/S1Bz44J0a.png) #### Solution After launching the instance we are provided with two hosts, one of them leaks very crucial information: ![image](https://hackmd.io/_uploads/S1aO4NkCp.png) And the other host will ask us for the password and two more other questions: ![image](https://hackmd.io/_uploads/ryBCEE1Ra.png) Upon answering these questions we are then granted access to the host there are two intereting files "banner" and "text": ![image](https://hackmd.io/_uploads/HyWzBVJC6.png) Digging further, I get the flag.txt file in the /root directory but it's not readable although the script is readable: ![image](https://hackmd.io/_uploads/HJFFH4kRT.png) From reviewing the code, we realize that since root is running this script and it's printing a file that we have permission to read and write to. Means we can easily create a symbolic link to the file banner with `/root/flag.txt` and print flag.txt from the banner we saw earlier. ![image](https://hackmd.io/_uploads/BJRJLE10p.png) Now let's get our flag: ![image](https://hackmd.io/_uploads/HJuWLVkRa.png) FLAG : picoCTF{b4nn3r_gr4bb1n9_su((3sfu11y_ed6f9c71} ## BINARY EXPLOITATION ### Format String 0 #### Description ![image](https://hackmd.io/_uploads/BJkF34kCp.png) #### Solution Provided with a source code, reviewing it I realized that there is no room for non-required input! As in what you put is what is defined. Passing the first condition of the binary we head to the second condition where the third option seems like by default would leak some juicy information to us: ![image](https://hackmd.io/_uploads/BJFJTNyRp.png) Testing the logic locally I was able to leak my content in `flag.txt`: ![image](https://hackmd.io/_uploads/HJrXa41Ra.png) Let's get the flag: ![image](https://hackmd.io/_uploads/S1aVpVk06.png) FLAG : picoCTF{7h3_cu570m3r_15_n3v3r_SEGFAULT_63191ce6} ## heap 0 ### Description ![Screenshot 2024-03-13 at 18-48-02 picoCTF - picoCTF 2024](https://hackmd.io/_uploads/By-JaNkR6.png) ## solution Were provided with the binary with its source, but i didn't want to bother to download the source code or the binary you can just start the instance and proceed with the binary ![Screenshot from 2024-03-13 18-50-41](https://hackmd.io/_uploads/BkWP6EyAp.png) I went direct to the input of the buffer and i inputed as max valua as i can like this ![Screenshot from 2024-03-13 18-47-16](https://hackmd.io/_uploads/H1S5a4y06.png) simple like that and we get the flag ``` picoCTF{my_first_heap_overflow_76775c7c} ``` ### Format String 1 #### Description ![image](https://hackmd.io/_uploads/BkNYMH1Ap.png) #### Solution ## CYRPTOGRAPHY ### [Chalenge Name] #### Description #### Solution