---
# System prepended metadata

title: KashiCTF 2025

---

Team : `KCSC`

# Lost Frequencies


Given : 

```111 0000 10 111 1000 00 10 01 010 1011 11 111 010 000 0```

I use dCode's Cipher Identifier to find the encryption type.
![image](https://hackmd.io/_uploads/S11Cz6Oqkx.png)
Morse Decode : 
![image](https://hackmd.io/_uploads/SJACz6O5yl.png)

Flag : ```KashiCTF{OHNOBINARYMORSE}```

# Key Exchange

Source : 

```
from redacted import EllipticCurve, FLAG, EXIT
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
import hashlib
import random
import json
import os

def encrypt_flag(shared_secret: int):
    sha1 = hashlib.sha1()
    sha1.update(str(shared_secret).encode("ascii"))
    key = sha1.digest()[:16]
    iv = os.urandom(16)
    cipher = AES.new(key, AES.MODE_CBC, iv)
    ciphertext = cipher.encrypt(pad(FLAG, 16))
    data = {}
    data["iv"] = iv.hex()
    data["ciphertext"] = ciphertext.hex()
    return json.dumps(data)

#Curve Parameters (NIST P-384)
p = 39402006196394479212279040100143613805079739270465446667948293404245721771496870329047266088258938001861606973112319
a = -3
b = 27580193559959705877849011840389048093056905856361568521428707301988689241309860865136260764883745107765439761230575
E = EllipticCurve(p,a,b)
G = E.point(26247035095799689268623156744566981891852923491109213387815615900925518854738050089022388053975719786650872476732087,8325710961489029985546751289520108179287853048861315594709205902480503199884419224438643760392947333078086511627871)

n_A = random.randint(2, p-1)
P_A = n_A * G

print(f"\nReceived from Weierstrass:")
print(f"   Here are the curve parameters (NIST P-384)")
print(f"   {p = }")
print(f"   {a = }")
print(f"   {b = }")
print(f"   And my Public Key: {P_A}")

print(f"\nSend to Weierstrass:")
P_B_x = int(input("   Public Key x-coord: "))
P_B_y = int(input("   Public Key y-coord: "))

try:
    P_B = E.point(P_B_x, P_B_y)
except:
    EXIT()

S = n_A * P_B

print(f"\nReceived from Weierstrass:")
print(f"   Message: {encrypt_flag(S.x)}")
```

We didn't know the secret key and couldn't compute the discrete logarithm in NIST P-384, but we could choose a point to generate the key. So I choose `G` because I have `n_A * G` -> Get key -> Decrypt flag  

![image](https://hackmd.io/_uploads/B1timaOcJg.png)

```python3= 

from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
import hashlib
import random
import json
import os

def encrypt_flag(shared_secret,iv,ciphertext):
    sha1 = hashlib.sha1()
    sha1.update(str(shared_secret).encode("ascii"))
    key = sha1.digest()[:16]
  
    cipher = AES.new(key, AES.MODE_CBC, iv)
    ciphertext = cipher.decrypt(ciphertext)
    return ciphertext

iv  = bytes.fromhex("64bfec5a865fd6ceea42801aee359859")
ciphertext = bytes.fromhex("364045520c5df308c0d6a07786b30fb8af5fb28107f9a71b6f8873fea1716a3994bee7502755ced9ddb5bd24636bbd25251e99c039c20f02f940fd19309d81d14c6172dcac987396cd33933e069051fb6af388194b2958e81581ddfd7b562889")
shared = 25752146156231184352136833690884074974815288724508095765146482713286084034793899492822768810986485913758095295188712
print(encrypt_flag(shared,iv,ciphertext))
```

Result : 
```
b'NaeusGRX{L_r3H3Nv3h_kq_Sun1Vm_O3w_4fg_4lx_1_t0d_a4q_lk1s_X0hcc_Dd4J_wEBQCIuo}\n\nHint: DamnKeys\x03\x03\x03'
```

I think it's `Vigenere Cipher` and try decode : 
![image](https://hackmd.io/_uploads/BJcvVTd9kx.png)

Flag : ```KashiCTF{I_r3V3Al3d_my_Pub1Ic_K3y_4nd_4ll_1_g0t_w4s_th1s_L0usy_Fl4G_wSOGYKcl}```
# MMDLX
- This challenge encoded (**base64**) the $\text{Flag}$ multiple times and did one **caesar encryption**  the last result.

- So, we need to brute force the $\text{key}$ for the caesar decryption, and use the `while` loop to decode the base64-encoded flag.

- **Script**:
    ```python=
    from base64 import b64decode
    from string import *
    from tqdm import trange

    b64_data = open("MMDLX.txt", "r").read()

    upper_alphabet = ascii_uppercase
    lower_alphabet = ascii_lowercase

    def caesar_decrypt(ciphertext, key):
        plaintext = ""
        for i in ciphertext:
            if i.isalpha():
                if i.isupper():
                    plaintext += upper_alphabet[(upper_alphabet.index(i) - key) % len(upper_alphabet)]
                else:
                    plaintext += lower_alphabet[(lower_alphabet.index(i) - key) % len(lower_alphabet)]
            else:
                plaintext += i
        return plaintext


    for key in trange(0, 26):
        caesar_data = caesar_decrypt(b64_data, key)
        decoded_data = caesar_data
        try:
            while True:
                decoded_data = b64decode(decoded_data)

                if decoded_data == b"": # trường hợp mà nó tính base64 vô hạn lần
                    break

                if b"KashiCTF{" in decoded_data:
                    print(decoded_data)
                    exit()
        except:
            continue
    ```
- Flag: **KashiCTF{w31rd_numb3r5_4nd_c1ph3r5}**
# Random-Inator 

Source : 

```python3= 
from redacted import PRNG, FLAG
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad

def encrypt(key, plaintext, iv):
    cipher = AES.new(key, AES.MODE_CBC, iv)
    ciphertext = cipher.encrypt(pad(plaintext, 16))
    return iv+ciphertext

    # KashiCTF{

P = PRNG()
KEY = P.getBytes(16)
IV = P.getBytes(16)

print(f"Doofenshmirtz Evil Incorporated!!!\n")
print(f"All right, I don't like to repeat myself here but it just happens\nAnyhow, here's the encrypted message: {encrypt(KEY, FLAG, IV).hex()}\nOhh, How I love EVIL")
while True:
    iv = P.getBytes(16) 
    try:
        pt = input("\nPlaintext >> ")
        pt = bytes.fromhex(pt)
    except KeyboardInterrupt:
        break
    except:
        print("Invalid input")
        continue

    ct = encrypt(KEY, pt, iv)
    print(ct.hex())

```

I don't know anything about the PRNG library, so what I can do is connect to the server and take a look.

And I realized that the IV is repeated, and the key and IV are both generated by getBytes(16), so they share the same repetition.

![image](https://hackmd.io/_uploads/r1vNIT_q1x.png)


We can see  , in example `key=iv`. I didn't choose a different ciphertext because before it, there could be one or two other random values, so I was too lazy to find a new one. But before `9634..`, there was only `9634...`
![image](https://hackmd.io/_uploads/rJaivp_9ye.png)

So  i brute-force when `iv+ciphertext` start with `9634..`

![image](https://hackmd.io/_uploads/SJ8tO6u5Je.png)

```python3=

from Crypto.Cipher import AES
from Crypto.Util.Padding import pad

def encrypt(key, plaintext, iv):
    cipher = AES.new(key, AES.MODE_CBC, iv)
    ciphertext = cipher.decrypt(plaintext)
    return iv+ciphertext

    # KashiCTF{

ct = bytes.fromhex("963483730151eb82840db14f17159c66ae57740f73423743302ecca63e5aee7b0d839df2585fb603e40526ac54099cf103529b23aac735a0c0e8e43a81cf113682e606f65bb42d1426cfebb94e8100818a77f0fa6c14e13476ec388aa8d3d0d0")
iv = ct[:16]
ciphertext = ct[16:]
key = iv

print(encrypt(key,ciphertext,iv))
```

Flag : ```KashiCTF{Y0u_brOK3_mY_R4Nd0m_In4t0r_Curse_yOu_Perry_tH3_Pl4TYpus_n1iK9jh1}```

# Absolutely Encrypted Shenanigans

Source : 

```python3=
from AES import encrypt, pad
from redacted import secret, flag, EXIT
import json
import os

plaintext = pad(flag, 16)

for _ in range(10):
    iv = os.urandom(8)*2
    key = os.urandom(16) 
    try:
        ciphertext = encrypt(key, plaintext, mode="CBC", iv=iv)
    except:
        EXIT()
    print(json.dumps({
        'key': key.hex(),
        'ciphertext': ciphertext.hex()
    }))
    inp = input("Enter iv: ")
    if (iv.hex() != inp):
        EXIT()
    print()

plaintext = pad(secret, 16)
iv = os.urandom(8)*2
key = os.urandom(16)
try:
    ciphertext = encrypt(key, plaintext, mode="CBC", iv=iv) 
except:
    EXIT()
print(json.dumps({
    'key': key.hex(),
    'ciphertext': ciphertext.hex()
}))


def xor(b1, b2):
    if len(b1)!=len(b2):
        raise ValueError("Lengths of byte strings are not equal")
    return bytes([b1[i]^b2[i] for i in range(len(b1))])

def bytes2matrix(text):
    return [list(text[i:i+4]) for i in range(0, len(text), 4)]

def matrix2bytes(matrix):
    s = b""
    for l in matrix:
        s += bytes(l)
    return s
    
def shift_rows(s):
    s[2][2], s[2][1], s[0][3], s[2][0], s[3][3], s[2][3], s[3][1], s[1][3], s[0][2], s[1][0], s[0][1], s[0][0], s[1][1], s[3][0], s[3][2], s[1][2] = s[2][2], s[3][3], s[0][0], s[1][1], s[2][1], s[1][2], s[3][0], s[2][3], s[0][3], s[0][2], s[3][2], s[0][1], s[3][1], s[1][0], s[2][0], s[1][3]
    return s


xtime = lambda a: (((a << 1) ^ 0x1B) & 0xFF) if (a & 0x80) else (a << 1)


def mix_single_column(a):
    t = a[0] ^ a[1] ^ a[2] ^ a[3]
    u = a[0]
    a[0] ^= t ^ xtime(a[0] ^ a[1])
    a[1] ^= t ^ xtime(a[1] ^ a[2])
    a[2] ^= t ^ xtime(a[2] ^ a[3])
    a[3] ^= t ^ xtime(a[3] ^ u)
    return a


def mix_columns(s):
    for i in range(4):
        s[i] = mix_single_column(s[i])
    return s


s_box = (
    0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,
    0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0,
    0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,
    0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75,
    0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,
    0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,
    0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8,
    0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2,
    0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,
    0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,
    0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79,
    0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,
    0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A,
    0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E,
    0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
    0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16,
)

    
def add_round_key(s, k):
    ns = []
    for i in range(4):
        ns.append([])
        for j in range(4):
            ns[i].append(s[i][j]^k[j][i])
    return ns

def sub_bytes(s, sbox=s_box):
    resmatrix = []
    for i in range(4):
        resmatrix.append([])
        for j in range(4):
            hexval=hex(s[i][j])[2:]
            if len(hexval)==1:
                a,b = 0,int(hexval,16)
            else:
                a,b = int(hexval[0],16), int(hexval[1],16)
            resmatrix[i].append(sbox[a*16+b])
            
    return resmatrix


N_ROUNDS = 10


def expand_key(master_key):
    r_con = (
        0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40,
        0x80, 0x1B, 0x36, 0x6C, 0xD8, 0xAB, 0x4D, 0x9A,
        0x2F, 0x5E, 0xBC, 0x63, 0xC6, 0x97, 0x35, 0x6A,
        0xD4, 0xB3, 0x7D, 0xFA, 0xEF, 0xC5, 0x91, 0x39,
    )
    key_columns = bytes2matrix(master_key)
    iteration_size = len(master_key) // 4
    i = 1
    while len(key_columns) < (N_ROUNDS + 1) * 4:
        word = list(key_columns[-1])
        if len(key_columns) % iteration_size == 0:
            word.append(word.pop(0))
            word = [s_box[b] for b in word]
            word[0] ^= r_con[i]
            i += 1
        elif len(master_key) == 32 and len(key_columns) % iteration_size == 4:
            word = [s_box[b] for b in word]
        word = bytes(i^j for i, j in zip(word, key_columns[-iteration_size]))
        key_columns.append(word)
    return [key_columns[4*i : 4*(i+1)] for i in range(len(key_columns) // 4)]


def encrypt_block(key, pt_block):
    round_keys = expand_key(key)
    state = bytes2matrix(pt_block)
    state = add_round_key(state, round_keys[0])
    state = sub_bytes(state)
    state = shift_rows(state)

    for i in range(1,N_ROUNDS):
        state = mix_columns(state)
        state = add_round_key(state, round_keys[i])
        state = sub_bytes(state)
        state = shift_rows(state)
    
    state = add_round_key(state, round_keys[N_ROUNDS])
    ct_block = matrix2bytes(state)

    return ct_block


def encrypt(key, plaintext, mode="ECB", iv=None):
    if len(plaintext)%16 != 0:
        raise ValueError("Invalid Plaintext")
    elif len(key)!=16:
        raise ValueError("Invalid Key")
    ciphertext = b""
    if mode=="ECB":
        for i in range(0, len(plaintext), 16):
            ciphertext += encrypt_block(key, plaintext[i: i+16])
        
    elif mode=="CBC":
        if (iv==None or len(iv)!=16):
            raise ValueError("Invalid IV")
        ciphertext += iv
        for i in range(0, len(plaintext), 16):
            ciphertext += encrypt_block(key, xor(ciphertext[i: i+16], plaintext[i: i+16]))
        
    return ciphertext[16:]


def pad(text, blocksize):
    padding_len = blocksize - (len(text)%blocksize)
    padding = bytes([padding_len])*padding_len
    return text+padding
```

The important thing here is. 

```
iv = os.urandom(8)*2```
``` 

We  have format flag is `KashiCTF` (8 characters)
And we have key, and we can decrypt cipher in mode ECB and xor it with `KashiCTF` we  can get iv. 

The different here is AES.py, we didnt have function `decrypt` , so i use chatgpt to make this. 

```python3
def inv_shift_rows(s):
    s[2][2], s[3][3], s[0][0], s[1][1], s[2][1], s[1][2], s[3][0], s[2][3], s[0][3], s[0][2], s[3][2], s[0][1], s[3][1], s[1][0], s[2][0], s[1][3] = s[2][2], s[2][1], s[0][3], s[2][0], s[3][3], s[2][3], s[3][1], s[1][3], s[0][2], s[1][0], s[0][1], s[0][0], s[1][1], s[3][0], s[3][2], s[1][2]
    return s


def inv_sub_bytes(s, sbox=s_box):
    inv_sbox = [sbox.index(x) for x in range(256)]
    return [[inv_sbox[b] for b in row] for row in s]


def inv_mix_columns(s):
    for i in range(4):
        u = xtime(xtime(s[i][0] ^ s[i][2]))
        v = xtime(xtime(s[i][1] ^ s[i][3]))
        s[i][0] ^= u
        s[i][1] ^= v
        s[i][2] ^= u
        s[i][3] ^= v
    return mix_columns(s)  # Using the original mix_columns again


def decrypt_block(key, ct_block):
    round_keys = expand_key(key)
    state = bytes2matrix(ct_block)
    state = add_round_key(state, round_keys[N_ROUNDS])
    
    for i in range(N_ROUNDS - 1, 0, -1):
        state = inv_shift_rows(state)
        state = inv_sub_bytes(state)
        state = add_round_key(state, round_keys[i])
        state = inv_mix_columns(state)
    
    state = inv_shift_rows(state)
    state = inv_sub_bytes(state)
    state = add_round_key(state, round_keys[0])
    
    return matrix2bytes(state)


def decrypt(key, ciphertext, mode="ECB", iv=None):
    if len(ciphertext) % 16 != 0:
        raise ValueError("Invalid Ciphertext")
    elif len(key) != 16:
        raise ValueError("Invalid Key")
    plaintext = b""
    
    if mode == "ECB":
        for i in range(0, len(ciphertext), 16):
            plaintext += decrypt_block(key, ciphertext[i: i+16])
    
    elif mode == "CBC":
        if iv is None or len(iv) != 16:
            raise ValueError("Invalid IV")
        prev_ct_block = iv
        for i in range(0, len(ciphertext), 16):
            decrypted_block = decrypt_block(key, ciphertext[i: i+16])
            plaintext += xor(prev_ct_block, decrypted_block)
            prev_ct_block = ciphertext[i: i+16]
    
    return plaintext


def unpad(text):
    padding_len = text[-1]
    if text[-padding_len:] != bytes([padding_len]) * padding_len:
        raise ValueError("Invalid Padding")
    return text[:-padding_len]
```


Script : 

```
from AES import * 
from pwn import *
from ast import literal_eval

io = remote("kashictf.iitbhucybersec.in", 51946)

for i in range(10) : 
    
    if i >=1 :
        print(io.recvline().decode())
    datas = literal_eval(io.recvline().decode())
    print(datas)
    
    key = bytes.fromhex(datas["key"])
    ciphertext = bytes.fromhex(datas["ciphertext"]
                               )
   
    test = decrypt(key,ciphertext)
    iv =  xor(test[:8] , b'KashiCTF')
    print(decrypt(key,ciphertext,"CBC", iv*2))

    io.recvuntil(b"Enter iv:")
    io.sendline(str(iv.hex()).encode()*2)
    
    # print(decrypt(key,ciphertext,"CBC" , iv*2))

ciphertext = bytes.fromhex("67865f6cd1c006b2bfcbff3070b35a2baeb57be84376d9a5a84053ae03e1ef97f8bb2480fde468f39699ef496c72bbfdc8618166a1fe002aa5bca0b9aad52462")
key  =bytes.fromhex("3f916873df6a91297f50646442f2dc5a")

test = decrypt(key,ciphertext)
iv = xor(test[:8] , b'KashiCTF')
print(decrypt(key,ciphertext,"CBC" , iv*2))
io.interactive()
```

Flag  : ```KashiCTF{AES_Unbr34KAbl3_but_t0T4lly_br3Akable_mAyb3_AHEaoEeN}```

We can't use a library like pycryptodome to decrypt AES because some parts of it work differently, such as:

```
def shift_rows(s):
    s[2][2], s[2][1], s[0][3], s[2][0], s[3][3], s[2][3], s[3][1], s[1][3], s[0][2], s[1][0], s[0][1], s[0][0], s[1][1], s[3][0], s[3][2], s[1][2] = s[2][2], s[3][3], s[0][0], s[1][1], s[2][1], s[1][2], s[3][0], s[2][3], s[0][3], s[0][2], s[3][2], s[0][1], s[3][1], s[1][0], s[2][0], s[1][3]
    return s
```

The correct code from : https://github.com/boppreh/aes/blob/master/aes.py

# Broken ? 

I think it should be in tag crypto 

```
#!/usr/bin/env python3

import hashlib
import socket
import signal
import sys

HOST = "0.0.0.0"
PORT = 1337
SECRET_KEY = b"REDACTED"

def generate_hmac(message):
    return hashlib.sha1(SECRET_KEY + message.encode()).hexdigest()

def signal_handler(sig, frame):
    print("\n[!] Server shutting down...")
    sys.exit(0)

signal.signal(signal.SIGINT, signal_handler)

def handle_client(client, addr):
    print(f"[*] Connection from {addr}")

    try:
        original_data = "count=10&lat=37.351&user_id=1&long=-119.827&file=random.txt"
        original_hmac = generate_hmac(original_data)

        client.sendall(f"Retrieve file using format: data|hmac\nExample: {original_data}|{original_hmac}\n".encode())

        data = client.recv(1024)
        if not data:
            print(f"[-] Client {addr} disconnected.")
            return

        try:
            decoded_data = data.decode("utf-8").strip()
        except UnicodeDecodeError:
            decoded_data = data.decode("latin-1").strip()

        print(f"[*] Received Data: {decoded_data}")

        if "|" not in decoded_data:
            client.sendall(b"Invalid format. Use data|hmac\n")
            return

        user_data, received_hmac = decoded_data.rsplit("|", 1)

        user_data_bytes = bytes(user_data, "utf-8").decode("unicode_escape").encode("latin-1")

        h = hashlib.sha1()
        h.update(SECRET_KEY + user_data_bytes)
        computed_signature = h.hexdigest()

        print(f"[*] Computed Signature: {computed_signature} for body: {repr(user_data)}")
        print(f"[*] Received Signature: {received_hmac}")

        if computed_signature != received_hmac:
            client.sendall(b"Invalid HMAC. Try again.\n")
        else:
            try:
                params = dict(param.split("=") for param in user_data.split("&") if "=" in param)
                filename = params.get("file")
                if filename:
                    with open(filename, "r") as f:
                        content = f.read()
                    client.sendall(f"File Contents:\n{content}\n".encode())
                else:
                    client.sendall(b"Invalid request format.\n")
            except FileNotFoundError:
                client.sendall(b"File not found.\n")

    except ConnectionResetError:
        print(f"[!] Client {addr} forcibly disconnected.")

    except Exception as e:
        print(f"[!] Error handling client {addr}: {e}")

    finally:
        client.close()
        print(f"[-] Closed connection with {addr}")

def start_server():
    print(f"[*] Listening on {HOST}:{PORT} ...")

    server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    server.bind((HOST, PORT))
    server.listen(5)

    while True:
        try:
            client, addr = server.accept()
            handle_client(client, addr)
        except KeyboardInterrupt:
            print("\n[!] Shutting down server...")
            server.close()
            sys.exit(0)

if __name__ == "__main__":
    start_server()
```

This challenge is simply about a hash length extension attack. We just need to append `&flag.txt` to the plaintext and then compute the signature. The important part here is that we don’t know the length of the secret, but we can brute-force it (though it’s usually 16 or 32).

https://github.com/thecrabsterchief/hash-length-extension

Script 

```python3= 
from pwn import *
import HashTools
from tqdm import trange
for i in trange(64) :
    io = remote("kashictf.iitbhucybersec.in", 59457)

    io.recvuntil(b"Example: ")
    datas = io.recvline().decode()[:-1].split("|")
   
    original_data = datas[0].encode()
    sig = datas[1]
    append_data = b"&file=flag.txt"
    
    magic = HashTools.new("sha1")
    new_data, new_sig = magic.extension(
        secret_length=i, original_data=original_data,
        append_data=append_data, signature=sig
        )
   
        # print(str(new_data))
    send_data = str(new_data)[2:][:-1] + '|' + str(new_sig)
    user_data, received_hmac = send_data.rsplit("|", 1)
  
    try :
        user_data_bytes = bytes(user_data, "utf-8").decode("unicode_escape").encode("latin-1")
      
        io.sendline(send_data.encode())
        print(io.recvall())
        exit()
    except :
        pass
    io.close()
```
![image](https://hackmd.io/_uploads/H1hfnp_91l.png)

I think i didnt need bruteforce, just guess =)) 

Flag : ```KashiCTF{Close_Yet_Far_wUWyw7UEL}```

# Easy Jail 

```
#!/usr/bin/env python3

print("           _            _       _             ")
print("          | |          | |     | |            ")
print("  ___ __ _| | ___ _   _| | __ _| |_ ___  _ __ ")
print(" / __/ _` | |/ __| | | | |/ _` | __/ _ \| '__|")
print("| (_| (_| | | (__| |_| | | (_| | || (_) | |   ")
print(" \___\__,_|_|\___|\__,_|_|\__,_|\__\___/|_|   ")

def calc(op):
	try : 	
		res = eval(op)
	except :
		return print("Wrong operation")
	return print(f"{op} --> {res}")

def main():
	while True :
		inp = input(">> ")
		calc(inp)

if __name__ == '__main__':
	main()
```

This challenge doesn’t have any blacklist, so we just need to import os, find the file `flag.txt path`, and read it.

![image](https://hackmd.io/_uploads/HkxnbaaO9kx.png)

Flag : ```KashiCTF{3V4L_41NT_54F3_fD389n9T}```

# Easy Jail 2 

```
#!/usr/bin/env python3

print("           _            _       _             ")
print("          | |          | |     | |            ")
print("  ___ __ _| | ___ _   _| | __ _| |_ ___  _ __ ")
print(" / __/ _` | |/ __| | | | |/ _` | __/ _ \| '__|")
print("| (_| (_| | | (__| |_| | | (_| | || (_) | |   ")
print(" \___\__,_|_|\___|\__,_|_|\__,_|\__\___/|_|   ")

BLACKLIST = ["open", "input", "eval", "exec", "import", "getattr", "sh", "builtins", "global"]
def calc(op):
	try : 	
		res = eval(op)
	except :
		return print("Wrong operation")
	return print(f"{op} --> {res}")

def main():
	while True :
		inp = input(">> ")
		if any(bad in inp for bad in BLACKLIST) :
			print("Are you tying to hack me !!!!!")
		else : 
			calc(inp)

if __name__ == '__main__':
	main()#!/usr/bin/env python3

print("           _            _       _             ")
print("          | |          | |     | |            ")
print("  ___ __ _| | ___ _   _| | __ _| |_ ___  _ __ ")
print(" / __/ _` | |/ __| | | | |/ _` | __/ _ \| '__|")
print("| (_| (_| | | (__| |_| | | (_| | || (_) | |   ")
print(" \___\__,_|_|\___|\__,_|_|\__,_|\__\___/|_|   ")

BLACKLIST = ["open", "input", "eval", "exec", "import", "getattr", "sh", "builtins", "global"]
def calc(op):
	try : 	
		res = eval(op)
	except :
		return print("Wrong operation")
	return print(f"{op} --> {res}")

def main():
	while True :
		inp = input(">> ")
		if any(bad in inp for bad in BLACKLIST) :
			print("Are you tying to hack me !!!!!")
		else : 
			calc(inp)

if __name__ == '__main__':
	main()
```

Black list here is :  `["open", "input", "eval", "exec", "import", "getattr", "sh", "builtins", "global"]`

I read from https://jbnrz.com.cn/index.php/2024/08/15/pyjail/ , use `breakpoint` to bypass blacklist and do like `Easy Jail`

![image](https://hackmd.io/_uploads/HyOja6d51e.png)

Flag : ```KashiCTF{C4N_S71LL_CL3AR_8L4CKL15T_mBLcLrsB}```














