top | item 40843160

(no title)

qweqwe14 | 1 year ago

In case you're interested, it's usually done via ptrace by attaching to every process and modifiying the syscall arguments every time it makes one. There are performance issues associated with that (ptracing is rather expensive) and IMO it's more complex than LD_PRELOAD. Furthermore, ptrace may be disabled altogether on some installations, even for root. See yama_ptrace_scope

I wouldn't say it's a practical approach. Works for a cool demo, sure, but as an adversary I would be hesitant to use this widely.

discuss

order

grugq|1 year ago

And you can detect when you are being ptrace()d because a process cannot be ptrace()d twice. Unless they changed Linux again.

There are also timing issues that show up, and you can do any number of anti-debugging tricks which would reveal that the environment is being manipulated. Which is an instant red flag.

In general if the attacker is running at the same privilege level, you can probably evade it or at least detect it. I’m somewhat surprised there isn’t a basic forensics tool that automates all of these tests already.

“sus: [-h] [-v] [-V] [-o file] [-O format]

Sus tests for common indicators of compromise using on generic tests for common methods of implementing userland rootkits. It will check for LD_PRELOAD, ptrace(), inotify() and verify the system binaries match the upstream distribution hashsums. It can be used to dump the file system directly (warning, slow!) for comparison against the output of `find`. See EXAMPLES for more.”

Implementation is left as an exercise for the reader.

qweqwe14|1 year ago

There's also TracerPid field in /proc/PID/status, which is non-zero when a process is being ptraced

> Sus tests for common indicators of compromise

There's a lot of stuff that Linux malware tends to do that almost no legitimate program does, this can be incorporated into the tool. Just off the top of my head, some botnet clients delete their executable after launch, in addition to being statically linked, which is an almost 100% guarantee that it's malware.

Check for deleted executables: ls -l /proc/*/task/*/exe 2>/dev/null | grep ' \(deleted\)$'

(not really reliable) check for statically linked running programs: wc -c $(grep -L libc /proc/*/task/*/maps 2>dev/null) 2>/dev/null | grep -v '^0 '

Although a malicious process can just mmap libc for giggles, and also theoretically libc can be named in a way that doesn't contain "libc". A more reliable method is parsing the ELF header in /proc/PID/exe to determine if there's an ELF interpreter defined.

You can also check for processes that trace themselves (TracerPid in status == process id), this is a common anti-debug tactic.

You can also hide the process by mounting a tmpfs on top of it's proc directory, tools like ps ignore empty proc directories due to the possibility that the process has terminated but it's proc directory is still around. This is obviously easily detectable by checking /proc/mounts or just listing empty directories with numeric names in /proc

Another heuristic can be checking /proc/PID/cmdline for two NUL bytes in a row, some malware tries to change it's process name and arguments by modifying the argv array, however they are unable to change the size of cmdline, hence having multiple NUL bytes is a viable detection mechanism. Legitimate programs do this too, but it's rather uncommon.

You can obviously combine these heuristics to make a decision whether the process is malicious, as by themselves they aren't very reliable

blincoln|1 year ago

I am reasonably sure that the intended behaviour of Linux is that a process can only be ptraced by one other process level at a time.

However, a few years ago, I discovered that a process inside a container being ptraced could be ptraced by a second process running as root at the host level.[1][2] I don't know if that's been patched away since then, but my assumption at the time was that it meant that the "there can be only one" aspect of ptrace was more of an arbitrary decision, not a hard limit.

[1] https://assets.bishopfox.com/prod-1437/Documents/Guides/2022...

[2] I'm not sure if the "double ptrace" scenario made it into the final document, but it's the same techniques discussed in there, just attach a tracer to the containerized process from inside the container before you attach gdb or asminject.py from outside of the container.

kuskosho|1 year ago

I cannot find any reference to sus project, care to link some?