总结一下:检测SMTP主要的威胁主要是破解和溢出,SNORT签名存在固有的弱点,我们在做分析的时候要多考虑以下几个要素:
a) 破解本身要基于时间统计来做检测,不能单独的只检测一个expn root或其他
b) 溢出的检测要基于其原理来分析,不能只做某个溢出工具的检测
F) SMB微软网络共享协议的特征和识别
1) SMB登陆检测
my_schema = library_schema:new(1, ["time", "ip", "int", "ip", "int", "str"],
scope());
my_recorder = recorder ("bin/list %c", "my_schema");
_:reg_callback(ssax_client, "SMB", 0x73, "CLIENT");
_:reg_callback(ssax_server, "SMB", 0x73, "SERVER");
func reg_callback {
# Register callbacks for guest accounts. Called functions will be called
# with no arguments.
# Pass in: Function to call.
CALL_GUEST_ACCOUNT = listadd(CALL_GUEST_ACCOUNT, $1);
}
func ssax_client {
declare $Username inside tcp.connsym;
if (!$2)
$wco = 36;
else
$wco = $2;
$SMBBlob = $1;
$word_count = byte($SMBBlob, $wco);
# post NTLM 0.12, without extended security bit set word count == 13
if ($word_count == 13) {
$ansi_pw_len = le_ushort($SMBBlob, $wco + 15);
$unicode_pw_len = le_ushort($SMBBlob, $wco + 17);
$tmp_offset = $wco + 30 + $ansi_pw_len + $unicode_pw_len;
if (($tmp = substr($SMBBlob, $tmp_offset, (_:absindex($SMBBlob,
"\x00\x00", $tmp_offset) + 1) - $tmp_offset))
== "\x00" ) {
$Username = "NULL_UID";
} else {
$Username = _:shrink($tmp, "\x00");
}
}
# pre NTLM 0.12 word count should be 10.
else if ($word_count == 10) {
# ANSI password should be the first item in the ByteCount
# buffer.
$pw_len = le_ushort($SMBBlob, $wco + 15);
if ($pw_len == 0) {
#NULL PASSWORD?
}
$tmp = substr($SMBBlob, $wco + 23 + $pw_len);
if (prefix($tmp, "\x00")) {
$Username = "NULL_UID";
} else {
$Username = _:shrink($tmp, "\x00");
}
}
##else if ($word_count == 12) { ##NTLMSSP Challenge Response }
}
func ssax_server {
$SMBBlob = $1;
# A NULL long() int the NT Status field indicates success.
$errors = le_long($SMBBlob, 9);
if ($errors == -1073741802) {
#NTLMSSP Chalenge Response
#NT STATUS MSG MORE PROCCESSING REQUIRED
return;
}
declare $Username inside tcp.connsym;
if ($Username == "NULL_UID" || $Username == "GUEST") {
# foreach guest account callback inside those things
foreach $c inside (CALL_GUEST_ACCOUNT) {
($c)();
}
}
if (SMB_LOGIN_NOTIFY_AUTHENTICATION) {
if ($errors == 0) {
#SUCCESSFUL LOGIN
$authblob["STATUS"] = 1;
} else {
#FAILED LOGIN
$authblob["STATUS"] = 0;
}
$authblob["IP_ADDR_SRC"] = tcp.connsrc;
$authblob["IP_ADDR_DST"] = tcp.conndst;
$authblob["PASSWORD"] = -1;
$authblob["USERNAME"] = $Username;
$authblob["SERVICE_NAME"] = "SMB";
authentication_authentication:authdata($authblob);
}
}
这里申明一点微软的SMB协议格式是未公开的,现在根本没有好的解码办法,这里写的用户名的检测是根据SMB包里的UNICODE编码转化成ASCII的字符的,本身SMB的用户名是可读的,但是密码是没办法的,密码是被HASH的
密码登陆成功与否的状态也是可读的,就是用SNORT来写规则也是可以作到的
总结一下:目前SMB协议的解码都是难题,这里的SMB登陆检测
也是用没办法的办法做的,其他一些比如SSH,HTTPS等的协议也是有一些没办法的办法来做一些事情的,也是可以考虑导进一些默认证书的办法,可以做一定层次的DECODE的
G) 基于统计的签名的特征和开发
1) WEBCC检测
这里说一下NFR的引擎的内置函数timeout:
filter checkem timeout (sec: INTERVAL, repeat)
这个内置函数在SENSOR上是作为一个定时器的作用,没有它,我们没办法做基于时间特征的统计.我们这里就不详细解释webcc的写法了,下面还会提到.
NFR的引擎还有内置函数except,exception,也就是运行NCODE或处理协议栈异常的时候调用的,在下面的SYNFLOOD的检测代码里用到的.
总结一下:我们一般使用到与时间有关系的统计签名的时候请大家考虑一下timeout函数,遇到代码异常可以考虑except
H) 基于协议异常的特征的开发和编写
1) SYNFLOOD
filter synflood except (tcpsynacktimeout) {
if (tcp.connsyn) {
if (!SynTimeoutCnt[tcp.connsrc]) {
SynTimeoutCnt[tcp.connsrc] = 1;
} else {
SynTimeoutCnt[tcp.connsrc] = SynTimeoutCnt[tcp.connsrc] + 1;
}
# grab packets if we’re gonna alert
if (!Context[tcp.connsrc] && SynTimeoutCnt[tcp.connsrc] > THRESHOLD) {
Context[tcp.connsrc] = attack:context(synflood_alert);
if (AGGRESSIVE_PREVENTION)
announce_synflood();
}
}
debug:trace("synflood: ",tcp.connsrc, Context[tcp.connsrc], SynTimeoutCnt[tcp.connsrc]);
}
上面说的意思是统计半开放连接的个数是否超过上限
filter synflood_is_working except (tcpsyntimeout) {
debug:trace("tcp syn timeout", tcp.connsrc, Context[tcp.connsrc], FloodTimer[Context[tcp.connsrc]]);
if (Context[tcp.connsrc] && !FloodTimer[Context[tcp.connsrc]]) {
announce_synflood();
FloodTimer[Context[tcp.connsrc]] = system.time;
StartTime[system.time] = listadd(StartTime[system.time], tcp.connsrc);
}
}
跟踪每个半开放连接的超时时间
在SNORTRULES 2.3里检测SYN有一条