RNRF 2021. 11. 3. 01:09

35. Buffer overflwo on a modern ststem impossible? stack0: part 1 - bin.0x21

: "protoostar" has been completed
-> That means you are familiar with the basic knowledge of how binary exploit works.
-> Now, it's not easy anymore.
-> This is because we generally try to copy the source code and compile it on our own modern Linux machines.
-> So I think it will be interesting to introduce and exploit modern technology.
: Let's try again to solve some of the "protoostar" problems in Ubuntu now.
-> Can it still be exploited?
: Let's take a look at the simple source code (stack0.c).
-> There was a "modified" variable, buffer and modified integer and it was set to "0".
-> Then there is a "gets()" function, which reads the input into the buffer.
-> But there is no way to check the length.
-> In this way, you can fill the buffer completely and use it beyond.
-> There was a modified variable in the binary of the previous "protostar VM" immediately after the buffer.
-> Thus, if you have written more than 64 bytes, the attack succeeds by overwriting the "0" value of the modified variable.

: Let's try again on the latest system.
-> I’m using digitalocean to quickly spin up a new ubuntu linux machine and ssh into it.
-> Then, write and compile the code.
-> Because it is a newly installed system, the compiler "gcc" must be installed.
-> gcc stack0.c -o stack0
stack0.c: In function ‘main’:
stack0.c:11:3: warning: implicit declaration of function ‘gets’; did you mean ‘fgets’? [-Wimplicit-function-declaration]
   gets(buffer);
   ^~~~
   fgets
/tmp/ccT7mLob.o: In function `main':
stack0.c:(.text+0x32): warning: the `gets' function is dangerous and should not be used.
-> Compiling shows that the compiler warns against "gets()" use.
-> As you know, these programming mistakes must actually be ignored by developers.
-> You don’t really have to know about the dangers from somewhere else anymore, it tells you right away.
: Let's enter a lot of characters and see if we can change the modified variable.
-> ./stack0
AAAAAAAABBBBBBBBAAAAAAAABBBBBBBBAAAAAAAABBBBBBBBAAAAAAAABBBBBBBBAAAAAAAABBBBBBBBAAAAAAAABBBBBBBB
Try again?
*** stack smashing detected ***: <unknown> terminated
Aborted (core dumped)
-> But it doesn't seem to work.
-> The only thing we can get is the error that stack smashing is detected.
-> And the process is interrupted.
-> That is the first proof that a little more is going on here.
: Let's look at the assembly code generated by the compiler.
-> First of all let’s check why we couldn’t overwrite the modified variable.
-> Does the stack smashing detected have to do anything with it?
-> gdb ./stack0
-> set disassembly-flavor intel
-> disassemble main
Dump of assembler code for function main:
   0x00000000000006fa <+0>: push   rbp
   0x00000000000006fb <+1>: mov    rbp,rsp
   0x00000000000006fe <+4>: sub    rsp,0x70
   0x0000000000000702 <+8>: mov    DWORD PTR [rbp-0x64],edi
   0x0000000000000705 <+11>: mov    QWORD PTR [rbp-0x70],rsi
   0x0000000000000709 <+15>: mov    rax,QWORD PTR fs:0x28
   0x0000000000000712 <+24>: mov    QWORD PTR [rbp-0x8],rax
   0x0000000000000716 <+28>: xor    eax,eax
   0x0000000000000718 <+30>: mov    DWORD PTR [rbp-0x54],0x0 # modified = 0;
   0x000000000000071f <+37>: lea    rax,[rbp-0x50]
   0x0000000000000723 <+41>: mov    rdi,rax
   0x0000000000000726 <+44>: mov    eax,0x0
   0x000000000000072b <+49>: call   0x5d0 <gets@plt>
   0x0000000000000730 <+54>: mov    eax,DWORD PTR [rbp-0x54]
   0x0000000000000733 <+57>: test   eax,eax
   0x0000000000000735 <+59>: je     0x745 <main+75>
   0x0000000000000737 <+61>: lea    rdi,[rip+0xba]        # 0x7f8
   0x000000000000073e <+68>: call   0x5b0 <puts@plt>
   0x0000000000000743 <+73>: jmp    0x751 <main+87>
   0x0000000000000745 <+75>: lea    rdi,[rip+0xd5]        # 0x821
   0x000000000000074c <+82>: call   0x5b0 <puts@plt>
   0x0000000000000751 <+87>: mov    eax,0x0
   0x0000000000000756 <+92>: mov    rdx,QWORD PTR [rbp-0x8]
   0x000000000000075a <+96>: xor    rdx,QWORD PTR fs:0x28
   0x0000000000000763 <+105>: je     0x76a <main+112>
   0x0000000000000765 <+107>: call   0x5c0 <__stack_chk_fail@plt>
   0x000000000000076a <+112>: leave  
   0x000000000000076b <+113>: ret    
