binarystackbase-address

How to calculate start address of the stack of a pie binary on a system with full ASLR enabled?


I have a pie binary(ELF) with nx and pie bit enabled on a System with Full ASLR enabled. I have problem for finding out the stack's base address. I want to ret2mprotect and then ret2shellcode on the stack, but my exploit doesn't work because offset we use to calcuate stack's base address changes on every run of binary. Could you please help me to solve the problem?

Here is my vulnerable code:

#include <stdio.h>
int main(int argc,char* argv[]) {
        char buffer[256];
        printf(argv[1]);
        printf("\n");
        gets(buffer);
        return 0;
}

my compile command:

gcc -Wall -g -O0 -Wl,-rpath,./ -fcf-protection=none -fno-stack-protector -fpic vuln.c -o vuln

I got required leaked from this format-string(below value passed to the program): %1$p:%41$p 1st leak address is in range of stack. 41th leak address is in range of libc library.

I got this sample values to determine offset based on it: (ex means example)

exStackStart        =   0x7ffee8986000
exStackEnd          =   0x7ffee89a8000
exLibcStart         =   0x7fea59ec5000
exLibcEnd           =   0x7fea5a03d000
exGetsBuffer        =   0x7ffee89a5d50
exStackLeaked       =   0x7ffee89a5f48
exLibcLeaked        =   0x7fea59ec7083

offsetStackLeaked2StackEnd = exStackEnd - exStackLeaked
offsetStackLeaked2GetsBuffer = exStackLeaked - exGetsBuffer
offsetLibcLeaked2LibcStart = exLibcLeaked - exLibcStart
stackSize = exStackEnd - exStackStart

io = start()

output = str(io.recvuntil(b'\n')).split(':')
runStackLeaked = int(output[0][2:], 16)
runLibcLeaked = int(output[1][:-3], 16)
runStackEnd = runStackLeaked + offsetStackLeaked2StackEnd
runStackStartRaw = runStackEnd - stackSize
runStackStart = runStackStartRaw & (~4095)                       <====== here is the problem!  sometimes this is correct and sometimes this is 0x1000 or 0x2000 far from correct address
runGetsBuffer = runStackLeaked - offsetStackLeaked2GetsBuffer
runLibcStart = runLibcLeaked - offsetLibcLeaked2LibcStart

io.send(b'A' * 300 + b'\n')
io.interactive()

Update:

The vuln​ gives me a address which is in range of the stack(I've check using vmmap​ command in gdb​) using format string vulnerablitiy.

Full ASLR on my OS is enabled, so address of stack for my binary vary on each run of the binary, so I would like to achieve an offset that I can add/substract to/from leaked address and get to start of the stack(which vmmap​ show me).

I have checked the distance between the leaked address and start of the stack and take note it somewhere, so I want to automatically calculate start address of the stack just by adding/substracting the offset to/from the leaked address without manually check in gdb​.

but unfortunately the offset differs on every run of the binary, so the offset we achieved is not valid.

offset from leaked address to stack's start-address(got from gdb vmmap​):

(following numbers is in decimal)

run1: 127480

run2: 128584

run3: 130632

run4: 126008

run5: 127656

As you can see, the distance between the offset and start of the stack differs on each run.

What cause the problem and how to defeat(achieve/calulcate) it?

following two pictures are for two run of the program, but result is not like we expected. result of run1 result of run2

I expected the offset from start of the stack to any location in the stack is fixed but it vary for my binary each time, and As far as I know ASLR only affects base address of memory regions(like stack, heap, ...) and offset between the variable inside one memory area must be fixed.


Solution

  • The offset from the buffer to the start of the stack frame is indeed fixed. The offset from the buffer to the start of the stack is not consistent.