Utar CTF
I participated in the UTAR CTF 2024 with team A1ph4_Sh4rk, alongside with my teammates Miracle0604, Teng, and myself. It was an exhausting experience, as we departed from KL to Kampar at 5 AM and had to drive back to KL after the competition. In the end, we managed to secure 1st runner-up and here is our writeup for the challenges.
Binary/binary100
Solution:
Used Detect It Easy
to determine that the exe file is a C/C++ program.
Opened the exe file in dotPeek to decompile the code.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
using System;
namespace UTAR_bin000
{
internal class Program
{
private static Random random = new Random(123456);
private static byte[] secret = new byte[38]
{
(byte) 95,
(byte) 80,
(byte) 67,
(byte) 92,
(byte) 100,
(byte) 32,
(byte) 58,
(byte) 56,
(byte) 116,
(byte) 40,
(byte) 103,
(byte) 57,
(byte) 37,
(byte) 52,
(byte) 47,
(byte) 64,
(byte) 127,
(byte) 45,
(byte) 35,
(byte) 48,
(byte) 42,
(byte) 99,
(byte) 120,
(byte) 71,
(byte) 52,
(byte) 104,
(byte) 101,
(byte) 99,
(byte) 44,
(byte) 118,
(byte) 108,
(byte) 36,
(byte) 71,
(byte) 49,
(byte) 19,
(byte) 96,
(byte) 120,
(byte) 110
};
private static void Main(string[] args)
{
Console.WriteLine("Welcome to UTAR bin100");
int l33tWatchaNumber = Program.getUltraSuperL33tWatchaNumber();
int num1 = 0;
for (int index = 0; index < l33tWatchaNumber; ++index)
num1 = Program.getSuperL33tNumber();
int num2 = (int) Program.secret[l33tWatchaNumber - 1] ^ (int) (byte) num1;
Console.Write("Flag is : ...");
Console.Write(Convert.ToChar(num2));
Console.WriteLine("...");
}
private static int getUltraSuperL33tWatchaNumber() => new Random().Next(1, 38);
private static int getSuperL33tNumber() => Program.random.Next(1, 38);
}
}
The decompiled C# code uses a secret
array of bytes and XOR one of its elements with a randomly generated number to produce the flag.
To retrieve the random number, we set a break point in num1 = Program.getSuperL33tNumber();
and modified the l33tWatchaNumber
to 38, so we can retrieve the sequence of random numbers.
We extracted the sequence of numbers generated and convert them to hexadecimal.
1
2
3
4
5
# Decimal
10 4 2 14 31 19 8 15 21 30 4 13 22 4 27 33 27 24 26 3 18 6 25 33 4 13 3 1 26 21 15 23 34 4 32 4 27 19
# Hex
a 4 2 e 1f 13 8 f 15 1e 4 d 16 4 1b 21 1b 18 1a 3 12 6 19 21 4 d 3 1 1a 15 f 17 22 4 20 4 1b 13
Finally, we write a Python script to XOR the secret array with the extracted key to get the flag.
1
2
3
4
5
ct = [95, 80, 67, 92, 100, 32, 58, 56, 116, 40, 103, 57, 37, 52, 47, 64, 127, 45, 35, 48, 42, 99, 120, 71, 52, 104, 101, 99, 44, 118, 108, 36, 71, 49, 19, 96, 120, 110]
key = [0xA, 0x4 , 0x2 , 0xE, 0x1f, 0x13, 0x8, 0xF, 0x15, 0x1e, 0x4, 0xD, 0x16, 0x4, 0x1b, 0x21, 0x1b, 0x18, 0x1A, 0x3, 0x12, 0x6, 0x19, 0x21, 0x4, 0xd, 0x3, 0x1, 0x1a, 0x15, 0xF, 0x17, 0x22, 0x4, 0x20, 0x4, 0x1b, 0x13]
for i in range(len(ct)):
print(chr(ct[i] ^ key[i % len(key)]), end="")
Flag:
UTAR{327a6c4304ad5938eaf0efb6cc3e53dc}
Binary/binary200
Solution:
We eopened the provided exe file in IDA, and navigated to View > Open subviews > strings, we found a suspicos string: f17b245513f53cef837b54g9:7b2:99b
.
When we forward the suspicious string, we found the function:
1
2
3
4
5
6
7
8
9
10
11
12
loc_1400012B8: ; CODE XREF: sub_140001140+16E↑j
cmp [rsp+58h+var_58], 20h ; ' '
jge short loc_1400012E2
movsxd rax, [rsp+58h+var_58]
movsx eax, [rsp+rax+58h+var_40]
inc eax
movsxd rcx, [rsp+58h+var_58]
lea rdx, ct ; "f17b245513f53cef837b54g9:7b2:99b"
movsx ecx, byte ptr [rdx+rcx]
cmp eax, ecx
jz short loc_1400012E0
jmp short loc_1400012E9
This is the critical function of this file as the instruction movsx eax, [rsp+rax+58h+var_40]
will move a byte (character) into the register and convert it into a 32bit signed integer (ASCII value). Besides, inc eax
changes the original character by incrementing its ASCII value by 1.
To reverse this process, we wrote a python script:
1
2
3
4
ct = "f17b245513f53cef837b54g9:7b2:99b"
for c in ct:
print(chr(ord(c) - 1), end="")
It will get the ASCII value for each of the character, subtract it by 1 and lastly convert it back to a character.s
Flag:
UTAR{e06a134402e42bde726a43f896a1988a}
Crypto/CryptoQuest
Solution:
This is a reused challenge from Cyber Apocalypse 2022 CTF. We found the solution on YouTube and adapted it to solve this challenge.
Final Script:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
from sympy import igcd, Symbol, solve
from Crypto.Util.number import long_to_bytes
n1 = 93768948782729745478599497793422837990844683777054239378160474776560328573740431328119069546474726108930506737169994788955100441012384360021152667154287992695010195576758316949585621551596158372376345419456965488254521532147792713935363300735987030988082563979975500168572577260733535458985853917764527363407769270888828243816895641732445160252301964925541012207546553786760547571437309
c1 = 3621040439219007434888695593528949492599239288972667623035553668240449325367907807190984382
n2 = 91025568464739694140466003159234293768290991283984557403047262623528591078227010433420470804003649933884386662079743329798798525248580861464365943451120270370457258649269769883650838118032727366611574875678349888523527808307940817294050887454976727571614338539148795127773589683011325602555167585577233867721677509481441225602003683137182844508449837448007714031771752450966624270918589
c2 = 1407336180112944499971322497698050797074666521478341254597057144222846308346063835176567810
coeff = igcd(n1 - 4, n2 - 4)
for i in range(3, 1000):
while coeff % i == 0:
coeff = coeff // i
x = Symbol('x')
roots1 = solve(x**2 + (coeff * x) - c1, x)
flag_part1 = long_to_bytes(int(roots1[1]))
roots2 = solve(x**2 + (coeff * x) - c2, x)
flag_part2 = long_to_bytes(int(roots2[1]))
flag = flag_part1 + flag_part2
print(flag.decode())
Flag:
UTAR{19225ed7185d6b5211065eb201aa9e78}
Forensic/Forensic200
Challenge Description:
We were provided with a shell script named persistence.sh
:
Solution:
Executing the command:
Flag:
UTAR{9ce23f07e6b9bfc37508163b07e4d1b5}
Forensic/a Letter please?
Challenge Description:
We are given a zip but in fact it is not a zip file:
Solution:
We checked the file content and found a base64 encoded docx file:
After googling and we found a tool can be used to convert base64 to a file:
After downloading the file, We can find the flag inside it.
Flag:
UTAR{InvisibleEvidenceSpeaks}
Forensic/Hex is Fun
Solution:
We used binwalk to analyse the file and found that there is a hidden file secretmessage.tar
.
We then used -e flag with binwalk to extract the hidden file:
The flag was found when we read the content of the extracted file:
Flag:
UTAR{BitsNeverLie}
Wireshark/book club
Solution:
The challenge description revealed that we need to look for an Excel file. We open the PCAP file and navigated to File > Objects > HTTP, we found an Excel file. Flag is inside the Excel file.
Flag:
UTAR{978-1878424310}
Wireshark/bad http
Solution:
By using strings
and grep
command, we can locate the flag:
Flag:
UTAR{b7539e107ce57da91c5cebbcff1cb3516a2b86bc248a1f50e6ba18871fbf1a7a}
Wireshark/Riddle is Fun
Challenge Description:
In this challenge, we were provided with a password hint and encrypted file (encrypted_message.enc).
password_hint.txt:
1
2
1: In a famous tale, a protagonist's insatiable thirst for knowledge led them to open a forbidden door, revealing wonders beyond imagination.
2: I have no special talents. I am only passionately curious. -Albert Einstein.
Solution:
Based on the provided hints, we guessed that the password is “curiosity”. The command used to decrypt the file is:
1
openssl enc -d -aes-256-cbc -in encrypted_message.enc -out decrypted_message.txt -pass pass:curiosity
We successfully decrypted the encrypted file and retrieved the flag.
Flag:
UTAR{curiosity}
Web
Solution:
In the web challenge, we are given a VM file to access the challenge, but we used unintended way to retrieve all the flags.
First, we boot into the GRUB menu. In this case, SHIFT
key doesn’t works, but ESC
key works well.
Next, press e
to edit the boot parameters.
Modify the ro
parameter to rw init=/bin/bash
to boot into a root shell.
Press CTRL + X
to continue booting with the modified parameters. After booting, the system provides root access without requiring a password.
Due to the screen size, we decided to change the root password and login as root to get a better screen size.
Now we can restart the VM and log in as root using the new password. After some exploration, we found the challenge files under /var/chroot
.
By examing the source code files, we can easily identify the flag for each challenge.