仅需要很短的时间,nessusd会加载所有的脚本。所以写一个好的脚本一定要用到其他脚本的测试结果。 比如,一个脚本在尝试连接FTP服务器时,应该首先检查远程端口21是否开放。这将节省时间已经带宽,也大大加快了对于目的主机防火墙屏蔽21端口的情况。
get_port_state(<portnum>)函数在端口开放时返回TRUE,反之返回FALSE。如果该端口未被扫描,同样返回TRUE。这时候端口的状态是未知的。 这个函数仅占用很少的CPU,在需要的情况下,应该尽可能的调用它。
nesssusd为每个主机都维护着一个知识库( KB ), 它包含了一次测试过程中,所有脚本测试产生的信息。安全测试脚本从中读取内容,也会将获取的信息返回给知识库。端口的状态,实际上被记在知识库的某个地方。
知识库被分为好几类。”Services”类包含了所有已经服务的端口。比如,Services/smtp 的值很可能是25. 然而,如果远程主机有个隐藏的SMTP服务配置在2500端口而不是25端口上,那么该条记录的值会更新为2500。
看 附录 可以了解更多知识库的细节。
注意:你不能马上读取你刚刚设置的值。例如,以下代码可能不会有想象中的结果:
set_kb_item(name:"attack", value:TRUE);
if(get_kb_item("attack"))
{
# Perform the attack - will not be executed
# because our local KB has not been updated
}
原因是因为安全考虑以及代码隔离。实际上,nessusd为每个新起的脚本拷贝一份知识库,而不是原始知识库,set_kb_item()函数会将值设置到原始知识库中,在当前正在跑的脚本中,nessusd是不会去更新它的拷贝知识库的。(这点很重要)
每个NASL脚本都必须向Nessus服务端注册自己。注册包括,脚本名称,描述,作者等等。 这样,NASL脚本可能会是像下面这样的结构。
#
# Nasl script to be used with nessusd
#
if(description)
{
# register information here...
#
# I will call this section the 'register'
# section
#
exit(0);
}
#
# Script code here. I will call this section the
# 'attack' section.
#
description是一个全局变量,它会被设置成TRUE或者FALSE,基于该脚本必须还是非必须注册。
script_name(language1:<name>, [...]) 设置脚本名称,将会在客户端显示。
script_description(language1:<desc>, [...]) 设置描述信息,用户点击脚本名称时显示。
script_summary(language1:<summary>, [...]) 设置脚本摘要,将会在提示信息中显示。
script_copyright(language1:<copyright>, [...]) 设置脚本版权信息。可以是你的名字或者其他任何东西。
你可能已经注意到了,这些函数大部分由language1参数。实际上,并不是这样的。
NASL提供了多语言支持。每个脚本必须至少支持英语。这些函数准确的语法应该是这样:
script_function(english:english_text, [francais:french_text,
deutsch:german_text,
...]);
除此者外,script_dependencies()函数也可能被调用。它的作用是告诉nessusd,当前脚本是在某些其他脚本之后加载。这很有用,尤其你想要使用其他规则的测试结果时。语法是:
script_dependencies(filename1 [,filename2, ..., filenameN]);
filename参数就是脚本在磁盘上存储的名称。
攻击部分可能包含任何你认为对攻击测试有用的代码。 一旦你的攻击完成,你可以通过security_warning()或者security_hole()函数来打印报告。 security_warning()用于攻击成功,但并不是一个很严重的漏洞,意指这个漏洞并不会导致攻击者立马获取访问权限。 这两个函数的语法如下:
security_warning(<port> [, protocol:<proto>]);
security_hole(<port> [, protocol:<proto>]);
security_warning(port:<port>, data:<data> [, protocol:<proto>]);
security_hole(port:<port>, data:<data> [, protocol:<proto>]);
第一种情况,客户端显示的是script_description()函数定义的脚本描述信息。由于多语言支持的存在,这很方便。 第二种情况,客户端显示的是data参数的内容。这同样很方便,比如必须显示版本信息的时候。
CVE是一个试图解决所有安全漏洞之间关系的产品。访问 cve.mitre.org 获取更多信息。
Nessus是完全CVE兼容的。如果你正在为一个CVE定义过的漏洞编写脚本,请在描述部分调用script_cve_id()函数,用法如下:
script_cve_id(string);
例子:
script_cve_id("CVE-1999-0991");
相对与仅仅在报告中打印出CVE编号,单独调用这个函数非常重要,Nessus客户端会积极的使用这个函数带来的信息。
除了安全测试, NASL也可以做一些维护工作。比如下面这个例子,该脚本会取人哪些主机运行着SSH,哪些主机没有运行SSH。
#
# Check for ssh
#
if(description)
{
script_name(english:"Ensure the presence of ssh");
script_description(english:"This script makes sure that ssh is running");
script_summary(english:"connects on remote tcp port 22");
script_category(ACT_GATHER_INFO);
script_family(english:"Administration toolbox");
script_copyright(english:"This script was written by Joe U.");
script_dependencies("find_service.nes");
exit(0);
}
#
# First, ssh may run on another port.
# That's why we rely on the plugin 'find_service'
#
port = get_kb_item("Services/ssh");
if(!port)
port = 22;
# declare that ssh is not installed yet
ok = 0;
if(get_port_state(port))
{
soc = open_sock_tcp(port);
if(soc)
{
# Check that ssh is not tcpwrapped. And that it's really
# SSH
data = recv(socket:soc, length:200);
if("SSH" >< data)
ok = 1;
}
close(soc);
}
#
# Only warn the user that SSH is NOT installed
#
if(!ok)
{
report = "SSH is not running on this host !";
security_warning(port:22, data:report);
}
在一次测试过程中,nessusd可能会加载超过200条脚本。如果脚本都没有优化过,那么将耗费很长的时间去执行他们。这也是为什么需要你确保你的脚本越快越好。
仅当参数中列出的端口至少有一个开放时,才会执行你的脚本。<port>参数可以是整数(例如:80)或者一个 KB 中定义的字符串(例如:”Services/www”)。
script_require_ports(80, "Services/www")
注意,如果端口状态是未知(比如还没有扫描任何端口),脚本还是会被执行。
仅当 KB 中包含所有参数值时,nessusd才会执行你的脚本。
script_require_keys("ftp/anonymous", "ftp/writeable_dir")
仅当远程FTP服务器提供匿名访问,且存在可以文件夹时,才会执行脚本。
当 KB 中没有包含所给参数中的至少一个时,nessusd将不会执行你的脚本