unpackme - PicoCTF Write-Up
A write-up on the challenge unpackme.
Introduction
Hello! 👋 Today, we’re going to take a look at the ‘unpackme’ challenge on PicoCTF by LT ‘syreal’ Jones. The difficulty level is medium.”
Challenge Description
Can you get the flag?
Reverse engineer this binary.
Solution
So, let’s make the binary executable using chmod.
1
chmod +x unpackme-upx
Now, let’s try running the executable and see what it does.
1
2
3
4
┌──(printn㉿printn)-[~]
└─$ ./unpackme-upx
What's my favorite number? 1
Sorry, that's not it!
From the first hint, we are asked what UPX is, and a quick search online gives us this: UPX is a free and open-source executable packer that compresses and reduces the size of executable files
So let’s unpack the binaray with UPX.
1
2
3
4
5
6
7
8
9
10
11
┌──(printn㉿printn)-[~]
└─$ upx -d unpackme-upx
Ultimate Packer for eXecutables
Copyright (C) 1996 - 2024
UPX 4.2.2 Markus Oberhumer, Laszlo Molnar & John Reiser Jan 3rd 2024
File size Ratio Format Name
-------------------- ------ ----------- -----------
1006445 <- 379188 37.68% linux/amd64 unpackme-upx
Unpacked 1 file.
We can now open it up in Ghidra and analyze it with the default settings. After it has analyzed we Ghidra finds 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
undefined8 main(void)
{
long in_FS_OFFSET;
int local_44;
char *local_40;
undefined8 local_38;
undefined8 local_30;
undefined8 local_28;
undefined4 local_20;
undefined2 local_1c;
long local_10;
local_10 = *(long *)(in_FS_OFFSET + 0x28);
local_38 = 0x4c75257240343a41;
local_30 = 0x30623e306b6d4146;
local_28 = 0x6865666430486637;
local_20 = 0x36636433;
local_1c = 0x4e;
printf("What\'s my favorite number? ");
__isoc99_scanf(&DAT_004b3020,&local_44);
if (local_44 == 0xb83cb) {
local_40 = (char *)rotate_encrypt(0,&local_38);
fputs(local_40,(FILE *)stdout);
putchar(10);
free(local_40);
}
else {
puts("Sorry, that\'s not it!");
}
if (local_10 != *(long *)(in_FS_OFFSET + 0x28)) {
/* WARNING: Subroutine does not return */
__stack_chk_fail();
}
return 0;
}
We see that it checks if our input is the same as 0xb83cb
, which is encrypted in base 16 (hexadecimal). Converting it to base 10, we get the number 754635
.
1
2
3
4
┌──(printn㉿printn)-[~]
└─$ ./unpackme-upx
What's my favorite number? 754635
picoCTF{up><_m3_f7w_5769b54e}
And we get the flag 😃: picoCTF{up><_m3_f7w_5769b54e}