Evasion
Evasion and countermeasures to various exploit mitigation mechanisms.
Last updated
Evasion and countermeasures to various exploit mitigation mechanisms.
Last updated
of known offsets in libc packages to that database
So you've leaked a libc address, but you don't know the distance to system
?
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!
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.
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.
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.
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!
mmap()
to allocate next to another segmentIt seems that the heap allocator likes to snug up against other allocated memory...?
malloc()
to infer empty spacesIf you've leaked libc, it contains a global variable pointing to the env data, which is on the stack.
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.
_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.
Use existing code instead. There's usually a pop rdi
gadget in libc which is useful to smuggle in a first argument.
Apparently, it's cool to reduce the amount of data hanging around in executable space.
_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.
GCC uses a stack canary which contains (starts with) a NULL byte.
printf("%1337$lx")
If you're able to print anything that's on the stack, why not the cookie?
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?
Cookie is the same across parent and all child processes.
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 syscall is only available on linux >= 3.19.
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.
(See paper 20:07)
scanf
is a possible for this
creates an "executable" with the target as a shebang #!/read_flag
in order to also circumvent AppArmor.