I participated in the Africa CyberFest CTF competition with my team (team !ethical), we came first during the qualifiers and came second after the final round
Lets take a look at the challs I solved
Challenges Solved
General
- Do you read
- Say Hello
- Do you read 2
Misc
- Nulockās nemesis 1
- fun???
Web
- Mystique
- Troll
Cryptography
- S1mple
Steganography
- Plane Sight
- Plane Sight 2
Forensics
- Whispers in the Wires
- InvasioIn!
- mem mem meme?
General
Do you read
Thereās a landing page which is the url where the challs are hosted on, this url.
Checking the page source should fetch you the flag
FLAG:-ACTF{dont_skip_cutscenes}
Say Hello
The question asked here was āAre you following these twitter accounts??ā, since I already follow all of them before now my response is āyesā
FLAG:-yes
Do you read 2
Yeah, you can already see the flag thereš
FLAG:-actf{i_did_not_skip_this_cutscene}
Misc
Nulockās nemesis 1
Lets connect to the challenge instance
You can see from the above screenshot that we canāt use the normal linux commands here.
To solve this chall weāll make use of wildcards
Wildcards are characters used in shell commands to represent one or more other characters. They're commonly used in file management commands to specify patterns of filenames that you want to match. Here are some common wildcards:
* (asterisk): Matches any sequence of characters, including none.
? (question mark): Matches any single character.
[ ] (square brackets): Matches any one character within the specified range or set.
Here's how they work in practice:
*: Matches zero or more characters.
Example: *.txt matches any file ending in .txt.
?: Matches exactly one character.
Example: file?.txt matches file1.txt, fileA.txt, but not file12.txt.
[ ]: Matches any one character within the specified range or set.
Example: [123].txt matches 1.txt, 2.txt, or 3.txt.
Lets try to cause an error
You can see that theereās a bash script in that directory but then we donāt know the directory we are sitted at
To try to read a file in this directory we can try using the wildcards we can just use the wildcard . ????
where ??? represents the length of the file we want to read
and ```. when used as a standalone character refers to the current working directory
We were able to read the lol.txt
file
Lets make an assumption here, weāll assume that the flag is in the flag.txt
file, so to read this we can use the wildcard . ????????
We got our flag
FLAG:-ACTF{Th4t_w4s_5impl3_wasnt_it?}
fun???
Solving the āInvasion!ā chall before this actually made this chall very easyš
When you inspect element youāll see this
This actually has something to do with unicode steganography with zero-width characters
So just copy the text and paste it here
We got our flagš
FLAG:-ACTF{Alw4ys_in_pl4in_sight!!}
Web
Mystique
Navigate to the webpage
We have this login page, yeah we canāt signup because the signup button isnāt working and yeah default creds aināt working hehe
Note: Most of the obfuscated variables were renamed for better understanding
onSubmit, the login() function is called which sets the following varaibles.
- publicKey stores a JSEncrypt key object gotten from the setPublicKey() function.
- The setPublicKey() function stores a PEM key in the key variable.
- creates a new JSEncrypt object and stores it in the jsEncryptedKey variable.
- it finally uses the .setPublicKey() method on the JSEncrypt object to the set the public key to the PEM key above.
- randomText stores a randomText generated by the generateRandomText() function
- I donāt think this is really important
- encryptedData stores the encrypted data returned from the encryptData() function which takes publicKey and randomText as arguments
- The encryptData function stores the result of concatinating āuserā + randomText in a variable data.
- encrypts the data using the publicKey.encrypt() method
- sendEncryptedData makes a POST request to the /Flag endpoint with the encryptedData as argument.
- before the request is sent, the encryptedData is url-encoded
[+] Steps to recreate In your console, run the following
var key = '-----BEGIN PUBLIC KEY-----\n MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ziDyee9fICsEJ5ebGyv\n N1toEnOGBwYQrehsuOfkNXm4BKoBgiSXJGAeU/+4JeXrkaX7pejDF1loZvKXFIfA\n RaaNIqDbsZfIYPB0nMpaYrXreO6R+7jyWN6a0uPTOyaYYlCdhLRjciV8w7PBcO/e\n iVzCajZSp+uNqlVz3s83o+LOl0B/RLNNUPrUjwvj7s4dattJhtKLts1mC1V7aHcL\n JquS5E2OqAzps2DzVJ1sezHmvJGw9/8+58AMwqFTwixP37+FhuAbNGUN5DHRUjSK\n zscmDAgE+HN+GPwOx6ynpVmrubqWsZ0CL14mxtfVYNUBopI/BACZYdn2B/Eze1ay\n uQIDAQAB\n -----END PUBLIC KEY-----\n';var jsEncryptedKey = new JSEncrypt();jsEncryptedKey.setPublicKey(key);sendEncryptedData(jsEncryptedKey.encrypt("admin"+generateRandomText()))
Yup, thatās our flag
FLAG:-ACTF{that_was_easy}
Troll
Navigate to the webpage
You see itās blank, viewing the page source
Also blank
Lets fuzz for directories using ffuf
command:ffuf -u "https://afr1cacyb3rfe5t-troll.chals.io/FUZZ" -w /usr/share/wordlists/dirb/common.txt -e .zip,.sql,.php,.phtml,.bak,.backup
We have the /robots.txt
directory, checking this directory
We have another directory here, lets navigate to this directory
So navigating to that directory gives us a file to download
āāā(bl4ck4nonš½bl4ck4non-sec)-[~/Downloads/CTF/africa_cyberfest/web]
āā$ ls -la
total 444
drwxr-xr-x 2 bl4ck4non bl4ck4non 4096 May 19 07:18 .
drwxr-xr-x 7 bl4ck4non bl4ck4non 4096 May 19 03:43 ..
-rw-r--r-- 1 bl4ck4non bl4ck4non 444640 May 19 07:17 robots.txt
āāā(bl4ck4nonš½bl4ck4non-sec)-[~/Downloads/CTF/africa_cyberfest/web]
āā$ file robots.txt
robots.txt: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=35a237ca786dd7f433a5e3761cef1b76eb451a25, for GNU/Linux 3.2.0, not stripped
oops, thatās a binary.
Using the command strings robots.txt | grep "actf{"
or the command strings robots.txt | grep "ACTF{"
wonāt get you the flag actuallyš. This is because the flag format actually changed (case-sensitive wise). So, running only the strings
command on the binary gives you the flag
command:strings robots.txt
We got the flag
FLAG:-aCtF{robotTxt_and_strings_as_requested}
Cryptography
S1mple
Lets download the file and check the content
That looks like binary but then thatās a lot of space, well from experience I can tell that Iām meant to use stegsnow
to solve this hehe
To install this tool you can use the command sudo apt install stegsnow
To use the tool
command:stegsnow -C simple.txt
āāā(bl4ck4nonš½bl4ck4non-sec)-[~/Downloads/CTF/africa_cyberfest/cryptography]
āā$ stegsnow -C simple.txt
ĆCĆĆ{1òñ_jó57_Ć 5_5èìïë3_4Ʊ_1ò_100ĆŖ5!!!}
Now, thatās some weird cipher, thatās what I thought at firstš.
But then, this is actually not a cipher hehe, it is an encoding, itās called a cyrillic encoding
We can decode this using this webpage
You can see we have some weird output, now lets select the āsource encodingā and also the ādisplayed asā option
Now, we have a more resonable output
I was actually stuck here for a while because I thought this guy ŠCТФ{1ŃŃ_jŃ57_а5_5импл3_4Ń_1Ń_100Šŗ5!!!}
was an encoding but then I thought wrong, itās actually a language lool.
We can translate this using google translator
Yup, thatās our flag hehe
FLAG:-ACTF {1ts_ju57_a5_5impl3_4s_1t_100k5!!!}
Steganography
Plane Sight
Download the file to your machine for analysis
Running the exiftool
command youāll find something interesting
command:exiftool mashle.jpg
Similar to the āS1mpleā chall youāll find out that what we have there is actually not a cipher, it is an encoding. Yeah, itās a cyrillic encoding
We can use this webpage to decode
Well, thatās a very weird output. Lets try to select a successful sample
That looks less weird hehe, apparently itās not an encoding, itās a language. This means we can use google translator to translate this
We still have to translate this
Now, this makes more sense but then it didnāt work when I tried ACTF{flag=17>>5_a11_1n_Th3_m3T4d473}
, we could have guessed this though to say it's all in the metadata
so thatāll be ACTF{flag=17'5_a11_1n_Th3_m3T4d473}
but then it still didnāt work.
Apparently I was meant to remove the flag=
FLAG:-ACTF{17'5_a11_1n_Th3_m3T4d473}
Now, this is actually not the way to goš, what if it is not a guessable word??
As you can seeš
Thatās why I had to use another cyrillic decoder, you can see it here
After several tries, I got this
Yup, thatās the proper way of solving it
Plane Sight 2
Download the image for proper analysis
As you can see, this chall is similar to the āplane sightā chall.
Lets use this webpage to decode this cyrillic encoding
Yup, thatās our flag, just as we did for the first plane sight chall weāll be removing flag=
which gives us a working flag
FLAG:-ACTF{17'5_a11_1n_Th3_m3T4d473}
Forensics
Whispers in the Wires
Download the pcap file
āāā(bl4ck4nonš½bl4ck4non-sec)-[~/ā¦/CTF/africa_cyberfest/forensics/whispers_in_the_wires]
āā$ ls -la
total 7828
drwxr-xr-x 2 bl4ck4non bl4ck4non 4096 May 20 12:15 .
drwxr-xr-x 7 bl4ck4non bl4ck4non 4096 May 20 17:39 ..
-rw-r--r-- 1 bl4ck4non bl4ck4non 8006936 May 19 15:27 ctf.pcapng
Running the strings
command I found the string shadowheadquaters.com
pop up multiple times
So my teammate gave a one-liner command
command:tshark -r ctf.pcapng | grep shadowheadquarters.com | grep -v response | cut -d "A" -f 2 | cut -d "." -f 1 | xxd -r -p > abeg
This command
1. Extracts packets containing "shadowheadquarters.com"
2. Filters out response packets
3. Extracts the domain name
4. Saves it to "abeg" in raw binary format
Lets run the command
Lets view that image
command:open abeg
Yup, thats our flag
FLAG:-ACTF{our_secrets_are_in_plain_sight!!}
Invasion!
This is actually a huge file just so you knowš , download this file to your machine and unzip, you should see this
āāā(bl4ck4nonš½bl4ck4non-sec)-[~/Downloads/CTF/africa_cyberfest/forensics]
āā$ cd disk_image
āāā(bl4ck4nonš½bl4ck4non-sec)-[~/ā¦/CTF/africa_cyberfest/forensics/disk_image]
āā$ ls -la
total 18074244
drwxr-xr-x 2 bl4ck4non bl4ck4non 4096 May 19 04:08 .
drwxr-xr-x 3 bl4ck4non bl4ck4non 4096 May 19 07:11 ..
-rw------- 1 bl4ck4non bl4ck4non 9346220032 Apr 25 04:09 'doh ctf.vmdk'
We have a āvmdkā image, well what I did was convert this to a raw image using qemu
To install qemu you can use the command sudo apt-get install qemu-utils
To convert to raw image you can use the command qemu-img convert -f vmdk -O raw doh\ ctf.vmdk doh.raw
Now that we are done converting we can mount this using autopsy
Weāll be analyzing the C:\
drive, thatās where juicy stuffās at
Weāll do a file analysis
This user actually has something juicy in his Desktop directory hehe
We have this docx file, but then when you view the hex display youāll see that it has a different header
Whatās a PK header??
A PK header is a 4-byte sequence (50 4B 03 04) that identifies a file as a ZIP archive, serving as a file signature.
This means itās not really a docx file, rather itās a zip file.
Now this is what weāll do, weāll export this file to our machine then we change the extension from .docx
to .zip
Nice, now lets try to unzip
You can see that a password is required, zip2joh wonāt work because the password isnāt in rockyouš
Lets go back to autopsy and check the /Africa Cyberfest/
directory
We can see that .DAT
file
NTUSER.DAT is a Windows file storing user-specific settings and configuration data, including preferences, application settings, and account information, personalizing the Windows experience for each user.
Lets export this file too
If you run strings
and grep
youāll see this
This means our passwordās there actually
To extract data from this windows registry file we can use a tool reglookup
, you can use the sudo apt-get install reglookup
to install the tool
command:reglookup NTUSER.DAT > abeg.txt
āāā(bl4ck4nonš½bl4ck4non-sec)-[~/Downloads/CTF/africa_cyberfest/forensics]
āā$ reglookup NTUSER.DAT > abeg.txt
Now we can grep out the password from this txt file
command:strings abeg.txt| grep "shadow_commander_password"
āāā(bl4ck4nonš½bl4ck4non-sec)-[~/Downloads/CTF/africa_cyberfest/forensics]
āā$ strings abeg.txt| grep "shadow_commander_password"
/Environment/shadow_commander_password,SZ,'%225dUiSm*4*m$A$',
Now thereās a bit of a twist here, %22
is the url encoded form of "
, it was the tool I used that actually url encoded it
So we can say the password is "5dUiSm*4*m$A$
. weāll use this password to extract the zip file
This is what you get after you unzip the file, we have another zip file but then is this really a zip file??
command:file shadow_document4.5.zip
āāā(bl4ck4nonš½bl4ck4non-sec)-[~/ā¦/CTF/africa_cyberfest/forensics/shadow_document4.5]
āā$ file shadow_document4.5.zip
shadow_document4.5.zip: CDFV2 Encrypted
Doing a little bit of research
We can see that files like this do have the .docx
extension, so weāll change the extension from .zip
to .docx
āāā(bl4ck4nonš½bl4ck4non-sec)-[~/ā¦/CTF/africa_cyberfest/forensics/shadow_document4.5]
āā$ ls -la
total 100
drwxr-xr-x 2 bl4ck4non bl4ck4non 4096 May 20 17:45 .
drwxr-xr-x 7 bl4ck4non bl4ck4non 4096 May 20 17:39 ..
-rw-r--r-- 1 bl4ck4non bl4ck4non 94208 Apr 20 18:57 shadow_document4.5.docx
Nice, now lets try to open this file
oops, a password is required, we can reuse the password we got earlier
We have this blank page, scrolling down we get this
But then when you use ctrl + A
youāll see something hehe
When you copy this and paste it into a normal text editor, you get this,
But when you paste it into sublime text, youāll see that thereās actually something there
Now, this has something to do with zero width joiner
and we can decode this using this website
We got our flag hehe
FLAG:-ACTF{Sh4d0w_3xc3ut3d-haqhaq!}
This chall just shows how messed up the brain of the creator is, broās a maniac frš
mem mem meme?
Download this file to your machine and unzip
Iāll actually be needing volatility for this, but damnnn Iāve been finding it difficult to install
Now that Iāve installed volatility, lets cook
To install volatility, you can get it here
Thereāll be 2 ways to approach this, the intended method and the unintended method.
Unintended Method
Weāll start out by checking the OS and kernel details of the memory sample we want to analyze using the windows.info.Info
plugin
command:python3 vol.py -f ../../../../Downloads/CTF/africa_cyberfest/forensics/mem_mem_meme\?/challenge.vmem windows.info.Info
From the above screenshot, we can see the kernel name and also the layer name
Using the windows.pslist.PsList
plugin, we can list the processes present in the windows memory image
command:python3 vol.py -f ../../../../Downloads/CTF/africa_cyberfest/forensics/mem_mem_meme\?/challenge.vmem windows.pslist.PsList
We can see that thereās a notepad.exe
process running with a pid of 3064
To get more details about these process we can use the windows.cmdline.CmdLine
plugin to list the process command line arguments
command:python3 vol.py -f ../../../../Downloads/CTF/africa_cyberfest/forensics/mem_mem_meme\?/challenge.vmem windows.cmdline.CmdLine
Now this is more detailed, the first time we checked the proccess running we found a notepad.exe
process with a pid of 3064
, but then we can see from the above screenshot that this proccess has the args "C:\Windows\system32\NOTEPAD.EXE" \\172.16.56.1\share\ip.txt
. We can also see that thereās another notepad.exe
process with a pid of 3044
and that it has the arg "C:\Windows\system32\NOTEPAD.EXE" C:\Users\Crash Override again\Desktop\password.txt
. In summary we can say PID 3044 is a Notepad process that has opened the file āpassword.txtā located on the desktop of the user āCrash Override againā.
One thing we can do here is try to dump the process, to do this I actually didnāt use volatility3, I used volatility2 and this is because of the memdump
plugin. You can get volatility2 here
To use volatility2 weāll need the memory profile, we can get this using the imageinfo
plugin
command:python2 vol.py -f ../../../../Downloads/CTF/africa_cyberfest/forensics/mem_mem_meme\?/challenge.vmem imageinfo
INFO : volatility.debug : Determining profile based on KDBG search...
Suggested Profile(s) : Win7SP1x64, Win7SP0x64, Win2008R2SP0x64, Win2008R2SP1x64_24000, Win2008R2SP1x64_23418, Win2008R2SP1x64, Win7SP1x64_24000, Win7SP1x64_23418
AS Layer1 : WindowsAMD64PagedMemory (Kernel AS)
AS Layer2 : FileAddressSpace (/home/bl4ck4non/Downloads/CTF/africa_cyberfest/forensics/mem_mem_meme?/challenge.vmem)
PAE type : No PAE
DTB : 0x187000L
KDBG : 0xf80002a510a0L
Number of Processors : 2
Image Type (Service Pack) : 1
KPCR for CPU 0 : 0xfffff80002a52d00L
KPCR for CPU 1 : 0xfffff880009ef000L
KUSER_SHARED_DATA : 0xfffff78000000000L
Image date and time : 2024-04-25 07:59:23 UTC+0000
Image local date and time : 2024-04-25 08:59:23 +0100
You should get that output, we have different profiles here, lets go with this profile Win7SP1x64
Now that weāve goten the profile lets use the memdump plugin to help us dump the notepad.exe
process
command:python2 vol.py -f ../../../../Downloads/CTF/africa_cyberfest/forensics/mem_mem_meme\?/challenge.vmem --profile=Win7SP1x64 memdump --dump-dir=/home/bl4ck4non/Downloads/CTF/africa_cyberfest/forensics/mem_mem_meme\?/ -p 3044
--dump-dir
specifies the directory where the dumped memory will be saved, in this case, a directory named ā/home/bl4ck4non/Downloads/CTF/africa_cyberfest/forensics/mem_mem_meme\?/ā
-p
specifies the PID of the process for which to extract the memory dump
āāā(bl4ck4nonš½bl4ck4non-sec)-[~/Documents/Tools/forensics/volatility]
āā$ python2 vol.py -f ../../../../Downloads/CTF/africa_cyberfest/forensics/mem_mem_meme\?/challenge.vmem --profile=Win7SP1x64 memdump --dump-dir=/home/bl4ck4non/Downloads/CTF/africa_cyberfest/forensics/mem_mem_meme\? -p 3044
Volatility Foundation Volatility Framework 2.6.1
************************************************************************
Writing notepad.exe [ 3044] to 3044.dmp
Nice, now lets get our flag
āāā(bl4ck4nonš½bl4ck4non-sec)-[~/ā¦/CTF/africa_cyberfest/forensics/mem_mem_meme?]
āā$ ls -la 3044.dmp
-rw-r--r-- 1 bl4ck4non bl4ck4non 209444864 May 25 17:18 3044.dmp
āāā(bl4ck4nonš½bl4ck4non-sec)-[~/ā¦/CTF/africa_cyberfest/forensics/mem_mem_meme?]
āā$ file 3044.dmp
3044.dmp: Windows Event Trace Log
All thatās left is to grep the flag out
command:strings 3044.dmp | grep -i "actf"
Yup, thatās our flag
FLAG:-ACTF{Sh4d0w_1nc1d3nt_C0mp1ic4t10n}
Till Next Time :xD