End of assembler dump.
-> In the stack, this is where the modified local variable is stored.
-> This can be seen because the "0" value has moved, as in C code. 
-> And this here is the buffer on the stack you can see that because the address of it is passed to gets. Like in the C code. 
-> So when you look at this you notice, that the modified variable is NOT located after the buffer anymore.
-> We can write as many characters as we want, but we will never overwrite modified.
-> You can also try to reorder the variables in the C code but that has no effect on the assembler code either.
-> And that’s not a coincidence.
-> Buffers or arrays are risky compared to simple integer variables.
-> Buffers are prone to buffer overflows.
-> So the compiler made the decision to order the local variables in a particular way.
-> And it kinda has something to do with the stack smashing detected message.
-> You see this message is caused because a stack cookie or stack canary or stack guard was overwritten.
: What exactly is it?
-> Open the compiled binary from the Disorder to take a closer look.
-> If you are still learning about this content, the assembler code is always very threatening.
-> However, it is about pattern recognition and learning.
-> One of these patterns is here with stack cookies.
-> Many things can be basically ignored when reverse engineering a program.
-> At the beginning of the function the value was moved from a strange place.
-> "28" has been moved to register "rax".
-> 0x0000000000000709 <+15>: mov    rax,QWORD PTR fs:0x28 # segment register
-> The values are then placed in the stack.
-> 0x0000000000000712 <+24>: mov    QWORD PTR [rbp-0x8],rax
-> And at the end of the function, just before the return, this value is read again from the stack and then xored with this mysterious value in fs hex 28.
-> This is just a check if the two values are the same.
-> If they are equal the function is allowed to return.
-> 0x0000000000000756 <+92>: mov    rdx,QWORD PTR [rbp-0x8]
-> 0x000000000000075a <+96>: xor    rdx,QWORD PTR fs:0x28
-> If they are equal the function is allowed to return.
-> 0x000000000000076a <+112>: leave  
-> 0x000000000000076b <+113>: ret
-> If the check failed, and those values are different, then there is a call to stack_check_fail and the program will never return.
-> 0x0000000000000765 <+107>: call   0x5c0 <__stack_chk_fail@plt>
: And this makes sense right.
-> So some unknown value is written onto the Stack at the beginning, then stuff happens, for example the gets() call which can overflow the buffer, And at the end the value on the stack is compared again to this mysterious value.
-> Therefore, this cookie If you have a buffer overflow, the written this stack the inspection fails.
-> So fs, or gs or other segment registers, are special registers with varying usages depending on 32bit or 64bit and if you are on windows or linux and if you write low level boot or kernel ring 0 code or if you write userspace ring 3 programs.
: And there is a lot of historical baggage with them. And to be completely honest with you, I don’t fully understand it.
-> You can imagine the fs register to point to some memory.
-> And from the perspective of the process we actually don’t really know where it points to.
-> The kernel (I think) set up where it points to.
-> Thus, the process can be used without worrying about where it actually points.
-> You can then refer to a different value at a specific offset for that memory.
-> For example, stack cookies are stored in the hexadecimal "28" offset.
-> In practice, the location should be somewhere in the process's virtual memory.
-> Install "peda" which is an improvement over "gdb" with good memory finding.
-> git clone https://github.com/longld/peda.git ~/peda
-> echo "source ~/peda/peda.py" >> ~/.gdbinit
-> echo "DONE! debug your program with gdb and enjoy"
-> gdb stack0
-> we can test this by setting a breakpoint at the stack cookie handling routines and search the process memory for this value.
-> r
-> disassemble main
ump of assembler code for function main:
   0x00005555555546fa <+0>: push   rbp
   0x00005555555546fb <+1>: mov    rbp,rsp
   0x00005555555546fe <+4>: sub    rsp,0x70
   0x0000555555554702 <+8>: mov    DWORD PTR [rbp-0x64],edi
   0x0000555555554705 <+11>: mov    QWORD PTR [rbp-0x70],rsi
   0x0000555555554709 <+15>: mov    rax,QWORD PTR fs:0x28
   0x0000555555554712 <+24>: mov    QWORD PTR [rbp-0x8],rax
   0x0000555555554716 <+28>: xor    eax,eax
   0x0000555555554718 <+30>: mov    DWORD PTR [rbp-0x54],0x0
   0x000055555555471f <+37>: lea    rax,[rbp-0x50]
   0x0000555555554723 <+41>: mov    rdi,rax
   0x0000555555554726 <+44>: mov    eax,0x0
   0x000055555555472b <+49>: call   0x5555555545d0 <gets@plt>
   0x0000555555554730 <+54>: mov    eax,DWORD PTR [rbp-0x54]
   0x0000555555554733 <+57>: test   eax,eax
   0x0000555555554735 <+59>: je     0x555555554745 <main+75>
   0x0000555555554737 <+61>: lea    rdi,[rip+0xba]        # 0x5555555547f8
   0x000055555555473e <+68>: call   0x5555555545b0 <puts@plt>
   0x0000555555554743 <+73>: jmp    0x555555554751 <main+87>
   0x0000555555554745 <+75>: lea    rdi,[rip+0xd5]        # 0x555555554821
   0x000055555555474c <+82>: call   0x5555555545b0 <puts@plt>
   0x0000555555554751 <+87>: mov    eax,0x0
   0x0000555555554756 <+92>: mov    rdx,QWORD PTR [rbp-0x8]
   0x000055555555475a <+96>: xor    rdx,QWORD PTR fs:0x28
   0x0000555555554763 <+105>: je     0x55555555476a <main+112>
   0x0000555555554765 <+107>: call   0x5555555545c0 <__stack_chk_fail@plt>
   0x000055555555476a <+112>: leave  
   0x000055555555476b <+113>: ret    
