May 28, 2025

Pwnable.kr - flag

This was an interesting and challenging exercise for me. The clue given:

Papa brought me a packed present! let’s open it. Download : http://pwnable.kr/bin/flag This is reversing task. all you need is binary

$ file flag
flag: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, no section header

I checked strings flag | less to see if anything jumped out, and it was mostly character salad. I did notice this string at this point, but I didn’t investigate it further until later:

$Info: This file is packed with the UPX executable packer http://upx.sf.net $
$Id: UPX 3.08 Copyright (C) 1996-2011 the UPX Team. All Rights Reserved. $

I ran gdb flag, hoping to crack the binary open and see what lays within, but no luck.

Reading symbols from flag...
(No debugging symbols found in flag)
(gdb) disas main
No symbol table is loaded.  Use the "file" command.
(gdb) file
No executable file now.
No symbol file now.

After some google-fu, I discovered that this file is stripped, meaning that there isn’t an easy way to get gdb to open it up. I decided to execute the file and see what it does. But first, I fired up a Kali VM to act as a sandbox, because I’m just not that trusting. First I had to sudo chmod +x flag to make it executable.

$ ./flag
I will malloc() and strcpy the flag there. take it.

That sounded familiar from when I learned C language a few years ago. Admittedly, my C is rusty, so off to check the man-pages and some more googling. That helped refresh my memory a bit, but I was still not sure where to start attacking this binary.

The next night, I returned to see if I could make any progress. I tried using radare2 to see if I could find a starting point, and while I did get some interesting output, I was feeling pretty stumped.

[0x0044a4f0]> i
fd       3
file     flag
size     0x51db8
humansz  327.4K
minopsz  1
maxopsz  16
invopsz  1
mode     r-x
format   elf64
iorw     false
block    0x100
type     EXEC (Executable file)
arch     x86
baddr    0x400000
binsz    811736
bintype  elf
bits     64
canary   false
class    ELF64
crypto   false
endian   little
havecode true
laddr    0x0
lang     c
linenum  true
lsyms    true
machine  AMD x86-64 architecture
nx       false
os       linux
pic      false
relocs   true
rpath    NONE
sanitize false
static   true
stripped false
subsys   linux
va       true

My takeaway from radare2 is that I will need to spend some time learning how to use it effectively, but it looks like an awesome tool.

I started looking for some clues from people that have done this CTF before, but wasn’t getting any hits in the Discord servers I lurk in. So I found a walkthrough, and quickly found that I had overlooked a big clue at the beginning: the strings output that “this file is packed with UPX…” coupled with the clue given at the beginning “Papa brought me a packed present!” Finally I had a jumping-off point! I set the walkthrough aside, and started digging some more. A quick search led me to https://upx.github.io, where I downloaded the upx tool.

$ upx -h
                       Ultimate Packer for eXecutables
                          Copyright (C) 1996 - 2024
UPX 4.2.4       Markus Oberhumer, Laszlo Molnar & John Reiser    May 9th 2024

Usage: upx [-123456789dlthVL] [-qvfk] [-o file] file..

Commands:
  -1     compress faster                   -9    compress better
  --best compress best (can be slow for big files)
  -d     decompress                        -l    list compressed file
  -t     test compressed file              -V    display version number
  -h     give this help                    -L    display software license

Options:
  -q     be quiet                          -v    be verbose
  -oFILE write output to 'FILE'
  -f     force compression of suspicious files
  --no-color, --mono, --color, --no-progress   change look
[ ... ]

I used the -d switch to unpack the file.

$ upx flag -d
                       Ultimate Packer for eXecutables
                          Copyright (C) 1996 - 2024
UPX 4.2.4       Markus Oberhumer, Laszlo Molnar & John Reiser    May 9th 2024

        File size         Ratio      Format      Name
   --------------------   ------   -----------   -----------
    887219 %3C-    335288   37.79%   linux/amd64   flag

Unpacked 1 file.

Then I checked the file information again, and was really happy to see that it is now “not stripped!”

$ file flag
flag: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, for GNU/Linux 2.6.24, BuildID[sha1]=96ec4cc272aeb383bd9ed26c0d4ac0eb5db41b16, not stripped

So I started gdb again and this time was able to disassemble the main function. A quick scan showed one line with a comment # 0x6c2070 <flag>. That looks promising. Let’s see what’s at that address…

(gdb) disas main
Dump of assembler code for function main:
   0x0000000000401164 <+0>:	push   rbp
   0x0000000000401165 <+1>:	mov    rbp,rsp
   0x0000000000401168 <+4>:	sub    rsp,0x10
   0x000000000040116c <+8>:	mov    edi,0x496658
   0x0000000000401171 <+13>:	call   0x402080 <puts>
   0x0000000000401176 <+18>:	mov    edi,0x64
   0x000000000040117b <+23>:	call   0x4099d0 <malloc>
   0x0000000000401180 <+28>:	mov    QWORD PTR [rbp-0x8],rax
   0x0000000000401184 <+32>:	mov    rdx,QWORD PTR [rip+0x2c0ee5]        # 0x6c2070 <flag>
   0x000000000040118b <+39>:	mov    rax,QWORD PTR [rbp-0x8]
   0x000000000040118f <+43>:	mov    rsi,rdx
   0x0000000000401192 <+46>:	mov    rdi,rax
   0x0000000000401195 <+49>:	call   0x400320
   0x000000000040119a <+54>:	mov    eax,0x0
   0x000000000040119f <+59>:	leave
   0x00000000004011a0 <+60>:	ret
End of assembler dump.
(gdb) x/1s *0x6c2070
0x496628:	"UPX...? sounds like a delivery service :)"
(gdb)

And there is the flag, revealed!