In this CTF competition, our team - Mugiwara - has a third place in KMA Scoreboard (9th place in expanding scoreboard).
You can follow our write up for all category here
During the competition, I couldn't solve this challenge. So, I took time solving it after the competition ended.
The challenge gives us a Linux memory dump file.
The first thing I do when I met a memory dump is using volatility3 to determine its symbol/profile.
I use plugin banners
.
Okay, the OS version of this memory dump is Ubuntu 20.04
, Linux kernel version is 5.4.0-122-generic
. And the version of Ubuntu can be analysed using Volatility2
First, we have to create a profile for memory dump. There are a lot of methods you can follow, I won't mention here.
After get profile, I start to analyse mem.bin
. I'll check linux bash first using linux_bash
plugin.
It's like attacker control the victim machine and download something to exfiltrate data. Okay, we have to find and dump a file name toy.zip
to analyse how it works and what data was exfiltrated.
I can find it using linux_enumerate_files
plugin.
And dump it using linux_find_file
plugin.
I extract it, but the zip has some problems.
deman.sh
is OK, but evil
isn't extracted full data.
After drop it to hex editor, I understand why: the zip file lost more than half of the data after I dump it.
So I asked author for help, and he gave me a pcapng
file captured the packet while he's downloading toy.zip
.
Follow TCP stream and I can see toy.zip
data.
I copy it and paste to HxD, remove the HTTP header and save it with the name "toy2.zip", then I extract it with password "maltoy" and get Evil
full data.
deman.sh
Let's see what is in deman.sh
Overview you can see this code take input, do something and upload it to transfer.sh as robots.txt
Back to the bash history, the attacker execute evil
, remove qr.png
and then run deman.sh
with input = qr.png.enc
and output = out.gif
.
Okay, I presume that the attacker encodes qr.png
to qr.png.enc
and use it as input for deman.sh
, then exports output as out.gif
.
In the deman.sh
source code, you can see that the script remove all output, input, so you couldn't find anything in memory dump.
But we can recover $output.kcs
. Transfer.sh is a service that you can share file from the command-line. When you upload a file to transfer.sh, it will return a link to download. That is mean, we can download $out.kcs
https://github.com/dutchcoders/transfer.sh
https://ubunlog.com/vi/transfer-compartir-archivos-terminal/
So I dug into memory dump with strings grep
(the ultimate weapon that we can use to beat any memory dump challenge) to find the download link.
Using wget
, you can easily download this file.
The first time I saw this link, I thought it was a link that we could not access. After the competition ended, I solved it again and when I solved this challenge, I could not access this link, so I took a long time to find another way to solve it. I'm not the only one who have a problem with this link.
Fortunately, @1259iknowthat had downloaded it before and he send me robots.txt
I renamed it to out.gif.kcs
Let's analyse deman.sh
more detail to see how it works.
deman.sh
assign "output" as a default value of $output
. And check if the file does not exist, the program will stop.
The program assign file size of file to filesize
. And you don't need to care if [ "$(uname)" == "Darwin" ]
, the code run on Ubuntu linux machine, not the MacOS.
nchunks
is the number of chunks split from the file.
The program split data of $file
into nchunks
chunks and each chunk has name "chunk_"
The program use qrencode
tool to generate QRCode from data of Chunk file and each QRCode has name "frame_"
The program use ffmpeg
to make a gif from frame
and export it as $output
. Remove all chunk and frame file.
Then use xortool-xor xor $output
with random 100-byte length hex and write data to $output.kcs
.
Okay, so if the xor key is random, how can we recover out.gif
?
I did a few tests
First, I created siu.png.enc
file.
Next, I modified deman.sh
Then, I executed it
Okay, I got out.gif
, let's see its hex dump.
As you can see there are a lot of null bytes. So, I check out.gif.kcs
, which is created by XOR out.gif
with random key.
As you know, which one xor with null is equal to itself. We can recover xorkey by copy 100 hex from offset 64 to offset C7 (100 hex after)
Using xortool-xor with this key to recover out.gif
In order to get the content of qr.png.enc
, I write a bash
script split gif file into frames and scan QRCode.
Content of qr.png.enc
Evil
It is ELF file, so I used IDA64
to analyse it.
It is likely Python ELF file.
I used PyInstaller Extractor to extract the contents of ELF.
And then, using uncompyle6
to decompile evil.pyc
This is a python code that encrypts data of qr.png
to qr.png.enc
using the AES CFB algorithm.
The script takes key from user input
, padding bytes until it reaches the required size of key. It also takes input filename and then uses filename and key to encrypt using the encryption function.
The encryption function reads data from file and encrypts it with AES Mode CFB, and then writes data to qr.png.enc
file.
IV is encoded base64 and added to the beginning of ciphertext, so we can retrieve IV by taking 16-bytes at the beginning of qr.png.enc
.
IV = s1VGv0oBj4Wsz+GqR5nYdw==
So, where to find the key?
Well, after knowing the key is from user input, I thought I could retrieve keyboard input data in event0 but couldn't. I also tried aeskeyfind, but all the key I got are wrong.
I did a test, that is using Evil
to encrypt a png
file.
And I remembered that the key was entered first then the filename, so I searched in memory dump the evil executable command and found:
At first sight, I didn't think it was a key, but everything could be a key, a strange key like this just in order to make the player skip.
Okay, so I wrote python script to solve it.
Decode QR Code and get flag:
Flag: KCSC{K1_n13m_L1nuX}