The National Cyber Security Congress (NCSC) is a three-day event that brings together cyber security enthusiasts and experts. The event features a wide range of activities, including workshops, talks, conferences, and two exciting CTF competitions.

As a technical team member, I had the chance to create challenges in Kubernetes, Digital Forensics, Misc, Hardware, and Game Hacking categories.

The NCSC CTF provided a unique opportunity for cyber security enthusiasts to demonstrate their problem-solving abilities, teamwork, and technical proficiency in a fun and competitive environment. Overall, the event was an exciting and rewarding experience for all involved.

In this blog, I will share some write-ups that players have requested!

# Digital Forensics : Mokni & Seals

We got a zip file! I bet that file is a memory dump! So i tried to run the volatility imageinfo plugin but it takes a long time. So I tried to figure out if this file is Linux memory dump or not!

linux or win ?
1
2
raf@4n6nk8s: strings data.raw | grep "Linux version" 
Linux version 5.8.0-43-generic (buildd@lcy01-amd64-018) (gcc (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0, GNU ld (GNU Binutils for Ubuntu) 2.34) 49~20.04.1-Ubuntu SMP Fri Feb 5 09:57:56 UTC 2021 (Ubuntu 5.8.0-43.49~20.04.1-generic 5.8.18)

And yes it’s a Linux Memory dump! I guess its time to start finding/making a profile but let me check that is memory dump can be analyzed with a profile or not!

checking
1
2
3
4
strings data.raw | grep -i insmod       
sudo insmod ./lime-5.8.0-43-generic.ko path=../../Linux64.mem format=raw
sudo insmod ./lime-5.8.0-43-generic.ko "path=../../Linux64.mem format=raw"
sudo insmod ./lime-5.8.0-43-generic.ko "path=../../Linux64.mem format=raw"

Oh! The format is ram! which means that even if we get the correct profile volatility can’t analyze this memory dump! Strings time! The author want us to solve this mem dump using strings !

Let’s try to figure out some command lines! Bash history! Let me show you this trick!

extract bash history
1
2
3
4
5
6
7
8
9
10
11
12
13
strings data.raw | grep -Ei "@*:~\\$"     
raf-square@ubuntu:~$ vim /etc/containers/registries.conf
raf-square@ubuntu:~$
raf-square@ubuntu:~$ echo "This Is My Secret" > secret.txt
raf-square@ubuntu:~$
raf-square@ubuntu:~$ podman login -u $(head -n 2 secret.txt | tail -n 1 | awk '{ print $4 }') -p $(head -n 3 secret.txt | tail -n 1 | awk '{ print $4 }')
raf-square@ubuntu:~$ podman pull nginx
^Craf-square@ubuntu:~$ cd LiME/src/
raf-square@ubuntu:~$ vim /etc/containers/registries.conf
raf-square@ubuntu:~$
raf-square@ubuntu:~$ vim /etc/containers/registries.conf
raf-square@ubuntu:~$
u:~$ podman login -u $(head -n 2 secret.txt | tail -n 1 | awk '{ print $4 }') -p $(head -n 3 secret.txt | tail -n 1 | awk '{ print $4 }')

Mmmm nice! now at least we got some commands and we got the user-name and host-name !
From these commands we can understand that the user edit /etc/containers/registries.conf , then create a secret.txt . Then logged in with podman using that secret.txt. But we don’t have any information about the content of the creds in these commands!.

We have 2 methods to figure out what’s happen and get the creds!

either running a strings and grepping on CMDLINE=podman login or grepping on This Is My Secret and check the lines before and after to see the content!

extract creds
1
2
strings data.raw | grep -Ei "CMDLINE=podman login"       
_CMDLINE=podman login -u 2ecf92b1-83a8-4355-8cb7-8354f4677894 -p fwO8Q~XTlBmpYoG43J~OusANA_azV02ZS3PuzaXb

OR

extract creds
1
2
3
4
5
6
7
8
9
10
11
12
13
strings data.raw | grep -Ei -C 2 "This Is My Secret" 
Documents LiME Music Public Templates
Desktop Downloads Linux64.mem Pictures secret.txt Videos
raf-square@ubuntu:~$ echo "This Is My Secret" > secret.txt
raf-square@ubuntu:~$
fctt
--
application/octet-stream
text/plain
This Is My Secret
Service principal ID: 2ecf92b1-83a8-4355-8cb7-8354f4677894
Service principal password: fwO8Q~XTlBmpYoG43J~OusANA_azV02ZS3PuzaXb
--

So the creds are 2ecf92b1-83a8-4355-8cb7-8354f4677894:fwO8Q~XTlBmpYoG43J~OusANA_azV02ZS3PuzaXb

But I didn’t think this is a normal creds for dockerhub or any public famous container registry! Espacially he pulled a container named nginx! I bet that nginx is a customized one and its a trick!

Editing /etc/containers/registries.conf can confirm that change something! This configuration file used by the container runtime environment on Linux systems. This file specifies a list of container image registries that are trusted by the system and can be used to download container images.

So let’s discover how to get the registry! Pulling nginx means he pulled the latest tag or at least he tried that! So let’s grep on nginx:latest

extract registry
1
2
3
4
5
6
7
strings data.raw | grep -Ei "nginx:latest"  
Trying to pull qualsk8s.azurecr.io/nginx:latest...
Trying to pull qualsk8s.azurecr.io/nginx:latest...
", "qualsk8s.azurecr.io/nginx:latest") not found
Trying to pull qualsk8s.azurecr.io/nginx:latest...
Trying to pull qualsk8s.azurecr.io/nginx:latest...
Trying to pull qualsk8s.azurecr.io/nginx:latest...

Bingo! qualsk8s.azurecr.io is the container registry! If you are an Azure guy you can get that from the previous step! when we get this output!

creds
1
2
Service principal ID: 2ecf92b1-83a8-4355-8cb7-8354f4677894
Service principal password: fwO8Q~XTlBmpYoG43J~OusANA_azV02ZS3PuzaXb

Ok it’s time to login and pull that image and run it!

login and pull
1
2
3
docker login qualsk8s.azurecr.io -u 2ecf92b1-83a8-4355-8cb7-8354f4677894 -p fwO8Q~XTlBmpYoG43J~OusANA_azV02ZS3PuzaXb 

docker pull nginx

After checking the image! I got that it’s a static web page so let’s run it!

run nginx
1
docker run --name chall -p 80:80 -d nginx 

After running this container we got this web-page and guess what!! There is a flag icon! Let’s check it !

This flag icon lead you to this link https://pastebin.com/vjFtjMga which is protected pastebin
how to get that password now! Let’s check the docker history!

docker history
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
mohamed@RafSquare:~$ docker history qualsk8s.azurecr.io/nginx
IMAGE CREATED CREATED BY SIZE COMMENT
093f65335d3a 13 days ago ENTRYPOINT ["nginx" "-g" "daemon off;"] 0B buildkit.dockerfile.v0
<missing> 13 days ago RUN /bin/sh -c chmod +r -R . # buildkit 563kB buildkit.dockerfile.v0
<missing> 13 days ago RUN /bin/sh -c mv password.txt .hidden.txt #… 11B buildkit.dockerfile.v0
<missing> 13 days ago COPY ./ ./ # buildkit 563kB buildkit.dockerfile.v0
<missing> 3 weeks ago RUN /bin/sh -c rm -rf ./* # buildkit 0B buildkit.dockerfile.v0
<missing> 3 weeks ago WORKDIR /usr/share/nginx/html 0B buildkit.dockerfile.v0
<missing> 5 weeks ago /bin/sh -c set -x && apkArch="$(cat /etc… 29.2MB
<missing> 5 weeks ago /bin/sh -c #(nop) ENV NJS_VERSION=0.7.9 0B
<missing> 5 weeks ago /bin/sh -c #(nop) CMD ["nginx" "-g" "daemon… 0B
<missing> 5 weeks ago /bin/sh -c #(nop) STOPSIGNAL SIGQUIT 0B
<missing> 5 weeks ago /bin/sh -c #(nop) EXPOSE 80 0B
<missing> 5 weeks ago /bin/sh -c #(nop) ENTRYPOINT ["/docker-entr… 0B
<missing> 5 weeks ago /bin/sh -c #(nop) COPY file:e57eef017a414ca7… 4.62kB
<missing> 5 weeks ago /bin/sh -c #(nop) COPY file:abbcbf84dc17ee44… 1.27kB
<missing> 5 weeks ago /bin/sh -c #(nop) COPY file:5c18272734349488… 2.12kB
<missing> 5 weeks ago /bin/sh -c #(nop) COPY file:7b307b62e82255f0… 1.62kB
<missing> 5 weeks ago /bin/sh -c set -x && addgroup -g 101 -S … 4.45MB
<missing> 5 weeks ago /bin/sh -c #(nop) ENV PKG_RELEASE=1 0B
<missing> 5 weeks ago /bin/sh -c #(nop) ENV NGINX_VERSION=1.23.3 0B
<missing> 5 weeks ago /bin/sh -c #(nop) LABEL maintainer=NGINX Do… 0B
<missing> 5 weeks ago /bin/sh -c #(nop) CMD ["/bin/sh"] 0B
<missing> 5 weeks ago /bin/sh -c #(nop) ADD file:40887ab7c06977737… 7.05MB

And yes!! There is .hidden.txt that contain a password for sure ! let’s get that password!

docker exec
1
2
docker exec -it 460fc5a977c5 cat .hidden.txt
vT56X19Qu3

We got this pastebin !

This is will lead us to word sheet that contains a hex data!

The hex data seams introducing spaces and tabs! I don’t care let’s decode it and see what’s will be!
I’ll try to convert it to a file using xxd and import that file to dcode.fr

xxd
1
xxd -r -p hex.txt > result.txt

Yeah it’s a file that contains a lot of spaces! Its whitespaces

Bingo! This is the flag Securinets{208e5976c9d654e47d73ef44cabc272d}

# Digital Forensics: Recover my Work 😦

We got a file named memory.dmp . It’s a memory dump for sure! Let’s run imageinfo plugin to get our profile!

profile
1
2
3
4
5
6
7
vol.py -f memory.dmp imageinfo
Volatility Foundation Volatility Framework 2.6.1
INFO : volatility.debug : Determining profile based on KDBG search...
WARNING : volatility.debug : Alignment of WindowsCrashDumpSpace64 is too small, plugins will be extremely slow
WARNING : volatility.debug : Alignment of WindowsCrashDumpSpace64 is too small, plugins will be extremely slow
WARNING : volatility.debug : Alignment of WindowsCrashDumpSpace64 is too small, plugins will be extremely slow
WARNING : volatility.debug : Alignment of WindowsCrashDumpSpace64 is too small, plugins will be extremely slow

But sadly we got this type of outpût! I bet that the suggested profile (in case it exists) will be wrong! Let’s know the exact profile with my own way! Let’s run strings the file and grep “service pack”

Extract info
1
Windows 7 Professional, 64-bit Service Pack 1 (Build 7601)

Cool, This build and service pack is supported by Win7SP1x64 ! I guess that imageinfo plugin got problem because the iso is customizated !

Let’s start checking our memory dump! First thing should be checked is the running processes! I’ll use pstree for that thing!

MMMM intersting! Found chrome, firefox, outlook and RDP opened! what a trip! After digging on chrome history and firefox, I found rabbit holes and some links to wordlists! Bad Author (Me).

Checking the consoles plugin too. Another rabbit hole! rabbit hole everywhere!

It’s time to check and figure out that outlook process!
Outlook save the mails as pst or ost files! These files contains the mails data such as the message, attachements, sender/receiver information!

So let’s try to extract these files !

check files
1
2
3
4
5
6
7
vol.py -f memory.dmp --profile=Win7SP1x64 filescan | grep -i pst$
0x000000007d81a490 5 5 RW-r-- \Device\HarddiskVolume2\Users\Raf_Square\AppData\Local\Microsoft\Outlook\Outlook.pst
0x000000007dd59340 5 5 RW-r-- \Device\HarddiskVolume2\Users\Raf_Square\AppData\Local\Microsoft\Outlook\Work Progress.pst
0x000000007dd73220 1 0 R--rw- \Device\HarddiskVolume2\Users\Raf_Square\AppData\Local\Microsoft\Outlook\Work Progress.pst
0x000000007e3f8b30 5 5 RW-r-- \Device\HarddiskVolume2\Users\Raf_Square\AppData\Local\Microsoft\Outlook\Forgot the password.pst
0x000000007e5297a0 1 0 R--rw- \Device\HarddiskVolume2\Users\Raf_Square\AppData\Local\Microsoft\Outlook\Forgot the password.pst
0x000000007e5eee60 30 0 RW-r-- \Device\HarddiskVolume2\Users\Raf_Square\AppData\Local\Microsoft\Outlook\Outlook.pst

After extracting the files using dumpfiles plugin and making sure that the files are safe and not corrupted. I opened them using a pst online viewer!

The 1st mail i got it is from Adam! He send to me a zip file inside mega storage after our online meeting! I bet that zip is protected with that boring password

Ah my bad! The mega too is protected! We need the encryption key!

Let’s check the other mail! and as expected Adam forget to share the decryption key of the mega link to open the zip!

Bingo we got the zip! But it’s protected! Tried bruteforcing the password. But I failed!

Mmmm Let’s think a little bit! The author said that he used to use the same password! We need to find another usage of that password to open the zip and get the flag!

And It’s time to investigate the mstsc.exe or let’s just say the RDP! Remote Desktop?? Mmmm how to extract information from that thing?

Let’s talk brievly! Extracting the memory part used by RDP can save our life! I’ll try to recover what the user see when he used RDP!!!

Yes this possible dear reader, Don’t worry You’ll see how! Just make sure that you have Gimp

Let’s now extract the memory part used by RDP process using the memdump plugin in volatility!

memdump
1
2
3
4
vol.py -f memory.dmp --profile=Win7SP1x64 memdump -p 360 -D .
Volatility Foundation Volatility Framework 2.6.1
************************************************************************
Writing mstsc.exe [ 360] to 360.dmp

After getting that file! Let’s change its extension from .dmp to .data and open that file with gimp!

Now it’s time for focusing! Yeah focusing will save your time! Many people can’t figure or recover images quickly! But believe me focusing on the noise will help you recover the data in a short time!

After 4 mins of playing with offset and width i got it!

Check the offset and the width!

Ohhh man! The user was opened https://ctf.securinets.tn (check it for know more information about our CTFs events xD ) and tried to secure a zip file with that shitty password!

Finally This is the flag Securinets{R3M0tE_DeSKtOp_1s_FunNy_!_!}

# Hardware: Liquid Display

We got an image and a data file!

The image contains an LCD 16x2 SPI connected to something called WOKWI LOGIC

After some searching I got that this component is a logic analyzer. But wait!! What is that??

A logic analyzer is an electronic instrument that captures and displays multiple signals from a digital system or digital circuit. A logic analyzer may convert the captured data into timing diagrams, protocol decodes, state machine traces…

As my friend said this is the hardware wireshark xD

So we can understand now that this circuit capture the signals of each pin of the LCD and the data file is the capture file that contains the files!

So after some searching we get how to open that data file (which is a ASCII text file, I didn’t recommend to analyse it as text file).

You can check this link to get more information about the logic analyzer!

PulseView is an open source Logic Analyzer GUI belongs to The sigrok project that aims at creating a portable, cross-platform, Free/Libre/Open-Source signal analysis software suite that supports various device types

I’ll use that Logic Analyzer GUI for this challenge!

Import the file data in this way! and let’s the show begin!

A lot of fun wait us right?! Don’t worry man! This is not that super hard! Just all what we need to do now is to simulate these signals manually! These signals are sent to the LCD and that LCD display something (It should be the flag!). So we need to understand how LCD works! I recommend to read the datasheet this thing!

I will not re-write what the datasheet said! so read it! You should understand how the LCD dispaly chars!

Also don’t forget to check the instruction table and understand how these instruction works!

Let’s just take an example of the 1st instruction! The Clear Display . This instruction clear all the data and return the cursor to the original status! Ah yeah of course you must to understand that LCD have cursors, display modes …

After understand how this LCD works it’s time to check how characters are written on that LCD!

This table will help us to convert the signals to chars and recover our flag!

After reading the datasheet. You will understand that the D0 (that correspond to RS pin) can help you to understand when the display device clear the chars and reset the cursor or write something on the screen!

If you take a closer look you’ll get it! The guy who write the program write something and clear it then write another thing then delete it and so on!

So now it’s time to check the write blocks and check what that guy try to do! After reversing all the block i got the flag! It’s on the last block! Let me show you how I recover that data!

Using the characters table you can recover the flag! Mapping the signal and the Big table lead you to the flag!

And This is will be our flag! Securinets{LcD_1s_H4rD_!:(}

# Game Hacking: Platformer:

In this challenge we have a game made by unity! It’s 2D platformer game where the player can jump and run in the map! But where is the flag??

Mmmmm my sixth sense told me that the flag is hidden somewhere in the map and the player can’t reach it! Hack Time!!!

Let’s change the player ability and let him can move in any place we want it. By disabling the collision and physics mechanism! Good bye gravitiy,Rigidbody,collisions!

To do this let’s open Assembly-CSharp.dll located in Platformer_Data/Managed folder.

Wow! This is the player controller code! that allow the player to move and the animation to be played and responsable for jumping and detect ground detection to deny player to jump many times on the air!

Boring mechanism!! Let me change this shitty code by mine! I’ll let the player move to any point he want!


You can copy that code

change mechanism
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
private void Start()
{
this.rb = base.GetComponent<Rigidbody2D>();
this.rb.isKinematic = true;
this.anim = base.GetComponent<Animator>();
this.mySpriteRenderer = base.GetComponent<SpriteRenderer>();
}

// Token: 0x06000005 RID: 5
private void FixedUpdate()
{
float axisRaw = Input.GetAxisRaw("Horizontal");
float verticalInput = Input.GetAxisRaw("Vertical");
Vector3 movement = new Vector3(axisRaw, verticalInput, 0f).normalized * 10f * Time.deltaTime;
base.transform.Translate(movement);
}

After applying the changes our player can now go to any place we want! But i didn’t find the flag! Oh god! This is what i found!

I checked all the map and sadly nothing interesting 😦

Let’s check the files again! Maybe we will find something!

Oh man look here! I found that there is levels on this game! Let me back to the decompiled code!

Oh no! The game is opened on the 2nd level! Let’s change this room to “Level1” and Play again! And yes It’s a new Level

After moving right and left, I found the flag!

And Yes We did it! Just move right and left and collect the letters ! and you’ll get this one ! Wrap it in Securinets{}

Flag: Securinets{Gam1ng_AnD_L0VE}

# Misc: Full Difference

Full Difference, The difference will make a difference! What is that thing ?? we got 2 images with different type but same picture!

Thinking a little bit can we understand what the author means! Full difference! It means that the pixels should be different a full difference! which means the Red,Green and Blue channels should be differents!

“Will make a difference!” After extracting the different pixels we should calculate the difference between each channels ?? Mmmmm makes sense!

solver
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from PIL import Image
import string
im1=Image.open("tobi.jpg")
im2=Image.open("tobi.png")
pix2=im2.load()
pix1=im1.load()
width,height=im1.size
result=""
data=[]
for i in range(0,width):
for j in range(0,height):
if pix1[i,j] != pix2[i,j] and pix1[i,j][0] != pix2[i,j][0] and pix1[i,j][1] != pix2[i,j][1] and pix1[i,j][2] != pix2[i,j][2]:
for k in range(0,3):
data.append(chr(abs(pix1[i,j][k] - pix2[i,j][k])))

for char in data:
if char in string.ascii_letters + string.digits + string.punctuation:
result+=char


print(result)

So the logic behind that code is to extract the pixels that have a full difference then calculate the difference between them. After that we convert the numbers to chars (should be printable!)

This expression will give us the different pixels

exp
1
pix1[i,j] != pix2[i,j] and pix1[i,j][0] != pix2[i,j][0] and pix1[i,j][1] != pix2[i,j][1] and pix1[i,j][2] != pix2[i,j][2]

In addition this expression collect the result of calculation the diff between the 2 pixels of each image!

diff
1
data.append(chr(abs(pix1[i,j][k] - pix2[i,j][k])))

Then it’s time to convert it to printable data!

print
1
2
3
for char in data:
if char in string.ascii_letters + string.digits + string.punctuation:
result+=char

Running this code will give you this base64 encoding! dGgxNV8xNV9zaDB1TGRfYjNfaDRyRA==

Bingo we got this statement! th15_15_sh0uLd_b3_h4rD . Let’s wrap it in Securinets! Oh nooo! Didn’t work. I guess the challenge is not finished!

We have 2 images! PNG and JPEG. Mmmm Let’s try to do some steganography on these images using the password/key that we got previously.

The 1st idea in my mind is to try steghide! Nothing else! Let’s try it

YEEES MAAN! We got a flag.zip file! But wait it’s protected again 😦. I tried to brute force that thing using rockyou but failed !!! What is going on here! The flag is inside that zip what we should to do now!

Let’s extract more information about the zip using 7z utility

7z
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
7z l  -slt flag.zip

Path = flag.txt
Folder = -
Size = 40
Packed Size = 52
Modified = 2022-11-18 21:17:23
Created =
Accessed =
Attributes = A
Encrypted = +
Comment =
CRC = 4F639BBA
Method = ZipCrypto Store
Host OS = FAT
Version = 20
Volume Index = 0

Nice the flag.txt size is 40 bytes! So our flag is 40-chars strings! The encryption method is ZipCrypto !

Bingoo! This method is vulnerable! Let’s check how can we get our flag!

After some searching we found a repository talking about “Crack legacy zip encryption with Biham and Kocher’s known plaintext attack.”

I recommend to check this repo and understand how this attack can be manipulated and how to install that tool!

Let’s now start downloading the tool

wget
1
wget https://github.com/kimci86/bkcrack/releases/download/v1.5.0/bkcrack-1.5.0-Linux.tar.gz

We need to recover the internal key that will allow us to extract the file!

The attack requires at least 12 bytes of known plaintext. At least 8 of them must be contiguous. The larger the contiguous known plaintext, the faster the attack. In our case we have a flag.txt that contains Securinets{*}

In our case we know 11 chars ( Securinets{ ) and the last char }

Let’s recover our key now!

prepare our data
1
2
echo -n "Securinets{" > plaintext.txt
echo -n "}" | xxd # 7d is the result

The attack requires the plain text content and in case there is another seperate bytes we can specify the offset and the byte value in hex

Now time to work !

get the key
1
2
3
4
5
6
7
8
9
10
bkcrack-1.5.0-Linux/bkcrack -C flag.zip -c flag.txt -p plaintext.txt -x 39 7d 

bkcrack 1.5.0 - 2022-07-07
[16:21:19] Z reduction using 4 bytes of known plaintext
100.0 % (4 / 4)
[16:21:19] Attack on 1405963 Z values at index 6
Keys: 184a904b d4557686 2222c7f2
9.2 % (129555 / 1405963)
[16:24:40] Keys
184a904b d4557686 2222c7f2

We got the keys ! 184a904b d4557686 2222c7f2 . Now we can decipher/decrypt the file! which means extract it from the zip!

extract
1
2
3
4
5
bkcrack-1.5.0-Linux/bkcrack -C flag.zip -c flag.txt -k 184a904b d4557686 2222c7f2 -d my_flag.txt   

bkcrack 1.5.0 - 2022-07-07
[16:32:25] Writing deciphered data my_flag.txt (maybe compressed)
Wrote deciphered data.

Bingo We got the flag!!! How 2 images can hide data like that!

Flag: Securinets{Z1p_CRyPt0_&_5t3gH1d3_1s_BAd}

# Kubernetes challenge serie

NCSC’2023 consider the 1st tunisian CTF competition that have a whole Kubernetes Category! These are oriented for beginners/Intermediate users to consodilate their basic knowledge in Kubernetes!

# Kubernetes: Secrets:

In this challenge we get an IP and the author told us that he have a secret in the cluster!

Visiting the IP on the browser will lead us to the author page! This is not our objective!

We need to access to the API-Server. Let’s check the default port 6443

curl
1
curl -sk https://20.169.73.19:6443/version

And this request is failed! Mmmm The author change the default api-server?? Nmap time! Let’s scan that IP!

After checking the IP we get that port opened 7443!

And Yes! We got a response! It’s KUBERNETES TIME!!

Let’s check what permission we have as an anonymous users! To be honest I’ll try to check if I can got namespaces Or secrets first! Let me check that!

curl-namespaces
1
curl -sk https://20.169.73.19:7443/api/v1/namespaces | grep '"name": "'

And we got a list of namespaces! This is cool! We have task1,task2,task3 and task4 namespaces! I bet that each challenge is in single namespace! This is Great!

Hummm We need secrets and this is the 1st challenge! So We are sure that we can list the secrets in the task1 namespace!

curl-namespaces
1
curl -sk https://20.169.73.19:7443/api/v1/namespaces/task1/secrets

Bingo We got the Secrets List! We are on the right way!

Flag : Securinets{S3crEts_Ar3_S0_CriT1c4LL}

We got a message! We must check it for sure!

Look what we got here !

check
1
2
Look here YOU will need this one believe me!!!
eyJhbGciOiJSUzI1NiIsImtpZCI6IkZwcWlIMGR2QlJ5Q0ZwTHV5a0JFQnlEcVI5UWZHLUdsY2NLQkkyMGlZWU0ifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJ0YXNrMiIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJwb2QtbGlzdGVyLXRva2VuLXpoNHM2Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQubmFtZSI6InBvZC1saXN0ZXIiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC51aWQiOiIyZjc2YjA3ZS0wY2NjLTRhMDQtYWUxZi1jNGJhMzIxZjYzZmQiLCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6dGFzazI6cG9kLWxpc3RlciJ9.cewI8cdU8u-MxhLW5enn9bqj2DnD6Kn6iJZD2Y70uSIN-Pdq4VGrCNN0oB0edWaNZd_2o3NCVfE1GY9JRIjQeMuV_Uk5-tEQ62TS1b2hpHPoq8FtRFDyji26LyTR2XGU7gSYdQV6G8axOU3z8_RRWQarN5VfSgDp-WmwizjwWJLMhENGgvWBxOKjHrF0tDCEmshH1g841NB4XtzeiXRxEC1AN9kNv-7SZvYWasHbPuva-fsGBp-AvhUUTStcCVahZ8VElJ51q3VxKBTXX-DoDWfsVD5rOcCse0yj4jxgN3GIqjIaAcjBiPI2XmhQv-tMMbYpj7gfAxrzhdh77UfaBg

# Kubernetes: Pody:

After getting the secrets we can move to the next challenge that named Pody

In this challenge the author told us that the container is inside a pod! So how can we get inside that pod? Thinking a little bit we didn’t get any solution expect opening a shell session inside the pod!

Kubectl Are you there?? Yes! It’s Kubectl time! I love to work with kubectl I will not waste my time curling endpoints 😃 So I’ll make my kubeconfig file for this challenge!

When I checked the secrets in the previous challenge I got the certificate authority Certifcate. And of course don’t forget the token that we got!

This token is used for authentication and authorization in kubernetes. This authorization is occur on the api-server level not the etcd!

Let’s make our kubeconfig! But wait! In case you don’t have kubectl, it’s time to install it! You can follow this guide to install it

kubeconfig
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
apiVersion: v1
kind: Config
clusters:
- cluster:
certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUMvakNDQWVhZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBREFWTVJNd0VRWURWUVFERXdwcmRXSmwKY201bGRHVnpNQjRYRFRJek1ETXdOVEV5TWpVMU1sb1hEVE16TURNd01qRXlNalUxTWxvd0ZURVRNQkVHQTFVRQpBeE1LYTNWaVpYSnVaWFJsY3pDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBTDEzCm0rOG5ySVlXU21hQjREMU9yWWJVS1hycE4rS2ZUZDk1TjA2UTQ5U3IyUU1FZkZXZHhjSGJadThRVWRIVXo1dFcKdmVvRnk4cFBpcmhhNHdGYnJEbXczdFp4NlgxbGxEZlp4b29jd1ZBOS9pMTBjNGE4TURvOGVuc1hlYWU1TytZcQpMZmdiM04zcWZYYjZmSHAzekwxeHJzWThPUEZVeHhmU3AxaElXa0RNZ0tZY0lhU2NoRVUzYTk0ZityY2tIOUFwCnltRi95TlB3bXgyU1RFZUVFSkZoZFdWUzVVamdSTmxnNzFPWklyb05DMXMzWEJxb2RiZ1FWUjBUeTI5bnJGc0QKQnBJQW1WQVRCS3QxTjcyRjRMRDA0c3M3QVUxU0NDSCtoUmlrTWE1ZkdtOTBjMWRacEVuZ1IyVEUwSzZ4WVY3TAplOElrcE5WOVBaLy9RT2ZqSnFFQ0F3RUFBYU5aTUZjd0RnWURWUjBQQVFIL0JBUURBZ0trTUE4R0ExVWRFd0VCCi93UUZNQU1CQWY4d0hRWURWUjBPQkJZRUZBWWUzVktNRDY3T3V5NWhWTGxTN0RWeU52SExNQlVHQTFVZEVRUU8KTUF5Q0NtdDFZbVZ5Ym1WMFpYTXdEUVlKS29aSWh2Y05BUUVMQlFBRGdnRUJBSE9EMUNTNGQzNjJLRXE1dTZyQwpQOEF6a3hDMTJDdVF1bDh4aUVTajZ4M25wb25oT2M3WU0zRUhQZk5wNHRDZmNsdFpDMU51SXNrVDRuSkRLRTFYCjRNVFNOL0kxVDlGSHd5SUhNbDZMZm1RL1ZLVlo1YlZJMEZlUENQanFnOWZSbHFYaitsRUxJQnRJVE0xbUlmeW0KZlZmMisrS3h4OTFTME54bWRKUzU0amY1SUJMRVh2SnRiWFYrblZ1ekhER3l5eDREblVDMm4zR3NrcEtBOGRJRQpZZktRWk5IZjJ4L0FySWM2a3A0em9TSWI1RVQvdDk4b3p5R2pldlVnbDd1L0orUzkwTS9pWWgyaGlGSXRRVE1WCnBTa0pQM1lIbDlzWVRSS0dXZTBtcEtnVm1RZm9VTVNzdURrRnZ4ZFNhVG9QQUN6aUdxdUNnVXVyWHMxNXJjOWkKR2xBPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==
server: https://20.169.73.19:7443
name: raf-k8s
contexts:
- context:
name: ncsc-sa@raf-k8s
context:
cluster: raf-k8s
user: ncsc-sa
current-context: ncsc-sa@raf-k8s
users:
- name: ncsc-sa
user:
token: eyJhbGciOiJSUzI1NiIsImtpZCI6IkZwcWlIMGR2QlJ5Q0ZwTHV5a0JFQnlEcVI5UWZHLUdsY2NLQkkyMGlZWU0ifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJ0YXNrMiIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJwb2QtbGlzdGVyLXRva2VuLXpoNHM2Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQubmFtZSI6InBvZC1saXN0ZXIiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC51aWQiOiIyZjc2YjA3ZS0wY2NjLTRhMDQtYWUxZi1jNGJhMzIxZjYzZmQiLCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6dGFzazI6cG9kLWxpc3RlciJ9.cewI8cdU8u-MxhLW5enn9bqj2DnD6Kn6iJZD2Y70uSIN-Pdq4VGrCNN0oB0edWaNZd_2o3NCVfE1GY9JRIjQeMuV_Uk5-tEQ62TS1b2hpHPoq8FtRFDyji26LyTR2XGU7gSYdQV6G8axOU3z8_RRWQarN5VfSgDp-WmwizjwWJLMhENGgvWBxOKjHrF0tDCEmshH1g841NB4XtzeiXRxEC1AN9kNv-7SZvYWasHbPuva-fsGBp-AvhUUTStcCVahZ8VElJ51q3VxKBTXX-DoDWfsVD5rOcCse0yj4jxgN3GIqjIaAcjBiPI2XmhQv-tMMbYpj7gfAxrzhdh77UfaBg

This kubeconfig file will allow us to authenticate to the api-server using kubectl utility without wasting time specifying the token and other stuff!

Assume that you save that file in name ncsc-k8s.conf . Let’s export the KUBECONFIG env var.

1
2
3
4
$ export KUBECONFIG=ncsc-k8s.conf
$ kubectl get pods -n task2
NAME READY STATUS RESTARTS AGE
web-app 1/1 Running 3 (2d19h ago) 17d

Bingo !! We got access and everything is ok until now. Let’s describe the pod and check what we have first before getting a shell !

describe pod
1
2
3
4
5
6
7
8
9
10
11
kubectl describe pod web-app -n task2   
Name: web-app
Namespace: task2
...
...
Mounts:
/etc/nginx/flag.txt from flag-configmap (rw,path="flag.txt")
/var/cache/nginx from tmpfs-2 (rw)
/var/run from tmpfs-1 (rw)
/var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-wrfpc (ro)
...

Wow there is flag.txt file inside the pod! Let’s be more accurate! The flag is in /etc/nginx/flag.txt

Let’s get a shell or run a command from the pod using the kubectl exec command!

Yes we got the flag! And another message: Your current token is enough!

I tried to delete the flag! But as expected the author make the pod Read-only file system

Flag : Securinets{Ex3c_1s_DAnGer0uS_B3_C4r3fUL}

# Kubernetes: Hidden? :

We still have the same token! Our kubectl works fine. So no worries we can do it!

In this challenge the flag is hidden?? But how!? Let’s check first what can we do in our task3 namespace

service
1
2
3
kubectl get service -n task3        
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
web-app ClusterIP 10.109.128.98 <none> 80/TCP 17d

We can access to services! In case you don’t know what is service I recommend to check this page. As we understand, There is a pod inside task3 namespace but we don’t have any access to it 😦!. No worries we still have services! This service as we can see its attached to that pod. Let’s get our flag!

After a little bit of thinking, I got an idea! Let’s access to the service from our previous pod!

YES MAN! pods and services can communicate between each others

Ok let’s do it then, we have the service internal IP and we can run curl command inside our previous pod!

Bingo! Flag: Securinets{K8s_S3rV1cEs_ArE_P0wErFull}
And as Usual! another token for the next challenge :

1
2
In The Next Challenge You will Need This one!
eyJhbGciOiJSUzI1NiIsImtpZCI6IkZwcWlIMGR2QlJ5Q0ZwTHV5a0JFQnlEcVI5UWZHLUdsY2NLQkkyMGlZWU0ifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJ0YXNrNCIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJuY3NjLXBhcnRpY2lwYW50LXRva2VuLTdnZ2JxIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQubmFtZSI6Im5jc2MtcGFydGljaXBhbnQiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC51aWQiOiIwNmM3OGJhZC01NjAwLTQ2N2QtYjdhYi0wNWQzN2RjMjg0MzIiLCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6dGFzazQ6bmNzYy1wYXJ0aWNpcGFudCJ9.exWa8skN0HdscxzG2PBFYn9eU9l_sL7hAjUw8sFPsnjUKHPHzmqwDpN4WfSPCHFOfv7KKimYvr9SuMjB75KuapxXKnyBwEaIZEkH3c0lavBCPYfGou_BrVsAHVSdbw6pQ9YYonuc3WTiGkcXC-XjKXfY8PGppmnGh7gUsuxY9xwpju10PutjIs8s0g9z2tTBYUhOraa54WRCODDGw-o415rXsaVHuV8A2Cj3jQZVBzXXi5-snfvjX27-nMyGDh4F0gu8sXD3PZfLjLdrOQpP6s_jzbUN9G1g8iLQTXNjCvgUw2cnBOvWtRGLtbdizOazlKUyJAOSXfmu3W45bMJPOg

# Kubernetes: Special :

After getting the new token it’s time to edit the kubeconfig file! Just replace the old toke by the new one! To work with kubectl correctly!

Something Special?? What a special? Everything in Kubernetes is SO Special!! So no worries, We can deal with that kind of things!

Talking about something special take me to think about what we can call it Custom Resources Definition in Kubernetes!

In Kubernetes, a custom resource is an extension of the Kubernetes API that allows you to define your own custom resources with their own custom controllers.

A custom resource definition (CRD) is used to create a new custom resource type in Kubernetes. A CRD defines the structure and behavior of the new custom resource, including its name, attributes, and API endpoints. Once a CRD is defined, instances of the custom resource can be created and managed using Kubernetes tools like kubectl and the Kubernetes API.

api-resources
1
2
3
4
5
6
7
8
9
10
11
kubectl api-resources
NAME SHORTNAMES APIVERSION NAMESPACED KIND
bindings v1 true Binding
componentstatuses cs v1 false ComponentStatus
configmaps cm v1 true ConfigMap
...
...
rolebindings rbac.authorization.k8s.io/v1 true RoleBinding
roles rbac.authorization.k8s.io/v1 true Role
priorityclasses pc scheduling.k8s.io/v1 false PriorityClass
ncscctfs securinets.com/v1alpha1 true NCSCCtf

But wait! I am right! There is an api-group and a custom resource called ncscctfs!

Now it’s time to get the flag!

get
1
2
3
kubectl get ncscctfs -n task4           
NAME AGE
flag 17d

And yes there is a ncscctf resource named flag! Let’s describe that thing and get the flag!

describe
1
kubectl describe ncscctfs flag -n task4 

Flag: Securinets{CuSt0m_REs0urcEs_ArE_P0wErFul}

# Final Words

In conclusion, the success of this event and competition is due in no small part to the dedication and hard work of the technical team. Their expertise and professionalism were instrumental in overcoming the various challenges we faced throughout the event lifecycle, and their tireless efforts ensured that we delivered a product that met the highest standards of quality and performance. On behalf of the team, I would like to express our sincere gratitude to our technical colleagues for their unwavering commitment to the project, and for their invaluable contributions to its success

Edited on