מעבדת בלאקבוקס — חדר בריחה טכנולוגי
הגשת תשובות, רמזים ובדיקת AI דורשים חיבור לאתר. פתרונות ששת שלבי הליבה נחשפו באתר כדי לפתוח את שלבי ההמשך.
שלב 1 · שלב 1 — מי דיבר עם מי
שלב 1 — מי דיבר עם מי קיבלתם תמצית תעבורה מרשת עמוסה. רוב האירועים לגיטימיים. זהו את הכתובת החשודה, את טכניקת הסריקה ואת הפעולה שביצעה אחרי שמצאה שירות זמין. edge_capture.log 10:02:11.083 10.0.0.12:53144 -> 10.0.0.1:53 UDP DNS query intranet.local 10:02:11.129 10.0.0.1:53 -> 10.0.0.12:53144 UDP DNS response NOERROR 10:02:12.402 10.0.0.31:49822 -> 10.0.0.20:443 TCP ACK len=0 10:02:13.010 10.0.0.47:42001 -> 10.0.0.18:445 TCP SYN seq=18421 10:02:13.011 10.0.0.7:5353 -> 224.0.0.251:5353 UDP mDNS query printer.local 10:02:13.019 10.0.0.18:445 -> 10.0.0.47:42001 TCP SYN,ACK seq=991 ack=18422 10:02:13.020 10.0.0.47:42001 -> 10.0.0.18:445 TCP RST seq=18422 10:02:13.184 10.0.0.47:42002 -> 10.0.0.6:445 TCP SYN seq=55210 10:02:13.201 10.0.0.6:445 -> 10.0.0.47:42002 TCP RST,ACK 10:02:13.398 10.0.0.24:54401 -> 10.0.0.20:443 TCP PSH,ACK len=612 10:02:13.447 10.0.0.47:42003 -> 10.0.0.23:445 TCP SYN seq=12004 10:02:13.460 10.0.0.23:445 -> 10.0.0.47:42003 TCP RST,ACK 10:02:13.711 10.0.0.47:42004 -> 10.0.0.11:445 TCP SYN seq=33017 10:02:13.724 10.0.0.11:445 -> 10.0.0.47:42004 TCP RST,ACK 10:02:14.003 10.0.0.16:49214 -> 10.0.0.1:53 UDP DNS query updates.vendor.net 10:02:14.061 10.0.0.47:42005 -> 10.0.0.29:445 TCP SYN seq=7612 10:02:14.079 10.0.0.29:445 -> 10.0.0.47:42005 TCP RST,ACK 10:02:14.880 10.0.0.47:42110 -> 10.0.0.18:445 TCP ACK len=0 10:02:14.892 10.0.0.47:42110 -> 10.0.0.18:445 SMB2 SESSION_SETUP user=backup_svc auth=NTLM 10:02:14.917 10.0.0.18:445 -> 10.0.0.47:42110 SMB2 STATUS_LOGON_FAILURE 10:02:15.044 10.0.0.8:68 -> 10.0.0.1:67 UDP DHCP request
פתרון והסבר
הפתרון של השלב 10.0.0.47 ביצעה SYN scan חצי־פתוח על SMB בפורט 445; לאחר שמצאה את 10.0.0.18 פתוחה היא ניסתה אימות NTLM לחשבון backup_svc, שנכשל. הרעש הלגיטימי מפוזר בין פרוטוקולים ויעדים רגילים. לעומתו, 10.0.0.47 שולחת SYN במהירות לפורט 445 בחמישה יעדים לא־רציפים. מול השרת היחיד שהחזיר SYN-ACK היא משיבה RST, ולכן לחיצת היד לא מושלמת — חתימה קלאסית של SYN scan חצי־פתוח. פחות משנייה אחר כך היא חוזרת לשרת שנמצא ומנסה SMB2 SESSION_SETUP באמצעות NTLM. הלוג מוכיח ניסיון אימות אך לא מספיק כדי לקבוע לבדו Pass-the-Hash.
שלב 2 · שלב 2 — הקובץ שמתחזה
שלב 2 — הקובץ שמתחזה
הקובץ vacation.png נפתח כתמונה תקינה, אך מערכת ה-DLP סימנה בו תוכן נוסף. נתחו את ההקסה ואת פלט הסריקה: אילו שני פורמטים חיים באותו קובץ, ואיפה מתחיל המטען השני?
vacation.png — hexdump
binwalk.txt
00000000 89 50 4e 47 0d 0a 1a 0a 00 00 00 0d 49 48 44 52 |.PNG........IHDR|
00000010 00 00 01 40 00 00 00 f0 08 06 00 00 00 71 2d bd |...@.........q-.|
00000020 6b 00 00 00 19 74 45 58 74 53 6f 66 74 77 61 72 |k....tEXtSoftwar|
00000030 65 00 43 61 6d 65 72 61 20 45 78 70 6f 72 74 00 |e.Camera Export.|
...
00018f20 00 00 00 00 49 45 4e 44 ae 42 60 82 50 4b 03 04 |....IEND.B`.PK..|
00018f30 14 00 00 00 08 00 91 52 36 5b 7a 19 22 8c 2f 01 |.......R6[z."./.|
00018f40 00 00 a0 02 00 00 0c 00 00 00 6e 6f 74 65 73 2e |..........notes.|
00018f50 74 78 74 8d 90 41 6b c3 30 10 85 ef fd 15 43 2f |txt..Ak.0.....C/|
...
000190a0 50 4b 03 04 14 00 00 00 08 00 91 52 36 5b 44 a1 |PK.........R6[D.|
000190b0 9c 72 8b 03 00 00 00 08 00 00 0d 00 00 00 73 74 |.r............st|
000190c0 61 67 65 72 2e 62 69 6e 7b 9f 22 18 e1 4c 00 a7 |ager.bin{."..L..|ראיה נוספת: binwalk.txt
DECIMAL HEXADECIMAL DESCRIPTION -------------------------------------------------------------------------------- 0 0x0 PNG image, 320 x 240, 8-bit/color RGBA 33 0x21 PNG tEXt chunk 102184 0x18F28 End of PNG image (IEND) 102192 0x18F30 ZIP local file header, version 2.0 102560 0x190A0 ZIP local file header, file name: stager.bin 104021 0x19655 End of ZIP archive
פתרון והסבר
הפתרון של השלב זה Polyglot תקין מסוג PNG+ZIP: התמונה מתחילה ב-0x0, ואחרי IEND מתחיל ארכיון ZIP ב-offset 0x18F30 שמכיל notes.txt ו-stager.bin. הקובץ מתחיל ונגמר כמבנה PNG תקין, ולכן מציג תמונה. מיד אחרי chunk הסיום IEND מופיעה חתימת ZIP 50 4B 03 04. קורא PNG סובל בדרך כלל מידע נגרר, בעוד קורא ZIP מוצא את ה-central directory מן הסוף; לכן אותו רצף בתים מתקבל בשני המפענחים. חילוץ החל מ-0x18F30 יחשוף את הארכיון ואת stager.bin, בלי להריץ דבר.
שלב 3 · שלב 3 — הפונקציה האילמת
שלב 3 — הפונקציה האילמת
לפניכם פונקציה בלי שם משמעותי ובלי תיעוד. מה היא מחשבת? תנו שם מדויק לפעולה.
mystery.py
def f(n):
c = 0
while n:
c += n & 1
n >>= 1
return c
print(f(7)) # ?
print(f(8)) # ?
print(f(255)) # ?פתרון והסבר
הפתרון של השלב הפונקציה סופרת כמה ביטים דלוקים (1) יש בייצוג הבינארי של n — popcount / Hamming weight זה מנגנון קלאסי: n & 1 מחזיר את הביט הפחות משמעותי, ההזזה ימינה מקדמת לביט הבא, והלולאה נעצרת כשכל הביטים נגמרו. 7=111 → 3, 8=1000 → 1, 255=11111111 → 8. השם המקצועי הוא popcount (או Hamming weight), ומשתמשים בו בהצפנה, בדחיסה ובאלגוריתמי גרפים.
שלב 4 · שלב 4 — ההודעה המוצפנת
שלב 4 — ההודעה המוצפנת יירטנו blob טקסטואלי בלי מטא־דאטא מסגיר. קבעו את שרשרת העיבוד, מצאו את המפתח הקצר ופענחו את ההודעה. נדרש להסביר גם אילו סימנים סטטיסטיים הובילו אתכם. intercepted.blob byte_profile.txt ajBgPGwubihvNH9LbD9sPXQraC55I2w3azhu
ראיה נוספת: byte_profile.txt
sample_length : 36 chars alphabet : A-Z a-z 0-9 + / padding : absent candidate_decode_len : 27 bytes shannon_entropy : 4.31 bits/byte index_of_coincidence : even=0.071 odd=0.068 all=0.039 key_length_estimate : 2 printable_if_xor : high for key candidates 0x20..0x7e
פתרון והסבר
הפתרון של השלב השרשרת היא Base64 ואז XOR מחזורי במפתח 2D 71; הטקסט המפוענח הוא GAMMA_CYBER:ANALYZE_TRAFFIC. האלפבית מצביע על Base64, אך הפלט הבינארי שלו אינו טקסט. מדד צירוף גבוה יותר כשמפצלים בתים לפי זוגי/אי־זוגי הוא רמז למפתח XOR מחזורי באורך 2. חיפוש 65,536 המפתחות האפשריים ודירוג לפי ASCII קריא מחזיר 2D 71. לאחר XOR מתקבל GAMMA_CYBER:ANALYZE_TRAFFIC. האנטרופיה בינונית — גבוהה מטקסט רגיל אך נמוכה מהצפנה חזקה — ולכן קידוד ו-XOR קצר הם השערה טובה יותר מצופן מודרני.
שלב 5 · שלב 5 — הבאג הרועד
שלב 5 — הבאג הרועד
שרת מקבל אורך מתוך header חתום. בדיקת הגבולות נראית תקינה במבט ראשון, אך קלט שלילי גורם לכתיבה עצומה. זהו את החולשה, הסבירו את ההמרה המדויקת והציעו תיקון בטוח.
packet.c
asan.log
#include <stdint.h>
#include <string.h>
int copy_payload(const uint8_t *packet, size_t packet_size) {
int16_t wire_len;
char dst[64];
if (packet_size < 2) return -1;
memcpy(&wire_len, packet, sizeof(wire_len));
if (wire_len <= 64) {
memcpy(dst, packet + 2, wire_len);
return 0;
}
return -1;
}ראיה נוספת: asan.log
input header bytes : f0 ff wire_len (int16_t) : -16 bounds check : -16 <= 64 => true memcpy size_t arg : 18446744073709551600 ERROR: AddressSanitizer: negative-size-param / stack-buffer-overflow WRITE beyond stack object 'dst' (size 64)
פתרון והסבר
הפתרון של השלב זו חולשת Integer Signedness שמובילה ל-stack buffer overflow: אורך int16_t שלילי עובר את הבדיקה ואז מומר ל-size_t עצום ב-memcpy. יש לדחות אורך לא־חיובי, לבדוק מול sizeof(dst) ומול packet_size, ורק אז להמיר ל-size_t. wire_len הוא int16_t חתום ולכן -16 מקיים -16 <= 64. בקריאה ל-memcpy הוא מומר ל-size_t, ועל מערכת 64 ביט מתקבל 2^64-16 — גודל עצום שגולש מעבר ל-dst שעל המחסנית. תיקון בטוח בודק תחילה wire_len > 0, שומר אותו במשתנה size_t רק לאחר האימות, דורש len <= sizeof(dst), ודורש len <= packet_size - 2. כך מטפלים גם ב-signedness וגם בקלט קטוע.
שלב 6 · שלב 6 — לאן זה מדבר
שלב 6 — לאן זה מדבר בתוך לוג DNS רועש מסתתר beacon עם jitter. זהו את הדומיין, הוכיחו את טווח התזמון, קבעו את הקידוד וחברו את תתי־הדומיין כדי לחלץ את המידע שהודלף. dns_queries.txt timing_stats.txt 12:00:01 ws-14 clients4.google.com A 12:00:03 ws-27 INAVGRJN.sync-cdn.link TXT 12:00:08 ws-09 login.microsoftonline.com A 12:00:21 ws-14 api.github.com A 12:00:34 ws-27 GUYDUSSJ.sync-cdn.link TXT 12:00:42 ws-03 time.windows.com A 12:00:59 ws-27 KRKEKURN.sync-cdn.link TXT 12:01:02 ws-18 ocsp.digicert.com A 12:01:19 ws-09 fonts.googleapis.com A 12:01:34 ws-27 IZHVKTSE.sync-cdn.link TXT 12:01:47 ws-03 telemetry.vendor.net AAAA 12:02:02 ws-27 INAVGRJN.sync-cdn.link TXT 12:02:17 ws-14 intranet.local A 12:02:35 ws-27 GUYDUSSJ.sync-cdn.link TXT 12:02:39 ws-18 ntp.org A
ראיה נוספת: timing_stats.txt
host : ws-27 parent_domain : sync-cdn.link observed_times : 12:00:03, 12:00:34, 12:00:59, 12:01:34, 12:02:02, 12:02:35 intervals_sec : 31, 25, 35, 28, 33 mean : 30.4 sec range : 25..35 sec exact_periodic : false label_alphabet : A-Z, 2-7 label_length : 8
פתרון והסבר
הפתרון של השלב ws-27 מתקשרת ב-DNS beaconing עם sync-cdn.link ב-jitter של 25–35 שניות. תתי־הדומיין מקודדים ב-Base32; חיבור ארבעת ה-chunks הראשונים מפוענח ל-CASE-50:JITTER-FOUND. האירועים של ws-27 מול sync-cdn.link מופיעים במרווחים 31, 25, 35, 28 ו-33 שניות: ממוצע 30.4 שניות עם jitter מכוון בטווח 25–35, שמטשטש חוק זיהוי של מחזור קבוע. האלפבית A-Z ו-2-7 וה-labels באורך אחיד מצביעים על Base32. חיבור ארבעת החלקים הייחודיים הראשונים ופענוחם מחזיר CASE-50:JITTER-FOUND; שתי הבקשות האחרונות הן חזרות שידור. זהו גם beacon וגם DNS exfiltration, לא רק דומיין חשוד.
מתקדם 1 · מתקדמים 1 — חטיפת Session והרכבת Fragments
מתקדמים 1 — חטיפת Session והרכבת Fragments נתחו שיחת TCP ופרגמנטים של פרוטוקול מותאם אישית. חשבו את SEQ/ACK הדרושים להזרקה, הרכיבו את המטען לפי offset ולא לפי זמן ההגעה, והסבירו מדוע IDS נאיבי עלול להחמיץ אותו. session.pcap.txt # src -> dst flags seq ack len 10.1.4.8:41000 -> 10.1.4.20:9001 SYN 1000 0 0 10.1.4.20:9001 -> 10.1.4.8:41000 SYN,ACK 7000 1001 0 10.1.4.8:41000 -> 10.1.4.20:9001 ACK 1001 7001 0 10.1.4.20:9001 -> 10.1.4.8:41000 PSH,ACK 7001 1001 18 10.1.4.8:41000 -> 10.1.4.20:9001 ACK 1001 7019 0 # captured IP fragments, datagram id=0x4a2 (offset shown in bytes) arrival=1 offset_bytes=16 MF=1 payload="|AUTH|role=admin" arrival=2 offset_bytes=32 MF=0 payload="|END" arrival=3 offset_bytes=0 MF=1 payload="HELLO|nonce=7f3a"
מתקדם 2 · מתקדמים 2 — Stack Corruption ו-Reverse
מתקדמים 2 — Stack Corruption ו-Reverse
חשבו offset מדויק לשינוי משתנה סמוך במחסנית, כתבו את ארבעת הבתים הדרושים ב-little-endian, ושחזרו את פעולת פונקציית האסמבלי.
auth.c
check.asm
struct Frame {
char name[24];
uint32_t admin_flag;
};
int login(int fd) {
struct Frame f = {0};
read(fd, f.name, 32);
return f.admin_flag == 1;
}ראיה נוספת: check.asm
; rdi = int32_t *arr, esi = count
check:
xor eax, eax
test esi, esi
jle .done
.loop:
add eax, dword ptr [rdi]
add rdi, 4
dec esi
jne .loop
.done:
retמתקדם 3 · מתקדמים 3 — Known Plaintext נגד XOR
מתקדמים 3 — Known Plaintext נגד XOR
קובץ תמונה הוצפן ב-XOR מחזורי במפתח קצר. השתמשו בחתימת PNG הידועה כדי לחלץ את המפתח, אמתו אותו על chunk מסוג IHDR והסבירו כיצד מפענחים את כל הקובץ.
encrypted_image.hex
offset encrypted bytes
0000 c2 63 05 74 46 39 51 39
0008 4b 33 4b 3e 02 7b 0f 61
0010 4b 33 4a 73 4b 33 4b c3
known PNG prefix:
89 50 4e 47 0d 0a 1a 0a
expected chunk near 000C: 49 48 44 52 (IHDR)מתקדם 4 · מתקדמים 4 — שחזור קובץ שהודלף ב-DNS
מתקדמים 4 — שחזור קובץ שהודלף ב-DNS ה-collector כתב אירועים בסדר קליטה מבולגן וכולל retransmissions. סננו את הרעש, סדרו את המקטעים, הסירו כפילויות ופענחו את שם הקובץ שהודלף. resolver_collector.log ingest=901 ts=14:23:00 host=hr-04 q=03-51332e43.cache-sync.one TXT ingest=902 ts=14:22:05 host=hr-04 q=01-46494e41.cache-sync.one TXT ingest=903 ts=14:22:11 host=dev-08 q=packages.internal A ingest=904 ts=14:23:29 host=hr-04 q=04-5356.cache-sync.one TXT ingest=905 ts=14:22:32 host=hr-04 q=02-4e43455f.cache-sync.one TXT ingest=906 ts=14:23:07 host=hr-04 q=03-51332e43.cache-sync.one TXT retry=1 ingest=907 ts=14:23:34 host=mail-02 q=mx.vendor.net MX