a, a.visited { color: inherit; text-decoration: underline; } .pdf-relative-link-path { font-size: 80%; color: #444; } h1, h2, h3 { letter-spacing: -0.01em; line-height: 1.2; font-weight: 600; margin-bottom: 0; } .page-title { font-size: 2.5rem; font-weight: 700; margin-top: 0; margin-bottom: 0.75em; } h1 { font-size: 1.875rem; margin-top: 1.875rem; } h2 { font-size: 1.5rem; margin-top: 1.5rem; } h3 { font-size: 1.25rem; margin-top: 1.25rem; } .source { border: 1px solid #ddd; border-radius: 3px; padding: 1.5em; word-break: break-all; } .callout { border-radius: 3px; padding: 1rem; } figure { margin: 1.25em 0; page-break-inside: avoid; } figcaption { opacity: 0.5; font-size: 85%; margin-top: 0.5em; } mark { background-color: transparent; } .indented { padding-left: 1.5em; } hr { background: transparent; display: block; width: 100%; height: 1px; visibility: visible; border: none; border-bottom: 1px solid rgba(55, 53, 47, 0.09); } img { max-width: 100%; } @media only print { img { max-height: 100vh; object-fit: contain; } } @page { margin: 1in; } .collection-content { font-size: 0.875rem; } .column-list { display: flex; justify-content: space-between; } .column { padding: 0 1em; } .column:first-child { padding-left: 0; } .column:last-child { padding-right: 0; } .table_of_contents-item { display: block; font-size: 0.875rem; line-height: 1.3; padding: 0.125rem; } .table_of_contents-indent-1 { margin-left: 1.5rem; } .table_of_contents-indent-2 { margin-left: 3rem; } .table_of_contents-indent-3 { margin-left: 4.5rem; } .table_of_contents-link { text-decoration: none; opacity: 0.7; border-bottom: 1px solid rgba(55, 53, 47, 0.18); } table, th, td { border: 1px solid rgba(55, 53, 47, 0.09); border-collapse: collapse; } table { border-left: none; border-right: none; } th, td { font-weight: normal; padding: 0.25em 0.5em; line-height: 1.5; min-height: 1.5em; text-align: left; } th { color: rgba(55, 53, 47, 0.6); } ol, ul { margin: 0; margin-block-start: 0.6em; margin-block-end: 0.6em; } li > ol:first-child, li > ul:first-child { margin-block-start: 0.6em; } ul > li { list-style: disc; } ul.to-do-list { padding-inline-start: 0; } ul.to-do-list > li { list-style: none; } .to-do-children-checked { text-decoration: line-through; opacity: 0.375; } ul.toggle > li { list-style: none; } ul { padding-inline-start: 1.7em; } ul > li { padding-left: 0.1em; } ol { padding-inline-start: 1.6em; } ol > li { padding-left: 0.2em; } .mono ol { padding-inline-start: 2em; } .mono ol > li { text-indent: -0.4em; } .toggle { padding-inline-start: 0em; list-style-type: none; } /* Indent toggle children */ .toggle > li > details { padding-left: 1.7em; } .toggle > li > details > summary { margin-left: -1.1em; } .selected-value { display: inline-block; padding: 0 0.5em; background: rgba(206, 205, 202, 0.5); border-radius: 3px; margin-right: 0.5em; margin-top: 0.3em; margin-bottom: 0.3em; white-space: nowrap; } .collection-title { display: inline-block; margin-right: 1em; } .page-description { margin-bottom: 2em; } .simple-table { margin-top: 1em; font-size: 0.875rem; empty-cells: show; } .simple-table td { height: 29px; min-width: 120px; } .simple-table th { height: 29px; min-width: 120px; } .simple-table-header-color { background: rgb(247, 246, 243); color: black; } .simple-table-header { font-weight: 500; } time { opacity: 0.5; } .icon { display: inline-block; max-width: 1.2em; max-height: 1.2em; text-decoration: none; vertical-align: text-bottom; margin-right: 0.5em; } img.icon { border-radius: 3px; } .user-icon { width: 1.5em; height: 1.5em; border-radius: 100%; margin-right: 0.5rem; } .user-icon-inner { font-size: 0.8em; } .text-icon { border: 1px solid #000; text-align: center; } .page-cover-image { display: block; object-fit: cover; width: 100%; max-height: 30vh; } .page-header-icon { font-size: 3rem; margin-bottom: 1rem; } .page-header-icon-with-cover { margin-top: -0.72em; margin-left: 0.07em; } .page-header-icon img { border-radius: 3px; } .link-to-page { margin: 1em 0; padding: 0; border: none; font-weight: 500; } p > .user { opacity: 0.5; } td > .user, td > time { white-space: nowrap; } input[type="checkbox"] { transform: scale(1.5); margin-right: 0.6em; vertical-align: middle; } p { margin-top: 0.5em; margin-bottom: 0.5em; } .image { border: none; margin: 1.5em 0; padding: 0; border-radius: 0; text-align: center; } .code, code { background: rgba(135, 131, 120, 0.15); border-radius: 3px; padding: 0.2em 0.4em; border-radius: 3px; font-size: 85%; tab-size: 2; } code { color: #eb5757; } .code { padding: 1.5em 1em; } .code-wrap { white-space: pre-wrap; word-break: break-all; } .code > code { background: none; padding: 0; font-size: 100%; color: inherit; } blockquote { font-size: 1.25em; margin: 1em 0; padding-left: 1em; border-left: 3px solid rgb(55, 53, 47); } .bookmark { text-decoration: none; max-height: 8em; padding: 0; display: flex; width: 100%; align-items: stretch; } .bookmark-title { font-size: 0.85em; overflow: hidden; text-overflow: ellipsis; height: 1.75em; white-space: nowrap; } .bookmark-text { display: flex; flex-direction: column; } .bookmark-info { flex: 4 1 180px; padding: 12px 14px 14px; display: flex; flex-direction: column; justify-content: space-between; } .bookmark-image { width: 33%; flex: 1 1 180px; display: block; position: relative; object-fit: cover; border-radius: 1px; } .bookmark-description { color: rgba(55, 53, 47, 0.6); font-size: 0.75em; overflow: hidden; max-height: 4.5em; word-break: break-word; } .bookmark-href { font-size: 0.75em; margin-top: 0.25em; } .sans { font-family: ui-sans-serif, -apple-system, BlinkMacSystemFont, "Segoe UI Variable Display", "Segoe UI", Helvetica, "Apple Color Emoji", Arial, sans-serif, "Segoe UI Emoji", "Segoe UI Symbol"; } .code { font-family: "SFMono-Regular", Menlo, Consolas, "PT Mono", "Liberation Mono", Courier, monospace; } .serif { font-family: Lyon-Text, Georgia, ui-serif, serif; } .mono { font-family: iawriter-mono, Nitti, Menlo, Courier, monospace; } .pdf .sans { font-family: Inter, ui-sans-serif, -apple-system, BlinkMacSystemFont, "Segoe UI Variable Display", "Segoe UI", Helvetica, "Apple Color Emoji", Arial, sans-serif, "Segoe UI Emoji", "Segoe UI Symbol", 'Twemoji', 'Noto Color Emoji', 'Noto Sans CJK JP'; } .pdf:lang(zh-CN) .sans { font-family: Inter, ui-sans-serif, -apple-system, BlinkMacSystemFont, "Segoe UI Variable Display", "Segoe UI", Helvetica, "Apple Color Emoji", Arial, sans-serif, "Segoe UI Emoji", "Segoe UI Symbol", 'Twemoji', 'Noto Color Emoji', 'Noto Sans CJK SC'; } .pdf:lang(zh-TW) .sans { font-family: Inter, ui-sans-serif, -apple-system, BlinkMacSystemFont, "Segoe UI Variable Display", "Segoe UI", Helvetica, "Apple Color Emoji", Arial, sans-serif, "Segoe UI Emoji", "Segoe UI Symbol", 'Twemoji', 'Noto Color Emoji', 'Noto Sans CJK TC'; } .pdf:lang(ko-KR) .sans { font-family: Inter, ui-sans-serif, -apple-system, BlinkMacSystemFont, "Segoe UI Variable Display", "Segoe UI", Helvetica, "Apple Color Emoji", Arial, sans-serif, "Segoe UI Emoji", "Segoe UI Symbol", 'Twemoji', 'Noto Color Emoji', 'Noto Sans CJK KR'; } .pdf .code { font-family: Source Code Pro, "SFMono-Regular", Menlo, Consolas, "PT Mono", "Liberation Mono", Courier, monospace, 'Twemoji', 'Noto Color Emoji', 'Noto Sans Mono CJK JP'; } .pdf:lang(zh-CN) .code { font-family: Source Code Pro, "SFMono-Regular", Menlo, Consolas, "PT Mono", "Liberation Mono", Courier, monospace, 'Twemoji', 'Noto Color Emoji', 'Noto Sans Mono CJK SC'; } .pdf:lang(zh-TW) .code { font-family: Source Code Pro, "SFMono-Regular", Menlo, Consolas, "PT Mono", "Liberation Mono", Courier, monospace, 'Twemoji', 'Noto Color Emoji', 'Noto Sans Mono CJK TC'; } .pdf:lang(ko-KR) .code { font-family: Source Code Pro, "SFMono-Regular", Menlo, Consolas, "PT Mono", "Liberation Mono", Courier, monospace, 'Twemoji', 'Noto Color Emoji', 'Noto Sans Mono CJK KR'; } .pdf .serif { font-family: PT Serif, Lyon-Text, Georgia, ui-serif, serif, 'Twemoji', 'Noto Color Emoji', 'Noto Serif CJK JP'; } .pdf:lang(zh-CN) .serif { font-family: PT Serif, Lyon-Text, Georgia, ui-serif, serif, 'Twemoji', 'Noto Color Emoji', 'Noto Serif CJK SC'; } .pdf:lang(zh-TW) .serif { font-family: PT Serif, Lyon-Text, Georgia, ui-serif, serif, 'Twemoji', 'Noto Color Emoji', 'Noto Serif CJK TC'; } .pdf:lang(ko-KR) .serif { font-family: PT Serif, Lyon-Text, Georgia, ui-serif, serif, 'Twemoji', 'Noto Color Emoji', 'Noto Serif CJK KR'; } .pdf .mono { font-family: PT Mono, iawriter-mono, Nitti, Menlo, Courier, monospace, 'Twemoji', 'Noto Color Emoji', 'Noto Sans Mono CJK JP'; } .pdf:lang(zh-CN) .mono { font-family: PT Mono, iawriter-mono, Nitti, Menlo, Courier, monospace, 'Twemoji', 'Noto Color Emoji', 'Noto Sans Mono CJK SC'; } .pdf:lang(zh-TW) .mono { font-family: PT Mono, iawriter-mono, Nitti, Menlo, Courier, monospace, 'Twemoji', 'Noto Color Emoji', 'Noto Sans Mono CJK TC'; } .pdf:lang(ko-KR) .mono { font-family: PT Mono, iawriter-mono, Nitti, Menlo, Courier, monospace, 'Twemoji', 'Noto Color Emoji', 'Noto Sans Mono CJK KR'; } .highlight-default { color: rgba(50, 48, 44, 1); } .highlight-gray { color: rgba(115, 114, 110, 1); fill: rgba(115, 114, 110, 1); } .highlight-brown { color: rgba(159, 107, 83, 1); fill: rgba(159, 107, 83, 1); } .highlight-orange { color: rgba(217, 115, 13, 1); fill: rgba(217, 115, 13, 1); } .highlight-yellow { color: rgba(203, 145, 47, 1); fill: rgba(203, 145, 47, 1); } .highlight-teal { color: rgba(68, 131, 97, 1); fill: rgba(68, 131, 97, 1); } .highlight-blue { color: rgba(51, 126, 169, 1); fill: rgba(51, 126, 169, 1); } .highlight-purple { color: rgba(144, 101, 176, 1); fill: rgba(144, 101, 176, 1); } .highlight-pink { color: rgba(193, 76, 138, 1); fill: rgba(193, 76, 138, 1); } .highlight-red { color: rgba(205, 60, 58, 1); fill: rgba(205, 60, 58, 1); } .highlight-default_background { color: rgba(50, 48, 44, 1); } .highlight-gray_background { background: rgba(248, 248, 247, 1); } .highlight-brown_background { background: rgba(244, 238, 238, 1); } .highlight-orange_background { background: rgba(251, 236, 221, 1); } .highlight-yellow_background { background: rgba(251, 243, 219, 1); } .highlight-teal_background { background: rgba(237, 243, 236, 1); } .highlight-blue_background { background: rgba(231, 243, 248, 1); } .highlight-purple_background { background: rgba(248, 243, 252, 1); } .highlight-pink_background { background: rgba(252, 241, 246, 1); } .highlight-red_background { background: rgba(253, 235, 236, 1); } .block-color-default { color: inherit; fill: inherit; } .block-color-gray { color: rgba(115, 114, 110, 1); fill: rgba(115, 114, 110, 1); } .block-color-brown { color: rgba(159, 107, 83, 1); fill: rgba(159, 107, 83, 1); } .block-color-orange { color: rgba(217, 115, 13, 1); fill: rgba(217, 115, 13, 1); } .block-color-yellow { color: rgba(203, 145, 47, 1); fill: rgba(203, 145, 47, 1); } .block-color-teal { color: rgba(68, 131, 97, 1); fill: rgba(68, 131, 97, 1); } .block-color-blue { color: rgba(51, 126, 169, 1); fill: rgba(51, 126, 169, 1); } .block-color-purple { color: rgba(144, 101, 176, 1); fill: rgba(144, 101, 176, 1); } .block-color-pink { color: rgba(193, 76, 138, 1); fill: rgba(193, 76, 138, 1); } .block-color-red { color: rgba(205, 60, 58, 1); fill: rgba(205, 60, 58, 1); } .block-color-default_background { color: inherit; fill: inherit; } .block-color-gray_background { background: rgba(248, 248, 247, 1); } .block-color-brown_background { background: rgba(244, 238, 238, 1); } .block-color-orange_background { background: rgba(251, 236, 221, 1); } .block-color-yellow_background { background: rgba(251, 243, 219, 1); } .block-color-teal_background { background: rgba(237, 243, 236, 1); } .block-color-blue_background { background: rgba(231, 243, 248, 1); } .block-color-purple_background { background: rgba(248, 243, 252, 1); } .block-color-pink_background { background: rgba(252, 241, 246, 1); } .block-color-red_background { background: rgba(253, 235, 236, 1); } .select-value-color-default { background-color: rgba(84, 72, 49, 0.08); } .select-value-color-gray { background-color: rgba(84, 72, 49, 0.15); } .select-value-color-brown { background-color: rgba(210, 162, 141, 0.35); } .select-value-color-orange { background-color: rgba(224, 124, 57, 0.27); } .select-value-color-yellow { background-color: rgba(236, 191, 66, 0.39); } .select-value-color-green { background-color: rgba(123, 183, 129, 0.27); } .select-value-color-blue { background-color: rgba(93, 165, 206, 0.27); } .select-value-color-purple { background-color: rgba(168, 129, 197, 0.27); } .select-value-color-pink { background-color: rgba(225, 136, 179, 0.27); } .select-value-color-red { background-color: rgba(244, 171, 159, 0.4); } .checkbox { display: inline-flex; vertical-align: text-bottom; width: 16; height: 16; background-size: 16px; margin-left: 2px; margin-right: 5px; } .checkbox-on { background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%20fill%3D%22none%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%3Crect%20width%3D%2216%22%20height%3D%2216%22%20fill%3D%22%2358A9D7%22%2F%3E%0A%3Cpath%20d%3D%22M6.71429%2012.2852L14%204.9995L12.7143%203.71436L6.71429%209.71378L3.28571%206.2831L2%207.57092L6.71429%2012.2852Z%22%20fill%3D%22white%22%2F%3E%0A%3C%2Fsvg%3E"); } .checkbox-off { background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%20fill%3D%22none%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%3Crect%20x%3D%220.75%22%20y%3D%220.75%22%20width%3D%2214.5%22%20height%3D%2214.5%22%20fill%3D%22white%22%20stroke%3D%22%2336352F%22%20stroke-width%3D%221.5%22%2F%3E%0A%3C%2Fsvg%3E"); }

Writeups

LLM summer :-

AKTH{T00_L1TTLE_7RUS7}

Forensics :-

Andor’s Systematic Corruption

Opening the file in a hex viewer

we can see some strings where there should be 00 bytes
we know that xorring the text with itself gives us the null bytes so we can try bruteforcing the xor key as we know the first header of a png is 89 50 4E 47 0D 0A 1A 0A

Using this script:-

def derive_key(ciphertext, key_length, header):
    key = bytearray(key_length)
    for i in range(len(header)):
        key[i % key_length] = ciphertext[i] ^ header[i]
    return bytes(key)

def test_key(ciphertext, key):
    dec = bytes([b ^ key[i % len(key)] for i, b in enumerate(ciphertext[:128])])
    chunks = [b'IHDR', b'IDAT', b'IEND', b'pHYs', b'tEXt']
    for i in range(len(dec) - 4):
        if dec[i:i+4] in chunks:
            return True, dec
    return False, dec

def main():
    header = bytes([0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A])
    with open("andor_flag.png", "rb") as f:
        data = f.read()

    for key_len in range(1, 17):
        key = derive_key(data, key_len, header)
        if bytes([data[i] ^ key[i % key_len] for i in range(len(header))]) != header:
            continue
        ok, sample = test_key(data, key)
        if ok:
            print("Key length:", key_len)
            print("Key (hex):", key.hex())
            with open(f"decrypted_{key_len}.png", "wb") as out:
                out.write(bytes([b ^ key[i % key_len] for i, b in enumerate(data)]))
            break

main()

We get the output file

AKTH{c0rrupt10n_15_b4d}

Fangs

we are given a large jpg file

if we look into its exif data we can see the following

from this we can makeout that the last characters of the exif tags makeup our flag so we extract all and we get

nKH{a_g__TAm_a}

since we know the flag format

AKTH{}

after replacing we are left with AKTH{a_g_a_m_n}

using the name of the challenge as Fangs we can see it is hinting at FAANG which we know after facebook changed its name to meta is known as MAANG we get our flag


AKTH{m_a_a_n_g}

I got bored and can't make another challenge name

we are given 14 flag files inside a zip files so after extracting it we just run

zsteg -a image_*

and we can see the flag in the first image itself

so just reverse in python

AKTH{FOLLOW_PIXEL_CLUB}

OSINT

Unmarked Rural Roads

initially started by searching for Bright Home Public School we can see there is one nearby Ashoka University which is in Haryana Sonepat


So just bruteforcing nearby locations we get our flag as

AKTH{asawarpur}

Mr. India

We start by reverse searching the image and see its a loaction in ashoka university itself

we go here and see the virtual tour of the campus

we “change our angle” and see the name we need on the nameplate making the flag

AKTH{priyank_narayan}

WEB

Not Just Bots

simply going to the robots.txt file, as suggested by the title and the description on the website. we get our flag

AKTH{n0t_11ms.txt} 

Legion

Not sure if this was the intended way to solve as the hint suggests otherwise but

first off removing the cookie header from the request we can see the response

we start by going to /onions on the site

changing our useragent to be Tor’s useragent and lastly adding the dnt:1 header in our request gives us the flag

AKTH{v33_h4v3_14y3r5_2}

Holding the line

Welcome, Agent. There's a call waiting for you on the phone, the number's 65432. You know the address well.

hmm since we know the address well its probably the CTF sites address only and on port 65432

we can see the server is responding us with Marco in different time intervals each time we send “Polo”

so we can write a script to track the time taken between each iteration

Using this script

import socket
import time

HOST = 'ctf.ieee-ashoka.in'
PORT = 65432

def main():
    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
        s.connect((HOST, PORT))
        data = s.recv(1024)
        print(f"Received: {data.decode().strip()}")
        for i in range(200):  
            start = time.time()
            s.sendall(b'Polo\n')  
            data = s.recv(1024)
            end = time.time()

            response = data.decode().strip()
            duration = end - start
            print(f"iteration {i+1}: Received '{response}' in {duration:.4f} seconds")

main()

we can see the output from the server as

Something like this so we can see its either 1.xx seconds or 0.xx seconds or 3.xx seconds

so we can map these as

01310131300031011031130000130103101031111130110311111301003111111310110

seeing as we have the least amount of 3’s they probably correspond to spaces so lets change that

now we have

01 101 1 000 10110 11 00001 010 1010 11111 0110 11111 0100 111111 10110

which is morso code for

AKTS(M4RC0P0L�(

not quite right but we can see what the author was going for with the flag so after fixing it up a bit we have

AKTH(M4RC0P0L0}

Daddy Issues

opening up the request in burpsuite

we can see that there is a hidden url at the end of the servers response

and from the link on the page at the top we first get here

decoding that string from base64 gives us

159.89.175.173:63453

from where we get our static_key.pem file which we use to decode the capture file we got from

opening the pcap file in wireshark and going to prefrences

then setting the file as the key here

then refreshing wireshark after hitting apply and searching for the string AKTH{

we get

AKTH{jawWired}

Fib's Eve

will not bore you with the WHOLE PROCESS of getting to the flag this one was a really guessy/farfetched one so here is the solution

the 2 sequences we are looking for are

fibonacci sequence and the sieve of eratosthenes

so fib and s eve

then from here we get that that the pages we need to select are from the fib sequence so and the description tells us to skip 6 so we skip the first six and start from the 8th page which is the because 8 is 7th in fib sequence so we start from 8th we have

(The reason for picking fib as the pages is also that there are total 46368 pages which is not a prime and a term of the fib series)

alot to take in but basically we can spot some fragments of the flag that are not supposed to be a part of base64 charset which are { _ } these

so we can make many guesses and finally reach the solution that we have to use the sieve of eratosthenes (just primes) as our indexes as the characters are on indexes which are prime numbers so writing a pretty basic script we can achieve this

def sieve(n):
    primes = [True] * (n + 1)
    primes[0] = primes[1] = False
    p = 2
    while p * p <= n:
        if primes[p]:
            for i in range(p * p, n + 1, p):
                primes[i] = False
        p += 1
    return [i for i, is_prime in enumerate(primes) if is_prime]
    #sieve to be fancy :P

max_lines = 500 
primes = sieve(4000)[:max_lines]

with open("fib_pages.txt", "r") as f:
    lines = [line.strip() for line in f if line.strip()]

result = []
for i, line in enumerate(lines):
    if i < len(primes):
        prime_index = primes[i]
        if prime_index < len(line):
            result.append(line[prime_index])

final_string = ''.join(result)
print(final_string)

we get a string

W8WH8mAKTH{5ub4n_pr0uD}Al

skipping the first 6 and removing the padding at the end we have our flag

AKTH{5ub4n_pr0uD}

LAST wave too lazy to categorize now: -

AI Winter

found that the response from the AI had trailing hidden characters

got that we have to convert it into tabs and spaces because the challenge was clearly hinting at “stegsnow”


Now for the way in which we had to replace the tabs and spaces for the unicode characters i just wrote a bruteforce script with chatgpt xd.


import os
import re
from pathlib import Path

invisible = """the strings here of unicode characters"""
binary = ""
for char in invisible:
    if char == '\u200c':
        binary += '0'
    elif char == '\u200d':  
        binary += '1'

out_dir = Path("grids")
out_dir.mkdir(exist_ok=True)
count = 0
for rows in range(1, 21):
    for cols in range(1, 201):
        if rows * cols > len(binary):
            continue

        sliced = binary[:rows * cols]
        lines = [
            ''.join(
                '\u200c' if bit == '0' else '\u200d'
                for bit in sliced[r*cols:(r+1)*cols]
            ) for r in range(rows)
        ]

        replaced = "\n".join(
            line.replace('\u200c', ' ').replace('\u200d', '\t')
            for line in lines
        )

        file_path = out_dir / f"grid{rows}x{cols}.txt"
        with open(file_path, 'w', encoding='utf-8') as f:
            f.write(replaced)
        count += 1

print(f":bricks: Generated {count} grid files in {out_dir}/") 

Now also wrote a simple bashscript to run stegsnow on all the grids that were created
this is way faster than just guessing.

for file in grid*; do
echo "checking: $file"
stegsnow -C "$file"
done

then we get our flag

AKTH{SN0-W4Y} #could not be exact becausee i no longer have the chall file xd the site was taken down when writing this

Deep

run binwalk on the image to extract a zip file from it that is password locked

in the exifdata of the image we can also see a google drive link

on the google drive link we find an X account

the X account has some seemingly random information but we can make a guess that this information is used to build up a wordlist (I have solved a similar challenge before)
build a wordlist using
samuel, Ameera and 1995 as the birth year

bruteforce the zip with the created wordlist

After finding the correct password we have 2 files

file1.txt and file2.txt

they are almost the same but searching AKTH{ in file 2 gives back a result

so we take the difference of the two files (so the only unique characters)

and we find our flag

AKTH{w0rdl15t_m4g1c} #not sure same reason as above 

Crypto

not going to explain the whole thing but

we dont have to check for block 0 as we know it should be

AKTH so bruteforcing it we also see that it corresponds to the k1lo function

we run this code to find it for d3lt4

import itertools
from fractions import Fraction as F

# Function Definitions
def d3lt4(msg_x1):
    if len(msg_x1) == 1:
        return ord(msg_x1)
    msg_x1 = msg_x1[::-1]
    _countdown = len(msg_x1) - 1
    vX, vY = F(ord(msg_x1[0]), _countdown).denominator, F(ord(msg_x1[0]), _countdown).numerator
    _countdown -= 1
    for idx in range(1, len(msg_x1) - 1):
        x = ord(msg_x1[idx]) + F(vX, vY)
        vY, vX = x.denominator, x.numerator
        vX, vY = vY, _countdown * vX
        _countdown -= 1
    x = ord(msg_x1[-1]) + F(vX, vY)
    vX, vY = x.denominator, x.numerator
    return (vY, vX)

def k1lo(msg_b2):
    if len(msg_b2) == 1:
        return ord(msg_b2)
    msg_b2 = msg_b2[::-1]
    pwr = (-1) ** len(msg_b2)
    f_ = F(ord(msg_b2[0]), pwr)
    a1, b2 = f_.denominator, f_.numerator
    pwr *= -1
    for idx in range(1, len(msg_b2) - 1):
        temp = ord(msg_b2[idx]) + F(a1, b2)
        b2, a1 = temp.denominator, temp.numerator
        a1, b2 = b2, pwr * a1
        pwr *= -1
    temp = ord(msg_b2[-1]) + F(a1, b2)
    a1, b2 = temp.denominator, temp.numerator
    return (b2, a1)

def zx9t(msg_c3):
    if len(msg_c3) == 1:
        return ord(msg_c3)
    msg_c3 = msg_c3[::-1]
    chaos = (-1) ** int(F(len(msg_c3), len(msg_c3)**2))
    start = F(ord(msg_c3[0]), chaos)
    l1, l2 = start.denominator, start.numerator
    chaos **= -1
    chaos = int(chaos)
    for idx in range(1, len(msg_c3) - 1):
        res = ord(msg_c3[idx]) + F(l1, l2)
        l2, l1 = res.denominator, res.numerator
        l1, l2 = l2, chaos * l1
        chaos **= -1
        chaos = int(chaos)
    final = ord(msg_c3[-1]) + F(l1, l2)
    l1, l2 = final.denominator, final.numerator
    return (l2, l1)

# Data
tuples = [(29490244, 453603), (28735866, 233597), (59585246, 551617), 
          (113048061, 1076555), (65009469, 969989)]
remaining_tuples = tuples[1:]
chars = [chr(i) for i in range(32, 127)]
functions = [d3lt4, k1lo, zx9t]
func_names = ["d3lt4", "k1lo", "zx9t"]

# Start with known prefix
flag = "AKTH{"
segments = ["AKTH"]
counts = {"d3lt4": 0, "k1lo": 1, "zx9t": 0}  # k1lo used once

# Build flag incrementally
for i, target in enumerate(remaining_tuples, 1):
    candidates = []
    if i == 1:  # Second segment starts with '{'
        for s in itertools.product(chars, repeat=3):
            seg = "{" + ''.join(s)
            for j, func in enumerate(functions):
                if func(seg) == target and (func_names[j] != "d3lt4" or counts["d3lt4"] < 2) and \
                   (func_names[j] != "k1lo" or counts["k1lo"] < 2) and \
                   (func_names[j] != "zx9t" or counts["zx9t"] < 1):
                    candidates.append((seg, func_names[j]))
    else:  # Full 4-char segments
        for s in itertools.product(chars, repeat=4):
            seg = ''.join(s)
            for j, func in enumerate(functions):
                if func(seg) == target and (func_names[j] != "d3lt4" or counts["d3lt4"] < 2) and \
                   (func_names[j] != "k1lo" or counts["k1lo"] < 2) and \
                   (func_names[j] != "zx9t" or counts["zx9t"] < 1):
                    candidates.append((seg, func_names[j]))
    
    # Select candidate (highest "confidence" = first match)
    if candidates:
        seg, func_name = candidates[0]  # Could rank by flag-like properties
        flag += seg
        segments.append(seg)
        counts[func_name] += 1
        print(f"Tuple {i}: {seg} with {func_name}, Flag so far: {flag}")
    else:
        print(f"No match for tuple {i}")
        break

# Finalize flag
flag += "}"
print("Final Flag:", flag)
print("Function counts:", counts)

From this we were only able to get the second block was matching

d3lt4 → {Def

then we run this code

import itertools
import string
from fractions import Fraction as F

def d3lt4(msg_x1):
    if len(msg_x1) == 1:
        return ord(msg_x1)
    msg_x1 = msg_x1[::-1]
    _countdown = len(msg_x1) - 1
    vX, vY = F(ord(msg_x1[0]), _countdown).denominator, F(ord(msg_x1[0]), _countdown).numerator
    _countdown -= 1
    for idx in range(1, len(msg_x1) - 1):
        x = ord(msg_x1[idx]) + F(vX, vY)
        vY, vX = x.denominator, x.numerator
        vX, vY = vY, _countdown * vX
        _countdown -= 1
    x = ord(msg_x1[-1]) + F(vX, vY)
    vX, vY = x.denominator, x.numerator
    return (vY, vX)

def k1lo(msg_b2):
    if len(msg_b2) == 1:
        return ord(msg_b2)
    msg_b2 = msg_b2[::-1]
    pwr = (-1) ** len(msg_b2)
    f_ = F(ord(msg_b2[0]), pwr)
    a1, b2 = f_.denominator, f_.numerator
    pwr *= -1
    for idx in range(1, len(msg_b2) - 1):
        temp = ord(msg_b2[idx]) + F(a1, b2)
        b2, a1 = temp.denominator, temp.numerator
        a1, b2 = b2, pwr * a1
        pwr *= -1
    temp = ord(msg_b2[-1]) + F(a1, b2)
    a1, b2 = temp.denominator, temp.numerator
    return (b2, a1)

def zx9t(msg_c3):
    if len(msg_c3) == 1:
        return ord(msg_c3)
    msg_c3 = msg_c3[::-1]
    chaos = (-1) ** int(F(len(msg_c3), len(msg_c3)**2))
    start = F(ord(msg_c3[0]), chaos)
    l1, l2 = start.denominator, start.numerator
    chaos **= -1
    chaos = int(chaos)
    for idx in range(1, len(msg_c3) - 1):
        res = ord(msg_c3[idx]) + F(l1, l2)
        l2, l1 = res.denominator, res.numerator
        l1, l2 = l2, chaos * l1
        chaos **= -1
        chaos = int(chaos)
    final = ord(msg_c3[-1]) + F(l1, l2)
    l1, l2 = final.denominator, final.numerator
    return (l2, l1)

encrypted_tuples = [
    (29490244, 453603),
    (28735866, 233597),
    (59585246, 551617),
    (113048061, 1076555),
    (65009469, 969989)
]

fixed_segments = ["AKTH", "{Def"]
remaining_usage = {"d3lt4": 1, "k1lo": 1, "zx9t": 1}
allowed_chars = string.ascii_lowercase + string.digits + "_"
allowed_chars_seg4 = string.ascii_letters + string.digits + "{}_"
segment_length = 4
functions = [d3lt4, k1lo, zx9t]
func_names = ["d3lt4", "k1lo", "zx9t"]

def build_candidates(target, allowed_chars, segment_length, require_brace=False):
    cand = {fname: [] for fname in func_names}
    for s in itertools.product(allowed_chars, repeat=segment_length):
        seg = ''.join(s)
        if require_brace and '}' not in seg:
            continue
        for f, fname in zip(functions, func_names):
            if f(seg) == target:
                cand[fname].append(seg)
    return cand

cand_seg2 = build_candidates(encrypted_tuples[2], allowed_chars, segment_length, require_brace=False)
cand_seg3 = build_candidates(encrypted_tuples[3], allowed_chars, segment_length, require_brace=False)
cand_seg4 = build_candidates(encrypted_tuples[4], allowed_chars_seg4, segment_length, require_brace=True)

print("Candidates for seg2:")
for fname, segs in cand_seg2.items():
    print(f"  {fname}: {segs}")
print("Candidates for seg3:")
for fname, segs in cand_seg3.items():
    print(f"  {fname}: {segs}")
print("Candidates for seg4:")
for fname, segs in cand_seg4.items():
    print(f"  {fname}: {segs}")

solutions = []
for fname2, segs2 in cand_seg2.items():
    for s2 in segs2:
        for fname3, segs3 in cand_seg3.items():
            if fname3 == fname2:
                continue
            for s3 in segs3:
                for fname4, segs4 in cand_seg4.items():
                    if fname4 == fname2 or fname4 == fname3:
                        continue
                    for s4 in segs4:
                        full_flag = fixed_segments[0] + fixed_segments[1] + s2 + s3 + s4
                        solutions.append((full_flag, (fname2, fname3, fname4)))

if solutions:
    print("\nCandidate full flag(s) found:")
    for flag, assignment in solutions:
        print("Flag:", flag, "with function assignment for seg2,seg3,seg4:", assignment)
else:
    print("No full flag candidate found under current constraints.")

after that this code gives us this

now we are missing the only last block

we currently have

AKTH{Defl4gging_

and I just guessed the last word :P

which was C0de

making our flag

AKTH{Defl4gging_C0de}

DONT EVEN ASK ME ABOU THIS CHALLENGE I HAD AN AI FIELD DAY WITH THIS ONE