สคริปต์ Python นี้มีฟังก์ชันในการแยกวิเคราะห์บันทึกประเภทต่างๆ: บันทึก URL บันทึกไฟร์วอลล์ และบันทึกเหตุการณ์ แต่ละฟังก์ชันใช้นิพจน์ทั่วไปเพื่อดึงข้อมูลที่เกี่ยวข้องจากรายการบันทึกและส่งกลับพจนานุกรมพร้อมข้อมูลที่แยกวิเคราะห์
เซิร์ฟเวอร์ Syslog ได้รับการกำหนดค่าตามคำแนะนำที่นี่: https://documentation.meraki.com/General_Administration/Monitoring_and_Reporting/Syslog_Server_Overview_and_Configuration
สามารถดูตัวอย่าง Meraki Syslog ได้ที่นี่: https://documentation.meraki.com/General_Administration/Monitoring_and_Reporting/Syslog_Event_Types_and_Log_Samples
ฉันสร้างสคริปต์ง่ายๆ นี้ขึ้นมาเพื่อรวบรวมเว็บไซต์ 100 อันดับแรก คุณสามารถรันบนเครื่องที่อยู่ด้านหลัง Meraki MX และมันจะสร้าง Syslog จำนวนมาก
https://github.com/repenno/top_100
ฉันพัฒนาสคริปต์นี้เพื่อแยกวิเคราะห์ Syslogs ลงในออบเจ็กต์ JSON และแทรกลงใน VectorDB ที่รองรับการสืบค้นตามเวลา
ฉันใช้ Langchain และ OpenAI เพื่อสร้างแชทบอทตามความต้องการสำหรับเหตุการณ์ด้านความปลอดภัยและค้นคว้าข้อมูลเชิงลึกเกี่ยวกับกิจกรรมเครือข่าย
parse_url_log(log_entry: str) -> dict
: แยกวิเคราะห์บันทึก URLparse_firewall_log(log_entry: str) -> dict
: แยกวิเคราะห์บันทึกไฟร์วอลล์parse_event_log(log_entry: str) -> dict
: แยกวิเคราะห์บันทึกเหตุการณ์ เรามาแจกแจงนิพจน์ทั่วไปที่ใช้ในสคริปต์กัน:
วิธีการ parse_url_log:
รูปแบบนิพจน์ทั่วไปที่ใช้ในวิธีนี้ได้รับการออกแบบให้ตรงกับรายการบันทึก URL นี่คือรายละเอียดของรูปแบบ:
(?P<date>w{3}s+d{1,2}s+d{2}:d{2}:d{2})
: ส่วนนี้ของรูปแบบตรงกับวันที่ w{3}
จับคู่อักขระคำใดๆ (เท่ากับ [a-zA-Z0-9_]) 3 ครั้งพอดี ซึ่งสอดคล้องกับตัวย่อสามตัวอักษรสำหรับวันในสัปดาห์ (จันทร์ อังคาร ฯลฯ) s+
จับคู่อักขระช่องว่าง (ช่องว่าง แท็บ ตัวแบ่งบรรทัด) หนึ่งครั้งหรือมากกว่า d{1,2}
จับคู่ตัวเลขใดๆ (เท่ากับ [0-9]) ระหว่าง 1 ถึง 2 ครั้ง ซึ่งสอดคล้องกับวันของเดือน (1-31) d{2}:d{2}:d{2}
จับคู่เวลาในรูปแบบ HH:MM:SS
(?P<ip>d{1,3}.d{1,3}.d{1,3}.d{1,3})
: ส่วนนี้ของรูปแบบตรงกับ IP ที่อยู่. d{1,3}
จับคู่ตัวเลขใดๆ ระหว่าง 1 ถึง 3 ครั้ง ซึ่งสอดคล้องกับแต่ละออคเต็ตของที่อยู่ IP (0-255) .
ตรงกับจุดตัวอักษร
(?P<id>d+.d+)
: ส่วนนี้ของรูปแบบตรงกับ ID ที่ประกอบด้วยตัวเลขหนึ่งหลักขึ้นไป จุด และตัวเลขหนึ่งหลักขึ้นไป
(?P<user>w+)
: ส่วนนี้ของรูปแบบตรงกับชื่อผู้ใช้ที่ประกอบด้วยอักขระคำตั้งแต่หนึ่งตัวขึ้นไป
(?P<type>w+)
: ส่วนนี้ของรูปแบบตรงกับประเภทที่ประกอบด้วยอักขระคำตั้งแต่หนึ่งตัวขึ้นไป
src=(?P<src>d{1,3}.d{1,3}.d{1,3}.d{1,3}:d+)
: ส่วนนี้ของ รูปแบบตรงกับที่อยู่ IP และพอร์ตต้นทาง โครงสร้างคล้ายกับรูปแบบที่อยู่ IP ด้านบน แต่มี :d+
ต่อท้ายเพื่อให้ตรงกับหมายเลขพอร์ต
dst=(?P<dst>d{1,3}.d{1,3}.d{1,3}.d{1,3}:d+)
: ส่วนนี้ของ รูปแบบตรงกับที่อยู่ IP ปลายทางและพอร์ต โครงสร้างจะคล้ายกับที่อยู่ IP ต้นทางและรูปแบบพอร์ตด้านบน
mac=(?P<mac>[0-9A-Fa-f:]{17})
: ส่วนนี้ของรูปแบบตรงกับที่อยู่ MAC [0-9A-Fa-f:]
จับคู่ตัวเลขหรือตัวอักษรตั้งแต่ A ถึง F (เป็นตัวพิมพ์ใหญ่หรือตัวพิมพ์เล็ก) หรือโคลอน {17}
ระบุว่ารูปแบบนี้ควรมีความยาว 17 อักขระพอดีเพื่อให้ตรงกับรูปแบบที่อยู่ MAC
agent='(?P<agent>.+?)'
: ส่วนนี้ของรูปแบบตรงกับสตริงตัวแทนผู้ใช้ที่อยู่ในเครื่องหมายคำพูดเดี่ยว
request:s+(?P<request>w+s+w+://.+)
: ส่วนนี้ของรูปแบบตรงกับวิธีการร้องขอและ URL
วิธีการ parse_firewall_log:
รูปแบบนิพจน์ทั่วไปที่ใช้ในวิธีนี้ได้รับการออกแบบให้ตรงกับรายการบันทึกไฟร์วอลล์ คล้ายกับรูปแบบรายการบันทึก URL แต่รวมช่องเพิ่มเติมเฉพาะสำหรับบันทึกไฟร์วอลล์ เช่น โปรโตคอล กีฬา (พอร์ตต้นทาง) dport (พอร์ตปลายทาง) และรูปแบบ
วิธีการ parse_event_log:
รูปแบบนิพจน์ทั่วไปที่ใช้ในวิธีนี้ได้รับการออกแบบให้ตรงกับรายการบันทึกเหตุการณ์ คล้ายกับรูปแบบก่อนหน้านี้ แต่มีฟิลด์เพิ่มเติมเฉพาะสำหรับบันทึกเหตุการณ์ เช่น event_type, url, หมวดหมู่ (ไม่บังคับ), เซิร์ฟเวอร์ และ client_mac
แต่ละกลุ่มในรูปแบบเหล่านี้ตั้งชื่อโดยใช้ ?P<name>
ซึ่งช่วยให้แยกส่วนข้อมูลเฉพาะจากรายการบันทึกได้ง่ายขึ้น
fw_log_entry = "Oct 2 21:22:43 192.168.128.1 1 1696306963.825147405 satosugu firewall src=fe80::cde:941e:d4ef:3d22 dst=ff02::fb protocol=udp sport=5353 dport=5353 pattern: 1 all"
parsed_log = MerakiMXSyslogParser . parse_firewall_log ( fw_log_entry )
print ( parsed_log )
url_log_entry = "Oct 2 21:18:42 192.168.128.1 1 1696306722.864107379 satosugu urls src=192.168.128.3:58754 dst=192.229.211.108:80 mac=0C:4D:E9:BE:F4:B2 agent='Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/118.0' request: POST http://ocsp.digicert.com/"
parsed_log = MerakiMXSyslogParser . parse_url_log ( url_log_entry )
print ( parsed_log )
event_log_entry = "Oct 2 21:09:28 192.168.128.1 1 1696306168.009553886 satosugu events content_filtering_block url='https://youtube.com/...' category0='User-defined Blacklist' server='192.178.50.78:443' client_mac='0C:4D:E9:BE:F4:B2'"
parsed_log = MerakiMXSyslogParser . parse_event_log ( event_log_entry )
print ( parsed_log )
event_log_entry = "Oct 2 21:12:00 192.168.128.1 1 1696306320.822027826 satosugu events content_filtering_block url='https://xvideos.com/...' server='185.88.181.2:443' client_mac='0C:4D:E9:BE:F4:B2'"
parsed_log = MerakiMXSyslogParser . parse_event_log ( event_log_entry )
print ( parsed_log )
ผลลัพธ์ของแต่ละฟังก์ชันจะเป็นพจนานุกรมที่มีข้อมูลที่แยกวิเคราะห์จากรายการบันทึก
{ 'date' : 'Oct 2 21:22:43' , 'ip' : '192.168.128.1' , 'id' : '1696306963.825147405' , 'user' : 'satosugu' , 'type' : 'firewall' , 'src' : 'fe80::cde:941e:d4ef:3d22' , 'dst' : 'ff02::fb' , 'protocol' : 'udp' , 'sport' : '5353' , 'dport' : '5353' , 'pattern' : '1 all' }
{ 'date' : 'Oct 2 21:18:42' , 'ip' : '192.168.128.1' , 'id' : '1696306722.864107379' , 'user' : 'satosugu' , 'type' : 'urls' , 'src' : '192.168.128.3:58754' , 'dst' : '192.229.211.108:80' , 'mac' : '0C:4D:E9:BE:F4:B2' , 'agent' : 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/118.0' , 'request' : 'POST http://ocsp.digicert.com/' }
{ 'date' : 'Oct 2 21:09:28' , 'ip' : '192.168.128.1' , 'id' : '1696306168.009553886' , 'user' : 'satosugu' , 'type' : 'events' , 'event_type' : 'content_filtering_block' , 'url' : 'https://youtube.com/...' , 'category' : 'User-defined Blacklist' , 'server' : '192.178.50.78:443' , 'client_mac' : '0C:4D:E9:BE:F4:B2' }
{ 'date' : 'Oct 2 21:12:00' , 'ip' : '192.168.128.1' , 'id' : '1696306320.822027826' , 'user' : 'satosugu' , 'type' : 'events' , 'event_type' : 'content_filtering_block' , 'url' : 'https://xvideos.com/...' , 'category' : None , 'server' : '185.88.181.2:443' , 'client_mac' : '0C:4D:E9:BE:F4:B2' }
สคริปต์นี้ต้องการโมดูล re
ในตัวของ Python สำหรับนิพจน์ทั่วไป
ยินดีต้อนรับคำขอดึง! สำหรับการเปลี่ยนแปลงที่สำคัญ โปรดเปิดประเด็นก่อนเพื่อหารือเกี่ยวกับสิ่งที่คุณต้องการเปลี่ยนแปลง