Introduction
On Fri, 27th June 2025 — Sun, 29th June 2025, We Fr334aks-mini had some fun playing the Industrial Intrusion CTF by TryHackMe.
It hosted challenges in:
- OSINT
- Web 3
- Networking
- Forensics
- Boot2Root
- Cryptography
- SCADA/ICS
- …And more!
I will break down one of the challenges I solved.
Reverse Engineering
Auth
We re given a zip file and a remote server.
Checking the unzipped file type, we see it’s a non-stripped ELF. From the strings it seems we need to enter some code te get the flag.
On running it, I tried a couple of “codes” and got denials. I opened Ghidra to see what was fueling the denial fire.
We’ve got 2 functions of interest; main and transform.
The main function:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
undefined8 main(void)
{
int iVar1;
char *pcVar2;
undefined8 uVar3;
size_t sVar4;
FILE *__stream;
long in_FS_OFFSET;
undefined8 local_168;
undefined8 local_160;
undefined8 local_158 [8];
char local_118 [264];
long local_10;
local_10 = *(long *)(in_FS_OFFSET + 0x28);
local_160 = 0xefcdab8967452301;
printf("[?] Enter unlock code: ");
pcVar2 = fgets((char *)local_158,0x40,stdin);
if (pcVar2 == (char *)0x0) {
fwrite("Error reading input\n",1,0x14,stderr);
uVar3 = 1;
}
else {
sVar4 = strcspn((char *)local_158,"\r\n");
*(undefined1 *)((long)local_158 + sVar4) = 0;
sVar4 = strnlen((char *)local_158,0x40);
if (sVar4 == 8) {
local_168 = local_158[0];
transform(&local_168,8);
iVar1 = memcmp(&local_168,&local_160,8);
if (iVar1 == 0) {
__stream = fopen("flag.txt","r");
if (__stream == (FILE *)0x0) {
perror("fopen");
uVar3 = 1;
}
else {
pcVar2 = fgets(local_118,0x100,__stream);
if (pcVar2 == (char *)0x0) {
fwrite("Error reading flag\n",1,0x13,stderr);
}
else {
printf("[+] Access Granted! Flag: %s",local_118);
}
fclose(__stream);
uVar3 = 0;
}
}
else {
puts("[!] Access Denied!");
uVar3 = 1;
}
}
else {
puts("[!] Access Denied!");
uVar3 = 1;
}
}
if (local_10 != *(long *)(in_FS_OFFSET + 0x28)) {
/* WARNING: Subroutine does not return */
__stack_chk_fail();
}
return uVar3;
}
The transform function:
1
2
3
4
5
6
7
8
9
10
11
12
void transform(long param_1,ulong param_2)
{
undefined8 local_10;
for (local_10 = 0; local_10 < param_2; local_10 = local_10 + 1) {
*(byte *)(local_10 + param_1) = *(byte *)(local_10 + param_1) ^ 0x55;
}
return;
}
- Understanding the binary
Main function:
It reads an 8-byte code and checks if the input length is exactly 8 bytes. Applies transform to the input and compares the transformed input with a hardcoded value at (0xefcdab8967452301). If they match, it prints the flag from flag.txt.
Transform function:
It takes a buffer (param_1) and its length (param_2) then XORs each byte in the buffer with 0x55.
- Reverse the unlock code
The binary compares the transformed input with 0xefcdab8967452301.
Due to little-endian storage(which I struggled with), this is stored in memory as: 01 23 45 67 89 ab cd ef
To find the correct input, we XOR each target byte with 0x55 to get \x54\x76\x10\x32\xdc\xfe\x98\xba
- Targeting the remote server
1
echo -e "\x54\x76\x10\x32\xdc\xfe\x98\xba" | nc 10.10.255.232 9005
THM{Simple_tostart_nice_done_mwww}
- Conclusion
We just needed to XOR each byte of 0xefcdab8967452301 (little-endian) with 0x55 to get \x54\x76\x10\x32\xdc\xfe\x98\xba and send this to the server.
Till the next one.
And remember, there are many ways of killing Jerry!