Writeup: FlareOn 2021: 005 - FLARE Linux VM

1. TLDR

FLARE-Linux-VM graph

2. Dane wejściowe

Plik z zadaniem znajduje się tutaj. Hasło: flare.

Przedmiotem zadania był plik 05_FLARE_Linux_VM.7z. W archiwum znajdowały się 4 pliki:

'FLARE Linux VM.mf'
'FLARE Linux VM.ovf'
 FLARE_Linux_VM-disk1.vmdk
 intro.txt

Plik tekstowy zawierał wprowadzenie do zadania:

Because of your superior performance throughout the FLARE-ON 8 Challenge, the FLARE team has invited you to their office to hand you a special prize! Ooh – a special prize from FLARE ? What could it be? You are led by a strong bald man with a strange sense of humor into a very nice conference room with very thick LED dimming glass. As you overhear him mumbling about a party and its shopping list you notice a sleek surveillance camera. The door locks shut!

Excited, you are now waiting in a conference room with an old and odd looking computer on the table. The door is closed with a digital lock with a full keyboard on it.

Now you realise… The prize was a trap! They love escape rooms and have locked you up in the office to make you test out their latest and greatest escape room technology. The only way out is the door – but it locked and it appears you have to enter a special code to get out. You notice the glyph for U+2691 on it. You turn you attention to the Linux computer - it seems to have been infected by some sort of malware that has encrypted everything in the documents directory, including any potential clues.

Escape the FLARE Linux VM to get the flag - hopefully it will be enough to find your way out.

Hints:
- You can import "FLARE Linux VM.ovf" with both VMWare and VirtualBox.
- Log in as 'root' using the password 'flare'
- If you use VirtualBox and want to use ssh, you may need to enable port forwarding. The following link explains how to do it: https://nsrc.org/workshops/2014/btnog/raw-attachment/wiki/Track2Agenda/ex-virtualbox-portforward-ssh.htm

3. Analiza maszyny wirtualnej:

Po zalogowaniu się do maszyny, postanowiłem wykonać inspekcję ostatnio wykonywanych poleceń:

Last failed login: Sat Oct  9 07:24:35 UTC 2021 from 192.168.177.1 on ssh:notty
There was 1 failed login attempt since the last successful login.
Last login: Sat Oct  9 07:23:14 2021
Welcome to the FLARE Linux VM. :)
Have a lot of fun...
localhost:~ # ls -lah
total 16K
drwx------ 1 root root  118 Aug 26 15:04 .
drwxr-xr-x 1 root root  220 May 29 16:10 ..
-rw------- 1 root root  108 Aug 26 17:37 .bash_history
-rw-r--r-- 1 root root   52 Aug 26 14:59 .bash_profile
-rw-r--r-- 1 root root   59 Aug 26 14:59 .bashrc
drwx------ 1 root root    0 Mar 23  2021 .gnupg
-rw------- 1 root root 2.6K Aug 26 15:04 .viminfo
drwxr-xr-x 1 root root 1.1K Aug 26 17:37 Documents
drwxr-xr-x 1 root root    0 Mar 23  2021 bin
localhost:~ # cat ~/.bash_history
#1622565496
ip a
#1623075831
zypper refresh
#1623075992
zypper in --no-confirm openssh
#1629999465
poweroff
localhost:~ # pwd
/root
localhost:~ #

Z pliku powyżej można było się dowiedzieć, że w systemie jest aktywnie wykorzystywane oprogramowanie zyper. Postanowiłem poszukać interesujących, wykorzystywanych w systemie programów.

W pierwszej kolejności sprawdziłem crona:

localhost:~ # crontab -l
* * * * * /usr/lib/zyppe

W ten sposób ujawniłem podobnie nazwany plik wykonywalny. Przypadek czy konwencja nazewnicza? Postanowiłem przeszukać aktualnie uruchomione procesy…

localhost:~ # ps aux | grep zyp
root       1982  0.0  0.0   7432   884 pts/0    S+   08:01   0:00 grep --color=auto zyp

… oraz pliki wykonywalne dodane do zmiennej środowiskowej $PATH: localhost:~ # zypp zypp-CheckAccessDeleted zypp-NameReqPrv zypp-refresh zypper

Postawiłem w tym momencie hipotezę: zypper to znane oprogramowanie, natomiast zyppe to oprogramowanie je udające, które zostało dodane intencjonalnie do crona. Prosta inspekcja pozwoliła ujawnić, że plik /usr/lib/zyppe to 64-bitowy plik wykonywalny:

localhost:~ # file /usr/lib/zyppe
/usr/lib/zyppe: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=d06ba2636713b75af35025d6d85cc3d98b7b0192, for GNU/Linux 3.2.0, with debug_info, not stripped

Zanim przystąpiłem do analizy pliku zyppe, postanowiłem dokończyć przeszukiwanie katalogu użytkownika:

Odczytałem plik .bash_profile:

localhost:~ # cat .bash_profile
export NUMBER1=2
export NUMBER2=3
export NUMBER3=37
localhost:~ # cat .bashrc
alias FLARE="echo 'The 13th byte of the password is 0x35'"

W katalogu Documents ujawniłem kilkanaście plików z rozszerzeniem .txt.broken:

localhost:~/Documents # ls -la
total 112
drwxr-xr-x 1 root root 1102 Aug 26 17:37 .
drwx------ 1 root root  148 Oct  9 08:14 ..
-rw-r--r-- 1 root root 1024 Aug 26 15:05 .daiquiris.txt.broken
-rw-r--r-- 1 root root 1024 Aug 26 15:05 backberries.txt.broken
-rw-r--r-- 1 root root 1024 Aug 26 15:05 banana_chips.txt.broken
-rw-r--r-- 1 root root 1024 Aug 26 15:05 blue_cheese.txt.broken
-rw-r--r-- 1 root root 1024 Aug 26 15:05 donuts.txt.broken
-rw-r--r-- 1 root root 1024 Aug 26 15:05 dumplings.txt.broken
-rw-r--r-- 1 root root 1024 Aug 26 15:05 ice_cream.txt.broken
-rw-r--r-- 1 root root 1024 Aug 26 15:05 iced_coffee.txt.broken
-rw-r--r-- 1 root root 1024 Aug 26 15:05 instant_noodles.txt.broken
-rw-r--r-- 1 root root 1024 Aug 26 15:05 nachos.txt.broken
-rw-r--r-- 1 root root 1024 Aug 26 15:05 natillas.txt.broken
-rw-r--r-- 1 root root 1024 Aug 26 15:05 nutella.txt.broken
-rw-r--r-- 1 root root 1024 Aug 26 15:05 oats.txt.broken
-rw-r--r-- 1 root root 1024 Aug 26 15:05 omelettes.txt.broken
-rw-r--r-- 1 root root 1024 Aug 26 15:05 oranges.txt.broken
-rw-r--r-- 1 root root 1024 Aug 26 15:05 raisins.txt.broken
-rw-r--r-- 1 root root 1024 Aug 26 15:05 rasberries.txt.broken
-rw-r--r-- 1 root root 1024 Aug 26 15:05 reeses.txt.broken
-rw-r--r-- 1 root root 1024 Aug 26 15:05 sausages.txt.broken
-rw-r--r-- 1 root root 1024 Aug 26 15:05 shopping_list.txt.broken
-rw-r--r-- 1 root root 1024 Aug 26 15:05 spaghetti.txt.broken
-rw-r--r-- 1 root root 1024 Aug 26 15:05 strawberries.txt.broken
-rw-r--r-- 1 root root 1024 Aug 26 17:37 tacos.txt.broken
-rw-r--r-- 1 root root 1024 Aug 26 17:37 tiramisu.txt.broken
-rw-r--r-- 1 root root 1024 Aug 26 17:37 tomatoes.txt.broken
-rw-r--r-- 1 root root 1024 Aug 26 15:05 udon_noddles.txt.broken
-rw-r--r-- 1 root root 1024 Aug 26 15:05 ugali.txt.broken
-rw-r--r-- 1 root root 1024 Aug 26 15:05 unagi.txt.broken

4. Odszyfrowanie plików .broken

Pobieżna analiza pliku zyppe pozwoliła ujawnić następujące fakty:

  1. Program algorytmem RC4 szyfruje pliki txt wykorzystując zahardkowany klucz
  2. Wyniki zapisuje z plikach .broken

Postanowiłem zatem odszyfrować pliki, szyfrując je drugi raz:

