Resources

People often ask me "How did you learn how to hack?" The answer: by reading. This page is a collection of the blog posts and other articles that I have accumulated over the years of my journey. Enjoy!

PTrace Nightmare- 385

Linux OSPosted 5 Years Ago
  • The Ptrace API is how debuggers do what they do! Using this API, we can ask the kernel about information on another process. This API is very complicated and not the most well-documented. So, I wanted to add some personal notes on Ptrace while I have been dealing with it.
  • The core of the functionality can be found in the manual quite easily. But, the ptrace functionality is all in a single function! The first parameter is an ENUM that represents the call being made. The second is the PID and the next two are specific to the call being made.
  • Using this API, you can read/write registers and memory, pause execution, set breakpoints (kind of), send/view signals and set a bunch of flags for the connection. Usage of these functions is none trivial though; for instance, you have to get ALL registers, not just one.
  • Using this functionality, functions like backtrace, disassembly and other things are easy to implement. Adding in DWARF (debugging symbols) and ELF parsing, we can have source code level debugging too.
  • Breakpoints are complicated though... What we consider a breakpoint would be considered a watchpoint by the hardware. Linux x86 does not allow for setting the actual breakpoint hardware; instead, we have to modify the code (in the debuggee) to interrupt once it hits the line of code we are debugging.
  • To handle breakpoints (in the debugger), the function waitpid is used. This function stops once the process has changed state (crashed, breakpoint, start, etc.).
  • Ptrace on Linux is super buggy though. Here are a few things to consider:
    • Can only handle one threat at a time. I have no idea how GDB handles multi-threaded processes.
    • Does not have direct support for memory information about the process. Instead, /proc must be used. This is extremely annoying and tedious to work with.
    • I could never get the signal display working for waitpid. I have no idea why.
  • Clearly, being able to read from the memory of another process would cause a major security issue. Because of this, a few special security precautions have been added to this:
    • You cannot ptrace setuid binaries.
    • A special configuration file was created in order to specify WHO can attach to processes: ptrace_scope.
  • Prior to ptrace_scope malware was used to inject code into processes! Because of this, special permissions were added to who can and cannot use ptrace_scope.
    • 0 - classic ptrace permissions allow attaching to ANY process with the same UID
    • 1 - A process must have a predefined relationship, usually a parent-child relationship.
    • 2 - Admin only attaching. The user must have the CAP_SYS_PTRACE capability.
    • 3 - No attaching for debugging at all. Once set, this value CANNNOT be changed.
  • Besides the ptrace_scope, setuid processes cannot be debugged with ptrace to prevent easy privilege escalation. You can even ptrace your parent in some cases!
  • Next time you use GDB just think about how vastly complicated it actually is! I have a new-found appreciation of GDB after trying to make my own debugger.