Post

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.

light mode only dark mode only

Binary/binary100

Solution:

Used Detect It Easy to determine that the exe file is a C/C++ program.

light mode only dark mode only

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.

light mode only dark mode only

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:

light mode only dark mode only

Solution:

Executing the command:

light mode only dark mode only

Flag:

UTAR{9ce23f07e6b9bfc37508163b07e4d1b5}

Forensic/a Letter please?

Challenge Description:

We are given a zip but in fact it is not a zip file:

light mode only dark mode only

Solution:

We checked the file content and found a base64 encoded docx file:

light mode only dark mode only

After googling and we found a tool can be used to convert base64 to a file:

light mode only dark mode only

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:

light mode only dark mode only

The flag was found when we read the content of the extracted file:

light mode only dark mode only

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.

light mode only dark mode only

Flag:

UTAR{978-1878424310}

Wireshark/bad http

Solution:

By using strings and grep command, we can locate the flag:

light mode only dark mode only

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

light mode only dark mode only

We successfully decrypted the encrypted file and retrieved the flag.

light mode only dark mode only

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.

light mode only dark mode only

Next, press e to edit the boot parameters.

light mode only dark mode only

Modify the ro parameter to rw init=/bin/bash to boot into a root shell.

light mode only dark mode only

Press CTRL + X to continue booting with the modified parameters. After booting, the system provides root access without requiring a password.

light mode only dark mode only

Due to the screen size, we decided to change the root password and login as root to get a better screen size.

light mode only dark mode only

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.

light mode only dark mode only

By examing the source code files, we can easily identify the flag for each challenge.

This post is licensed under CC BY 4.0 by the author.