Pwnable.kr - flag

— Written by — 4 min read

flag

We continue our beginner series on Binary Exploitation with pwnable.kr which appears to have a reasonable curve of difficulty making it ideal for learning.

Let’s go for this 4rd challenge: flag.

Challenge Description

Flag

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

Test & Analysis

This time we can retrieve the binary but not its source code.

1
[hg8@archbook ~]$ wget [http://pwnable.kr/bin/flag](http://pwnable.kr/bin/flag)

The program doesn’t seem to take input:

1
2
3
4
[hg8@archbook ~]$ ./flag
I will malloc() and strcpy the flag there. take it.
[hg8@archbook ~]$ ./flag aaaaaaaaaaaaaaaaaaaa
I will malloc() and strcpy the flag there. take it.

Malloc

The binary output is taking about malloc(), what is that exactly ? Let’s take a look at the manual page:

1
2
3
4
5
[hg8@archbook ~]$ man malloc
DESCRIPTION
malloc()
The malloc() function allocates size bytes and returns a pointer to the allocated memory. The memory is not initialized. If size is 0, then malloc() returns a unique pointer value that can later be successfully passed to free(). (See "Nonportable behavior" for
portability issues.)

Malloc stands for “memory allocation”, it is to allocate memory dynamically during program execution. When you call malloc(), it reserves a block of memory of a specified size and returns a pointer to the first byte of this memory block. This memory is then typically used for creating dynamic data structures like arrays, linked lists, or other objects.

Binary analysis

Since we don’t have the source code, let’s see what informations we can retrieve from the binary itself, running file indicate the

1
2
[hg8@archbook ~]$ file flag
flag: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, no section header

Bummer, no section header means that all the debugging info, code, data, symbols, and other metadata have been stripped out.

Let’s now use strings to see if we can find some interesting strings in the binary:

1
2
3
4
5
[hg8@archbook ~]$ file flag
[...]
su`"]R
UPX!
UPX!

UPX is a name I am familiar with, it stands for “Ultimate Packer for Executables”. It is a compression utility designed to compress and decompress executable files.

This kind of tools are often referred as “packer”. It’s primarily used for reducing the size of executable files to save storage space and improve execution times, but it can also be employed for security-related tasks.

A good news with UPX, is that under normal conditions, it’s quite easy to decompress a packed executable. Let’s give a try by downloading and executing UPX:

1
2
3
4
5
6
7
8
9
10
[hg8@archbook ~]$ upx -d flag
Ultimate Packer for eXecutables
Copyright (C) 1996 - 2023
UPX 4.2.0 Markus Oberhumer, Laszlo Molnar & John Reiser Oct 26th 2023

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

Unpacked 1 file.

Dynamic Analysis

Now that we unpacked the binary, we can start with the usual dynamic analysis using gdb to understand what is happening the program is running.

Let’s start by disassembling the main():

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
[hg8@archbook ~]$ gdb flag-unpacked
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.

Seems like a comment is indicating a address of the flag: # 0x6c2070 <flag>

Let’s print out the content of 0x6c2070:

1
2
pwndbg> x/1s *0x6c2070
0x496628: "UPX...? sounds like a delivery service :)"

Bingo! We got our flag.

Turn out that since there is obfuscations we could also have used strings again to retrieve the flag:

1
2
[hg8@archbook ~]$ strings ./flag-unpacked | grep "delivery"
UPX...? sounds like a delivery service :)

Let’s do a proper analysis. First let’s set a breakpoint in main:

1
2
3
[hg8@archbook ~]$ gdb flag-unpacked
pwndbg> break main
Breakpoint 1 at 0x401168

Then run the program with r and run the binary step by step to see what’s happening in memory (ni).

After a few steps we can see malloc being called with 0x64 as argument (RDI), that 100.

https://github-production-user-asset-6210df.s3.amazonaws.com/9076747/280253789-52df00e1-b0f1-41f2-a6e7-01c89db5d9fb.png

And a few instruction further we can see the being send to the memory area reserved by malloc:

https://github-production-user-asset-6210df.s3.amazonaws.com/9076747/280254580-5b11293b-e809-448a-ba87-5032b363f983.png


That’s it folks! I hope you enjoyed this series on Buffer Overflow.

As always do not hesitate to contact me for any questions or feedback!

See you next time ;)

-hg8



CTFpwnableToddler's Bottle
, , , ,