for f in ./Documents/*.broken; do 
    mv -- "$f" "${f%.broken}"
done

Następnie uruchomiłem (de)szyfrator:

localhost:~ # /usr/lib/zyppe
backberries.txt is now a secret
banana_chips.txt is now a secret
blue_cheese.txt is now a secret
donuts.txt is now a secret
dumplings.txt is now a secret
ice_cream.txt is now a secret
iced_coffee.txt is now a secret
instant_noodles.txt is now a secret
nachos.txt is now a secret
natillas.txt is now a secret
nutella.txt is now a secret
oats.txt is now a secret
omelettes.txt is now a secret
oranges.txt is now a secret
raisins.txt is now a secret
rasberries.txt is now a secret
reeses.txt is now a secret
sausages.txt is now a secret
shopping_list.txt is now a secret
spaghetti.txt is now a secret
strawberries.txt is now a secret
tacos.txt is now a secret
tiramisu.txt is now a secret
tomatoes.txt is now a secret
udon_noddles.txt is now a secret
ugali.txt is now a secret
unagi.txt is now a secret

5. Odzyskanie hasła

Uważnie czytając zawartość plików odczytałem ich zawartość (kolejność plików nie wynika z kolejności ich odszyfrowania):

backberries.txt.broken      	: emit backberries.txt.broken | xor Reese's	: If you are not good in maths, the only thing that can save you is to be a bash expert. Otherwise you will be locked here forever HA HA HA!
banana_chips.txt.broken     	: emit banana_chips.txt.broken | xor Reese's: Are you good at maths? We love maths at FLARE! We use this formula a lot to decode bytes: "ENCODED_BYTE + 27 + NUMBER1 * NUMBER2 - NUMBER3"
blue_cheese.txt.broken			: emit blue_cheese.txt.broken | xor Reese's	: The 4th byte of the password is: 0x35
daiquiris.txt.broken			: CyberChef("Bifid Cipher Decode", KEYWORD="eggs")	: The 7th byte of the password is: 0x66
donuts.txt.broken           	: CyberChef("Bifid Cipher Decode", KEYWORD="eggs")	: Did you know that Giovan Battista Bellaso loved microwaves?
dumplings.txt.broken        	: CyberChef("Bifid Cipher Decode", KEYWORD="eggs")	: Are you missing something? You should search for it better! It's hidden, but not really.
ice_cream.txt.broken        	: emit ice_cream.txt.broken | sub 4
If this challenge is too difficult and you want to give up or just in case you got hungry, what about baking some muffins? Try this recipe:
0 - Cinnamon
1 - Butter 150gr
2 - Lemon 1/2
3 - Eggs 3
4 - Sugar 150gr
5 - Flour 250gr
6 - Milk 30gr
7 - Icing sugar 10gr
8 - Apple 100gr
9 - Raspberries 100gr

Mix 0 to 9 and bake for 30 minutes at 180°C.

iced_coffee.txt.broken      	: emit iced_coffee.txt.broken | sub 4
The only problem with RC4 is that you need a key. The FLARE team normally uses this number: "SREFBE" (as an UTF-8 string). If you have no idea what that means, you should give up and bake some muffins.

74wny0wl disclaimer: SREFBE = 493513

instant_noodles.txt.broken  	: emit instant_noodles.txt.broken | sub 4	: The 5th byte of the password is: 0xMS
nachos.txt.broken           	: emit nachos.txt.broken | rc4 493513	: In the FLARE team we really like Felix Delastelle algorithms, specially the one which combines the Polybius square with transposition, and uses fractionation to achieve diffusion.
natillas.txt.broken         	: emit natillas.txt.broken | rc4 493513	: Do you know natillas? In Spain, this term refers to a custard dish made with milk and KEYWORD, similar to other European creams as cr?me anglaise. In Colombia, the delicacy does not include KEYWORD, and is called natilla.

74wny0wl disclaimer: Article from wikipediia about natillas: KEYWORD = eggs

nutella.txt.broken          	: emit nutella.txt.broken | rc4 493513	: The 6th byte of the password is: 0x36
oats.txt.broken             	: emit oats.txt.broken | vigenere -i microwaves : You should follow the FLARE team in Twitter. They post a bunch of interesting stuff and have great conversation on Twitter!
https://twitter.com/anamma_06
https://twitter.com/MalwareMechanic

omelettes.txt.broken        	: emit omelettes.txt.broken | vigenere -i microwaves: You should follow the FLARE team in Twitter. Otherwise they may get angry and not let you leave even if you get the flag
.
https://twitter.com/anamma_06
https://twitter.com/osardar1
https://twitter.com/MalwareMechanic

oranges.txt.broken				: emit oranges.txt.broken | vigenere -i microwaves: The 8th byte of the password is: 0x60
raisins.txt.broken				: emit raisins.txt.broken | b64		: The 3rd byte of the password is.. it is a joke, we don't like raisins!
rasberries.txt.broken			: emit rasberries.txt.broken | b64	: The 3rd byte of the password is: 0x51
reeses.txt.broken				: emit reeses.txt.broken | b64		: We LOVE "Reese's", they are great for everything! They are amazing in ice-cream and they even work as a key for XOR encoding.
sausages.txt.broken				: emit sausages.txt.broken | rotl 1	: The 2st byte of the password is 0x34
shopping_list.txt.broken		: emit shopping_list.txt.broken		:

/
[U]don noodles
[S]trawberries
[R]eese's
/
[B]anana chips
[I]ce Cream
[N]atillas
/
[D]onuts
[O]melettes
[T]acos

spaghetti.txt.broken			: emit spaghetti.txt.broken | rotl 1: In the FLARE language "spaghetti" is "c3BhZ2hldHRp".
strawberries.txt.broken			: emit strawberries.txt.broken | rotl 1: In the FLARE team we like to speak in code. You should learn our language, otherwise you want be able to speak with us when you escape (if you manage to escape!). For example, instead of "strawberries" we say "c3RyYXdiZXJyaWVz".
tacos.txt.broken				: emit tacos.txt.broken | hex | aes -i "PIZZA00000000000" -m CBC "Sheep should sleep in a shed15.2"
tiramisu.txt.broken				: emit tiramisu.txt.broken | hex | aes -i "PIZZA00000000000" -m CBC "Sheep should sleep in a shed15.2"
The 9th byte of the password is the atomic number of the element moscovium
The 10th byte of the password is the bell number preceding 203
The 12th byte of the password is the largest known number to be the sum of two primes in exactly two different ways
The 14th (and last byte) of the password is the sum of the number of participants from Spain, Singapore and Indonesia that finished the FLARE-ON 7, FLARE-ON 6 or FLARE-ON 5


tomatoes.txt.broken				: emit tomatoes.txt.broken | hex | aes -i "PIZZA00000000000" -m CBC "Sheep should sleep in a shed15.2"

It seems you are close to escape... We are preparing the tomatoes to throw at you when you open the door! It is only a joke...
The 11th byte of the password is the number of unique words in /etc/Quijote.txt
The 13th byte of the password is revealed by the FLARE alias



udon_noddles.txt.broken			: emit udon_noddles.txt.broken		: "ugali", "unagi" and "udon noodles" are delicious. What a coincidence that all of them start by "u"!
ugali.txt.broken				: emit ugali.txt.broken				: Ugali with Sausages or Spaghetti is tasty. It doesn't matter if you rotate it left or right, it is still tasty! You should try to come up with a great recipe using CyberChef.
unagi.txt.broken				: emit unagi.txt.broken				: The 1st byte of the password is 0x45

W ten sposób oczytałem informację o haśle, oraz wskazówkę o pliku /usr/bin/dot

1: The 1st byte of the password is 0x45		=	E
2: The 2st byte of the password is 0x34		=	4
3: The 3rd byte of the password is: 0x51 	= 	Q
4: The 4th byte of the password is: 0x35	=   5
5: The 5th byte of the password is: 0xMS	=> "0x" + "6 - Milk 30gr" + "4 - Sugar 150gr" => 0x64 = d
6: The 6th byte of the password is: 0x36	= 	6
7: The 7th byte of the password is: 0x66	=	f
8: The 8th byte of the password is: 0x60	=	`
9: The 9th byte of the password is the atomic number of the element moscovium	=> chr(115)	=	s
10:The 10th byte of the password is the bell number preceding 203 => The first Bell numbers are: 1, 1, 2, 5, 15, 52, 203 => chr(52)	=	4
11: The 11th byte of the password is the number of unique words in /etc/Quijote.txt => (($(foreach ($line in Get-Content .\Quijote.txt) {$line.tolower().split(" .,?!;:")}
) | sort | Get-Unique).trim() -ne "").Count => 108 => chr(108) = 'l'
12: The 12th byte of the password is the largest known number to be the sum of two primes in exactly two different ways => (68=7+61=31+37)	=	D
13: The 13th byte of the password is 0x35 	=	5
14:	The 14th (and last byte) of the password is the sum of the number of participants from Spain, Singapore and Indonesia that finished the FLARE-ON 7, FLARE-ON 6 or FLARE-ON 5 => (9+19+0)+(7+25+2)+(4+6+1) = 73 => chr(73) = I

Zatem hasło to:

E4Q5d6f`s4lD5I

6. Odczytanie flagi

Wystarczyło uruchomić program /usr/bin/dot, podać hasło i odczytać flagę:

localhost:~/Documents # /usr/bin/dot
Password: E4Q5d6f`s4lD5I
Correct password!
Flag: H4Ck3r_e5c4P3D@flare-on.com