Detecting the Presence of a Debugger in Linux, (Tue, Nov 19th)

SANS Internet Storm Center, InfoCON: green 2024-11-19

Hello from Singapore where I'm with Johannes and Yee! This week, I'm teaching FOR710[1]. I spotted another Python script that looked interesting because, amongst the classic detection of virtualized environments, it also tries to detect the presence of a debugger. The script has been developed to target both environments: Windows & Linux.

On Windows, it's pretty easy to detect if a debugger has been attached to a process. The microsoft ecosystems has many ways to check this: A stealthy method is to check the PEB ("Process Environment Block")[2] that provides a "BeingDebugged" member in its structure. Another easy way is to use the Microsoft API call IsDebuggerPresent()[3]. Note that they are a lot of alternative techniques but I won't cover them here.

But how does it work in Linux? Because the malicious script is compatible with Linux, let's check the code:

def check_debugging():
    if True:
        try:
            if CURRENT_OS == "Windows":
                if ctypes.windll.kernel32.IsDebuggerPresent():
                    return True
            else:
                import re
                with open('/proc/self/status') as f:
                    status = f.read()
                    if re.search(r'TracerPid:\s+(?!0\n)', status):
                        return True
                except:
                    pass
    return False

If the script is executed on Windows, IsDebuggerPresent() will be called otherwise, the script will search for an interesting string in /proc/self/status:

xavier@rog:/proc/self$ cat status
Name:   bash
Umask:  0022
State:  S (sleeping)
Tgid:   352
Ngid:   0
Pid:    352
PPid:   351
TracerPid:      0
Uid:    1000    1000    1000    1000
Gid:    1000    1000    1000    1000
FDSize: 256
Groups: 4 20 24 25 27 29 30 44 46 116 1000
NStgid: 352
NSpid:  352
NSpgid: 352
NSsid:  352
VmPeak:     6216 kB
VmSize:     6216 kB
VmLck:         0 kB
VmPin:         0 kB
VmHWM:      5076 kB
VmRSS:      5076 kB
RssAnon:            1724 kB
RssFile:            3352 kB
RssShmem:              0 kB
VmData:     1736 kB
VmStk:       132 kB
VmExe:       892 kB
VmLib:      1864 kB
VmPTE:        48 kB
VmSwap:        0 kB
HugetlbPages:          0 kB
CoreDumping:    0
THP_enabled:    1
Threads:        1
SigQ:   1/30158
SigPnd: 0000000000000000
ShdPnd: 0000000000000000
SigBlk: 0000000000010000
SigIgn: 0000000000384004
SigCgt: 000000004b813efb
CapInh: 0000000000000000
CapPrm: 0000000000000000
CapEff: 0000000000000000
CapBnd: 000001ffffffffff
CapAmb: 0000000000000000
NoNewPrivs:     0
Seccomp:        0
Seccomp_filters:        0
Speculation_Store_Bypass:       thread vulnerable
SpeculationIndirectBranch:      conditional enabled
Cpus_allowed:   ffff
Cpus_allowed_list:      0-15
Mems_allowed:   1
Mems_allowed_list:      0
voluntary_ctxt_switches:        91
nonvoluntary_ctxt_switches:     1

The highlighted "TracerPid" line with the "0" indicates that no process is "tracing" this one. In Linux, a common technique used to analyze the behavious of a process is to use a tool like strace[4] to log all the activity performed at system calls level:

xavier@rog:/proc/self$ strace -f -p 352

Let's recheck the /proc/self/status now that it's being "traced":

xavier@rog:/proc/self$ cat status|grep TracerPid
TracerPid:      9731

The script (SHA256a9ba5856b97327cc6c68d461e903569e30d5bd507405b5ecb34b0c513c42d50e)[5] remains undetected by most AV (VT score: 2/64) but its final purpose remains unknown because the bytecode passed to exec() does not seems to work! I'm still investigating it...

[1] https://www.sans.org/cyber-security-courses/reverse-engineering-malware-advanced-code-analysis/ [2] https://learn.microsoft.com/en-us/windows/win32/api/winternl/ns-winternl-peb [3] https://learn.microsoft.com/en-us/windows/win32/api/debugapi/nf-debugapi-isdebuggerpresent [4] https://man7.org/linux/man-pages/man1/strace.1.html [5] https://www.virustotal.com/gui/file/a9ba5856b97327cc6c68d461e903569e30d5bd507405b5ecb34b0c513c42d50e/detection

Xavier Mertens (@xme) Xameco Senior ISC Handler - Freelance Cyber Security Consultant PGP Key

(c) SANS Internet Storm Center. https://isc.sans.edu Creative Commons Attribution-Noncommercial 3.0 United States License.