I'm doing a really simple example of buffer overflows, I have this code:
#include <stdio.h>
void secretFunction()
{
printf("Congratulations!\n");
printf("You have entered in the secret function!\n");
}
void echo()
{
char buffer[20];
printf("Enter some text:\n");
scanf("%s", buffer);
printf("You entered: %s\n", buffer);
}
int main()
{
echo();
return 0;
}
To start with, I compile this file with no stack protections, and aslr turned off:
gcc buf.c -o vuln_nostack -fno-stack-protector -m32 -no-pie
For exploiting this, we simply want to inject the memory adress of the secret function so that we can get to run it. This can be done with running the file with python generating the input:
$ python -c 'print "a"*32 + "\xd6\x91\x04\x08"' | ./vuln_nostack
Enter some text:
You entered: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa֑
Congratulations!
You have entered in the secret function!
Segmentation fault (core dumped)
Which hits my secret function. So this works.
But now the problem is that I want to to work with aslr as well, so I want to output the adress of the secret function at the start of the program, and then have the malicious input depend on that.
FOr that reason, I want to wait by inputting anything to the program, until I have seen what it has printed to me.
But if I now run the program where I just give the input manually while the program runs:
./vuln_nostack
Enter some text:
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa֑\xd6\x91\x04\x08
You entered: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa֑\xd6\x91\x04\x08
Segmentation fault (core dumped)
Then it simply handles my input correctly, and the value is not overflown. A segmentation error occurs, indicating that something is happening, but not the same direction to my secret function
I'm pretty new to overflows, and don't really understand why this is happening, when the python generated input actually works.
SO my question is whether there is a way to do this simple overflow "manually" while the program runs. Or if I will need to write some script (python perhaps) that can interact with this faulty program and give it correct input as it runs?
You say that your input is handled correctly in the second example but this is not the case, you can see that in the second time you ran the program, you got a segmentation fault, which means that you accessed memory which can't be deferenced(Either due to wrong memory protection or due to invalid memory address).
The reason that you failed to jump to secretFunction() on your second run, is that you were assuming that scanf parses escaped unicode values as unicode, but when you enter "\xd6" it is not parsed to a unicode value but it is parsed to 4 chars '' 'x' 'd' '6'. As you run on a 32 bit machine this is the address the program tries to execute which probably leads to a segfault as this memory is most likely not valid nor executable.
Just an idea on how to overcome ASLR without connecting with gdb after running the program and looking for the address the program was loaded to - you can try overflowing only the lower 2 bytes, as if I am not mistaken only the 2 upper bytes are randomized with ASLR, hence you only need to overflow the "offset" which is constant even with ASLR.
Here is some learning material regarding stack overflows:
https://insecure.org/stf/smashstack.html
Related
I am reading The shellcoder's Handbook and im currently at chapter 2 where i have a simple program to exploit by overflowing the expected input and then issuing a new location for the ret instruction so that the function return_input can be executed twice !
Here is the simple program made in C
void return_input (void)
{
char array[30];
gets (array);
printf(“%s\n”, array);
}
main()
{
return_input();
return 0;
}
And this is the disassembled version of the main fucntion where we can see the jump adress of the call function.
I use the following command and input the chars that overflow with the adress following them that should replace ret's content
But as you can see i do not run the return_input function twice instead it just prints out a question mark and says segmentation failed
gets read terminating byte in and replaced it with NULL byte and thus your desired ret was broken with that NULL byte.
The offset you saw in disassembly codes is NOT the real address, you compiled the program with PIE flag set so the real address may look like 0x55555????58a, that's why gdb didn't allow you to insert a break point because you might try to do b *0x58a or something. Compile with -no-pie would make life easier.
I am developing buffer overflow exercises for students. In this context you often have to provide arbitary bytes as input for programs (return addresses).
Assume this example:
#import <stdio.h>
#import <string.h>
void func() {
char buf[4];
gets(buf);
}
int main (int argc, char** argv) {
func();
return 0;
}
Normally I experiment with gdb, until I found a solution, which can then be formulated like
python -c 'print "A"*8+"\x08\x04\88\72"' | ./program
While developing more and more complex exercises, the difficulty to find a solution increases. Sometimes overwriting the return address in gdb via
set {int}address_of_address = new_address
works, but the python-approach does not. It would be nice to debug this and to be able to enter bytes like "\x04" in gdb, while the program is running, analyzing the effects.
Is there any way to do this?
This question seems related but is answered with the python-approach: Sending arbitrary bytes to fgets from stdin
Mine goes beyond that :-/
It would be nice to debug this and to be able to enter bytes like
"\x04" in gdb, while the program is running, analyzing the effects
To do this you need 2 consoles: the first one to enter bytes in program stdin, the second one for gdb debug session.
You can first run program in 1st console until it stops waiting for bytes from stdin. Then run gdb in 2nd console and attach to a program by it's pid. You will be able to debug and enter bytes simultaneously from 2 different consoles.
"while the program is running" is one part of the problem. The other one is being able to set breakpoints beforehand, to "analyze the effects".
GDB's default behaviour is to run the program as a child process, thus using the same standard streams. So it is impossible to write to the child's stdin while being in GDB's CLI because, at this moment, it is being read by GDB, not your program.
The simplest solution, avoiding tty workarounds (tty command + stty setups + reading/writing to /proc/<pid>/fd/{0,1}), is to make your code testable and "callable" from GDB. You'll then be able to pass your string arguments to your functions in order to test and debug them.
For example:
#include <stdio.h>
#include <unistd.h>
void exploitme(char* str)
{
printf(str);
}
int main()
{
while (1)
{
char str[10];
fgets(str, sizeof (str), stdin);
exploitme(str);
}
return 0;
}
exploitme() is the exploit case correctly wrapped in a single entry point so that it is now possible to call it once everything it uses is correctly initialized. You can then call it using command call once main() breakpoint is reached (so that the C runtime inits, performed in main's caller, are done).
~/test $ gdb ./a.out
(gdb) call exploitme("hello")
You can't do that without a process to debug.
(gdb) b main
Breakpoint 1 at 0x4005ae: file helloworld.c, line 14.
(gdb) r
Starting program: /home/julio/test/a.out
Breakpoint 1, main () at helloworld.c:14
14 fgets(str, sizeof (str), stdin);
(gdb) call exploitme("hello")
(gdb) call exploitme("hello\n")
hellohello
(gdb) call exploitme("AAAAAAAA\x08\x04\88\72\n")
AAAAAAA�:
(gdb) b exploitme
Breakpoint 2 at 0x400592: file helloworld.c, line 6.
(gdb) call exploitme("foo")
Breakpoint 2, exploitme (str=0x602010 "foo") at helloworld.c:6
6 printf(str);
The program being debugged stopped while in a function called from GDB.
Evaluation of the expression containing the function
(exploitme) will be abandoned.
When the function is done executing, GDB will silently stop.
Note that you benefit from GDB's argument expansion which includes the C string evaluation.
The other (longer and more complex) solution, as explained, is to run your program under another tty, so that you can independently write to GDB and your program.
I have the following C program:
#include<stdio.h>
main()
{
char buf[64];
gets(buf);
printf("Your input: %s\n", buf);
gets(buf);
printf("Your input: %s\n", buf);
}
I want to send data to the program using pipes or redirection. The problem is that the program don't wait for the second gets to enter new data.
e.g
$ echo "a" | ./test
Output:
Your input: a
Your input: a
How can I send let the program wait for the user input at each gets using pipes or redirection.
P.S I don't have persmission to write to /proc/$pid/fd/0 and I don't have to change the code.
Any help would be appreciated.
If you use pipes | to input data to a command, it is disconnected from the (input portion) of your terminal. gets reads the first line "a\n" and writes this to the buf as "a\0". Then it hits the end of the pipe, or EOF (end of file).
Your second gets then does nothing (as there is nothing to read after EOF) and lets buf alone; buf still contains "a\0", which is duly printed.
Further hints:
When doing I/O, which can inherently fail at any time, you have to check for errors after each and every call, or bad things will happen. Train yourself to do this and save lots of debugging time.
Never do an I/O like gets(buf) because it will lead to buffer overflows, the bane of computing security. If you input arbitrary data, you must use a call that lets you limit the number of bytes written. The man page for gets contains the sentence "Never use this function" right at the top. You can find other, better functions, read being a baseline, and if you are in C++ there will be plenty of other standard solutions for that.
EDIT: GDB was not the issue. Bugs in my code created the behaviour.
I am wondering how GDB's input works.
For example I created the following small c program:
#include <stdlib.h>
#include <stdio.h>
int main(){
setbuf(stdout,NULL);
printf("first:\n");
char *inp;
size_t k = 0;
getline(&inp, &k, stdin);
printf("%s",inp);
free(inp);
// read buffer overflow
printf("second:\n");
char buf[0x101];
read(fileno(stdin),buf,0x100);
printf("%s",buf);
printf("finished\n");
}
It reads two times a string from stdin and prints the echo of it.
To automate this reading I created following python code:
python3 -c 'import sys,time; l1 = b"aaaa\n"; l2 = b"bbbb\n"; sys.stdout.buffer.write(l1); sys.stdout.buffer.flush(); time.sleep(1); sys.stdout.buffer.write(l2); sys.stdout.buffer.flush();'
Running the c programm works fine. Running the c program with the python input runs fine, too:
python-snippet-above | ./c-program
Running gdb without an input file, typing the strings when requested, seems also fine.
But when it comes to using an inputfile in gdb, I am afraid I am using the debugger wrongly.
Through tutorials and stackoverflow posts I know that gdb can take input via file.
So I tried:
& python-snippet > in
& gdb ./c-program
run < in
I expected that gdb would use for the first read the first line of the file in and for the second read the second line of in.
in looks like (due to the python code):
aaaa
bbbb
But instead gdb prints:
(gdb) r < in
Starting program: /home/user/tmp/stackoverflow/test < in
first:
aaaa
second:
finished
[Inferior 1 (process 24635) exited with code 011]
Observing the variable buf after read(fileno(stdin),buf,0x100) shows me:
(gdb) print buf
$1 = 0x0
So i assume that my second input (bbbb) gets lost. How can I use multiple input inside gdb?
Thanks for reading :)
I am wondering how GDB's input works.
Your problem doesn't appear to have anything to with GDB, and everything to do with bugs in your program itself.
First, if you run the program outside of GDB in the same way, namely:
./a.out < in
you should see the same behavior that you see in GDB. Here is what I see:
./a.out < in
first:
aaaa
second:
p ��finished
So what are the bugs?
The first one: from "man getline"
getline() reads an entire line from stream, storing the address
of the buffer containing the text into *lineptr.
If *lineptr is NULL, then getline() will allocate a buffer
for storing the line, which should be freed by the user program.
You did not set inp to NULL, nor to an allocated buffer. If inp didn't happen to be NULL, you would have gotten heap corruption.
Second bug: you don't check return value from read. If you did, you'd discover that it returns 0, and therefore your printf("%s",buf); prints uninitialized values (which are visible in my terminal as ��).
Third bug: you are expecting read to return the second line. But you used getline on stdin before, and when reading from a file, stdin will use full buffering. Since your input is small, the first getline tries to read BUFSIZ worth of data, and reads (buffers) all of it. A subsequent read (naturally) returns 0 since you've already reached end of file.
You have setbuf(stdout,NULL);. Did you mean to disable buffering on stdin instead?
Fourth bug: read does not NUL-terminate the string, you have to do that yourself, before you can call printf("%s", ...) on it.
With the bugs corrected, I get expected:
first:
aaaa
second:
bbbb
finished
I was experimenting with a code described in the "Shell coders handbook" where you overflow a buffer and cause the same code to be executed twice...
void return_input (void)
{ char array[5];
gets (array);
printf(“%s\n”, array);
}
main()
{
return_input();
return 0;
}
The task was to overwrite the buffer and to replace the address of 'return 0' with the address of 'return_input()' so that the entered string is printed twice..
i compiled it as follows
gcc -fno-stack-protector overflow.c
to override the protection mechanisms. The problem is i cant get it to execute twice. in this case the address of the function ri() is at 0x08048440 . I gave the input as follows
./a.out
aaaaaaaaaaaaa\x40\x84\x04\x08
shouldnt this cause the function to be called twice?? It always returns
aaaaaaaaaaaaaaaa��
Segmentation fault (core dumped)
How can i overflow the buffer to call the function twice?
\x40\x84\x04\x08 is not supported. You should use some other program to translate the hex input to bytes.
If you are using bash, you can try echo -e '\x40\x84\x04\x08' | ./a.out. I found that solution at linux shell scripting: hex string to bytes
By definition, the behavior of a buffer overflow is unpredictable. You will only get the same behavior if you happen to be using the same version of the same compiler with the same settings on the same OS, etc., etc.
based on your machine type , you might need to adjust.
http://www.tenouk.com/Bufferoverflowc/Bufferoverflow4.html