suricata新增Mysql告警規則處理
- 協議解析后續處理內容
- 新增規則
- 規則解析關鍵字新增
- Setup用于初始化檢測項
- Free用于資源釋放
- AppLayerTxMatch用于協議解析完成后的規則檢測
- 針對pcap文件進行檢測
- 總結
協議解析后續處理內容
經過Mysql協議解析處理流程 介紹,我們在suricata中,新增加了Mysql協議處理相關的內容;
Mysql協議處理后,有兩種方式進行處理,
一是將協議解析的內容,進行結果輸出;(該內容相對比較簡單,在協議框架生成包含了相關處理內容)
二是,將解析的內容與檢測規則結合一起進行告警檢測
新增規則
假設,我們需要檢測Mysql sql語句中的所有truncate 語句,并進行告警。則規則形如:
alert mysql any any -> any 3306 (msg:"test mysql detect";mysql.sql:truncate;sid:10001;rev:1;)
規則解析關鍵字新增
如果,新增了以上規則,通過suricata進行引擎分析
suricata -c suricata.yaml --engine-analysis
會提示如下錯誤:
E: detect-parse: unknown rule keyword 'mysql.sql'.
E: detect: error parsing signature "alert mysql any any -> any 3306 (msg:"test mysql detect";mysql.sql:truncate;sid:10001;rev:1;)"
首先將mysql.sql加入到引擎檢測關鍵字列表中;
在協議框架生成會生成detect-mysql-mysql.h及detect-mysql-mysql.c兩個文件。
同時DetectMysqlmysqlRegister為注冊關鍵字及檢測函數的入口,
檢測注冊代碼如下
void DetectMysqlmysqlRegister(void)
{sigmatch_table[DETECT_AL_MYSQL_MYSQL].name = "mysql.sql";sigmatch_table[DETECT_AL_MYSQL_MYSQL].desc ="Mysql content modifier to match on the mysql buffers";sigmatch_table[DETECT_AL_MYSQL_MYSQL].Setup = DetectMysqlmysqlSetup;sigmatch_table[DETECT_AL_MYSQL_MYSQL].Free = DetectMysqlmysqlFree;sigmatch_table[DETECT_AL_MYSQL_MYSQL].AppLayerTxMatch = DetectMysqlMatch;
#ifdef UNITTESTSsigmatch_table[DETECT_AL_MYSQL_MYSQL].RegisterTests = DetectMysqlmysqlRegisterTests;
#endifsigmatch_table[DETECT_AL_MYSQL_MYSQL].flags |= SIGMATCH_INFO_STICKY_BUFFER;/* register inspect engines */DetectAppLayerInspectEngineRegister2("mysql.sql", ALPROTO_MYSQL, SIG_FLAG_TOSERVER, 0,DetectEngineInspectGenericList, NULL);g_mysql_rust_id = DetectBufferTypeGetByName("mysql.sql");SCLogNotice("Mysql application layer detect registered.");
}
其中sigmatch_table,為注冊各關鍵字的全局數組。
DETECT_AL_MYSQL_MYSQL為枚舉值,在協議框架生成時自動生成在enum DetectKeywordId 中
enum DetectKeywordId {DETECT_SID,DETECT_PRIORITY,DETECT_REV,DETECT_CLASSTYPE,...,DETECT_TARGET,DETECT_AL_MYSQL_MYSQL,...DETECT_AL_TEMPLATE_BUFFER,DETECT_AL_DHCP_LEASETIME,
}
同時將DetectMysqlmysqlRegister的調用加入到SigTableSetup中
void SigTableSetup(void)
{memset(sigmatch_table, 0, sizeof(sigmatch_table));DetectSidRegister();DetectPriorityRegister();DetectPrefilterRegister();DetectRevRegister();DetectClasstypeRegister();DetectReferenceRegister();DetectTagRegister();DetectThresholdRegister();DetectMetadataRegister();...DetectMysqlmysqlRegister();/* close keyword registration */DetectBufferTypeCloseRegistration();
}
完成以上代碼注冊后,再次執行引擎分析,發現錯誤已經消失。
Setup用于初始化檢測項
此例初始化中,對應mysql.sql:truncate,在執行Setup時,需要將truncate進行緩存,后續在規則檢測時進行處理。其處理代碼如下:
int DetectMysqlmysqlSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str)
{uint8_t *de = NULL;SigMatch *sm = NULL;s->init_data->list = g_mysql_rust_id;if (DetectSignatureSetAppProto(s, ALPROTO_MYSQL) != 0)return -1;sm = SigMatchAlloc();if (sm == NULL)goto error;sm->type = DETECT_AL_MYSQL_MYSQL;char *value = SCMalloc(strlen(str) + 1);strcpy(value, str);sm->ctx = (SigMatchCtx *)value;SigMatchAppendSMToList(s, sm, g_mysql_rust_id);return 0;error:if (de != NULL)SCFree(de);if (sm != NULL)SCFree(sm);return -1;return 0;
}
從以上代碼不難看出,此函數的處理,是把truncate進行了緩存處理。
Free用于資源釋放
在上一節的,初始化過程中,存在SigMatchAlloc申請資源的情況,需要在程序退出前執行資源釋放
void DetectMysqlmysqlFree(DetectEngineCtx *de_ctx, void *de_ptr)
{if (de_ptr != NULL)SCFree(de_ptr);
}
AppLayerTxMatch用于協議解析完成后的規則檢測
sigmatch_table[DETECT_AL_MYSQL_MYSQL].AppLayerTxMatch = DetectMysqlMatch;
此處注冊的函數DetectMysqlMatch,在Mysql協議解析過程中的每個Transaction都會執行一次檢測;本例中,相當于每執行一條sql語句就會執行一遍。
函數定義如下
static int DetectMysqlMatch(DetectEngineThreadCtx *det_ctx,Flow *f, uint8_t flags, void *state,void *txv, const Signature *s,const SigMatchCtx *ctx) {uint8_t ret = 0;const uint8_t *data = NULL;uint32_t data_len = 0;SCLogDebug("DetectMysqlMatch: flags %d, txv %p, s %p, ctx %p", flags, txv, s, ctx);if (flags & STREAM_TOSERVER) {rs_mysql_get_request_buffer(txv, &data, &data_len);} else if (flags & STREAM_TOCLIENT) {rs_mysql_get_response_buffer(txv, &data, &data_len); }SCLogDebug("DetectMysqlMatch: flags %d, txv %p, s %p, ctx %p done", flags, txv, s, ctx);if (data != NULL) {char* de = (char *)ctx;char *stripped_data = strip((const char *)data);return startsWith((const char *)stripped_data, de) ;}return 0;
}
其中rs_mysql_get_request_buffer,rs_mysql_get_response_buffer是rust中根據解析的內容,并返回緩存的函數。
其定義如下:
pub unsafe extern "C" fn rs_mysql_get_request_buffer(tx: *mut c_void, buf: *mut *const u8, len: *mut u32,
) -> u8 {let tx = cast_pointer!(tx, MysqlTransaction);if let Some(ref request) = tx.request {match request {MysqlFEMessage::SimpleQuery(quey) => {// If we have a login request, we can return the request buffer.if !quey.is_empty() {*len = quey.len() as u32;*buf = quey.as_ptr();return 1; // success}}_ => {return 0;}}}return 0;
}
此處,我們只返回了SimpleQuery對應的sql語句,正好對應了mysql.sql,對于其他關鍵字,可以根據實際情況進行修改,比如,檢測使用超級用戶(root/admin)進行遠程登錄,其檢測規則就需要修改成mysql.login_user:root;而后增加相應的規則處理即可。
此外,在檢測之前,執行了strip操作,是因為;默認sql語句前面會增加一些注釋,所以執行strip先去除注釋內容,而后使用startsWith函數進行檢測。(更嚴謹的做法,可能需要對sql語句進行語法分析后再檢測;待完善–)
針對pcap文件進行檢測
完成以上步驟后,使用pcap文件檢驗規則是否能產生告警
suricata -c suricata.yaml -k none -r mysql.pcap
打開eve.json后,查看alert情況
{"time":"2025-07-09T09:32:25.481582+0000","timestamp":1752053545481,"flow_id":"2036907348195717","pcap_cnt":54,"alarm_type":"alert","src_ip":"10.1.30.200","src_port":54366,"dest_ip":"10.1.1.3","dest_port":3306,"proto":"TCP","pkt_src":"wire/pcap","event_id":"ec830925-9c01-434c-9651-5e43c836da5f","tx_id":9,"alert":{"action":"allowed","gid":1,"signature_id":10001,"classification":"","rev":1,"signature":"test mysql detect","category":"","severity":3,"attack_result":"attempt","severity":3,"sid":10001},"tx_id":10,"request":{"message":"SimpleQuery","query":"/* ApplicationName=DBeaver 24.1.3 - SQLEditor <Script-17.sql> */ truncate tb_attack_20250111"},"protocol":"mysql","direction":"to_server","flow":{"pkts_toserver":35,"pkts_toclient":19,"bytes_toserver":5220,"bytes_toclient":11003,"start":"2025-07-09T09:31:27.146574+0000","src_ip":"10.1.30.200","dest_ip":"10.1.1.3","src_port":54366,"dest_port":3306}}
總結
通過以上操作,即完成了Mysql協議一條告警規則的新增及處理