Evasion
Evasion and countermeasures to various exploit mitigation mechanisms.
ASLR
Unknown libc version
Database of known offsets in libc packages Another interface to that database
So you've leaked a libc address, but you don't know the distance to system
?
Application pointer leak
A stack or .text pointer certainly is most useful. If you can locate libc, you're ready to go.
Craft a string without a NULL terminator and see what falls out!
Allocate a buffer but never write to it. See what it contains!
Format string vulnerability
On x86-64, arguments 7 and onward are on the stack. Use GDB to find offsets with interesting values. You can often score a stack address (local vars used as parameters), a .text address (return back into main
for example) and a .libc address (return from main
into __libc_start_main
) all at once! If you're out of ideas, you can also see the environment variables passed to main
on the stack.
Overwrite only a partial address
If your write primitive is limited, perhaps you can get away with only slightly overwriting an address in .got
or the like. Little-endian can be a blessing.
Massage ASLR first
Typically, the base of libc
is not only random, but the lowest 12 bits are uneven. If you have a complete libc leak but a write primitive limited to a single byte, you might try to restart the application until you have a nice predictable third nibble.
Forking server
Parent and Child processes share the same ASLR allcations (app and libraries are mapped identically). If you crash the child while leaking pointers, no worries! Just spawn a new one and keep working!
Get mmap()
to allocate next to another segment
mmap()
to allocate next to another segmentIt seems that the heap allocator likes to snug up against other allocated memory...?
Use malloc()
to infer empty spaces
malloc()
to infer empty spacesFinding the stack via libc
If you've leaked libc, it contains a global variable pointing to the env data, which is on the stack.
NX bit
mprotect
shellcode to be executable
mprotect
shellcode to be executableNX binaries never have Write and eXecute permissions on the same memory page. If we can call mprotect
, that can be adjusted.
Invoke _dl_make_stack_executable
_dl_make_stack_executable
This function is part of the GNU dynamic linker, but linked into some binaries for some weird reason. Maybe only in statically linked binaries? Does exactly what it looks like, and it's a wonderful way to get your shellcode running.
ROP
Use existing code instead. There's usually a pop rdi
gadget in libc which is useful to smuggle in a first argument.
SCOP
Tell me more (See paper 20:07)
Apparently, it's cool to reduce the amount of data hanging around in executable space.
Pointer Guard / pointer mangling
Use _dl_fini
to demangle function pointers
_dl_fini
to demangle function pointersThis is the function which calls .fini
pointers, and is sometimes registered with the exit handlers (see above). If glibc has pointer guard enabled, this can serve as a good known function pointer to calculate the guard value.
Stack Cookie/Canary
GCC uses a stack canary which contains (starts with) a NULL byte.
Format string vulnerability
printf("%1337$lx")
If you're able to print anything that's on the stack, why not the cookie?
Uninitialized stack buffers
If you can leak an uninitialized stack buffer, maybe there's a cookie laying around there from something else that used to have that stack space?
scanf
is a possible vector for this
Forking server
Cookie is the same across parent and all child processes.
Syscall filters (seccomp)
Lesser-known syscalls like execveat
(via fexecve
)
execveat
(via fexecve
)If there's a syscall blocklist, maybe this one was forgotten? It's like execve
but works on an open file descriptor. Perhaps combine with memfd_create
which opens memory as a file descriptor. The "executable" can even be a shell script!
This broken writeup creates an "executable" with the target as a shebang #!/read_flag
in order to also circumvent AppArmor.
This syscall is only available on linux >= 3.19.
32-bit syscalls
If the challenge uses seccomp to limit syscalls, the filter may be faulty. Use seccomp-tools to dump the BNF filter and verify. x86 syscall numbers are not the same as x86_64, and execution can be switched to x86 mode (and thus the X32 ABI) by
If the seccomp filter explicitly checks architecture, 32-bit syscalls can still be accessed using syscall numbers + 0x40000000.
Last updated