End of assembler dump.
-> break *0x000055555555475a
-> r
Starting program: /home/rnrf/stack0
-> AAAA(Enter Key)
Try again?

[----------------------------------registers-----------------------------------]
RAX: 0x0 
RBX: 0x0 
RCX: 0x7ffff7af4154 (<__GI___libc_write+20>: cmp    rax,0xfffffffffffff000)
RDX: 0x44ff012f21dba000 
RSI: 0x555555756670 ("Try again?\n")
RDI: 0x1 
RBP: 0x7fffffffdfe0 --> 0x555555554770 (<__libc_csu_init>: push   r15)
RSP: 0x7fffffffdf70 --> 0x7fffffffe0c8 --> 0x7fffffffe3fc ("/home/rnrf/stack0")
RIP: 0x55555555475a (<main+96>: xor    rdx,QWORD PTR fs:0x28)
R8 : 0x0 
R9 : 0x0 
R10: 0x555555756010 --> 0x0 
R11: 0x246 
R12: 0x5555555545f0 (<_start>: xor    ebp,ebp)
R13: 0x7fffffffe0c0 --> 0x1 
R14: 0x0 
R15: 0x0
EFLAGS: 0x206 (carry PARITY adjust zero sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x55555555474c <main+82>: call   0x5555555545b0 <puts@plt>
   0x555555554751 <main+87>: mov    eax,0x0
   0x555555554756 <main+92>: mov    rdx,QWORD PTR [rbp-0x8]
=> 0x55555555475a <main+96>: xor    rdx,QWORD PTR fs:0x28
   0x555555554763 <main+105>: je     0x55555555476a <main+112>
   0x555555554765 <main+107>: call   0x5555555545c0 <__stack_chk_fail@plt>
   0x55555555476a <main+112>: leave  
   0x55555555476b <main+113>: ret
[------------------------------------stack-------------------------------------]
0000| 0x7fffffffdf70 --> 0x7fffffffe0c8 --> 0x7fffffffe3fc ("/home/rnrf/stack0")
0008| 0x7fffffffdf78 --> 0x1756e6547 
0016| 0x7fffffffdf80 --> 0x9 ('\t')
0024| 0x7fffffffdf88 --> 0xf7dd7660 
0032| 0x7fffffffdf90 --> 0x7f0041414141 
0040| 0x7fffffffdf98 --> 0xf0b5ff 
0048| 0x7fffffffdfa0 --> 0x1 
0056| 0x7fffffffdfa8 --> 0x5555555547bd (<__libc_csu_init+77>: add    rbx,0x1)
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value

Breakpoint 1, 0x000055555555475a in main ()
-> And you can see what's displayed in some kind of mapped memory.
-> find 0x28889b47dbba3f00
Searching for '0x44ff012f21dba000' in: None ranges
Found 2 results, display max 2 items:
 mapped : 0x7ffff7fe04e8 --> 0x44ff012f21dba000  # Cookie on stack and somewhere else!
[stack] : 0x7fffffffdfd8 --> 0x44ff012f21dba000
-> And if you check the memory map, it's included here.
-> And that's actually where "fs" points.
-> info proc mappings
process 2114
Mapped address spaces:

          Start Addr           End Addr       Size     Offset objfile
      0x555555554000     0x555555555000     0x1000        0x0 /home/rnrf/stack0
      0x555555754000     0x555555755000     0x1000        0x0 /home/rnrf/stack0
      0x555555755000     0x555555756000     0x1000     0x1000 /home/rnrf/stack0
      0x555555756000     0x555555777000    0x21000        0x0 [heap]
      0x7ffff79e4000     0x7ffff7bcb000   0x1e7000        0x0 /lib/x86_64-linux-gnu/libc-2.27.so
      0x7ffff7bcb000     0x7ffff7dcb000   0x200000   0x1e7000 /lib/x86_64-linux-gnu/libc-2.27.so
      0x7ffff7dcb000     0x7ffff7dcf000     0x4000   0x1e7000 /lib/x86_64-linux-gnu/libc-2.27.so
      0x7ffff7dcf000     0x7ffff7dd1000     0x2000   0x1eb000 /lib/x86_64-linux-gnu/libc-2.27.so
      0x7ffff7dd1000     0x7ffff7dd5000     0x4000        0x0 
      0x7ffff7dd5000     0x7ffff7dfc000    0x27000        0x0 /lib/x86_64-linux-gnu/ld-2.27.so
      0x7ffff7fdf000     0x7ffff7fe1000     0x2000        0x0  # ???
      0x7ffff7ff8000     0x7ffff7ffb000     0x3000        0x0 [vvar]
      0x7ffff7ffb000     0x7ffff7ffc000     0x1000        0x0 [vdso]
      0x7ffff7ffc000     0x7ffff7ffd000     0x1000    0x27000 /lib/x86_64-linux-gnu/ld-2.27.so
      0x7ffff7ffd000     0x7ffff7ffe000     0x1000    0x28000 /lib/x86_64-linux-gnu/ld-2.27.so
      0x7ffff7ffe000     0x7ffff7fff000     0x1000        0x0 
      0x7ffffffde000     0x7ffffffff000    0x21000        0x0 [stack]
  0xffffffffff600000 0xffffffffff601000     0x1000        0x0 [vsyscall]
-> For example, this value can now be overwritten with hexadecimal "41", so it is capital "AAAAAAAAAAAA".
-> break *0x0000555555554712
-> r
Starting program: /home/rnrf/stack0 

[----------------------------------registers-----------------------------------]
RAX: 0x735ed7281f7bb400 
RBX: 0x0 
RCX: 0x555555554770 (<__libc_csu_init>: push   r15)
RDX: 0x7fffffffe0d8 --> 0x7fffffffe40e ("CLUTTER_IM_MODULE=xim")
RSI: 0x7fffffffe0c8 --> 0x7fffffffe3fc ("/home/rnrf/stack0")
RDI: 0x1 
RBP: 0x7fffffffdfe0 --> 0x555555554770 (<__libc_csu_init>: push   r15)
RSP: 0x7fffffffdf70 --> 0x7fffffffe0c8 --> 0x7fffffffe3fc ("/home/rnrf/stack0")
RIP: 0x555555554712 (<main+24>: mov    QWORD PTR [rbp-0x8],rax)
R8 : 0x7ffff7dd0d80 --> 0x0 
R9 : 0x7ffff7dd0d80 --> 0x0 
R10: 0x0 
R11: 0x0 
R12: 0x5555555545f0 (<_start>: xor    ebp,ebp)
R13: 0x7fffffffe0c0 --> 0x1 
R14: 0x0 
R15: 0x0
EFLAGS: 0x202 (carry parity adjust zero sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x555555554702 <main+8>: mov    DWORD PTR [rbp-0x64],edi
   0x555555554705 <main+11>: mov    QWORD PTR [rbp-0x70],rsi
   0x555555554709 <main+15>: mov    rax,QWORD PTR fs:0x28
=> 0x555555554712 <main+24>: mov    QWORD PTR [rbp-0x8],rax
   0x555555554716 <main+28>: xor    eax,eax
   0x555555554718 <main+30>: mov    DWORD PTR [rbp-0x54],0x0
   0x55555555471f <main+37>: lea    rax,[rbp-0x50]
   0x555555554723 <main+41>: mov    rdi,rax
[------------------------------------stack-------------------------------------]
0000| 0x7fffffffdf70 --> 0x7fffffffe0c8 --> 0x7fffffffe3fc ("/home/rnrf/stack0")
0008| 0x7fffffffdf78 --> 0x1756e6547 
0016| 0x7fffffffdf80 --> 0x9 ('\t')
0024| 0x7fffffffdf88 --> 0x7ffff7dd7660 (<dl_main>: push   rbp)
0032| 0x7fffffffdf90 --> 0x7fffffffdff8 --> 0x7fffffffe0c8 --> 0x7fffffffe3fc ("/home/rnrf/stack0")
0040| 0x7fffffffdf98 --> 0xf0b5ff 
0048| 0x7fffffffdfa0 --> 0x1 
0056| 0x7fffffffdfa8 --> 0x5555555547bd (<__libc_csu_init+77>: add    rbx,0x1)
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value

Breakpoint 2, 0x0000555555554712 in main ()
-> find 0x735ed7281f7bb400 # changing original cookie value
Searching for '0x735ed7281f7bb400' in: None ranges
Found 1 results, display max 1 items:
mapped : 0x7ffff7fe04e8 --> 0x735ed7281f7bb400
-> set {long}0x7ffff7fe04e8=0x4141414141414141 # overwrite original cookie
-> x/gx 0x7ffff7fe04e8
0x7ffff7fe04e8: 0x4141414141414141
-> c
Continuing.
-> AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA # overwrite cookie on stack
Try again?

[----------------------------------registers-----------------------------------]
RAX: 0x0 
RBX: 0x0 
RCX: 0x7ffff7af4154 (<__GI___libc_write+20>: cmp    rax,0xfffffffffffff000)
RDX: 0x4141414141414141 ('AAAAAAAA') # overflowed
RSI: 0x555555756670 ("Try again?\n")
RDI: 0x1 
RBP: 0x7fffffffdfe0 ('A' <repeats 34 times>)
RSP: 0x7fffffffdf70 --> 0x7fffffffe0c8 --> 0x7fffffffe3fc ("/home/rnrf/stack0")
RIP: 0x55555555475a (<main+96>: xor    rdx,QWORD PTR fs:0x28)
R8 : 0x0 
R9 : 0x0 
R10: 0x555555756010 --> 0x0 
R11: 0x246 
R12: 0x5555555545f0 (<_start>: xor    ebp,ebp)
R13: 0x7fffffffe0c0 --> 0x1 
R14: 0x0 
R15: 0x0
EFLAGS: 0x206 (carry PARITY adjust zero sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x55555555474c <main+82>: call   0x5555555545b0 <puts@plt>
   0x555555554751 <main+87>: mov    eax,0x0
   0x555555554756 <main+92>: mov    rdx,QWORD PTR [rbp-0x8] # compare cookie on stack with original value
=> 0x55555555475a <main+96>: xor    rdx,QWORD PTR fs:0x28
   0x555555554763 <main+105>: je     0x55555555476a <main+112>
   0x555555554765 <main+107>: call   0x5555555545c0 <__stack_chk_fail@plt>
   0x55555555476a <main+112>: leave  
   0x55555555476b <main+113>: ret
[------------------------------------stack-------------------------------------]
0000| 0x7fffffffdf70 --> 0x7fffffffe0c8 --> 0x7fffffffe3fc ("/home/rnrf/stack0")
0008| 0x7fffffffdf78 --> 0x1756e6547 
0016| 0x7fffffffdf80 --> 0x9 ('\t')
0024| 0x7fffffffdf88 --> 0xf7dd7660 
0032| 0x7fffffffdf90 ('A' <repeats 114 times>)
0040| 0x7fffffffdf98 ('A' <repeats 106 times>)
0048| 0x7fffffffdfa0 ('A' <repeats 98 times>)
0056| 0x7fffffffdfa8 ('A' <repeats 90 times>)
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value

Breakpoint 1, 0x000055555555475a in main ()
-> If you continue to enter a lot of data, you will overwrite the cookies.
-> And when we continue and enter a lot of data, a lot of As we will overwrite the cookie on the stack with hex 414141.
-> And when we now reach the end of the function the stack cookie value was obviously by us with 41414141.
-> But we also just set by hand the original value of the stack cookie to 41414.
-> And even though we cannot inspect and see where "fs" points to, the CPU knows where value is and will compare those two now.
-> x/gx 0x7ffff7fe04e8
0x7ffff7fe04e8: 0x4141414141414141
-> si

[----------------------------------registers-----------------------------------]
RAX: 0x0 
RBX: 0x0 
RCX: 0x7ffff7af4154 (<__GI___libc_write+20>: cmp    rax,0xfffffffffffff000)
RDX: 0x0 
RSI: 0x555555756670 ("Try again?\n")
RDI: 0x1 
RBP: 0x7fffffffdfe0 ('A' <repeats 34 times>)
RSP: 0x7fffffffdf70 --> 0x7fffffffe0c8 --> 0x7fffffffe3fc ("/home/rnrf/stack0")
RIP: 0x555555554763 (<main+105>: je     0x55555555476a <main+112>)
R8 : 0x0 
R9 : 0x0 
R10: 0x555555756010 --> 0x0 
R11: 0x246 
R12: 0x5555555545f0 (<_start>: xor    ebp,ebp)
R13: 0x7fffffffe0c0 --> 0x1 
R14: 0x0 
R15: 0x0
EFLAGS: 0x246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x555555554751 <main+87>: mov    eax,0x0
   0x555555554756 <main+92>: mov    rdx,QWORD PTR [rbp-0x8]
   0x55555555475a <main+96>: xor    rdx,QWORD PTR fs:0x28
=> 0x555555554763 <main+105>: je     0x55555555476a <main+112>
 | 0x555555554765 <main+107>: call   0x5555555545c0 <__stack_chk_fail@plt>
 | 0x55555555476a <main+112>: leave
 | 0x55555555476b <main+113>: ret
 | 0x55555555476c: nop    DWORD PTR [rax+0x0]
 |->   0x55555555476a <main+112>: leave  
       0x55555555476b <main+113>: ret
       0x55555555476c: nop    DWORD PTR [rax+0x0]
       0x555555554770 <__libc_csu_init>: push   r15
                                                                  JUMP is taken
[------------------------------------stack-------------------------------------]
0000| 0x7fffffffdf70 --> 0x7fffffffe0c8 --> 0x7fffffffe3fc ("/home/rnrf/stack0")
0008| 0x7fffffffdf78 --> 0x1756e6547 
0016| 0x7fffffffdf80 --> 0x9 ('\t')
0024| 0x7fffffffdf88 --> 0xf7dd7660 
0032| 0x7fffffffdf90 ('A' <repeats 114 times>)
0040| 0x7fffffffdf98 ('A' <repeats 106 times>)
0048| 0x7fffffffdfa0 ('A' <repeats 98 times>)
0056| 0x7fffffffdfa8 ('A' <repeats 90 times>)
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
0x0000555555554763 in main ()
-> (Enter Key*3)

Program received signal SIGSEGV, Segmentation fault.

[----------------------------------registers-----------------------------------]
RAX: 0x0 
RBX: 0x0 
RCX: 0x7ffff7af4154 (<__GI___libc_write+20>: cmp    rax,0xfffffffffffff000)
RDX: 0x0 
RSI: 0x555555756670 ("Try again?\n")
RDI: 0x1 
RBP: 0x4141414141414141 ('AAAAAAAA')
RSP: 0x7fffffffdfe8 ('A' <repeats 26 times>)
RIP: 0x55555555476b (<main+113>: ret)
R8 : 0x0 
R9 : 0x0 
R10: 0x555555756010 --> 0x0 
R11: 0x246 
R12: 0x5555555545f0 (<_start>: xor    ebp,ebp)
R13: 0x7fffffffe0c0 --> 0x1 
R14: 0x0 
R15: 0x0
EFLAGS: 0x10246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x555555554763 <main+105>: je     0x55555555476a <main+112>
   0x555555554765 <main+107>: call   0x5555555545c0 <__stack_chk_fail@plt>
   0x55555555476a <main+112>: leave  
=> 0x55555555476b <main+113>: ret    
   0x55555555476c: nop    DWORD PTR [rax+0x0]
   0x555555554770 <__libc_csu_init>: push   r15
   0x555555554772 <__libc_csu_init+2>: push   r14
   0x555555554774 <__libc_csu_init+4>: mov    r15,rdx
[------------------------------------stack-------------------------------------]
0000| 0x7fffffffdfe8 ('A' <repeats 26 times>)
0008| 0x7fffffffdff0 ('A' <repeats 18 times>)
0016| 0x7fffffffdff8 ("AAAAAAAAAA")
0024| 0x7fffffffe000 --> 0x100004141 
0032| 0x7fffffffe008 --> 0x5555555546fa (<main>: push   rbp)
0040| 0x7fffffffe010 --> 0x0 
0048| 0x7fffffffe018 --> 0x6582bf42f987be8a 
0056| 0x7fffffffe020 --> 0x5555555545f0 (<_start>: xor    ebp,ebp)
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
0x000055555555476b in main ()
-> And not suprisingly we continue to the return and get a segfault.
-> Instead of going to the stack_check_fail.
-> This means we actually have changed the original value of the stack cookie.
-> But you see it’s not really a bypass for cookies, it doesn’t help us in this particular case and magically make it exploitable.
-> We are just playing around with it to understand it better.
-> And we know that the original stack cookie value is stored somewhere in memory.
-> So those cookies serve a precise purpose, but it’s not the magic medicine that stops every exploit attempt.
-> But now you have a better understand of the limitations of stack cookies, they are just a value on the stack which are placed there at the beginning of a function and compared to the original value before the function returns.
-> This means we can overwrite the return pointer on the stack, but the issue is, that the function will never return because the cookie is wrong.
-> And if there are other variables on the stack before the cookie they could all be still overwritten.
-> So it actually just kinda protects you from smashing the return pointer for a classic buffer overflow.
-> It only stops the function form returning, but it might not stop other side effects due to things overwritten on the stack.
-> So in our case, theoretically if the modified variable would have been placed after the buffer, we could have still overwritten it without ever writing so far that we overwrite the stack cookie.
-> But the compiler developers know that buffer overflows are a common thing, so they buffers to be as close as possible to the stack cookie.
-> Which causes the modified and buffer variable to be reordered in this way.
-> The buffer is placed after the modified variable, closer to the cookie.

: There is another interesting thing about stack cookies.
-> Let’s rerun the program and collect a few random cookies.
-> gdb stack0
-> r
-> disassemble main
Dump of assembler code for function main:
   0x00005555555546fa <+0>: push   rbp
   0x00005555555546fb <+1>: mov    rbp,rsp
   0x00005555555546fe <+4>: sub    rsp,0x70
   0x0000555555554702 <+8>: mov    DWORD PTR [rbp-0x64],edi
   0x0000555555554705 <+11>: mov    QWORD PTR [rbp-0x70],rsi
   0x0000555555554709 <+15>: mov    rax,QWORD PTR fs:0x28
   0x0000555555554712 <+24>: mov    QWORD PTR [rbp-0x8],rax
   0x0000555555554716 <+28>: xor    eax,eax
   0x0000555555554718 <+30>: mov    DWORD PTR [rbp-0x54],0x0
   0x000055555555471f <+37>: lea    rax,[rbp-0x50]
   0x0000555555554723 <+41>: mov    rdi,rax
   0x0000555555554726 <+44>: mov    eax,0x0
   0x000055555555472b <+49>: call   0x5555555545d0 <gets@plt>
   0x0000555555554730 <+54>: mov    eax,DWORD PTR [rbp-0x54]
   0x0000555555554733 <+57>: test   eax,eax
   0x0000555555554735 <+59>: je     0x555555554745 <main+75>
   0x0000555555554737 <+61>: lea    rdi,[rip+0xba]        # 0x5555555547f8
   0x000055555555473e <+68>: call   0x5555555545b0 <puts@plt>
   0x0000555555554743 <+73>: jmp    0x555555554751 <main+87>
   0x0000555555554745 <+75>: lea    rdi,[rip+0xd5]        # 0x555555554821
   0x000055555555474c <+82>: call   0x5555555545b0 <puts@plt>
   0x0000555555554751 <+87>: mov    eax,0x0
   0x0000555555554756 <+92>: mov    rdx,QWORD PTR [rbp-0x8]
   0x000055555555475a <+96>: xor    rdx,QWORD PTR fs:0x28
   0x0000555555554763 <+105>: je     0x55555555476a <main+112>
   0x0000555555554765 <+107>: call   0x5555555545c0 <__stack_chk_fail@plt>
   0x000055555555476a <+112>: leave  
   0x000055555555476b <+113>: ret    
End of assembler dump.
-> break *0x0000555555554712
-> r
-> p $rax
$1 = 0x7633afa886b22300
-> r
-> p $rax
$2 = 0xaf4c4ea1f9c8d300
-> r
-> p $rax
$3 = 0x82655930fbefc700
-> r
-> p $rax
$4 = 0x59ef3b92b7153000
-> r
-> p $rax
$5 = 0xcd5f563548dde000
-> Do you notice something, they all start with a “0” byte. 
$1 = 0x7633afa886b22300
$2 = 0xaf4c4ea1f9c8d300
$3 = 0x82655930fbefc700
$4 = 0x59ef3b92b7153000
$5 = 0xcd5f563548dde000
-> So this is the little endian format but in memory the bytes would look like this.
-> $5 = 00 e0 dd 48 35 56 5f cd ( 1byte + 7bytes) # too much to bruteforce
-> Why would they not use all 8 bytes for random values but compromise one of these bytes be a static 0.
-> Doesn’t that make it weaker, because now you only have to bruteforce, eh guess, 7 bytes?
-> There are obviously various ways how you can attack a stack cookie, it obviously should not be guessable or bruteforcable, but 7 bytes is huuuuge number already. So probably good enough.
-> But as you know there are a lot of ways to leak values from memory for example with format string exploits.
-> So you use that to leak a stack cookie value and then your overflow is trivial again.
-> But some overflows happen because of a strcpy. And strings in C are zero terminated.
-> So even if you would know the stack cookie, and you have a vulnerable strcpy, you can never overwrite the cookie with the corerct value, because you cannot write a 0 byte.
-> Because a null byte marks the end of a string in c.
-> But in our example uses gets() and according to the man page you can see that gets only stops at a newline, so you could write 0 bytes with that.
-> So it’s a very clever choice to include a 0 byte in the cookie.
-> It’s an additional protection against strcpys, even if the cookie value is known.
-> But maybe you ask yourself now, what about 32bit?
-> Is there also a byte used for a null byte?
: Let’s find out.
-> To compile a 32bit program on 64bit you have to install some other stuff.
-> sudo apt-get install gcc-multilib
-> And we can also quickly check if this is not exploitable.
-> gcc -m32 stack0.c -o stack0_32
stack0.c: In function ‘main’:
stack0.c:11:3: warning: implicit declaration of function ‘gets’; did you mean ‘fgets’? [-Wimplicit-function-declaration]
   gets(buffer);
   ^~~~
   fgets
/tmp/ccli6vb9.o: In function `main':
stack0.c:(.text+0x3f): warning: the `gets' function is dangerous and should not be used.
-> And you can see that we also only get the stack smash protection error.
-> ./stack0_32
AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDDAAAAAAAABBBBBBBBCCCCCCCCDDDDDDDDEEEEEEEE
Try again?
*** stack smashing detected ***: <unknown> terminated
중지됨 (core dumped)
-> ./stack0_32
AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDDAAAAAAAABBBBBBBBCCCCCCCCDDDDDDDDEEEE    
Try again?
*** stack smashing detected ***: <unknown> terminated
중지됨 (core dumped)
-> ./stack0_32
AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDDAAAAAAAABBBBBBBBCCCCCCCCDDDDDDDDE   
Try again?
*** stack smashing detected ***: <unknown> terminated
-> ./stack0_32
AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDDAAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD 
Try again?
-> So let’s extract some stack cookies here.
-> gdb ./stack0_32
-> break *0
-> r
-> disassemble main
Dump of assembler code for function main:
   0x5655559d <+0>: lea    ecx,[esp+0x4]
   0x565555a1 <+4>: and    esp,0xfffffff0
   0x565555a4 <+7>: push   DWORD PTR [ecx-0x4]
   0x565555a7 <+10>: push   ebp
   0x565555a8 <+11>: mov    ebp,esp
   0x565555aa <+13>: push   ebx
   0x565555ab <+14>: push   ecx
   0x565555ac <+15>: sub    esp,0x60
   0x565555af <+18>: call   0x565554a0 <__x86.get_pc_thunk.bx>
   0x565555b4 <+23>: add    ebx,0x1a1c
   0x565555ba <+29>: mov    eax,ecx
   0x565555bc <+31>: mov    eax,DWORD PTR [eax+0x4]
   0x565555bf <+34>: mov    DWORD PTR [ebp-0x5c],eax
   0x565555c2 <+37>: mov    eax,gs:0x14
   0x565555c8 <+43>: mov    DWORD PTR [ebp-0xc],eax
   0x565555cb <+46>: xor    eax,eax
   0x565555cd <+48>: mov    DWORD PTR [ebp-0x50],0x0
   0x565555d4 <+55>: sub    esp,0xc
   0x565555d7 <+58>: lea    eax,[ebp-0x4c]
   0x565555da <+61>: push   eax
   0x565555db <+62>: call   0x56555410 <gets@plt>
   0x565555e0 <+67>: add    esp,0x10
   0x565555e3 <+70>: mov    eax,DWORD PTR [ebp-0x50]
   0x565555e6 <+73>: test   eax,eax
   0x565555e8 <+75>: je     0x565555fe <main+97>
   0x565555ea <+77>: sub    esp,0xc
   0x565555ed <+80>: lea    eax,[ebx-0x1900]
   0x565555f3 <+86>: push   eax
   0x565555f4 <+87>: call   0x56555430 <puts@plt>
   0x565555f9 <+92>: add    esp,0x10
   0x565555fc <+95>: jmp    0x56555610 <main+115>
   0x565555fe <+97>: sub    esp,0xc
   0x56555601 <+100>: lea    eax,[ebx-0x18d7]
   0x56555607 <+106>: push   eax
   0x56555608 <+107>: call   0x56555430 <puts@plt>
   0x5655560d <+112>: add    esp,0x10
   0x56555610 <+115>: mov    eax,0x0
   0x56555615 <+120>: mov    edx,DWORD PTR [ebp-0xc]
   0x56555618 <+123>: xor    edx,DWORD PTR gs:0x14
   0x5655561f <+130>: je     0x56555626 <main+137>
   0x56555621 <+132>: call   0x565556a0 <__stack_chk_fail_local>
   0x56555626 <+137>: lea    esp,[ebp-0x8]
   0x56555629 <+140>: pop    ecx
   0x5655562a <+141>: pop    ebx
   0x5655562b <+142>: pop    ebp
   0x5655562c <+143>: lea    esp,[ecx-0x4]
   0x5655562f <+146>: ret    
End of assembler dump.
-> p $eax
$1 = 0xf7ffd920 (= 20 d9 ff f7 = 1byte + 3bytes) # probably exploitable on 32bit
-> You can also see that a different segment register is used here on 32bit.
-> But same concept.
-> And who would have thought. Also a 0 byte in it.
-> So this makes only 3 bytes of randomness.
-> 16 million possible values.
-> <painful noise> mhmh. That sounds a bit more scary. 
-> 16 million depending on the context where and how the program is run is not much.
-> Maybe in our case it might actually make it exploitable.
-> I mean the original protostar VM was also 32bit, so I think it’s fair game.
-> But to be fair, 64bit probably makes it unexploitable.

: The PLAN…(So the plan is clear.)
-> We write a program that calls this 32bit version of stack level 0 all the time and send an exploit string to it, which uses random cookie cookie values to bruteforce it.
-> And at some point we might get lucky, guessed the correct cookie value, overflow the pointer and redirect code execution to the output, the if case, we want.
-> exec ./stack0_32
-> write “AAAAAAA…”
-> That could work!
-> We will need a bit more time for this so let’s do it in another video.
-> But it’s a fun challenge, so you should try that too.(= try it yourself!)

: Content
-> Stack Cookie

: Tips.
-> Installation “peda”
-> git clone https://github.com/longld/peda.git ~/peda
-> echo “source ~/peda/peda.py” >> ~/.gdbinit
-> echo “DONE! debug your program with gdb and enjoy”
-> Installation “gcc-multilib”
-> 64bit Changed 32bit

: The Plan
-> exec ./stack0_32
-> write “AAAAAAAA…”