CyberChallengeIT CTF - Group Challenge

During the last week of preparation for che Cyber Challenge IT CTF, we were asked to do a CTF challenge our self. We were divided in groups and given a month to come up with a challenge.

Our group create an easy and guided challenge, since we were required to solve it in one hour. It will cover some basic aspect of all the kind of challenges types like Web Security, Reversing, Forensics, Cryptography.

If you want to try the challenge yourself you will start by downloading this zip file:

challenge_gruppo_1.zip

Thank you to all the tutors and the other group members which made all the different parts of this challenge.

The source code for creating the challenge: CTF_CyberChallenge

Writeup

The challenge was Italy so the writeup is in Italian

Start

La challenge inizia con uno zip.

unzip challenge_gruppo_1.zip

Allinterno dello zip troviamo diversi file:

Sito

Accediamo al sito e troviamo che il campo username è vulnerabile a SQLI ber il bypass dellautenticazione.

admin' --

Questo ci permette di scaricare un file disk.

Il sito non utilizza un database in quanto è una pagina statica. Anche lo se lo script è minified, con un po di reversing si può benissimo trovare la funzione del download, però non è pratico in quanto per questioni di tempo la query è molto semplice.

Hint 1

Nel source del sito possiamo trovare un commento suggerisce di utilizzare SQL Injection.

Disk

Utilizzando il comando file su disk possiamo vedere:

disk: Linux rev 1.0 ext2 filesystem data, ...

Essendo un file-system procediamo quindi a creare una cartella dove eseguire il mount

mkdir mnt
sudo mount disk mnt

Nella cartella mnt troviamo i seguenti file:

Clippy nel suo messaggio cita un eseguibile di cui fare il reverse engineering, però non abbiamo al momento nessun eseguibile.

Hint 2

Analizziamo quindi il contenuto del file next_stage.txt

strings next_stage.txt
strings -10 next_stage.txt

Notiamo una stringa in base64, decodificata proseguiamo ad analizzarla notando che è stato applicato uno shift

echo "RnIgZnJ2IG95YnBwbmdiIHZhIGdoZ2d2IGRocmZndiBPVkEgY2ViaW4gbiBzbmVndiBoYW4gSk5ZWCA6KQo=" | base64 -d | tr ‘n-za-mN-ZA-M’ ‘a-zA-Z’
# Oppure se si ha installati bsd_games
echo "RnIgZnJ2IG95YnBwbmdiIHZhIGdoZ2d2IGRocmZndiBPVkEgY2ViaW4gbiBzbmVndiBoYW4gSk5ZWCA6KQo=" | base64 -d | rot13

Unendo le varie informazioni trovate sappiamo che sono stati eliminati dei file e ci viene citato binwalk.

Forensics

Il filesystem mantiene i dati scritti su disco anche dopo leliminazione dato che vengono solo eliminati i nodi e considerato come freespace. Per estrarre i dati ci sono vari modi: testdisk, ext-undelete, scalpel Noi mostreremo un metodo utilizzando binwalk.

Come suggerito proviamo a utilizzare binwalk su disk per trovare tutti i dati contenuti, nelle nuove versioni è necessario utilizzare il tag -b.

Facendo un prima analisi sul file disk possiamo notare che contiene file di estensione nota e che quando abbiamo fatto il mount non erano presenti

strings -10 disk | grep -i "[a-z_]*\.[a-z]*"
strings | head
# next_stage.txt
# sneaky.tar.gz
# helpful.png

Una volta visto lesistenza di un file non presente alla montatura procediamo con lestrazione e lanalisi dei files utilizzando binwalk con la flag -e.

binwalk -e -b disk
cd _disk.extracted/
file *
tar -xvf 7400

Il tar contiene i seguenti files:

Utilizzando lo strumento testdisk è possibile riconoscere il file rimosso, ma non è possibile lestrazione

Reverse Engineering

Analizzando crackme troviamo che dal main viene chiamata una funzione da un array di funzioni nominato table. La funzione chiamata è la funzione j, dato che viene lindice viene determinato dal calcolo di modular_exponentiation sulla base di parametri statici.

argv_to_int = atoi(*(char **)(param_2 + 8));
table_index = modular_exponentiation(3,0x2b,7);
cVar1 = *(table + (ulong)table_index * 8)((ulong)argv_to_int);

Proseguendo lanalisi della funzione j notiamo che al suo interno chiama una funzione di controllo (fourth_check) passando come argomento del binary. fourth_check divide il valore che abbiamo inserito in 4 variabili tramite operazioni binarie che utilizza poi in un sistema lineare a quattro incognite. La funzione j controllerà poi i risultati di questo sistema con i valori contenuti in un array inizializzato allinterno della procedura.

