ImaginaryCTF 2024 - Forensic
Hi everyone, Imaginary CTF 2024 was celebrated successfully and my team - World Wide Flags got 13th place, and this is my writeup for some challenges (this time I’m lazy 😂😂😂). Ok let’s go!
bom
In this challenge they gave us a file contains a Chinese string:
You just view hex value inside it and get the flag:
The flag became Chinese string because of a pair of hex value: FE and FF, you know that just one hex value be changed, all content of a file will be changed, and same with this challenge, because FE and FF are in Unicode range, the content of file also be affected!
Flag: ictf{th4t_isn7_chin3se}
packed & routed
I will solve two challenges at a time because they used one sample. In this case they gave us a .pkz file, it’s a Packet Tracer file. Very simple, you just download and install Packet Tracer and open file:
At first, I checked all configurations of this file but I could not find anything. After that I thought: “How about checking command history?”. Not waiting, I checked and I found many hints about flag (go to Option -> View command log):
Searched a bit, I found they typed password, and they used mode 7 for typing password:
Also I found an article talks about it. They noted that: “If that digit is a 7, the password has been encrypted with the weak algorithm.”. Very clear, we can decrypt this hash, and fortunately I found a tool that help me decrypt it:
Check the flag with MD5 in detail, it’s same, so it’s our flag for this challenge!
Flag 1: ictf{hidden_not_hashed}
For the second challenge, we need to dig deeper, and if you learn about .pkz file, you will know that .pkz files contain many files inside (you can read more here):
I used this tool to extract all files inside:
There’s a file named secret.png. Open it and you will get the flag:
Flag 2: ictf{ab4697882634d4aeb6f21141ea2724d0}
elf in front of a sunset
For this challenge, they gave us a picture, and we need to analyse it. First, I analysed hex values inside the picture:
If you notice, you will some familiar strings: GGGNNNUU -> GNU; llliiibbb666444 -> lib64;… from here I can be sure that there’s an executable file inside. Searched a bit and I found that it must be ELF file:
Ok so now this is how I extract ELF file. Because they just tripled the number of character, we just reduce it, and also we need to arrange so that all will combine correctly and make an ELF file. because ELF signature was placed in these last lines, I guessed maybe I just reversed it and then I could get ELF file. And now everything is clear, now we will extract it:
- Choose parts that have tripled characters:
- Check length of that part, and divide it into many smaller parts. I took the part that contain signature because it’s in these last lines, I guessed authors splited ELF file to many smaller parts that have same length with it. From here you can write a Python script to check length of it:
with open("C:\\Users\\Admin\\Documents\\Code\\Python\\payload", "r") as file:
print(len(file.read().strip().split(' ')))
(payload contains file signature part)
- Take the length of tripled part divide it by the length we found to find the number of smaller parts that was divided by authors:
with open("C:\\Users\\Admin\\Documents\\Code\\Python\\encrypted.txt", 'r') as file:
arr = file.read().strip().split(" ")
print(len(arr) / 3048)
- You can see that there’re 17 parts, and now as my thinking before, reverse it, decode from hex and we will get the ELF file:
with open("C:\\Users\\Admin\\Documents\\Code\\Python\\encrypted.txt", 'r') as file:
arr = file.read().strip().split(" ")
result = []
for i in range(0, len(arr), 3048):
result.append(arr[i:i+3048])
payload = result[::-1]
elf = ""
for j in payload:
for k in range(0, len(j), 3):
elf += j[k]
with open("C:\\Users\\Admin\\Documents\\Code\\Python\\result.txt", "w") as f:
f.write(elf)
Now we got the correct ELF file, we will use IDA or Ghidra to analyse this file:
int __fastcall main(int argc, const char **argv, const char **envp)
{
unsigned __int64 v3; // rbx
size_t v4; // rax
char v6; // [rsp+7h] [rbp-49h]
int i; // [rsp+8h] [rbp-48h]
char s[40]; // [rsp+10h] [rbp-40h] BYREF
unsigned __int64 v9; // [rsp+38h] [rbp-18h]
v9 = __readfsqword(0x28u); // Read the value of the FS segment base address, not important for the scrambling
strcpy(s, "_{f2isfsatutflwa_nh2}__asitib1leefwcuk"); // Copy the original string into s
srand(0x123123Du); // Seed the random number generator with a specific seed
for (i = 0; i < strlen(s); ++i) // Loop over each character in the string
{
v6 = s[i]; // Store the current character in v6
v3 = rand(); // Generate a random number
v4 = strlen(s); // Get the length of the string
s[i] = s[(int)(v3 % v4)]; // Replace the current character with the character at the random position
s[(int)(v3 % v4)] = v6; // Replace the character at the random position with the current character
}
puts(s); // Print the scrambled string
return 0;
}
From here I wrote a C code to decrypt it:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void shuffle(char* flag, int* swaps, int size) {
for (int i = 0; i < size; i++) {
int idx = rand() % size;
swaps[i] = idx;
char tmp = flag[i];
flag[i] = flag[idx];
flag[idx] = tmp;
}
}
void reverse_shuffle(char* flag, int* swaps, int size) {
for (int i = size - 1; i >= 0; i--) {
int idx = swaps[i];
char tmp = flag[i];
flag[i] = flag[idx];
flag[idx] = tmp;
}
}
int main() {
srand(0x123123D);
char scrambled_flag[] = "_{f2isfsatutflwa_nh2}__asitib1leefwcuk";
int size = strlen(scrambled_flag);
int swaps[40];
// Perform the shuffle to record the swaps
char dummy_flag[40];
strcpy(dummy_flag, scrambled_flag);
shuffle(dummy_flag, swaps, size);
// Reverse the shuffle to recover the original flag
reverse_shuffle(scrambled_flag, swaps, size);
puts(scrambled_flag);
return 0;
}
Flag: ictf{elf_waifus_best_waifus_2h12lntka}
Thank you for watching, hope you enjoy it 🫀. See you in the next writeup, bye!!!!!