Hacker News new | ask | show | jobs
by saagarjha 2359 days ago
> It seems like it's mostly useful for cases where people are blocking the ptrace syscall (like Docker's default syscall filter, maybe?) and not loading an LSM.

It’s a shot in the dark, but I’d guess this is designed to work with programs that neuter themselves or commit suicide if you ptrace them, as is common for mildly sophisticated malware or (less often) CTF challenges.

1 comments

How do you detect that you're being ptraced? I see the link to https://www.aldeid.com/wiki/Ptrace-anti-debugging in the README, but

a) the program has to actively run its check while being ptraced to notice. If you attach to the program (which pauses it), inject your code, run your code, and then detach, the program's own code will not notice it's being ptraced, no?

b) if you want to run the program's own code while being ptraced, can't you just stop on the ptrace syscall and lie about its result? I think `strace -e inject=ptrace:errno=0` will avoid the program in that wiki page from realizing it's being traced. (You can use seccomp-bpf for this if you don't want to take the performance overhead of stopping on every syscall.)

> a) the program has to actively run its check while being ptraced to notice. If you attach to the program (which pauses it), inject your code, run your code, and then detach, the program's own code will not notice it's being ptraced, no?

Depends on if all threads were put into a paused state. Also, the program that's being debugged might have spawned some additional processes that will be checking if the parent is being ptraced.

Replace "self" with the PID you want to check if it is being traced:

  $ cat /proc/self/status  | grep Tracer                                                                                                                                                                                                                                                                                                                                                                       
  TracerPid: 0
Ahhh, yes, it's probably hard to track down a random subprocess somewhere that's checking and then passing that info back to the original process. (I think the subprocess could even just try to PTRACE_ATTACH the original process and see if it works.)
Some of the detection methods methods were mentioned in a comment (here’s one more: timers), but I should also mention that some binaries try to resist ptrace attempts with ptrace(PTRACE_TRACEME, …) as well if you’re too slow to get in before that.
This might be off topic but I never really understood the utility of PTRACE_TRACEME. The documentation suggests that the parent must be a cooperating process (the wording "probably shouldn't" in the documentation is very suspicious). But if the parent knows it will ptrace the child, it could very well set up a pipe and have the child be blocked on it, then PTRACE_ATTACH, then unblock the child with the pipe.

As such, I never truly understood the semantics behind PTRACE_TRACEME, and I'm not sure what bad things will happen if you use that when the parent isn't expecting to ptrace the child.

As I understand it, PTRACE_TRACEME causes the process to be put into "traced" mode, where signals (and exec* calls, which will cause a SIGTRAP to be sent) cause the process to stop. This is useful in the context of a debugger because the debugger process will fork, the child will call ptrace(PTRACE_TRACEME, …) to put itself into "traced" mode, then exec the process you want to debug and be conveniently placed into ptrace stop at the first instruction to be executed in the new binary.

The problem with PTRACE_TRACEME is that if you do it to yourself and recieve a signal, you're put into ptrace stop there's and there's no way out of it unless the parent knows how to get you out of it (using ptrace, of course). Sending signals will not work, even SIGKILL; somewhat humorously, on iOS, if you attempt to do the equivalent (using the similar PT_TRACE_ME) and oops yourself, the entire system will slowly grind to a halt as it tries to (at least, I think…) SIGKILL your process for a variety of reasons and fails, at some point locking up waiting for process termination.