Conoscendo tutti questi valori possiamo quindi creare un sistema lineare dove poniamo come incognite le quattro parti in cui il nostro valore di ingresso è stato diviso e una volta che abbiamo ottenuto il valore andiamo a fare il reverse delloperazione di >> per ottenere il valore corretto.

import numpy as np
import math

""" fourth_check() - from ghidra
uint32_t a = n & 0xFF;
uint32_t b = (n >> 8) & 0xFF;
uint32_t c = (n >> 16) & 0xFF;
uint32_t d = (n >> 24) & 0xFF;

uint32_t v1 = 'J' * a + 'o' * b + 'j' * c + 'o' * d;
uint32_t v2 = 'D' * a + 'I' * b + 'O' * c + '!' * d;
uint32_t v3 = 'Z' * a + 'A' * b + 'W' * c + 'A' * d;
uint32_t v4 = 'R' * a + 'U' * b + 'D' * c + 'O' * d;

uint32_t vals[4] = {61319, 38111, 48787, 48939};
"""

def char_to_str(chrs):
return [ord(c) for c in chrs]

incognite = np.array([char_to_str("Jojo"), char_to_str("DIO!"), char_to_str("ZAWA"), char_to_str("RUDO")])
valori = np.array([61319, 38111, 48787, 48939])
risultato = np.linalg.solve(incognite, valori)
print("Values are: {}".format(risultato)) # Values are: [198.  96. 146. 185.]

values = [198, 96, 146, 185]
values.reverse()
binary = ["{0:08b}".format(b) for b in values]
print("Value: {}".format(int("".join(binary), 2))) # 3113377990

Eseguiamo quindi crackme passando come parametro il valore calcolato e otteniamo un HASH(SHA2).

./crackme 3113377990
# 0051377D1EE813EBFB59991D9165D88EC8C28C51AB37268A01DE386D00AE873AE34051D74CEEF2E457AB2D06BF283BEE87D0A209242B004DC27892DA6DB1AE1C
Hint 3

Nelleseguibile viene eseguito un controllo tra la stringa stuck e una variabile di nome hint. Se andiamo a controllare il valore della variabile, ci consiglia di trovare dinamicamente la funzione chiamata dal main o di cambiare il tipo della variabile table in un array di funzioni per capire quale di queste chiami. La stringa la possiamo notare eseguendo strings del nostro eseguibile.

Steganography

Consideriamo limmagine helpful.png

strings helpful.png
# at Least you're putting Significant effort into this challenge

Dato il suggerimento proviamo a vedere se abbiamo qualcosa nei bit meno significativi. Utilizzando il codice fornito allinterno della pagina web otteniamo il nostro messaggio nascosto.

import base64
from PIL import Image

image = Image.open("./helpful.png")
extracted = ''
pixels = image.load()
for x in range(0,image.width):
r,g,b = pixels[x,0]
extracted += bin(r)[-1]
extracted += bin(g)[-1]
extracted += bin(b)[-1]

chars = []
for i in range(len(extracted)//8):
byte = extracted[(i*8):(i+1)*8]
chars.append(chr(int(''.join([str(bit) for bit in byte]), 2)))

flag = ''.join(chars)
print(flag) # This website might help you a lot: https://ecavicc.github.io/cyberchallenge/

Un altro tool più popolare da utilizzabile è zsteg in ruby per ricavare direttamente il base64

Cracking

Andiamo a forzare lhash che abbiamo ottenuto dalleseguibile per ottenere la password che ci permetterà di ottenere la flag. Per crackare lhash andremo a utilizzare hashcat fornendo una wordlist, si può anche trovare la soluzione su CrackStation

hashcat -a 0 -m 1700 hash rockyou.txt
# Mr.Pickles

Hint 4

Il sito che abbiamo estratto dallimmagine contiene il simbolo # e un gattino da qui possiamo collegare i due elementi e ottenere hashcat. Inoltre il link presente infondo alla pagina, che porta alla canzione We Will Rock You, vuole essere un suggerimento a utilizzare una wordlist di supporto.

Conclusione

Eseguiamo il file python per ottenere la flag

echo "Mr.Pickles" > passwd
python3 get_flag.py < passwd

FLAG{i_7urn3d_mys31f_i1n70_4_pick13}

Extras

Piccoli easter-egg presenti nella sfida :smile: