Computas: Åpen Fagkveld CTF
Introduction⌗
Computas åpen fagkveld was IRL CTF hosted by Computas at DIGS in Trondheim. This was my first time playing in an IRL CTF and it was pretty exciting and I cannot wait to do another one!
Haven’t played CTFs in a while and this reminded me of the joy of solving infosec challenges which makes me realize how passionate I’m about this field and finding solutions to problems related to it.
Table of contents⌗
Challenge | Category | Points |
---|---|---|
Hello World! | Forensics | 10 |
Stegg | Forensics | 50 |
Hidden in Plain Sight | Forensics | 200 |
Secrets in secrets | Forensics | 300 |
Dørvakt | Reversing | 50 |
Avengers Assemble | Reversing | 100 |
Dørvakt 2 | Reversing | 100 |
java-encoder | Reversing | 350 |
Still pretty basic | Cryptography | 50 |
Velkommen til kodeknekking! | Cryptography | 50 |
Låst ned | Cryptography | 200 |
Show the seed | Cryptography | 200 |
Enten Eller | Cryptography | 250 |
SQL-Injection 101 | Web | 50 |
Robots4ever | Web | 75 |
Cookie-monster | Web | 100 |
Write-up⌗
Forensics⌗
Hello World!⌗
Velkommen til Capture The Flag! Her er et flagg for å starte :) ctf{v3lkommen_til_CTF!}
This one is pretty straight forward the flag is given on the challenge description :)
Flag: ctf{v3lkommen_til_CTF!}
Stegg⌗
Et enkelt bilde. Eller er det?
On this one we are given a PNG image file. From the challenge name we could derive that it has
something todo with stenography.
Before taking any other steps we could try to look for the flag by seeing which strings we could
read on the PNG file.
[morim@blossomsec stegg]$ file egg.png
egg.png: PNG image data, 360 x 360, 4-bit colormap, non-interlaced
[morim@blossomsec stegg]$ strings egg.png | grep ctf
ctf{sp3ilegg_er_best}
And there it is! We got the flag just by looking at the strings :)
Flag: ctf{sp3ilegg_er_best}
Hidden in Plain Sight⌗
Vent litt…. Hvor er oppgaven?
Now on this one I’ve got to admit that I’ve got pretty lost and wasted too much time on it. I couldn’t solve it during the CTF but aftewards I reached out to the CTF creators so they could help me find the flag.
It turns out the flag was hidden in an image file that was embedded on the source code of the index page of the CTF.
Once again we will try the easy way an search for the flag in the strings of the image file.
[morim@blossomsec hidden_in_plain_sight]$ file secret.png
secret.png: PNG image data, 1482 x 343, 8-bit/color RGBA, non-interlaced
[morim@blossomsec hidden_in_plain_sight]$ strings secret.png | grep ctf
ctf{made_you_look_at_the_brand!}
It turns out the easy way got us the flag again!
Flag: ctf{made_you_look_at_the_brand!}
Secrets in secrets⌗
To solve this challenge it was required to solve the Hidden in plain sight one.
By reading the name of it we will assume it is something about the secret.png
file where
we found the last flag.
That being said we’ll in take a deep look in to the image file to find any other files that might be embedded there.
[morim@blossomsec secrets_in_secrets]$ exiftool secret.png
ExifTool Version Number : 12.50
File Name : secret.png
Directory : .
File Size : 37 kB
File Modification Date/Time : 2023:04:15 23:48:34+02:00
File Access Date/Time : 2023:04:15 23:48:38+02:00
File Inode Change Date/Time : 2023:04:15 23:48:34+02:00
File Permissions : -rw-r--r--
File Type : PNG
File Type Extension : png
MIME Type : image/png
Image Width : 1482
Image Height : 343
Bit Depth : 8
Color Type : RGB with Alpha
Compression : Deflate/Inflate
Filter : Adaptive
Interlace : Noninterlaced
Pixels Per Unit X : 11811
Pixels Per Unit Y : 11811
Pixel Units : meters
Warning : [minor] Trailer data after PNG IEND chunk
Image Size : 1482x343
Megapixels : 0.508
After checking the metadata we got a warning saying that there is some data appended to the end of the file. We can use xxd to perform a hexdump so we can check for unusual data.
[morim@blossomsec secrets_in_secrets]$ xxd secret.png | tail
00008e10: 2100 0000 2100 0000 0400 1800 0000 0000 !...!...........
00008e20: 0100 0000 a481 0000 0000 666c 6167 5554 ..........flagUT
00008e30: 0500 03d2 7835 6475 780b 0001 04e8 0300 ....x5dux.......
00008e40: 0004 e803 0000 504b 0102 1e03 1400 0000 ......PK........
00008e50: 0800 7d86 8b56 2ddc 84a4 e42d 0000 6a31 ..}..V-....-..j1
00008e60: 0000 0d00 1800 0000 0000 0000 0000 a481 ................
00008e70: 5f00 0000 746f 7073 6563 7265 742e 6a70 _...topsecret.jp
00008e80: 6755 5405 0003 0d74 3564 7578 0b00 0104 gUT....t5dux....
00008e90: e803 0000 04e8 0300 0050 4b05 0600 0000 .........PK.....
00008ea0: 0002 0002 009d 0000 008a 2e00 0000 00 ...............
It looks like there are a few zip files appended on the image and the next step here is to extract them.
[morim@blossomsec secrets_in_secrets]$ binwalk -e secret.png
DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------
0 0x0 PNG image, 1482 x 343, 8-bit/color RGBA, non-interlaced
24434 0x5F72 Zip archive data, at least v1.0 to extract, compressed size: 33, uncompressed size: 33, name: flag
24529 0x5FD1 Zip archive data, at least v2.0 to extract, compressed size: 11748, uncompressed size: 12650, name: topsecret.jpg
36505 0x8E99 End of Zip archive, footer length: 22
[morim@blossomsec secrets_in_secrets]$ ls
secret.png _secret.png.extracted
[morim@blossomsec secrets_in_secrets]$ ls _secret.png.extracted/
5F72.zip flag topsecret.jpg
We successfuly extracted three files:
- 5F72.zip : A zip archive containing the files flag and topsecret.jpg
- flag : A text file with the flag of the previous challenge
- topsecret.jpg : A jpeg file of an old Computas logo
Once again we will try to check for embedded files on the newly discovered image.
[morim@blossomsec secrets_in_secrets]$ exiftool topsecret.jpg
ExifTool Version Number : 12.50
File Name : topsecret.jpg
Directory : .
File Size : 13 kB
File Modification Date/Time : 2023:04:11 16:51:57+02:00
File Access Date/Time : 2023:04:11 16:54:32+02:00
File Inode Change Date/Time : 2023:04:16 00:02:34+02:00
File Permissions : -rw-r--r--
File Type : JPEG
File Type Extension : jpg
MIME Type : image/jpeg
JFIF Version : 1.01
Resolution Unit : None
X Resolution : 1
Y Resolution : 1
Image Width : 512
Image Height : 171
Encoding Process : Baseline DCT, Huffman coding
Bits Per Sample : 8
Color Components : 3
Y Cb Cr Sub Sampling : YCbCr4:2:0 (2 2)
Image Size : 512x171
Megapixels : 0.088
[morim@blossomsec secrets_in_secrets]$ jhead topsecret.jpg
File name : topsecret.jpg
File size : 12650 bytes
File date : 2023:04:11 16:51:57
Resolution : 512 x 171
JPEG Quality : 84
This time there was nothing unusual on the image metadata so we will run binwalk and stegseek to look for any data that might be hidden.
[morim@blossomsec secrets_in_secrets]$ binwalk topsecret.jpg
DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------
0 0x0 JPEG image data, JFIF standard 1.01
[morim@blossomsec secrets_in_secrets]$ stegseek --seed topsecret.jpg
StegSeek 0.6 - https://github.com/RickdeJager/StegSeek
[i] Found (possible) seed: "0aec9e93"
Plain size: 56.0 Byte(s) (compressed)
Encryption Algorithm: rijndael-128
Encryption Mode: cbc
It seems that stegseek found a possible file that was hidden in the image using steghide. Since we don’t know the passphrase used to encrypt and hide the data on the file we are going to use stegseek to find the passphrase and extract the data for us.
[morim@blossomsec secrets_in_secrets]$ stegseek --crack topsecret.jpg ~/Documents/Wordlists/rockyou.txt
StegSeek 0.6 - https://github.com/RickdeJager/StegSeek
[i] Found passphrase: "1985"
[i] Original filename: "flag".
[i] Extracting to "topsecret.jpg.out".
[morim@blossomsec secrets_in_secrets]$ cat topsecret.jpg.out
ctf{w3lcome_to_c0mputas_41243}
Another flag secured!
ctf{w3lcome_to_c0mputas_41243}
Reversing⌗
Dørvakt⌗
Dørvakten slipper meg ikke inn! Kan du finne passordet?
We are given an ELF binary file and as we did on the forensics challenges above, before wasting any more time, we could search for the flag on the strings of the binary.
[morim@blossomsec dorvakt]$ file guard
guard: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=0fcc120ec49c276d18ad492cddcfccc87130fa6f, for GNU/Linux 3.2.0, not stripped
[morim@blossomsec dorvakt]$ strings guard | grep ctf
ctf{mellon_50423}
It seems like we did it again.
Flag: ctf{mellon_50423}
Avengers Assemble⌗
Jeg har testet ut denne nye metoden for å beskytte nettsiden min med en PIN-kode…
We are given a simple web app page with a submission form in which we can submit a PIN code to get the flag.
After checking the Javascript loaded on the page we can see that the PIN validation is made on the client side which is a big nono regarding appsecurity.
JS Embedded on the html:
import { checkPinCode } from "./build/debug.js";
function getFlag(pinCode) {
let key = "flag{w4sm_is_the_futur3_" + pinCode.toString() + "}";
return key;
}
function click() {
let userProvidedPin = document.getElementById("key").value;
let isPin = checkPinCode(userProvidedPin);
if (isPin) {
document.getElementById("flag").innerHTML = getFlag(userProvidedPin);
} else {
document.getElementById("flag").innerHTML = "That's not the right pin code :(";
}
}
document.getElementById("generate").addEventListener("click", click);
debug.js:
async function instantiate(module, imports = {}) {
const { exports } = await WebAssembly.instantiate(module, imports);
const memory = exports.memory || imports.env.memory;
const adaptedExports = Object.setPrototypeOf({
checkPinCode(a) {
// assembly/index/checkPinCode(i32) => bool
return exports.checkPinCode(a) != 0;
},
}, exports);
return adaptedExports;
}
export const {
memory,
checkPinCode
} = await (async url => instantiate(
await (async () => {
try { return await globalThis.WebAssembly.compileStreaming(globalThis.fetch(url)); }
catch { return globalThis.WebAssembly.compile(await (await import("node:fs/promises")).readFile(url)); }
})(), {
}
))(new URL("debug.wasm", import.meta.url));
debug.wasm:
(module
(table $0 (;0;) 1 1 funcref)
(memory $memory (;0;) (export "memory") 0)
(global $~lib/memory/__data_end (;0;) i32 (i32.const 8))
(global $~lib/memory/__stack_pointer (;1;) (mut i32) (i32.const 32776))
(global $~lib/memory/__heap_base (;2;) i32 (i32.const 32776))
(elem $0 (;0;) (i32.const 1) funcref)
(func $assembly/index/checkPinCode (;0;) (export "checkPinCode") (param $a (;0;) i32) (result i32)
(local $b i32)
(local $c i32)
(local $d i32)
local.get $a
i32.const 7
i32.div_s
local.set $b
local.get $b
i32.const 30
i32.mul
local.set $c
local.get $c
i32.const 1
i32.add
local.set $d
local.get $d
i32.const 5851
i32.eq
if
i32.const 1
return
else
i32.const 0
return
end
unreachable
)
)
The algorithm used to check if the provided PIN code is correct is on the debug.wasm
file,
since we can view the source code it’s just a matter of reversing the algorithm to derive the PIN
from the value used to check if it is correct.
The algorithm is pretty simple and we will resume it to this:
pin / 7 * 30 + 1 = 5851
So now we can get the pin by reverting order of the operations:
pin = (5851 - 1) / 30 * 7 = 1365
After submitting the value 1365 the web app generates the flag.
Flag: flag{w4sm_is_the_futur3_1365}
Dørvakt 2⌗
Jeg fant en ny dørvakt, men denne gangen ser det ut som det blir litt vanskeligere…
This one was quite more challenging than the first two challenges, so searching in the strings will not get us the flag this time!
We are given a ELF binary which uses the first argument passed on the code to generate the flag.
[morim@blossomsec dorvakt2]$ ./nerdy_guard
Please give a number as an argument
[morim@blossomsec dorvakt2]$ ./nerdy_guard 123
-7038
That wasn't the correct password :(
[morim@blossomsec dorvakt2]$
We are going to need to fire up Ghidra to help us solve this one.
After disassemble and decompiling the binary we can view the algorithm used to check if the provided PIN code is correct.
It looks like a pretty simple algorithm and it won’t take too much time bruteforcing it, so to do that we’ll write a python script:
#!/usr/bin/python
wanted_key = 433244
for argument_1 in range(1,2000000):
key = argument_1
for i in range(0,10):
key = key * 2 - (argument_1 + 7)
if key == wanted_key:
print(f"CRACKED_PIN: {argument_1}")
exit(0)
print("Better luck bruteforcing next time!")
[morim@blossomsec dorvakt2]$ time ./crack.py
CRACKED_PIN: 440405
real 0m0.770s
user 0m0.762s
sys 0m0.007s
[morim@blossomsec dorvakt2]$ ./nerdy_guard 440405
433244
ctf{the_password_is_440405}
[morim@blossomsec dorvakt2]$
After running the script above we cracked the PIN and got the flag!
Flag: ctf{the_password_is_440405}
java-encoder⌗
Enkoding er noe skikkelig dritt, forhåpentligvis blir alt bedre når man implemtenterer det i java. :)
Unfortunately I couldn’t finish this one before the CTF ended but still managed to solve it afterwards. We were given a java file which we are going to decompile so we can analyze our approach to getting the flag. To do this we are going to fire up jd-gui which will give us the code below:
class MyJavaEncoder {
public static void main(String[] args) {
String alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789{~-:}";
Scanner input = new Scanner(System.in);
System.out.println("Type in your flag guess: ");
String userFlagGuess = input.nextLine();
String[] flagParts = userFlagGuess.split("_");
if (flagParts.length==3){
Boolean split1 = part1(flagParts[Integer.parseInt("A74", 16)%14]);
Boolean split2 = part2(flagParts[(alphabet.length()+1)%4]);
Boolean split3 = part3(flagParts[67352854%19], alphabet,userFlagGuess.length()%50);
if (split1 && split2 && split3){
System.out.println("Correct flag! :)");
return;
}
}
System.out.println("That's not it, try again");
}
public static boolean part1(String s) {
if (s.length()!=12){return false;}
if (!s.substring(0,8).equals("d0ne~:cl")){return false;}
try {
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] digest = md.digest(s.getBytes());
BigInteger no = new BigInteger(1, digest);
String hash = no.toString(16);
while (hash.length() < 32) {
hash = "0" + hash;
}
return hash.equals("7716715cf6f91f8b4b51c55aa3312169");
}
catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
public static boolean part2(String s) {
try {
return Base64.getEncoder().encodeToString(s.getBytes(StandardCharsets.UTF_8.toString())).equals("Y3Rme0gwdH5kYW1u");
} catch(UnsupportedEncodingException ex) {
throw new RuntimeException(ex);
}
}
public static boolean part3(String s, String alphabet, int rot) {
String o = "";
for (char c: s.toCharArray()) {
int pos = alphabet.indexOf(c);
o += alphabet.charAt((pos+rot)%alphabet.length());
}
return o.equals("{H}X{JXQX6Z16HH{16Z");
}
}
After analyzing the code we can notice a few things:
- We have to input the actual flag to the provided code
- The flag is split up to three different sections and each section has a different validation algorithm
- We’ll need to reverse the checking algorithms on the three different sections to get the flag
part1(): This function validates flagParts[2]
and it does that by checking its length which needs to be bigger than 12, then it gives us part of the flag because it checks if its first 8 chars are equal to the substring d0ne~:cl
, after these two checks it calculates the MD5 hash of the provided flagPart. Since we got most of the flag, the hashing algorithm is MD5 and we are only missing three letters from this flagPart we can bruteforce our way out of this.
part2(): This one is pretty straight forward, it checks if the string in flagParts[0]
is equal to the decoded base64 value of Y3Rme0gwdH5kYW1u
.
part3(): This is were flagParts[1]
is going to be validated, the validation process used on this one is done by encoding the flagPart in a custom algorithm and check it against the value {H}X{JXQX6Z16HH{16Z
. To get this part we’ll need to revert the algorithm to decode the final value and it can be done by reversing the math operations done to determine the letter on the alphabet
value. Now it seems like we are missing the value for to variable rot
which is the length of the full flag, but we can determine its value by solving adding the length of the string {H}X{JXQX6Z16HH{16Z
plus the values of part1()
and part2()
plus the number two (which is the number of underscores used to split the flag).
Now that we know what the code does and what we need to do for solving this challenge we are going to write a script in Python to solve it:
#!/usr/bin/python
import hashlib
import itertools
import base64
alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789{~-:}"
def part3():
key = "d0ne~:cl"
attempts = 0
for guess in itertools.product(alphabet, repeat=3):
attempts += 1
guess = key+''.join(guess)+"}"
if hashlib.md5(guess.encode('utf-8')).hexdigest() == "7716715cf6f91f8b4b51c55aa3312169":
return guess
return ""
def part2(p1_p3_len):
cipher = "{H}X{JXQX6Z16HH{16Z"
rot = p1_p3_len + len(cipher) + 2
guess = ""
for l in cipher:
guess += alphabet[(alphabet.index(l)-rot)%len(alphabet)]
return guess
def part1():
return base64.b64decode("Y3Rme0gwdH5kYW1u").decode("utf-8")
def main():
part_1 = part1()
part_3 = part3()
part_2 = part2(len(part_1)+len(part_3))
print(f"{part_1}_{part_2}_{part_3}")
if __name__ == '__main__':
main()
[morim@blossomsec java-encoder]$ time ./solve.py
ctf{H0t~damn_r3ver5e-engin33ring_d0ne~:clap:}
real 0m0.034s
user 0m0.031s
sys 0m0.004s
Even thought it didn’t count to get us points on the scoreboard we’ve managed to get the flag.
Flag: ctf{H0t~damn_r3ver5e-engin33ring_d0ne~:clap:}
Cryptography⌗
Still pretty basic⌗
Vi brukte en litt nyere kode denne gangen: Y3Rme3ByZXR0eV9iYXNpY181MjI2OH0=
Straightforward challenge we just need to decode the provided base64.
Flag: ctf{pretty_basic_52268}
Velkommen til kodeknekking!⌗
Den første oppgaven er å knekke denne koden: pgs{nyyebnqfyrnqgbebzr} Lykke til!
We were given the value pgs{nyyebnqfyrnqgbebzr}
which looks like it was been passed through a ROT13 algorithm, so the get the flag we can use CyberChef to decode it.
Flag: ctf{allroadsleadtorome}
Låst ned⌗
“Vi fanget denne filen som ble sendt av en etteretningsorganisasjon, men vi klarer ikke å åpne den. Kan du hjelpe oss?”
We were given a password protected zipfile and a hint mentioning john the reaper. Since the hint mentioned john we will fire it up and crack the password using the rockyou.txt wordlist.
[morim@blossomsec last_ned]$ zip2john topsecret.zip > topsecret.hashes
topsecret.zip/topsecret/ is not encrypted!
ver 1.0 topsecret.zip/topsecret/ is not encrypted, or stored with non-handled compression type
ver 1.0 efh 5455 efh 7875 topsecret.zip/topsecret/flag PKZIP Encr: 2b chk, TS_chk, cmplen=37, decmplen=25, crc=E168A732
[morim@blossomsec last_ned]$ john --wordlist=~/Documents/Wordlists/rockyou.txt topsecret.hashes
Using default input encoding: UTF-8
Loaded 1 password hash (PKZIP [32/64])
Will run 4 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
JamesBond007 (topsecret.zip/topsecret/flag)
1g 0:00:00:00 DONE (2023-04-14 14:33) 25.00g/s 6348Kp/s 6348Kc/s 6348KC/s dolphins04..1badchick
Use the "--show" option to display all of the cracked passwords reliably
Session completed
[morim@blossomsec last_ned]$ unzip topsecret.zip && cat topsecret/flag
Archive: topsecret.zip
[topsecret.zip] topsecret/flag password:
extracting: topsecret/flag
ctf{positively_sh0cking}
Once again pretty straight forward and we got the flag. Flag: ctf{positively_sh0cking}
Sow the seed⌗
En kollega begynte å bruke AES-kryptering for å large passordet sitt til jobben. De er 100% sikre på at det ikke går an å knekke, men jeg er ikke så sikker på det..
Jeg tror fremdeles vi har ett ess i ermet vårt fordi jeg så på kameraene og fant ut at han krypterte passordet sitt kl 15:01:40 den 28. februar i år.
Jeg stjal også koden hans, så ikke si noe er du grei…
On this task we were given a zip archive in which we can find a JSON file that contains the flag in the form of ciphertext and the code used to generate that file. The first thing we need to do is analyzing the code.
from dataclasses import dataclass
import json
import random
import base64
from Crypto.Cipher import AES
@dataclass
class EncryptedMessage:
nonce: bytes
tag: bytes
ciphertext: bytes
def save(message: EncryptedMessage):
with open("melding.json", "w", encoding="utf-8") as f:
obj = {
"nonce": base64.b64encode(message.nonce).decode("utf-8"),
"tag": base64.b64encode(message.tag).decode("utf-8"),
"ciphertext": base64.b64encode(message.ciphertext).decode("utf-8"),
}
json.dump(obj, f, indent=4)
def load() -> EncryptedMessage:
with open("melding.json", "r", encoding="utf-8") as f:
obj = json.load(f)
nonce = base64.b64decode(obj["nonce"])
tag = base64.b64decode(obj["tag"])
ciphertext = base64.b64decode(obj["ciphertext"])
return EncryptedMessage(nonce, tag, ciphertext)
def encrypt(key: bytes, data: bytes) -> EncryptedMessage:
cipher = AES.new(key, AES.MODE_GCM)
nonce = cipher.nonce
ciphertext, tag = cipher.encrypt_and_digest(data)
return EncryptedMessage(nonce, tag, ciphertext)
def decrypt(key: bytes, message: EncryptedMessage) -> str:
cipher = AES.new(key, AES.MODE_GCM, nonce=message.nonce)
plaintext = cipher.decrypt(message.ciphertext).decode("utf-8")
try:
cipher.verify(message.tag)
print("The message is authentic!")
print("Plaintext: ", plaintext)
return plaintext
except ValueError:
print("Key incorrect or message corrupted")
return None
def main():
key = random.randbytes(16)
with open("flag.txt", "r", encoding="utf-8") as f:
data = f.read().encode("utf-8")
msg = encrypt(key, data)
#save(msg)
#msg = load()
#decrypt(key, msg)
if __name__ == "__main__":
main()
After looking at the code we can determine that to get the flag we need to decrypt the ciphertext in melding.json
. We’ve got the nonce and the tag to verify the validity of the decription, the only thing we are missing is the key. If we look at the main function we can see that the key was generated using python’s random.randbytes(16)
.
Python’s ‘random.randbytes’ uses time as a seed to its PRNG, so if we know the exact timestamp in which the key was generated we can reproduce the random sequence that was used as a key, this timestamp was given in the challenge description.
First we need to get the timestamp in the unix epoch format:
[morim@blossomsec stjalet-kode]$ python
Python 3.10.10 (main, Mar 5 2023, 22:26:53) [GCC 12.2.1 20230201] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import datetime
>>> t=datetime.datetime(2023,2,28,15,1,40)
>>> t.timestamp()
1677592900.0
Then we need to modify the stolen code to decrypt the flag:
...
def main():
random.seed(1677592900)
key = random.randbytes(16)
msg = load()
decrypt(key, msg)
...
After changing the code we need to run the code to get the flag:
[morim@blossomsec stjalet-kode]$ cp ../melding.json .
[morim@blossomsec stjalet-kode]$ python -mvenv env && source env/bin/activate && pip install -r requirements.txt
Collecting pycryptodome
Using cached pycryptodome-3.17-cp35-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (2.1 MB)
Installing collected packages: pycryptodome
Successfully installed pycryptodome-3.17
[notice] A new release of pip available: 22.3.1 -> 23.0.1
[notice] To update, run: pip install --upgrade pip
(env) [morim@blossomsec stjalet-kode]$ python main.py
The message is authentic!
Plaintext: b'ctf{d4t3tim3_f0r_crypt0_i5_n0t_pr3fer4ble}'
Flag: ctf{d4t3tim3_f0r_crypt0_i5_n0t_pr3fer4ble}
Enten Eller⌗
Jeg lagde min egen kode denne gangen! Men jeg vet ikke hvordan man dekrypterer den… Kan du hjelpe meg?
Ciphertext: 524d5e4e49564a6a574d4f6a04000807020845
key: 1985
On this challenge we were given a ciphertext, a key and a hint saying it has something to do with XOR and Vignere. This time I decided to use dcode.fr to decode the ciphertext throught this decoder:
And we secured another flag. Flag: ctf{xor_ftw_590231}
Web⌗
Unfortunately I couldn’t get the write-ups for this challenges before the CTF site was taken offline.
But I’ll do my best to recreate them from memory…
SQL-Injection 101⌗
This challenge was a simple webapp login page where we could inject a ' OR '1'=1';--
to get the flag
Robots4ever⌗
The name of this one was a hint for us to check for the robots.txt
file which contained a path where we could find the flag.
Cookie-monster⌗
On this challenge we need to create an account to access the webapp. After the account creation and login done, we needed to fiddle around with the cookies of the webapp to secure the flag. It was as simple as changing the user defined in the cookie to the value admin
and there it was!
Conclusion⌗
The CTF was great, had a good time playing, the hosts were amazing, and I’m definitely joining it again if it ever happens in the future.
Most of the challenges were entry level ones but since there was a time constraint of only a few hours they couldn’t be really hard ones or else we wouldn’t get a single point. It was a wise choice to make them entry level.
Great initiative on behalf of Computas for doing an event like this since security awareness plays a major role in these modern times.