We just finish the finals yesterday, it was difficult, and we managed to get 2nd place yeah!

scoreboard

Here is some writeups of the challenges

Challenges

Corrupt (Forensics)

Challenges file:

We are given a PNG image file, view it with Photo viewer looks blank..

Check it with file command it stated it only have 1x1 pixel:

file flag.png
flag.png: PNG image data, 1 x 1, 8-bit grayscale, non-interlaced

But it has 696 bytes, so I guess the size has been modify

Basically we need to change the PNG to the correct size to view the flag

After some research, found out we can modify the size of PNG using Hexeditor, based on this article

But how to we know the original PNG size??

Running pngcheck also shown no errors

pngcheck -v flag.png
File: flag.png (696 bytes)
  chunk IHDR at offset 0x0000c, length 13
    1 x 1 image, 8-bit grayscale, non-interlaced
  chunk pHYs at offset 0x00025, length 9: 5039x5039 pixels/meter (128 dpi)
  chunk tEXt at offset 0x0003a, length 25, keyword: Software
  chunk IDAT at offset 0x0005f, length 581
    zlib: deflated, 32K window, default compression
  chunk IEND at offset 0x002b0, length 0
No errors detected in flag.png (5 chunks, -69500.0% compression).

Find the original size

After some researching, I came across this article

In the pixel data part, we can see it calculate the expected IDAT size based on width and height

image1

Therefore, another way around we can also calculate width and height based on IDAT size!

To find IDAT data size, we need to decompress the zlib compression

It got many ways to do it, I use linux command to do it

First, I use binwalk to extract the zlib data

binwalk -e flag.png

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
0             0x0             PNG image, 1 x 1, 8-bit grayscale, non-interlaced
99            0x63            Zlib compressed data, default compression

Then go to _flag.png.extracted, running zlib-flate will decompress the zlib data, and wc will count the data size

zlib-flate -uncompress < 63.zlib | wc
      0       0   20100

Can see the data size is 20100, put it in the equation:

height x (1 + width x bytesPerPixel) = 20100

Next we need to find bytesPerPixel, if is RGBA image each pixel is 4 bytes long

This image is 8-bit grayscale, doing a quick google search can find it is 1 byte

image2

Therefore, the equation become:

height x (1 + width) = 20100

We can guess the height and width is 200 or 100

Lets try to edit the size using hexeditor

Hex of 200 is c8 and 100 is 64:

image3

View it in Photo Viewer, and we saw the flag!!

flag

Althought we didn’t solve this is finals, but still fun to solve it after


Parent Sharp

Challenge file:

We get a windows executable, running file command can see it is a .NET assembly (Means it written using microsoft .net framework)

file Parent_Sharp.exe
Parent_Sharp.exe: PE32+ executable (console) x86-64 Mono/.Net assembly, for MS Windows

We can view the source code and even debug it using dnSpy in windows

Using dnSpy to open Parent_Sharp.exe, we are able to see all of the source code inside:

image1

Press Start to run it, it just print some words and exit:

Baby Shark dududududu
Find the mini shark dododododo
Find the naugthy shark dadadadada

fsdududududucyberx is not the flag dududu

Notice after running it, got a new file MessageFromAuthor.txt add to same directory.. interesting

Inside the file is just Baby Shark dodododo Baby Sharp dudududu

Debug and analyze

Same as C program, it also have a Main function

Inside the main function we can see it got some byte array like pwx, dada dada2 dada3 dada4

Then it pass into a function in KJASD:

string @string = Encoding.UTF8.GetString(KJASD.cHalala(pwx, dada));
string string2 = Encoding.UTF8.GetString(KJASD.cHalala(pwx, dada2));
string string3 = Encoding.UTF8.GetString(KJASD.cHalala(pwx, dada3));
string string4 = Encoding.UTF8.GetString(KJASD.cHalala(pwx, dada4));

We can set a breakpoint to see what is the string returned

Just behind the line number then it set a breakpoint at this line:

image2

Click start, when enter the breakpoint the Locals tab will appear some variables

After that, click Step Over or F10 to move forward

Then you will see the string kernel32.dll return in Locals:

image3

Continue to step over, we can see the 4 strings return is:

"kernel32.dll"
"CreateFileA"
@".\MessageFromAuthor.txt"
"Baby Shark dodododo Baby Sharp dudududu"

Below got string5 which returns WriteFile

