CyberSpace'24 : Writeups
CyberSpace CTF 2024
Team: WhatIsThis
Total Score: 351 points @ 262nd place
User Name | Score |
---|---|
H4N5 | 251 |
ha1fdan | 100 |
Solves:
Challenge | Category | Value | User |
---|---|---|---|
Sanity Check | misc | 50 | H4N5 |
key | beginner | 50 | H4N5 |
Baby Pybash | beginner | 50 | H4N5 |
ZipZone | beginner | 50 | ha1fdan |
encryptor | beginner | 50 | ha1fdan |
🅰️ 🦵 🌱 | sponsor | 50 | H4N5 |
Feedback | misc | 1 | H4N5 |
flagprinter | crypto | 50 | H4N5 |
Score over time:
Sanity Check
Join our Discord!
Flag: CSCTF{54n17y_5ucc355fully_ch3ck3d!}
key
GDB is cool! Ghidra or IDA is helpful
File(s): key
Solution: Using https://dogbolt.org we can open the key
file using angr. We find the variables v3 to v34 wich all contains a decimal number. We can use this information to write a script to find the key.
- Original Solution code (C#):
using System;
class Program
{
static void Main()
{
int[] v6 = new int[]
{
67, 164, 65, 174, 66, 252, 115, 176,
111, 114, 94, 168, 101, 242, 81, 206,
32, 188, 96, 164, 109, 70, 33, 64,
32, 90, 44, 82, 45, 94, 45, 196
};
char[] s = new char[32];
for (int i = 0; i < 32; i++)
{
if (i % 2 == 0)
{
s[i] = (char)(v6[i] ^ i);
}
else
{
s[i] = (char)((v6[i] / 2) ^ i);
}
}
string key = new string(s);
Console.WriteLine("The correct key is: " + key);
}
}
- Solution code rewritten in Python:
v6 = [
67, 164, 65, 174, 66, 252, 115, 176,
111, 114, 94, 168, 101, 242, 81, 206,
32, 188, 96, 164, 109, 70, 33, 64,
32, 90, 44, 82, 45, 94, 45, 196
]
s = [''] * 32
for i in range(32):
if i % 2 == 0:
s[i] = chr(v6[i] ^ i)
else:
s[i] = chr((v6[i] // 2) ^ i)
key = ''.join(s)
print(key)
Flag: CSCTF{u_g0T_it_h0OrAy6778462123}
Baby Pybash
I made a very secure bash terminal in Python. I don’t think anyone can break in!
nc baby-pybash.challs.csc.tf 1337
File(s): handout_baby_pybash.zip
Solution: The script uses a regular expression to block most characters, but it allows $
and 0
. By combining these, we get $0
, which refers to the first argument of the initial command (bash). This allows us to invoke a bash shell and execute cat flag.txt
to retrieve the flag.
== proof-of-work: disabled ==
Welcome to Baby PyBash!
Enter a bash command: $0
cat flag.txt
CSCTF{b4sH_w1z4rd_0r_ju$t_ch33s3_m4st3r?_c1d4eeb2a}
Flag: CSCTF{b4sH_w1z4rd_0r_ju$t_ch33s3_m4st3r?_c1d4eeb2a}
ZipZone
I was tired of trying to find a good file server for zip files, so I made my own! It’s still a work in progress, but I think it’s pretty good so far.
https://zipzone-web.challs.csc.tf/
File(s): handout_zipzone.zip
Solution: The app.py uses subprocess.call to unzip our uploaded zip file, therefore we can create a symlink to /tmp/flag.txt using ln -s /tmp/flag.txt flag.txt
and zip the symlink using zip --symlinks exploit.zip flag.txt
. After uploading the zip file, we get: https://zipzone-web.challs.csc.tf/files/a58a980e-aeb8-4c33-888d-328280bb463f
; append /flag.txt
to the url and we get the content of /tmp/flag.txt
.
Flag: CSCTF{5yml1nk5_4r3_w31rd}
encryptor
My friend sent me this app with an encoded flag, but he forgot to implement the decryption algorithm! Can you help me out?
File(s): encryptor.apk
Solution: Opening the file with Archive Manager we find /assets/enc.txt
which contains encrypted flag OIkZTMehxXAvICdQSusoDP6Hn56nDiwfGxt7w/Oia4oxWJE3NVByYnOMbqTuhXKcgg50DmVpudg=
. By using https://www.decompiler.com we can decompile the apk and under souces/com/example/encrypter/MainActivity.java
. this class contains the encryption algorithm.
We can see a base64 string being decoded:
private String getKey() {
return new String(Base64.decode("ZW5jcnlwdG9yZW5jcnlwdG9y".getBytes(), 0));
}
Decoding the base64 string gives us the key encryptorencryptor
.
We can also find the encryption function:
private String encryptText(String str) throws InvalidKeyException, UnsupportedEncodingException, NoSuchPaddingException, NoSuchAlgorithmException, IllegalBlockSizeException, BadPaddingException {
SecretKeySpec secretKeySpec = new SecretKeySpec(getKey().getBytes("UTF-8"), "Blowfish");
Cipher instance = Cipher.getInstance("Blowfish");
if (instance != null) {
instance.init(1, secretKeySpec);
return Build.VERSION.SDK_INT >= 26 ? new String(Base64.encode(instance.doFinal(str.getBytes("UTF-8")), 0)) : "";
}
throw new Error();
}
The encryption happends using Blowfish, we can write a simple script to decrypt our flag:
import base64
from Crypto.Cipher import Blowfish
def get_key():
encoded_key = "ZW5jcnlwdG9yZW5jcnlwdG9y"
return base64.b64decode(encoded_key)
encrypted_text = "OIkZTMehxXAvICdQSusoDP6Hn56nDiwfGxt7w/Oia4oxWJE3NVByYnOMbqTuhXKcgg50DmVpudg="
cipher = Blowfish.new(get_key(), Blowfish.MODE_ECB)
encrypted_bytes = base64.b64decode(encrypted_text)
decrypted_bytes = cipher.decrypt(encrypted_bytes)
padding_length = decrypted_bytes[-1]
decrypted_text = decrypted_bytes[:-padding_length].decode('utf-8')
print(decrypted_text)
Flag: CSCTF{3ncrypt0r_15nt_s4Fe_w1th_4n_h4Rdc0d3D_k3y!}
🅰️ 🦵 🌱
There’s a bug bounty program on Intigriti I wanted to revisit. The problem is I only speak emojis these days and completely forgot the name of the program! Can you remind me?
Emojis: 🅰️ 🦵 🌱
https://go.intigriti.com/programs/
Note: Flag format is CSCTF{name_of_program}
Solution: The emojis (🅰️ 🦵 🌱
) can be broken down as follows: the first emoji represents the letter A, the second one is a leg, and the last one could stand for plant, seed, or grow. Putting these together, we can search the Programs page and find the word Allegro: A + leg + grow.
Flag: CSCTF{Allegro}
flagprinter
Instead of a challenge, here’s a solution. Hope you have plenty of RAM!
Solution: The original code attempted to build a massive sequence, which caused it to run out of memory. The optimized solution bypasses this issue by using a recursive function to calculate only the specific values needed at each step, rather than storing the entire sequence. This reduces memory usage significantly. By calculating values as they are needed, the program avoids crashing and successfully decrypts the flag. This approach allows us to handle much larger data without running into memory limitations, making the decryption process both efficient and effective.
from out import enc, R
from math import prod
def get_a_value(index, depth):
if depth == 0:
return 0
elif index < 3**(depth-1): # First third
return get_a_value(index, depth-1)
elif index < 2*3**(depth-1): # Second third
return get_a_value(index - 3**(depth-1), depth-1) + 1
else: # Third third
return get_a_value(index - 2*3**(depth-1), depth-1) + 2
def calculate_required_a_values(R_indices, depth):
return [get_a_value(idx, depth) for idx in R_indices]
flag = ''
depth = 0
# Estimate the required depth of recursion based on the number of iterations
while 3**depth < max(max(R) for R in R) + 1:
depth += 1
print(depth)
for i in range(355):
if i % 5 == 0:
required_values = calculate_required_a_values(R[i//5], depth)
flag += chr(enc[i//5] ^ prod(required_values))
print(flag)
Solution file: sol.py
Flag: CSCTF{2441d2f22fa1d5b9fc0a850dcfbbccf608cafbc22a1beaae0ac328ff6d218781}