pwnable.kr Toddler's Bottle (easy) write-up

pwnable.kr has a collection of pwning problems with a wide range of difficulty. This article is the write-up for Toddler’s Bottle (easy) section.

##fd (10/26/2015)

This is the easiest problem and is about Linux file descriptor. As given, connect to the server ssh fd@pwnable.kr -p 2222.

fd@ubuntu:~$ ls -al
total 32
drwxr-x---  4 root fd   4096 Aug 20  2014 .
dr-xr-xr-x 55 root root 4096 Sep 20 23:22 ..
d---------  2 root root 4096 Jun 12  2014 .bash_history
-r-sr-x---  1 fd2  fd   7322 Jun 11  2014 fd
-rw-r--r--  1 root root  418 Jun 11  2014 fd.c
-r--r-----  1 fd2  root   50 Jun 11  2014 flag
dr-xr-xr-x  2 root root 4096 Aug 20  2014 .irssi

It seems that you can read the source code for the program fd.

char buf[32];
int main(int argc, char* argv[], char* envp[]){
	if(argc<2){
		printf("pass argv[1] a number\n");
		return 0;
	}
	int fd = atoi( argv[1] ) - 0x1234;
	int len = 0;
	len = read(fd, buf, 32);
	if(!strcmp("LETMEWIN\n", buf)){
		printf("good job :)\n");
		system("/bin/cat flag");
		exit(0);
	}
	printf("learn about Linux file IO\n");
	return 0;

}

So it seems that when buf == "LETMEWIN\n, you can get the flag. Since fd == 0 is stdin, all you need to do is to give 0x1234 (4660 in decimal) as argv[1] and input “LETMEWIN\n”

fd@ubuntu:~$ ./fd 4660
LETMEWIN
good job :)
mommy! I think I know what a file descriptor is!!

Flag is: mommy! I think I know what a file descriptor is!!

##collision (10/26/2015)
Similar to fd, you can read the source code for the program col.

#include <stdio.h>
#include <string.h>
unsigned long hashcode = 0x21DD09EC;
unsigned long check_password(const char* p){
	int* ip = (int*)p;
	int i;
	int res=0;
	for(i=0; i<5; i++){
		res += ip[i];
	}
	return res;
}

int main(int argc, char* argv[]){
	if(argc<2){
		printf("usage : %s [passcode]\n", argv[0]);
		return 0;
	}
	if(strlen(argv[1]) != 20){
		printf("passcode length should be 20 bytes\n");
		return 0;
	}

	if(hashcode == check_password( argv[1] )){
		system("/bin/cat flag");
		return 0;
	}
	else
		printf("wrong passcode.\n");
	return 0;
}

At int *ip = (int*)p, const char *p is casted to int *. Since the size of int is 4 bytes, the size of char is 1 byte and the length of passcode is 20 bytes, you can read the flag when the sum of five int blocks is 0x21DD09EC. Since 0x21DD09EC = 0x06C5CEC8 * 4 + 0x06C5CECC and the system is little-endian, your injection code should be:

col@ubuntu:~$ ./col $(perl -e 'print "\xc8\xce\xc5\x06"x4 . "\xcc\xce\xc5\x06"')
daddy! I just managed to create a hash collision :)

Flag is: daddy! I just managed to create a hash collision :)

##flag (10/26/2015)
This is a reversing problem. You can download the file flag here.

taishi@sirius:~/blackhat_python/ctf/pwnable.kr|master⚡
⇒  file flag
flag: ELF 64-bit LSB  executable, x86-64, version 1 (GNU/Linux), statically linked, stripped
taishi@sirius:~/blackhat_python/ctf/pwnable.kr|master⚡
⇒  ./flag
I will malloc() and strcpy the flag there. take it.

As you execute, you see a weird message. However, you can’t analyze this program using GDB as shown below.

taishi@sirius:~/blackhat_python/ctf/pwnable.kr|master⚡
⇒  gdb -q flag            

warning: ~/.gdbinit.local: No such file or directory
Reading symbols from flag...(no debugging symbols found)...done.
gdb$ info files
Symbols from "/home/taishi/blackhat_python/ctf/pwnable.kr/flag".
gdb$ info functions
All defined functions:

This implies that some kind of anti-debugging techniques are applied to this program. Let’s examine.

taishi@sirius:~/blackhat_python/ctf/pwnable.kr|master⚡
⇒  strings flag | grep UPX
UPX!
$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. $
UPX!
UPX!

And here we go. flag file seems to be packed with UPX. You can easily unpack it using a tool (you can download the official UPX packer/unpacker here).

taishi@sirius:~/blackhat_python/ctf/pwnable.kr|master⚡
⇒  ./upx-3.91-i386_linux/upx -d flag 
Ultimate Packer for eXecutables
Copyright (C) 1996 - 2013
UPX 3.91        Markus Oberhumer, Laszlo Molnar & John Reiser   Sep 30th 2013

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

Unpacked 1 file.

Then you can analyze it with GDB.

taishi@sirius:~/blackhat_python/ctf/pwnable.kr|master⚡
⇒  gdb -q flag
gdb$ disassemble 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.

mov rdx, QWORD PTR [rip+0x2c0ee5] at <main+32> is interesting. Let’s set the breakpoint right after (<main+39>), and analyze what was passed to rdx.

gdb$ break *0x000000000040118b
Breakpoint 2 at 0x40118b
gdb$ c
Continuing.
gdb$ x/s $rdx
0x496628:	"UPX...? sounds like a delivery service :)"

Here it is! Flag is: UPX…? sounds like a delivery service :)

comments powered by Disqus