Notice the MessageFromAuthor.txt we saw before, we can guess the code below is just importing CreateFileA WriteFile from kernel32.dll and create the file with the name and write the file with the content

After that, you will see a large chunk of code with base64:

byte[] bytes = Encoding.ASCII.GetBytes("sqVv//z////7////AAD//0f/////////v///////////////////////////////////////////////f/////HgRfH/S/Yy3kf+szLeq5eWjN+PjZCYjZ6S35yekZGQi9+dmt+NipHflpHfu7Cs35KQm5rR8vL12/////////+vuv//m3n9/1yWUWX//////////w//3d/0/c///73////7///////////////f//////9//v/////f/////f//+//////////5//////////9f/////f////////z/n3r//7////////+////////////v////////3//////////////v//////////////////////////9///93/P//////////////////////////////////Y5///8f////////////////////////////////////////////////////////////////////////////////f//+3///////////////Ri5qHi////66+////3////73////9///////////////////f//+f0Y2MjZz///93/P///3/////7////u///////////////////v///......");
Type type = Assembly.Load(new bsd(Encoding.UTF8.GetString(bytes).ToCharArray()).gdgdgd()).GetType("Baby_Sharp.shark_call");
Console.WriteLine(Assembly.Load(new bsd(Encoding.UTF8.GetString(bytes).ToCharArray()).gdgdgd()));
object obj = Activator.CreateInstance(type);
Console.WriteLine(((string)type.GetMethod("dudu").Invoke(obj, null)).Substring(0, 87));
type.GetMethod("rktrkt");
Console.WriteLine((string)type.GetMethod("Sharp").Invoke(obj, new object[]
{
	array
}));

Basically the base64 is assembly machine code (also known as shellcode)

You can see it decode it and pass it into Assembly.Load:

Type type = Assembly.Load(new bsd(Encoding.UTF8.GetString(bytes).ToCharArray()).gdgdgd()).GetType("Baby_Sharp.shark_call");

Then it calls methods inside the Baby_Sharp.shark_call class, 3 methods dudu,rktrkt and Sharp

So how do we decompile or disassembly the bytes code??

Source of Baby_Sharp

Thanks to dnSpy, we no need to disassembly manually, we just need to keep clicking Step Into until it reach the Baby_Sharp methods

Then you will see the source code

First, we need to understand how to use the Step Into Step Over and Step Out when debugging

  1. Step Into is go into the next function
  2. Step Over is skip the next function
  3. Step Out is skip the current function

When it execute this statement:

Console.WriteLine(((string)type.GetMethod("dudu").Invoke(obj, null)).Substring(0, 87));

First it will call GetMethod then Invoke, Substring then WriteLine

We want to get into Invoke function, so we skip the first function

Steps to get in

  • Set breakpoint before it call dudu

image4

  • Click start then click step over and step into, you will see it get into the Invoke function

image5

  • Keep clicking step into, eventually it will reach the dudu function

image6

  • After that, the source code of Baby_Sharp is added in the left panel:

image7

Solving

Lets see the Sharp function:

public string Sharp(byte[] kay)
{
	if (File.Exists(".\\MessageFromAuthor.txt"))
	{
		return "fsdududududucyberx is not the flag dududu";
	}
	shark_call.rktrkt(shark_call.dada);
	byte[] bytes = shark_call.cHalala(kay, shark_call.dada);
	return Encoding.UTF8.GetString(bytes);
}

As you can see, it if the file MessageFromAuthor exists

If exist it returns the output we seen when we test run

Lets try what will happen when we delete the file in when running

Set a breakpoint before calling Sharp:

image8

Click start then delete the MessageFromAuthor.txt then click continue

Baby Shark dududududu
Find the mini shark dododododo
Find the naugthy shark dadadadada

fsB4bySh4rpcyberx

Boom! THE FLAG appear!

Looks like we just need to delete the txt file to solve this

Thats it, no need to analyse compilcated code we are able to solve this

Alternative Solution

After the finals, I notice we also can save the assembly of Baby_Sharp by debugging

Set a breakpoint at the Assembly.Load function:

image9

Click start, then keep step into and step out until it reach Assembly.Load function, you will see a rawBinary in the Locals tab:

image10

Right Click it > Save

image11

After that, open the binary with dnSpy you will get the source code of Baby_Sharp

Summary

It was a great CTF, can see it getting harder compare to last year. The challenges all were great and nice, this is the last year we participate for this competition because we graduated and this competition is only for Uni students. Hope in the future, our juniors can participate and win the prize!