--[ 14. Le saviez-vous ? La réponse ]------------------------------------ Suite à la compromission d'un serveur UNIX, des outils de post-exploitation sont souvent utilisés par l'attaquant pour rebondir sur d'autres systèmes et les compromettre. Un administrateur système ou investigateur inforensique désirant connaître le fonctionnement de tels outils utilise généralement un debugger pour procéder à une analyse dynamique. Dans certains cas les binaires sont protégés contre une telle analyse. Prenons l'exemple ci-dessous : $ cat antidebug.c #include #include int main() { if (ptrace(PTRACE_TRACEME, 0, 1, 0) < 0) { printf("DEBUGGING... Bye\n"); return 1; } printf("Hello\n"); return 0; } $ gcc -o antidebug antidebug.c $ ./antidebug Hello $ strace ./antidebug execve("./antidebug", ["./antidebug"], [/* 27 vars */]) = 0 brk(0) = 0x1f29000 access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory) mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f8a2fd53000 access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory) open("/etc/ld.so.cache", O_RDONLY) = 3 fstat(3, {st_mode=S_IFREG|0644, st_size=77160, ...}) = 0 mmap(NULL, 77160, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f8a2fd40000 close(3) = 0 access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory) open("/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY) = 3 read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\300\357\1\0\0\0\0\0"..., 832) = 832 fstat(3, {st_mode=S_IFREG|0755, st_size=1570832, ...}) = 0 mmap(NULL, 3684440, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f8a2f7b2000 mprotect(0x7f8a2f92c000, 2097152, PROT_NONE) = 0 mmap(0x7f8a2fb2c000, 20480, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x17a000) = 0x7f8a2fb2c000 mmap(0x7f8a2fb31000, 18520, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f8a2fb31000 close(3) = 0 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f8a2fd3f000 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f8a2fd3e000 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f8a2fd3d000 arch_prctl(ARCH_SET_FS, 0x7f8a2fd3e700) = 0 mprotect(0x7f8a2fb2c000, 16384, PROT_READ) = 0 mprotect(0x7f8a2fd55000, 4096, PROT_READ) = 0 munmap(0x7f8a2fd40000, 77160) = 0 ptrace(PTRACE_TRACEME, 0, 0x1, 0) = -1 EPERM (Operation not permitted) fstat(1, {st_mode=S_IFREG|0644, st_size=1806, ...}) = 0 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f8a2fd52000 write(1, "DEBUGGING... Bye\n", 17DEBUGGING... Bye ) = 17 exit_group(1) = ? Cet exemple montre bien que le binaire est protégé de l'analyse dynamique, rendant le travail d'inforensique beaucoup plus difficile, le debogueur étant inopérant car la fonction ptrace retourne le code d'erreur EPERM. Une solution facile d'accès est l'utilisation de SystemTap[1] qui permet de contourner ces protections anti-débogage car l'interception des appels système ne se fait pas via l'utilisation de ptrace(2) mais grâce à des sondes situées au niveau du noyau Linux lui-même. Afin de reproduire le même résultat qu'un strace(1), le script suivant est utilisé : $ cat strace.stp #! /usr/bin/env stap probe syscall.* { if (pid() == target()) printf("%s %s\n", name, argstr); } $ stap -v strace.stp -c ./antidebug Hello rt_sigaction SIGINT, {SIG_DFL}, 0x00000000, 8 rt_sigsuspend sigreturn rt_sigaction SIGUSR1, {SIG_DFL}, 0x00000000, 8 rt_sigprocmask SIG_SETMASK, [EMPTY], 0x00000000, 8 execve ./antidebug close 3 brk 0x00000000 access "/etc/ld.so.nohwcap", F_OK faccessat AT_FDCWD, "/etc/ld.so.nohwcap", F_OK mmap2 0x00000000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0 access "/etc/ld.so.preload", R_OK faccessat AT_FDCWD, "/etc/ld.so.preload", R_OK open "/etc/ld.so.cache", O_RDONLY fstat 3, 0xbf9b1014 mmap2 0x00000000, 26520, PROT_READ, MAP_PRIVATE, 3, 0 close 3 access "/etc/ld.so.nohwcap", F_OK faccessat AT_FDCWD, "/etc/ld.so.nohwcap", F_OK open "/lib/i686/cmov/libc.so.6", O_RDONLY read 3, 0xbf9b1140, 512 fstat 3, 0xbf9b1060 mmap2 0x00000000, 1333608, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0 mmap2 0xb76e1000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 319 mmap2 0xb76e4000, 10600, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0 close 3 mmap2 0x00000000, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0 set_thread_area 0xbf9b1500 mprotect 0xb76e1000, 8192, PROT_READ mprotect 0xb770c000, 4096, PROT_READ munmap 0xb76e7000, 26520 ptrace 0, 0, 0x00000001, 0x00000000 fstat 1, 0xbf9b1500 mmap2 0x00000000, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0 write 1, "Hello\n", 6 exit_group 0 exit 0 L'analyse dynamique à l'aide de SystemTap est passée outre la protection anti-ptrace, et le binaire peut être étudié de manière simple. Cette solution ne nécessite pas de talents particuliers en analyse de malware et a le mérite d'être disponible sur toutes les plates-formes Linux. -- Julien Reveret [1] SystemTap : http://sourceware.org/systemtap