1

I'm learning about format string exploits, and am attempting to use one on an example program to overwrite the .fini_array section in virtual memory with a stack address containing shellcode (and hence redirect execution to the shellcode once main exits). Unfortunately, trying to write to this address raises a segmentation fault, and I have written the following program to try to understand what's going on. (Disclaimer, I am running x64 linux with ASLR disabled while I am learning.)

//fini_test.c
#include <stdio.h>
#define OFFSET 0x555555554000

int main(int argc, char **argv) {
    unsigned long int addr;
    char **ptr;
    static int canary=0xdeadbeef;

    if(argc<2) {
        printf("Usage: %s <position to write to in object file>\n", argv[0]);
        exit(0); }

    addr=stroul(argv[1], ptr, 16)+OFFSET;

    printf("[*] about to print\n");
    printf("writing to %p\n%n", (void *) addr, (int *) addr);
    printf("[*] print complete\n");
    printf("canary @ %p\t%d\t0x%08x\n\n", &canary, canary, canary);
    exit(0);
}

So, the program simply takes a position in the object file as a command line argument, and then writes some bytes to the corresponding position in the virtual memory space of the process. With GDB I found that the right offset between the location in the object file and the location in the virtual memory space was 0x555555554000.

I then compiled and used objdump to find the desired sections in the object file.

$gcc fini_test.c -o fini_test
$objdump -h ./fini_test
Sections:
Idx Name          Size      VMA               LMA               File off  Algn
...
 19 .fini_array   00000008  0000000000200da8  0000000000200da8  00000da8  2**3
                  CONTENTS, ALLOC, LOAD, DATA
...
 22 .data         00000014  0000000000201000  0000000000201000  00001000  2**3
                  CONTENTS, ALLOC, LOAD, DATA
...

So, the position of the .data section in ./fini_test is 0x201000 and the position of the .fini_array section is 0x200da8. I also noted that, like the .data section, the .fini_array section does not have a READONLY flag, so I assumed that I should be able to write to it with the appropriate command line argument. However, this is how execution behaved:

$./dtors_test 0x2010000
[*] about to print
writing to 0x555555755000
[*] print complete
canary @ 0x555555755010 -559038737  0xdeadbeef

$./dtors_test 0x201010
[*] about to print
writing to 0x555555755010
[*] print complete
canary @ 0x555555755010 26  0x0000001a

$./dtors_test 0x200da8
[*] about to print
writing to 0x555555754da8
Segmentation fault (core dumped)

First, to verify that my code and choice of OFFSET were right, I tried to overwrite the value of canary. As a first approximation I just inputted the position of the .data section, which was unsuccessful because – as inspecting the outputted address of canary shows – the value of canary is stored beneath the two pointers addr and ptr. Hence I inputted the position of the .data section plus 0x10 to account for this, and indeed successfully overwrote the value of canary with the expected value of 26 (precisely the number of bytes in the string "writing to 0x555555755010\n".)

So everything to that point is working as expected. However, I then try to write to the start of the .fini_array section* and a segmentation fault is raised. This surprises me because this section is not marked as READONLY in the object file; can anyone help me understand what's going on? Thank you in advance


*I know that destructor addresses are not stored at exactly the start of the .fini_array section, and so even if I could write to that address it would not yield the desired results. But for now, before I cross that bridge, I'm just trying to understand why I can't write to an address that seemingly does not have a READONLY flag enabled. As a broader question, general references to understanding how .fini_array works in ELF files would be greatly appreciated!

1 Answers1

1

you can use -Wl,-z,norelro to disable RELRO.

schroeder
  • 123,438
  • 55
  • 284
  • 319
FromNand
  • 11
  • 1