this is what happens if you give a teen tech nerd too much free time…
Warning: Catastrophic levels of yapping (and possibly broken English) ahead, read on at your own risk!
Yet another year rolled around, and as the saying goes, “new year, new me”, I decided to join an actual CTF instead of doing exercises. And what better way to start the journey than to participate in the aptly named “New Year CTF”?
48 hours of ignoring schoolwork later, I got these results:

Personally, I think this is pretty okay for a beginner like me, however the way I solved some (most) of the challenges are unconventional, to say the least. In order for others to not learn from them, I’ve decided to exclude them from this writeup. That left me with only two challenges that I think are the most frustrating fun to solve.
Code analysis: Username (100)
Remember, every user leaves a digital footprint…
The challenge is a small executable file named “Task.exe” that is seemingly useless (like everything else provided in CTF challenges):
Running it normally gives this output:
You are not the owner of the flag.Code language: plaintext (plaintext)
Who could be the owner of the flag then? I decided to check strings for the answer. After skimming through a bunch of garbage data (foreshadowing), I found these interesting lines of readable text:
.NETFramework,Version=v4.7.2
FrameworkDisplayName
.NET Framework 4.7.2Code language: plaintext (plaintext)
So the program uses .NET, which is great since it’s relatively simple to decompile (as long as the organizers don’t intentionally screw me over). For the decompilation process, I used ILspy as it’s easy to use and doesn’t take up the entire hard drive.
Thankfully the program wasn’t obfuscated, and below is the decompiled source code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Text;
using Task;
internal static class Program
{
[UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode)]
private delegate bool GetFl4g(char[] lpBuffer, ref int lpnSize);
[DllImport("kernel32.dll", CharSet = CharSet.Ansi, SetLastError = true)]
private static extern IntPtr LoadLibrary(string lpFileName);
[DllImport("kernel32.dll", CharSet = CharSet.Ansi, SetLastError = true)]
private static extern IntPtr GetProcAddress(IntPtr hModule, string lpProcName);
public static void Main(string[] args)
{
byte[] flag = Get_Flag();
int[] array = getflag(flag);
int[] array2 = new int[16]
{
246, 253, 255, 228, 140, 144, 141, 235, 15, 76,
59, 211, 108, 3, 46, 114
};
for (int i = 0; i < array.Length; i++)
{
try
{
if (array[i] != array2[i])
{
GetFlag();
}
}
catch
{
GetFlag();
}
}
Console.Write("Write ur flag: ");
string value = Console.ReadLine();
if ((gEtFlag("103,114,111,100,110,111,123,109,121,95,117,115,51,114,110,52,109,51,95,49,115,95") + Encoding.UTF8.GetString(flag) + "}").Equals(value))
{
Console.WriteLine("Welcome");
}
else
{
GetFlag();
}
}
private static int[] getflag(byte[] bytes)
{
using MD5 mD = MD5.Create();
return ((IEnumerable<byte>)mD.ComputeHash(bytes)).Select((Func<byte, int>)((byte b) => b)).ToArray();
}
private static byte[] Get_Flag()
{
int lpnSize = 256;
char[] array = new char[lpnSize];
if (!_GetFlag<GetFl4g>(Encoding.UTF8.GetString(Convert.FromBase64String("YWR2YXBpMzIuZGxs")), Encoding.UTF8.GetString(Convert.FromBase64String("R2V0VXNlck5hbWVX")))(array, ref lpnSize))
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
byte[] array2 = new byte[lpnSize - 1];
for (int i = 0; i < lpnSize - 1; i++)
{
array2[i] = (byte)array[i];
}
return array2;
}
private static T _GetFlag<T>(string a_1, string a_2) where T : Delegate
{
IntPtr intPtr = LoadLibrary(a_1);
if (intPtr == IntPtr.Zero)
{
throw new DllNotFoundException(a_1 + " not found.");
}
IntPtr procAddress = GetProcAddress(intPtr, a_2);
if (procAddress == IntPtr.Zero)
{
throw new EntryPointNotFoundException(a_2 + " not found in " + a_1 + ".");
}
return Marshal.GetDelegateForFunctionPointer<T>(procAddress);
}
private static void GetFlag()
{
Console.WriteLine("You are not the owner of the flag.");
Console.ReadLine();
Environment.Exit(0);
}
private static string gEtFlag(string input)
{
string[] array = input.Split(',');
char[] array2 = new char[array.Length];
for (int i = 0; i < array.Length; i++)
{
array2[i] = (char)int.Parse(array[i]);
}
return new string(array2);
}
}
Code language: C# (cs)
One thing CTF challenges have taught me is “random strings = interesting”, and that’s why I went straight to CyberChef for anything that’s out of the ordinary. Most are irrelevant to the challenge, however the numbers gave the most promising results:
103,114,111,100,110,111,123,109,121,95,117,115,51,114,110,52,109,51,95,49,115,95
-> grodno{my_us3rn4m3_1s_Code language: plaintext (plaintext)
And that’s the first half of the flag! explodes from adrenaline rush
But where’s the other half? To find it, I was forced to actually look at the source code (in a code analysis challenge, how surprising), which was basically hell to a python-only dev. Tracing the array array (intentionally terrible naming), I found out that it gets the current Windows username and calculates the MD5 hash for it.
Guess what’s right below it! That’s right, it’s the MD5 hash itself, albeit in a weird format:
246, 253, 255, 228, 140, 144, 141, 235, 15, 76, 59, 211, 108, 3, 46, 114
//to hex -> f6fdffe48c908deb0f4c3bd36c032e72Code language: JavaScript (javascript)
Since MD5 is very much insecure and should not be used in any systems at all, I decided to just query an online rainbow table found on first page Google:

Combining the first and second half of the flag, we have:
grodno{my_us3rn4m3_1s_adminadmin}
which was the correct answer!
(Fun fact: I found the solution for the second half of the flag while sleeping on the bus. If that’s not dedication, I don’t know what is.)
Forensics: Favorite messenger (914)(!!!)
I got access to the device. But there was nothing useful on it. There is only a messenger, but the session is no longer active 🙁
File here (837 MB)
please don’t tell me they’re gonna make me download this from their crippling server infra-
They did, in fact, make me download a 800MB disk image over <1MB/s speed.
After waiting for half the event deadline to pass, I finally got the file – a virtual machine image called file.ova with this inside:

I then proceed to burn precious time by installing MEMU and trying to boot the VM to no avail (which was probably the point).
Screw it, let’s use 7-zip for everything now.
Using my experience from downloading “MOD APK UNLIMITED MONEY FREE NO VIRUS” and snooping around application files, I found out that the mentioned “messenger” was Telegram:

Looking into the data directory, I found an interesting file with the name tgnet.dat in /data/org.telegram.messenger/files:

This string reads a lot like hex-encoded ASCII, which rarely appears in normal configuration files…
67726f646e6f7b30333539363362313437663362346232373864366461643332346336343263367d
//to text -> grodno{035963b147f3b4b278d6dad324c642c6}Code language: JavaScript (javascript)
… and sure enough, that’s the flag itself!
Why this challenge was worth 900+ points is still beyond me to this day, but I’m not gonna complain about an insane +30% score boost!
With that said, I’ll be worshipping apk[REDACTED].com from now on, thank you for reading and have a nice day!