在《Suricata之dnslog域名检测》中,介绍了dnslog域名检测规则一步步的优化过程,从最初的content匹配,到pcre正则匹配,再到最终的pcrexform+dataset匹配。实现了规则与特征数据的分离,使得特征数据的管理更加直观和方便。同样的优化过程和方案,也适用于弱口令检测规则。
本文重点以Wordpress弱口令登录的检测为例,展示弱口令规则的优化过程和思路,另外还会对弱口令检测中常见的一种误报场景及其解决方法进行介绍。最后再简单介绍其他协议的弱口令检测。
Wordpress弱口令登录数据包
登录请求数据包
POST /wordpress/wp-login.php HTTP/1.1
Host: 192.168.169.160
Connection: keep-alive
Content-Length: 117
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: http://192.168.169.160
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Referer: http://192.168.169.160/wordpress/wp-login.php
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: wordpress_test_cookie=WP+Cookie+check
log=admin&pwd=admin123&wp-submit=Log+In&redirect_to=http%3A%2F%2F192.168.169.160%2Fwordpress%2Fwp-admin%2F&testcookie=1
登录成功响应数据包
HTTP/1.1 302 Found
Date: Mon, 03 Jun 2024 08:36:03 GMT
Server: Apache/2.4.18 (Ubuntu)
Expires: Wed, 11 Jan 1984 05:00:00 GMT
Cache-Control: no-cache, must-revalidate, max-age=0
Set-Cookie: wordpress_test_cookie=WP+Cookie+check; path=/wordpress/
X-Frame-Options: SAMEORIGIN
Set-Cookie: wordpress_2593e528a51693ac78094651c5d056d0=admin%7C1717576563%7Ch1aXHKoJnXh3BHapbS5eT2Tcjc4HkhRjXSzI6u8GUVV%7C02fcacd58739efbc1aefc85cee484c00ac1b1905da728d9c36bf4d4cb84cbd50; path=/wordpress/wp-content/plugins; HttpOnly
Set-Cookie: wordpress_2593e528a51693ac78094651c5d056d0=admin%7C1717576563%7Ch1aXHKoJnXh3BHapbS5eT2Tcjc4HkhRjXSzI6u8GUVV%7C02fcacd58739efbc1aefc85cee484c00ac1b1905da728d9c36bf4d4cb84cbd50; path=/wordpress/wp-admin; HttpOnly
Set-Cookie: wordpress_logged_in_2593e528a51693ac78094651c5d056d0=admin%7C1717576563%7Ch1aXHKoJnXh3BHapbS5eT2Tcjc4HkhRjXSzI6u8GUVV%7C3b6eb5f371b94fe41cff9b0e9ff70cf64a62c9e7d9979a33747a26463336f619; path=/wordpress/; HttpOnly
X-Redirect-By: WordPress
Location: http://192.168.169.160/wordpress/wp-admin/profile.php
Content-Length: 0
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Content-Type: text/html; charset=UTF-8
content规则检测弱口令
通过分析以上登录成功的请求和响应数据包,可以编写如下规则,用于检测使用弱口令admin123完成的登录:
alert http any any -> any any (msg:"content detect wordpress weakpass - attempt";flow:to_server,established;http.method;content:"POST";http.uri;content:"wp-login.php";http.request_body;content:"log=";content:"pwd=admin123";flowbits:set,wordpress-weakpass;sid:1001;)
alert http any any -> any any (msg:"content detect wordpress weakpass - success";flow:to_client,established;http.stat_code;content:"302";http.cookie;content:"wordpress_logged_in_";flowbits:isset,wordpress-weakpass;sid:1002;)
pcre规则检测弱口令
如下规则通过将content:"pwd=admin123";优化为pcre:"/(123456|admin|admin123|password)(&|$)/RP";就能够实现对多个弱口令的检测,之后只需要维护pcre规则中正则部分的弱口令列表即可:
alert http any any -> any any (msg:"pcre detect wordpress weakpass - attempt";flow:to_server,established;http.method;content:"POST";http.uri;content:"wp-login.php";http.request_body;content:"log=";content:"pwd=";pcre:"/(123456|admin|admin123|password)(&|$)/RP";flowbits:set,wordpress-weakpass;sid:1001;)
alert http any any -> any any (msg:"pcre detect wordpress weakpass - success";flow:to_client,established;http.stat_code;content:"302";http.cookie;content:"wordpress_logged_in_";flowbits:isset,wordpress-weakpass;sid:1002;)
pcrexform + dataset检测弱口令
同样为了实现规则与特征数据的分离,以及特征数据的扩展性和可维护性。在弱口令列表数据量不断增大后,就需要将pcre规则优化为dataset规则,通过pcrexform将弱口令部分进行提取,再交给dataset进行弱口令列表的匹配
alert http any any -> any any (msg:"Woredpress Weakpass - attempt";flow:to_server, established;http.method;content:"POST";http.uri;content:"wp-login.php";http.request_body;content:"log=";content:"pwd=";pcrexform:"pwd=(.*?)(?:&|$)";dataset:isset,weakpass,type string,load datasets/weakpass.list;flowbits:set,wordpress-weakpass;sid:1001;)
alert http any any -> any any (msg:"Woredpress Weakpass - success";flow:to_client, established;http.stat_code;content:"302";http.header.raw;content:"wordpress_logged_in_";flowbits:isset,wordpress-weakpass; sid:1002;)
通用性误报问题
如果直接以当前完成的规则上线到生产,一定会发现误报。这也是弱口令、未授权访问等规则中一类常见的误报场景。这主要与suricata的流检测机制有关。
suricata官方文档有一张用于解释使用flowbits进行流数据包检测原理的图片:
参考该图片,我们先画出理想状态下Wordpress弱口令检测的图片:
但是由于keep-alive机制的存在,通常一个流当中会有多个请求响应包,此时如果用户或攻击者通过首先尝试利用一个弱口令进行登录,会得到一个登录失败的响应。如果紧接着又使用了一个强口令成功登录,则会造成我们的规则产生误报。
误报过程分别用文字和图片描述如下:
1.请求弱口令登录:命中规则1001,标记flowbits:set,wordpress-weakpass
2.响应登录失败:未命中规则
3.请求强口令登录:未命中规则
4.响应登录成功:命中规则1002,flowbits:isset,wordpress-weakpass,产生告警
登录失败响应数据包
HTTP/1.1 200 OK
Date: Tue, 08 Oct 2024 15:11:16 GMT
Server: Apache/2.4.7 (Ubuntu)
X-Powered-By: PHP/5.5.9-1ubuntu4.19
Expires: Wed, 11 Jan 1984 05:00:00 GMT
Cache-Control: no-cache, must-revalidate, max-age=0
Pragma: no-cache
Set-Cookie: wordpress_test_cookie=WP+Cookie+check; path=/
X-Frame-Options: SAMEORIGIN
Vary: Accept-Encoding
Content-Encoding: gzip
Content-Length: 1579
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Content-Type: text/html; charset=UTF-8
......省略中间不关键部分.....
<div id="login">
<h1><a href="https://cn.wordpress.org/" title="......WordPress" tabindex="-1">WPVulDemo</a></h1>
<div id="login_error"> <strong>......</strong>...............<strong>admin</strong>........................... <a href="http://localhost:8000/wp-login.php?action=lostpassword">...............</a><br />
</div>
<form name="loginform" id="loginform" action="http://localhost:8000/wp-login.php" method="post">
<p>
<label for="user_login">..............................<br />
<input type="text" name="log" id="user_login" aria-describedby="login_error" class="input" value="admin" size="20" /></label>
</p>
<p>
<label for="user_pass">......<br />
<input type="password" name="pwd" id="user_pass" aria-describedby="login_error" class="input" value="" size="20" /></label>
为解决如上的误报场景,就需要新增一条规则,用于当发现流中存在登录失败的响应后,将flowbits标志给删除。
alert http any any -> any any (msg:"Woredpress Weakpass - error";flow:to_client, established;http.stat_code;content:"200";http.response_body;content:"aria-describedby=\"login_error\"";flowbits:isset,wordpress-weakpass;flowbits:unset,wordpress-weakpass;noalert;sid:1003;)
需要特别注意的是,虽然这条规则的目的仅仅是用于删除flowbits标志,但是由于其本身也是一条alert规则,因此同样会产生告警。所以需要添加noalert来抑制此条规则产生的告警。
其他协议弱口令检测
通过完成Wordpress弱口令检测规则,其他基于HTTP协议的弱口令规则也会是信手拈来,自然也想将pcrexform+dataset检测弱口令的模式应用于其他协议。但是pcrexform+dataset模式有其本身的局限性,这两个关键字,本身都只能用于从sticky buffer中匹配数据。如果其前面跟的不是sticky buffer,引擎会在规则加载阶段提示错误。
FTP协议
suricata支持FTP协议,但是提供的sticky buffer仅限于文件操作相关的指令(https://docs.suricata.io/en/latest/rules/ftp-keywords.html)。所以如果想要进行弱口令的匹配,只能直接在整个tcp数据中匹配。此时尝试使用pcrexform、dataset,就产生了规则引擎报错。
alert ftp any any -> any any (msg:"FTP Weakpass - attempt";flow:to_server,established;content:"PASS";startswith;pcrexform:"^PASS (.*?)\r\n";)
报错:Problem starting Suricata daemon: [76 - Suricata-Main] 2024-10-11 02:38:31 Error: detect-parse: transforms must directly follow stickybuffers
alert ftp any any -> any any (msg:"FTP Weakpass - attempt";flow:to_server,established;content:"PASS";startswith;dataset:isset,weakpass;)
报错:Problem starting Suricata daemon: [88 - Suricata-Main] 2024-10-11 02:40:08 Error: detect-dataset: datasets are only supported for sticky buffers
这种情况下只能暂时退而求其次,使用pcre规则,进行弱口令的匹配:
alert ftp any any -> any any (msg:"FTP Weakpass - attempt";flow:to_server,established;content:"PASS ";pcre:"/(echo|123456|password)\r\n/R";)
SMTP协议
alert smtp any any -> any any (msg:"STMP - request - 334 password";flow:to_client,established; frame:smtp.response_line;content:"334 UGFzc3dvcmQ6";startswith;flowbits:set,smtp-request-334;noalert;)
alert smtp any any -> any any (msg:"STMP - response - detect weakpass - attempt";flow:to_server,established; frame:smtp.command_line;datasets:isset,weakpass-base64,type string,load datasets/weakpass-base64.list;flowbits:isset,smtp-request-334;flowbits:unset,smtp-request-334;flowbits:set,smtp-weakpass-login;)
alert smtp any any -> any any (msg:"STMP - request - detect weakpass - success";flow:to_client,established; frame:smtp.response_line;content:"235 Authentication succe";startswith;flowbits:isset,smtp-weakpass-login;)
alert smtp any any -> any any (msg:"STMP - response - detect weakpass - failed";flow:to_client,established; frame:smtp.response_line;content:"535 ";startswith;flowbits:isset,smtp-weakpass-login;flowbits:unset,smtp-weakpass-login;noalert;)
只不过按照官方计划,想要用上suricata 8的beta版也要等到2025年4月1日了。当然,现在也可以像检测FTP弱口令那样,使用pcre来直接匹配tcp流量,进行SMTP弱口令检测。
alert smtp any any -> any any (msg:"STMP - request - 334 password";flow:to_client,established; content:"334 UGFzc3dvcmQ6";startswith;flowbits:set,smtp-request-334;noalert;)
alert smtp any any -> any any (msg:"STMP - response - detect weakpass - attempt";flow:to_server; pcre:"/(MTIzNDU2|YWRtaW4=|cGFzc3dvcmQ=|cHVuamFiQDEyMw==)\r\n/";flowbits:isset,smtp-request-334;flowbits:unset,smtp-request-334;flowbits:set,smtp-weakpass-login;)
alert tcp any any -> any any (msg:"STMP - response - detect weakpass - success";flow:to_client;content:"235 Authentication succe";flowbits:isset,smtp-weakpass-login;)
alert tcp any any -> any any (msg:"STMP - response - detect weakpass - failed";flow:to_client,established; content:"535 ";flowbits:isset,smtp-weakpass-login;flowbits:unset,smtp-weakpass-login;noalert;)
综上可以看出,pcrexform+dataset的检测能力是局限于suricata所支持的协议以及提供的sticky buffer的。好在由于suricata本身是开源的,如果确实有需求,可以自己实现特定协议的解析,来增加相关的sticky buffer。由于本人的C已经完全还给大学老师了,因此无法给大家做具体示例的展示,有需要可参考《suricata 开源工具学习-自定义协议开发》。