เช็ค Log หาร่องรอย PHP2Shell: ดู Log ไหน ย้อนไปถึงวันไหน และ grep อะไรได้บ้าง
เช็ค log หาร่องรอย PHP2Shell ย้อนไปถึง 17 ต.ค. 2026 ดู access log, error log, PHP-FPM และ WAF ด้วยคำสั่ง grep แบบอ่านอย่างเดียว พร้อมวิธีเก็บหลักฐานก่อน log หาย
เช็ค Log หาร่องรอย PHP2Shell: ดู Log ไหน ย้อนไปถึงวันไหน และ grep อะไรได้บ้าง
ถ้าจะเช็ค log หาร่องรอย PHP2Shell ให้ย้อนไปอย่างน้อยถึง 17 ตุลาคม 2026 วันแรกที่ Amazon เห็นความพยายามโจมตี ไม่ใช่วันที่ 21 ที่แพตช์ออก แล้วไล่ดู log ของ Nginx หรือ Apache, PHP-FPM, PHP, WAF และแอป ก่อนค้นให้คัดลอก log เก็บพร้อมค่า hash ไฟล์ที่ logrotate ลบไปแล้วกู้จากเครื่องนั้นไม่ได้
แหล่งข้อมูลที่เราตรวจเมื่อ 23 ต.ค. 2026 ไม่ได้ให้ลายเซ็นใน access log ของการโจมตีที่สำเร็จ และไม่ได้ให้ชื่อไฟล์ path หรือ hash ของ web shell ที่เจาะจงกับ PHP2Shell งานจริงจึงเป็นการหาความผิดปกติ ส่วนรายละเอียดช่องโหว่อยู่ในบทความหลักเรื่อง PHP2Shell
ต้องย้อน log ไปถึงวันไหน?
Amazon Threat Intelligence เห็นความพยายามโจมตีบน honeypot ตั้งแต่ 17 ต.ค. สี่วันก่อนแพตช์ และแนะนำให้เริ่มสืบจากวันนั้น เราแนะนำให้เผื่อเริ่มที่ 16 ต.ค. และเช็คเขตเวลาของ log แต่ละแหล่งก่อนเทียบเหตุการณ์ เช่น access log ของ Nginx และ Apache ตามค่าเริ่มต้นจะบันทึกเวลาท้องถิ่นของเครื่องพร้อม offset (เช่น +0700) เครื่องที่ตั้งเป็น UTC จะช้ากว่าเวลาไทย 7 ชั่วโมง
อย่าเดาว่า log ของสัปดาห์นี้ยังอยู่ครบ logrotate ลบไฟล์เก่าตามค่า rotate หรือ maxage เช็คค่าจริงและไฟล์ที่เหลือวันนี้ ไฟล์ .gz อ่านด้วย zgrep ได้ ไฟล์ที่ถูกลบจากเครื่องแล้วอาจยังมีใน backup, archive หรือระบบรวม log ปลายทาง
ผู้ให้บริการที่เข้าข่ายมาตรา 26 ของ พ.ร.บ.คอมฯ ต้องเก็บข้อมูลจราจรอย่างน้อย 90 วัน (อ่านเพิ่ม) แต่ log บนเครื่องเว็บอยู่นานแค่ไหนขึ้นกับ logrotate
Log อยู่ที่ไหน แต่ละตัวช่วยอะไร?
| Log | อยู่ที่ไหน | ช่วยอะไร | ข้อจำกัด |
|---|
| Nginx access / error | ตามบรรทัด access_log, error_log ใน config (ค่าตั้งต้น logs/access.log, logs/error.log) | method, path, status, user agent | format combined ไม่บันทึก body และ Content-Type |
| Apache access / error | Debian/Ubuntu: /var/log/apache2/ · RHEL/Fedora: /var/log/httpd/ | เหมือน Nginx และรับ error ของ PHP เมื่อใช้ mod_php, ไม่ได้ตั้ง error_log และเปิด log_errors | mod_php เสี่ยงสูงสุดตามทีม PHP ดูก่อน |
| PHP-FPM | error_log ใน php-fpm.conf, access.log และ slowlog ในไฟล์ pool | worker ที่ถูกตัดเพราะทำงานเกินเวลา | access.log ของ pool ไม่ได้เปิดเป็นค่าตั้งต้น |
| PHP error log | error_log ใน php.ini หรือ php_admin_value[error_log] | fatal error เช่นหน่วยความจำหมด | log_errors ปิด = PHP ไม่บันทึก error ใหม่ผ่านค่านี้ (ของเก่าและ log อื่นยังอาจมี) |
| WAF / reverse proxy | ตามผลิตภัณฑ์ | ที่หนึ่งที่อาจเห็น body ถ้าการบันทึกเก็บไว้ | ขึ้นกับการตั้งค่า |
| Log ของแอป | ตามเฟรมเวิร์ก | upload, login อาจมีข้อมูลจาก body ถ้าแอปบันทึก | แต่ละแอปไม่เหมือนกัน |
| Log ขาออกของไฟร์วอลล์ | ไฟร์วอลล์หรือ security group | เครื่องเว็บต่อไปหาใคร | ต้องเปิดไว้ก่อนเกิดเหตุ |
ถ้าต้องดูแลหลายเครื่อง ลองเทียบขอบเขตการเก็บ ปริมาณ log ต่อวัน และระยะเก็บที่ต้องการกับแพ็กเกจและราคาที่เผยแพร่ของ zcrLog และ zcrSIEM
path จริงดูจาก config: access_log/error_log ของ Nginx (รวมไฟล์ที่ include), CustomLog/ErrorLog ของ Apache (Debian ใต้ /etc/apache2, RHEL ใต้ /etc/httpd) และ error_log, access.log, slowlog ของ PHP-FPM
ขั้นที่ 0: เก็บหลักฐานก่อนค้น
NIST SP 800-86 แนะนำให้เทียบ hash ของต้นฉบับกับสำเนา (ใช้กับ log file ด้วย) โดยคัดลอกไฟล์ปัจจุบันและไฟล์ที่ rotate แล้วในรอบเดียวกัน ไฟล์ที่ยังถูกเขียนอาจเปลี่ยนระหว่างคัดลอก จึงควรจดเวลาไว้ ย้ายสำเนาไปนอกเครื่องแล้วค้นจากสำเนา การตรวจไฟล์บนดิสก์ process และเครือข่ายอยู่ในบทความรับมือเหตุ PHP2Shell
ทางแก้ระยะยาวคือส่ง log ออกจากเครื่องตั้งแต่ตอนเขียน ซึ่งตรงกับงานของ zcrLog ที่รับ syslog เก็บได้ 90 วันถึง 2 ปี และตรวจความครบถ้วนด้วย SHA-256
สัญญาณที่ค้นได้จาก log
คำสั่งด้านล่างค้นเฉพาะ log ที่มีอยู่ (รันกับสำเนา) และสมมติ format combined ของ Nginx และ Apache: ฟิลด์ 4 คือเวลา, 6 method, 7 path, 9 status ตัวแปร WIN จับเฉพาะฟิลด์เวลาช่วง 16–23 ต.ค. 2026 ไม่ใช่วันที่ใน URL, referrer หรือ user agent ถ้า format ต่างหรืออ่านหลังวันที่ 23 ต้องปรับเอง
WIN='^[^ ]+ [^ ]+ [^ ]+ \[(1[6-9]|2[0-3])/Oct/2026:'
1. POST ไปที่สคริปต์ PHP
AWS อธิบายว่าทั้งสองช่องโหว่เกิดตอน PHP จัดการ multipart/form-data ก่อนโค้ดของแอปจะทำงาน และ Sansec ให้เฝ้า request แบบนี้ที่ไปหา endpoint PHP แต่ combined ไม่เก็บ Content-Type จึงเห็นแค่ method กับ path
zgrep -hE "$WIN" access.log* \
| awk '$6 == "\"POST" {p=$7; sub(/\?.*/,"",p); print p}' \
| sort | uniq -c | sort -rn | head -30
แอปที่ใช้ URL สวยๆ วิ่งผ่าน index.php ตัวเดียว คำสั่งนี้จึงไม่กรอง .php
2. 4xx/5xx พุ่งที่ endpoint เดียว
zgrep -hE "$WIN" access.log* \
| awk '$9 ~ /^[45]/ {p=$7; sub(/\?.*/,"",p); print $9, p}' \
| sort | uniq -c | sort -rn | head -30
AWS ให้ดู error และ timeout ที่ซ้ำบน route ที่คนนอกส่งค่าได้ 5xx คือเงาของปัญหานั้น ส่วน 4xx กองโตมักมาจาก scanner
3. path PHP ที่มีคนเรียกแค่ IP เดียวหรือสองตัว
CISA เขียนว่าการนับความถี่ใน access log ช่วยหา web shell ได้ เพราะมักมีแค่คนวางที่เรียก
zgrep -hE "$WIN" access.log* \
| awk '{p=$7; sub(/\?.*/,"",p); if (p ~ /\.php$/) print $1, p}' | sort -u \
| awk '{print $2}' | sort | uniq -c | sort -n | head -30
บรรทัดบนสุดคือ path ที่มี IP ต่างกันน้อยที่สุด NSA เตือนว่าผลบวกลวงเยอะ และ $1 อาจเป็น IP ของ proxy ถ้าไม่ได้ตั้งให้บันทึก IP จริงจาก proxy ที่เชื่อถือได้
4. request ไปหาไฟล์ .php ในโฟลเดอร์ upload หรือ cache
CISA ให้ระวังไฟล์แปลกใน web root และไฟล์ที่สร้าง traffic ผิดประเภท ใน log หาได้จาก request ไปหา .php ในโฟลเดอร์ที่ควรมีแต่ไฟล์อัปโหลด (เปลี่ยนชื่อโฟลเดอร์ตามแอป)
zgrep -hE "$WIN" access.log* \
| awk '{p=$7; sub(/\?.*/,"",p); if (p ~ /\/(uploads?|cache|tmp)\// && p ~ /\.php$/) print $6, p, $9}' \
| sort | uniq -c | sort -rn
5. error log: หน่วยความจำหมดและ timeout ซ้ำๆ
Sansec ให้จับตา fatal error เรื่องหน่วยความจำหมด ข้อความด้านล่างมาจาก php-src: สองตัวแรกจาก engine ตัวที่สามคือ PHP-FPM ตัด worker ที่เกินเวลา
zgrep -HE 'Allowed memory size|Maximum execution time|execution timed out' \
error.log* php-fpm.log*
-H ใส่ชื่อไฟล์หน้าทุกบรรทัดไว้เทียบข้ามไฟล์ ถ้าขึ้นว่าไฟล์ไม่มีหรืออ่านไม่ได้ อย่ามองข้าม ดูว่าข้อความกระจุกที่ route เดียวตั้งแต่ 16–17 ต.ค. หรือไม่ บน worker ที่รันด้วย memory_limit=-1 จริง เฉพาะ "Allowed memory size" จะไม่ขึ้นอีก ข้อความ timeout เป็นอีกเรื่อง เพราะ PHP-FPM มี request_terminate_timeout คุมแยก
6. process ลูกและการเชื่อมต่อขาออก
Amazon ให้ตรวจ process ที่ไม่ควรรัน หน่วยงานไซเบอร์ของแคนาดา (CCCS) ให้ดูคำสั่งและการเชื่อมต่อขาออกที่ผูกกับ PHP ย้อนหลังจะเห็นได้ก็ต่อเมื่อมี log ของ EDR หรือ log ขาออกของไฟร์วอลล์ (วิธีตั้งค่า Firewall ให้ส่ง Syslog) การตรวจบนเครื่องอยู่ในบทความรับมือเหตุ
7. PHP_SESSION_UPLOAD_PROGRESS อยู่ใน body ไม่ใช่ access log
Amazon ให้หา POST ฟอร์ม upload ที่มีข้อความนี้ ซึ่งเป็นชื่อฟิลด์ของฟีเจอร์ session upload progress ที่ PHP เปิดไว้โดยปริยาย และอยู่ใน body ที่ access log แบบ combined ไม่บันทึก ที่ที่อาจเห็นคือ log ของ WAF หรือ proxy ถ้าเก็บ body ไว้ หรือ log ของแอปและระบบดักข้อมูลอื่น (WAF ช่วยได้แค่ไหนเทียบกับการแพตช์)
zgrep -F -c -- 'PHP_SESSION_UPLOAD_PROGRESS' '/path/to/body-capture.log.gz'
เปลี่ยน path เป็นไฟล์จริง -c นับ "บรรทัด" ที่ตรง ไม่ใช่จำนวน request หรือครั้งที่ถูกโจมตี เจอแล้วไม่ได้แปลว่าโดน ฟอร์มปกติก็ใช้ชื่อนี้ ส่วน IP ที่ Amazon ลงไว้เป็นเครือข่ายนิรนามที่ใช้ร่วมกัน ให้สืบต่อ ไม่ใช่บล็อกทันที
ข้อจำกัดที่ต้องพูดตรงๆ
แหล่งข้อมูลที่เราตรวจเมื่อ 23 ต.ค. 2026 ไม่ได้ให้ลายเซ็นใน access log ของการโจมตีที่สำเร็จ และไม่ได้ให้ชื่อไฟล์ path หรือ hash ของ web shell ที่เจาะจงกับ PHP2Shell ของที่เจอจึงเป็นแค่ "น่าสงสัย" และ AWS เขียนว่าการไม่มี error ไม่ใช่หลักฐานว่าปลอดภัย
log บนเครื่องที่อาจโดนเจาะเชื่อได้ไม่เต็มร้อย ผู้บุกรุกที่ได้สิทธิ์สูงพอแก้หรือหยุด log ได้ OWASP จึงแนะนำให้คัดลอก log ไปที่อ่านได้อย่างเดียวโดยเร็ว คู่มือ Apache ก็เตือนว่า log มีข้อมูลจาก client ที่ไม่ได้ escape อาจมีตัวอักษรควบคุมแฝง อ่านไฟล์ดิบอย่างระวัง
เจออะไรผิดปกติ ให้หยุดค้นแล้วไปตามขั้นตอนรับมือเมื่อสงสัยว่าโดน PHP2Shell
ตั้ง log ไว้ให้ครั้งหน้าเห็นมากกว่านี้
# Nginx (ใน http block): เพิ่ม Content-Type, ขนาด request และเวลาที่ใช้
log_format hunt '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" "$http_user_agent" '
'"$content_type" $request_length $request_time';
access_log logs/access_hunt.log hunt;
# Apache: %I ต้องเปิด mod_logio ก่อน
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\" \"%{Content-Type}i\" %I %D" hunt
CustomLog "logs/access_hunt_log" hunt
ฝั่ง PHP ตั้ง log_errors=On, error_reporting=E_ALL และ error_log ที่เขียนได้จริงตามที่ AWS แนะนำ และเปิด access.log ของ pool ใน PHP-FPM
grep ฟรีทำได้ดีแค่ไหน?
กับเซิร์ฟเวอร์ไม่กี่เครื่อง zgrep และ awk ค้นและสรุปหลักฐานที่มีได้ดีโดยไม่ต้องซื้ออะไร แต่พิสูจน์ไม่ได้ว่าโจมตีสำเร็จ สร้าง body ที่ไม่เคยถูกบันทึกไม่ได้ และย้อนดู process หรือการเชื่อมต่อในอดีตไม่ได้
การส่ง log ออกจากเครื่องลดการสูญเสียในอนาคตและลดการพึ่งหลักฐานบนเครื่องเดียว แต่กู้ record ที่ลบไปแล้วไม่ได้ และรับประกันไม่ได้ว่าเครื่องที่โดนเจาะส่ง log มาครบและจริง Nginx ส่ง log ทาง syslog ได้ด้วย prefix syslog: (ไม่ระบุ port ใช้ UDP 514) ส่วน error_log = syslog ของ PHP และ PHP-FPM ส่งเข้า syslog service บนเครื่อง การส่งต่อออกนอกเครื่องต้องตั้งค่า service นั้นเพิ่ม ปลายทางหนึ่งคือ zcrLog ระบบเก็บ log เพื่อ compliance ที่รับรองตามมาตรฐาน มศอ. 4003.1-2560 รอบนี้ที่ต้องลุ้นคือ log ของวันที่ 17 ต.ค. ยังเหลืออยู่ไหม ระบบนี้เก็บ log เก่าไว้ใน archive และ restore กลับมาได้ รอบหน้าจึงเริ่มจากค้น raw log ที่ส่งเข้าไปได้เลย ส่วนการแพตช์ PHP ก็ยังต้องทำเหมือนเดิม
การค้นทั้งองค์กรทีเดียวเป็นงานของ zcrSIEM ที่ซื้อแยกได้และไม่ต้องมี zcrLog ก่อน มี detection rule แบบเขียนเงื่อนไขเองหรือ Sigma และช่อง threat hunting ที่แปลงคำถามภาษาคนเป็น query ให้อ่านตรวจก่อนรัน สัญญาณข้างบนแปลงเป็น rule หรือ query ได้เฉพาะเมื่อเก็บ event เหล่านั้นไว้แล้ว ดูหน้าจอที่หน้าเดโม และอ่านเพิ่มในบทความ AI-Assisted Threat Hunting
zcr เป็นผู้ทำซอฟต์แวร์ ส่วนงานสืบสวนลงมือจริงทำผ่านพาร์ทเนอร์ของเรา
📞 ปรึกษาฟรี
บทความที่เกี่ยวข้อง
ผลิตภัณฑ์ที่เกี่ยวข้อง
zcrLog · zcrSIEM · ราคา · เดโม
แหล่งข้อมูลอ้างอิง
- Amazon Threat Intelligence identifies PHP2Shell exploitation prior to public disclosure in MadPot — AWS Security Blog, 21 ต.ค. 2026: เห็นความพยายามโจมตีตั้งแต่ 17 ต.ค., ให้หา
PHP_SESSION_UPLOAD_PROGRESS, IP เป็นเครือข่ายนิรนาม
- Using AWS WAF to apply mitigations for PHP2Shell — AWS Security Blog, อัปเดต 22 ต.ค. 2026: ต้นเหตุอยู่ที่ multipart, error ซ้ำบน route, การไม่มี error ไม่ใช่หลักฐาน, ค่า error logging
- PHP2Shell — Sansec, อัปเดต 22 ต.ค. 2026: multipart ไปหา endpoint PHP และ fatal error เรื่องหน่วยความจำ
- AL26-026 Critical vulnerabilities impacting PHP — Canadian Centre for Cyber Security, 21 ต.ค. 2026: process, คำสั่ง, ไฟล์ และการเชื่อมต่อขาออกที่ผูกกับ PHP
- PHP security release 8.5.12, 8.4.27, 8.3.36, 8.2.35 — php.net, 20–21 ต.ค. 2026: mod_php เสี่ยงสูงสุด, ทางเลี่ยง
memory_limit=-1
- Compromised Web Servers and Web Shells — CISA: นับความถี่ใน access log, ไฟล์แปลกใน web root, ไฟล์ที่สร้าง traffic ผิดประเภท
- Mitigating Web Shells — NSA: ผลบวกลวงของการวิเคราะห์ access log
- NIST SP 800-86 — เทียบ message digest ของต้นฉบับและสำเนา รวมถึง log file; ไฟล์บนระบบที่ทำงานอยู่อาจเปลี่ยนระหว่างคัดลอก
- OWASP Logging Cheat Sheet — คัดลอก log ไปที่อ่านอย่างเดียวโดยเร็ว
- Nginx: ngx_http_log_module, error_log, ตัวแปรของ ngx_http_core_module, Logging to syslog
- Apache: Log Files, mod_log_config, Distros default layout
- PHP: PHP-FPM configuration, Error handling configuration, memory_limit, Session configuration, ซอร์สโค้ด php-src (zend_alloc.c, zend_execute_API.c, fpm_request.c)
- man pages: logrotate, zgrep, grep, uniq, awk (POSIX)
- Computer-Related Crime Act B.E. 2550 (ฉบับแปลรวมฉบับแก้ไข 2560) — กระทรวงดิจิทัลฯ: มาตรา 26 เก็บข้อมูลจราจรไม่น้อยกว่า 90 วัน