I'm looking at a CVE for an old thrift shop router that amounts to a stack based buffer overflow with no NULL characters allowed. I can control the instruction pointer register as well as a few less useful registers. My goal is to perform a stack pivot to something I control. The router runs on MIPS big endian architecture so I can't leave the last 8 bits of a payload empty to get a leading NULL in an address. e.g. 0x00XXXXXX. I'm left to look for gadgets in shared objects (or the stack if cache flushed). I find that shared objects are generally loaded at higher addresses that make use of all 32 bits of the address. I cannot use gadgets from the vulnerable process because it was not compiled with -fpie and it loads at the same address with a leading NULL every time.

If I consistently want to be able to use gadgets in a shared object, it will need to be loaded with the same base address most of the time. Assuming no ASLR (not enabled on my router), what determines where a shared object will be loaded?

If I run ldd on the target binary, I get this:

$ mips-linux-ldd squashfs-root/sbin/my_binary
    /lib/ld-uClibc.so.0 => /lib/ld-uClibc.so.0 (0x00000000)

Not super useful. I know that ld-uClibc.so.0 doesn't get loaded at 0x00000000 and that there are several other libraries that get loaded for this process (not dlopen'ed) which are not listed. Perhaps the non-useful output is a toolchain thing or due to the fact that I'm not running on the target architecture.

Under the hood, I'd think we're looking at mmap logic.

I found this in an article from Oracle:

An executable or shared object file's base address is calculated during execution from three values: the memory load address, the maximum page size, and the lowest virtual address of a program's loadable segment

To me it seems like these things would never change when working with a specific firmware version where the binaries can always be expected to be the same.

My questions are:

  • Will shared objects get loaded in the same place every time on a Linux system with ASLR disabled?
    • Is the mapping deterministic?
  • What factors, if any will make the shared object map to a different address?
    • Perhaps 2 libraries conflict in a preferred address
  • Iff library loading is deterministic, can I assume the shared object will always be at the same address after checking once? The word deterministic answers my own question, but I want to be clear.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Browse other questions tagged or ask your own question.