Nessus安全测试插件编写教程(1)

1.简介 

  1.1.什么是NASL? 

  NASL是一个为网络安全扫描工具Nessus开发的脚本语言。通过它,任何人都可以方便快速地针对新出现的漏洞编写出测试插件,也便于不同操作系统的用户分享测试脚本。除此之外,NASL还可以保证编写的脚本只能用于针对目的主机的测试,使编写者难以使用编写的脚本用于恶意用途。 


  使用NASL,你可以很容易地打造IP报文,或者发送通常的报文。NASL中还有一些专门的函数用于向FTP和WEB服务器发送数据。另外,NASL还可以保证: 

   除了目标主机之外,不向任何的主机发送报文。 
   不允许在本地系统执行任何命令。 

  1.2.What NASL is not 

  NASL不是一种功能很强大的脚本语言。它的目的只是用于安全测试。因此,别指望使用这种脚本语言写出第三代的WEB服务器或者文件转换工具,要编写此类软件还是使用Perl、Python或者其它的脚本语言吧。用它们编写要比使用NASL快100倍。 

  另外,由于NASL的设计有些仓促,在语法上还有一些需要改进的地方。 

  1.3.为什么不在Nessus中使用Perl、Python、tcl或者其它脚本语言 

  我知道有很多功能非常强大的脚本语言,和它们相比NASL功能要弱很多。不过,虽然这些语言都非常强大,但是它们都不太安全。使用这些语言,你可以非常容易地编写出木马检测插件,泄露你的信息,让第三者知道你是一个Nessus用户,甚至会把一些敏感信息(例如:密码文件)发送到第三方主机。 

  使用这些语言还有另外一个问题,它们都会消耗大量的系统资源,尤其是内存。这非常令人头疼。以Perl为例,Perl非常棒,并且非常优美。但是,如果要使用它编写Nessus的测试插件,你需要消耗大量的时间安装必须的模块,Net::RawIP就是其中之一。 

  与此相反,NASL根本不会消耗大料的内存。因此,即使没有256M内存,你也可以同时启动20个nessusd线程。而且,对于编写检测插件,NASL本身就足够了,你不必为了为了编写新的安全检测插件而安装大量的软件包。 

  1.4.为什么你应该自己编写安全测试插件 

  你可能会盘算为了自己编写Nessus安全测试插件而在学习一种脚本语言是否值得?但是,你要知道: 

   * NASL为Nessus做过专门的优化,因此使用NASL编写的安全测试插件效率很高。 
   * 在很多方面,NASL和C非常类似,因此你没有必要担心很难掌握。 
   * NASL非常适合编写安全测试插件。 
   * NASL的移植性很好。在M$版本的Nessus发布之后,所有的安全测试插件根本勿需修改,就可以使用。 

  1.5.这个教程会教你一些什么东西 

  这个教程的目的是教你如何使用NASL编写自己的Nessus安全测试插件。 

  1.6.NASL的局限 

  我在上面讲过,NASL不是一种强大的脚本语言。它最大的局限是: 

   结构(structure)。目前NASL还不支持结构,可能在不久的将来可以支持。 
   一个调试程序。NASL还没有一个合适的debug程序。不过,有一个单独的解释程序nasl可以暂时用于排错。 

  1.7.感谢 

  下面这些人为NASL的设计提出了高贵的意见,作者在此致谢: 

   Denis Ducamp(denis@hsc.fr) 
   Fyodor(fyodor@dhp.com) 
   Noam Rathaus(nomr@securiteam.com) 

2.NASL基础:语法 

  在语法上,NASL非常类似于C,只是去掉了一些烦人的东西。你勿需顾及对象的类型,也不用为它们分配和释放内存;在使用变量之前不必事先声明。这样,你就可以只致力于安全测试插件的的编写。 

  如果你以前不懂C语言,读这个教程可能要费点劲,如果你对C语言已经很精通,读本教程将非常轻松。 

  2.1.注释 

  在NASL中,注释符是#。它只对当前行有效,例如: 

  有效的注释: 

   a = 1 ; #let a = 1 
   #set b to 2 
   b = 2; 

  无效的注释: 

   # 
   set a to 1 
   # 
   a = 1; 
   a = # set a to 1 # 1; 

  2.2.变量、变量类型、内存分配和包含(include) 

  与C语言不同,在使用变量之前,你不用事先声明,也不用关心它们的类型。如果你的操作错误(例如:把一个IP报文和一个整数相加),NASL就会提醒你。你也不必关心C语言中经常遇到的内存分配和包含(include)等问题,在NASL中没有include,而且内存是在需要时自动分配。 

  2.3.数字和字符串 

  NASL中的数字可以使用三种进制:十进制、十六进制和二进制。例如: 

   a = 1204; 
   b = 0x0A; 
   c = 0b001010110110; 
   d = 123 + 0xFF; 

  数组必须使用引号。注意:和C语言不同,除非使用string()函数,否则NASL解释器将不解释特殊字符(例如:\n)。例如: 

   a = "Hello\nI'm Renaud"; #a等于Hello\nI'm Renaud",\n没有特殊含义 
   a = string("Hello\nI'm Renaud");#b等于"Hello 
   # I'm Renaud" 
   c = string(a); #c等于b 

   string()函数将在“字符串处理”中详细讨论。 

  2.4.匿名/非匿名参数 

  非匿名函数(Non-anonymous Function) 

  NASL对函数参数的处理方式也C语言也不相同。在C语言中,程序员必须只参数的位置。 

  如果一个函数的参数超过10个,就非常让人头疼。例如,一个构造IP报文的函数就可能有很多参数。如果你需要使用这个函数,就得记住参数的确切次序,这非常浪费时间。 

  在NASL中尽量避免出现这种情况。 

  在NASL中,当函数的参数次序比较重要,并且当这个函数不同的参数是不同的类型,这个函数就是一个非匿名函数。也就是,你必须给出元素名。如果你忘记了某些元素,在运行时NASL会给你错误提示。例如: 

   forge_ip_packet()函数有很多参数。以下两种调用方式都有效并且执行相同的操作: 

    forge_ip_packet(ip_hl:5,ip_v:4,ip_p:IPPROTO_TCP); 
    forge_in_packet(ip_p:IPPROTO_TCP,ip_v:4,ip_hl:5); 

  在运行时,用户会被提示缺少参数(ip_len等)。 

  匿名函数(Anonymous function) 

  如果函数只有一个参数,或者所有参数的类型是相同的,这种函数就叫做匿名函数。例如: 

   send_packet(my_packet); 
   send_packet(packet1,packet2,packet3); 

  这些函数可以有选项。例如:在使用send_packet()函数时,你可以决定是否等待回应。如果你感觉没有必要接收目标的回应,你可以使用如下调用形式来加速安全测试速度: 

   send_packet(packet,use_pcap:FALSE); 

  2.5.for和while 

  在NASL中也存在for和while两种循环控制,和C语言的几乎完全相同,其语法格式如下: 

   for(instruct_start;condition;end_loop_instruction) 
    { 
     # 
     #需要执行的代码 
     # 
    } 

  或者 

   for(instruction_start;condition;end_loop_instruction)fuction(); 

  While的格式: 

   while(condition) 
    { 
     # 
     #执行的代码 
     # 
    } 

  或者: 

  while(condition)function(); 

  例如: 

   # 显示从1到0 
   for(i=1;i〈=10;i=i+1)display("i : ",i,"\n"); 

   # 显示从1到9以及它们是奇数还是偶数 
   for(j=1;j〈=10;j=j+1) 
    { 
     if (j&1)display(j," is odd\n"); 
      else display(j," is even\n"); 
    } 

   # 使用while 
   i = 0; 
   while(i〈10) 
    { 
     i=i+1; 
    } 

  2.6.用户定义的函数 

  NASL允许用户定义自己的函数。用户可以使用如下的语法定义自己的函数: 

   function my_func(argument1,argment2,....) 

  用户定义的函数必须使用非匿名(non-anonymous)参数,NASL能够处理递归调用。例如: 

   function fact() 
    { 
     if((n==0)││(n==1)) 
      return(n); 
     else 
      return(n*fact(n:n-1)); 
    } 

   display("b! is ",fact(n:5),"\n); 

  另外,用户自己定义的函数不能调用其它的用户定义函数(实际上是可以的但是遇到这种情况,NASL解释器会向你发出警告)。 

  注意:如果你需要让自己的函数返回一个值,需要使用return()函数。因为return()是一个函数,因此需要有括号,下面这种写法就是错误的: 

   function func() 
    { 
     return 1; #这种写法在C语言中是可以的,但是在NASL中不性 
    } 

  2.7.操作符 

  一些标准的C语言操作符也可以用于NASL,包括:+、-、*、/和%。目前,NASL还不支持操作符的优先级,但是以后版本将会支持操作符的优先级。另外,NASL也支持C语言的二进制操作符│和&。 

  除此之外,NASL还有两个独有的操作符: 

  x操作符 

  对于某些简单的循环使用for或者while非常不便,而且每次循环还需要对条件进行检查,造成效率的下降。因此NASL引入了一个x操作符来简化某些循环代码。例如:如果你需要发出10次UDP报文,使用x操作符,只要下面一行代码就可以了: 

   send_packet(udp)x10; 

  〉〈操作符 

  〉〈操作符是一个布尔型操作符,表示如果一个字符串A包含在另一个字符串B中,就返回真,例如: 

   a = "Nessus"' 
   b = "I like Nessus"; 
   if(a〉〈b) 
    { 
     #结果为真 
     display(a " is contained in ",b,"\n"); 
    } 

3.网络相关函数 

  3.1.套接字处理 

  套接字是使用TCP或者UDP协议和其它主机通讯的途径。在NASL中不允许你直接打开一个和测试目标通讯的套接字,因此你只能使用NASL提供的函数打开套接字。 

  3.1.1.如何打开一个套接字 

  在NASL中,函数open_sock_tcp()和open_sock_udp()分别用于打开一个TCP或者UDP套接字。这两个函数使用匿名(anonymous)参数。当前,你每次智能打开一个端口,将来的版本将解决这个问题。例如:你可以使用如下代码分别打开一个TCP和UDP套接字: 

   #在80端口打开一个TCP套接字 
   soc1=open_sock_tcp(80); 

   #在123端口打开一个UDP套接字 
   soc2=open_sock_udp(123); 

  如果无法和远程主机建立连接,这两个函数会返回0。不过,通常open_sock_udp()不会失败,因为没有办法确定远程主机的UDP端口是否开放,对于open_sock_tcp(),如果远程主机的端口是关闭的,它就会返回0。 

  open_sock_tcp()可以用于对TCP端口的简单扫描,例如: 

   start = prompt("First port to scan?"); #输入开始的端口 
   end = prompt("Last port to scan?"); #输入结束的端口 
   for(i=start;i〈end;i=i+1) 
    { 
     soc=open_sock_tcp(i); 
     if(soc) 
      { 
       display("Port ",i," is open\n"); 
       close(soc); 
      } 
    } 

  3.1.2.关闭一个端口 

  关闭一个端口使用close()函数,在close()内部,关闭端口之前,它首先会调用shutdown()函数。 

  3.1.3.读写套接字 

  根据被读写的套接字类型,可以选择使用如下函数完成这两项操作: 

   recn(socket:〈socketname〉,length:〈length〉 [,timeout:〈timeout〉]) 

  从套接字〈socketname〉读取〈length〉个字节,这个函数可以用于TCP和UDP。超时(timeout)参数是可选的,以秒为单位。 

   recv_line(socket:〈socketname〉,length:〈length〉 [,timeout:〈timeout〉]) 

  这个函数和recv()函数类似,只是如果遇到换行(\n)操作终止。这个函数只能用于TCP套接字。 

   send(socket:〈socket〉,data:〈data〉 [,length:〈length〉]) 

  从套接字〈socket〉发送数据〈data〉。可选参数length告诉函数发送〈length〉字节。如果没有设置length,发送操作就在遇到NULL时终止。 

  如果没有设置超时参数,读函数(recv()和recv_line())就使用默认的超时时间5秒。如果时间到,它们就返回FALSE。例如: 

   # 以下代码用于显示远程主机的banner信息 
   soc = open_sock_tcp(21); 
   if(soc) 
    { 
     data = recv_line(socket:soc,length:1024); 
     if(data) 
      { 
       display("The remote FTP banner is : \n",data,"\n"); 
      } 
     else 
      { 
       display("The remote FTP server seems to be tcp-wrapper\n"); 
      } 
     close(soc); 
    } 

  3.1.4.高层操作 

  NASL有一些针对FTP和WWW协议的函数,用于简化对这两个应用层协议的某些操作。 

   ftp_log_in(socket:〈soc〉,user:〈login〉,pass:〈pass〉) 

  尝试通过〈soc〉套接字登录到远程FP主机。如果用户名〈login〉和密码〈pass〉都正确,就返回TRUE,否则返回FALSE。 

  ftp_get_pasv_port(socket:〈soc〉) 

  向远程FTP服务器发出一个PASV命令,获得连接的端口。NASL脚本可以通过这个端口从FTP服务器下载数据。如果发生错误函数将返回FALSE。 

  is_cgi_installed(〈name〉) 

  测试远程WEB服务器是否安装了名为〈name〉的CGI程序。这个函数向远程WEB服务器发出GET请求实现这个目的。如果〈name〉不是以斜杠(/)开头,就认为它是相对于/cgi-bin/。 

  这个函数也可以用于确定某个文件是否存在。 

  示例脚本: 

   # 
   # 针对WWW服务器的测试 
   # 
   if(is_cgi_installed("/robots.txt")) 
    { 
     display("The file /robots.txt is present\n"); 
    } 

   if(is_cgi_installed("php.cgi")) 
    { 
     display("The CGI php.cgi is installed in /cgi-bin/\n"); 
    } 

   if(!is_cgi_installed("/php.cgi")) 
    { 
     display("There is no php.cgi in the remote web root\n"); 
    } 

   # 
   # 针对FTP服务器的测试 
   # 
   # 打开一个连接 
   soc = open_sock_tcp(21); 
   # 匿名登录到远程FTP主机 
   if(ftp_log_in(socket:soc,user:"anonymous",pass:"joe@")) 
    { 
     # 打开一个被动传输模式的端口 
     port = ftp_get_pasv_port(socket:soc); 
     if(port) 
      { 
       soc2 = open_sock_tcp(port); 
       #尝试获得远程系统的/etc/passwd文件 
       data = string("RETR /etc/passwd\r\n"); 
       send(socket:soc,data:data); 
       password_file = recv(socket:soc2,length:10000); 
       display(password_file); 
       close(soc2); 
      } 
     close(soc); 
    } 

  3.2.原始报文处理 

  NASL允许用户构造自己的IP报文,而且报文的定制是以一种智能的方式进行的。例如,如果你改变了一个TCP报文的某个参数,就会造成其TCP校验和发生改变,但是你不必为此费心,NASL会自动完成。 

  所有的原始报文构造函数都使用非匿名(non-anonymous)参数。参数的名字都是来自BSD的包含文件。因此一个IP报文的长度域叫做ip_len而不是length。 

  3.2.1.构造IP报文 

  在NASL中,你可以使用forge_ip_packet()函数构造一个新的IP报文;使用set_ip_element()函数获得报文某个域的值;使用set_ip_element()函数改变现有IP跋文某个域的值。forge_ip_packet函数的原形如下: 

   〈return_value〉=forge_ip_packet( 
     ip_hl :〈ip_hl〉, 
     ip_v :〈ip_v〉, 
     ip_tos :〈ip_tos〉, 
     ip_len :〈ip_len〉, 
     ip_id :〈ip_id〉, 
     ip_off :〈ip_off〉, 
     ip_ttl :〈ip_ttl〉, 
     ip_p :〈ip_p〉, 
     ip_src :〈ip_src〉, 
     ip_dst :〈ip_dst〉, 
     [ip_sum :〈ip_sum〉]); 

  其中,ip_sum参数是可选的,如果没有使用,NASL会自动计算报文的校验和。ip_p参数可以是一个整数值,或者是IPPROTO_TCP、IPPROTO_UDP、IPPROTO_ICMP、IPPROTO_IGMP或者IPPROTO_IP等常量中的某个值。 

  get_ip_element()函数的原型如下: 

   〈element〉=get_ip_element( 
     ip :〈ip_varible〉, 
     element :"ip_hl"│"ip_v"│ip_tos"│"ip_len"│ 
     "ip_id"│"ip_off"│"ip_ttl"│"ip_p"│ 
     "ip_sum"│"ip_src"│"ip_dst"); 

  get_ip_element()将返回报文中的某个域的值。element参数必须是"ip_hl"、"ip_v"、ip_tos"、"ip_len"、"ip_id"、"ip_off"、"ip_ttl"、"ip_p"、"ip_sum"、"ip_src"、"ip_dst"中的一个,而且引号是必不可少的。 

  set_ip_elements()函数的原型如下: 
   set_ip_elements( 
    ip :〈ip_variable〉, 
    [ip_hl :〈ip_hl〉,] 
    [ip_v :〈ip_v〉,] 
    [ip_tos :〈ip_tos〉,] 
    [ip_len :〈ip_len〉,] 
    [ip_id :〈ip_id〉,] 
    [ip_off :〈ip_off〉,] 
    [ip_ttl :〈ip_ttl〉,] 
    [ip_p :〈ip_p〉,] 
    [ip_src :〈ip_src〉,] 
    [ip_dst :〈ip_dst〉,] 
    [ip_sum :〈ip_sum〉] 
   ); 

  这个函数可以改变IP报文〈ip_varible〉的值,如果你没有修改ip_sum域的值,它会自动重新计算。这个函数没有构造报文的能力,因此需要把它放在forge_ip_packet()函数之后。 

  最后,还有一个函数dump_ip_packet()需要说明一下,这个函数能够以可读的方式把IP报文的内容输出到屏幕。这个函数应该只用于调试目的。 

  3.2.2.构造一个TCP报文 

  forge_tcp_packet()用来构造TCP报文。函数原型如下: 

   tcppacket = forge_tcp_packet( 
    ip :〈ip_packet〉, 
    th_sport :〈source_port〉, 
    th_dport :〈destination_port〉, 
    th_flags :〈tcp_flags〉, 
    th_seq :〈sequence_number〉, 
    [th_x2 :〈unused〉], 
    th_off :〈offset〉, 
    th_win :〈window〉, 
    th_urp :〈urgent_pointer〉, 
    th_sum :〈checksum〉, 
    [data :〈data〉]); 

  其中,标志参数th_flags必须是TH_SYN、TH_ACK、TH_FIN、TH_PUSH或者TH_RST,这些标志可以使用│操作符结合到一块。th_flags还可以使用一个整数值。ip_packet必须首先由forge_ip_packet()函数产生或者使用send_packet()、pcap_next()函数得到的返回值。 

  函数set_tcp_elements()能够修改TCP报文的内容,其原型如下: 

   set_tcp_elements( 
    tcp :〈tcp_packet〉, 
    [th_sport :〈source_port〉,] 
    [th_dport :〈destination_port〉,] 
    [th_flags :〈tcp_flags〉,] 
    [th_seq :〈sequence_number〉,] 
    [th_ack :〈acknowledgement_number〉,] 
    [th_x2 :〈unused〉,] 
    [th_off :〈offset〉,] 
    [th_win :〈window〉,] 
    [th_urp :〈urgent_pointer〉,] 
    [th_sum :〈checksum〉,] 
    [data :〈data〉]); 

  除非你自己设置th_sum参数,否则函数会自动计算报文的校验和。 

  函数get_tcp_element()用来设置TCP报文的内容,其原型如下: 

   element = get_tcp_elements( 
    tcp :〈tcp_packet〉, 
    element :〈element_name〉); 

  element_name必须是"tcp_sport"、"th_dport"、"th_flags"、"th_seq"、"th_ack"、"th_x2"、"th_off"、"th_win"、"th_urp"、"th_sum"其中之一。注意:引号是不可缺少的。 

  3.2.3.构造UDP报文 

  UDP报文构造函数forge_udp_packet()和TCP构造函数极为类似,其原型如下: 

   udp = forge_udp_packet( 
    ip :〈ip_packet〉, 
    uh_sport :〈source_port〉, 
    uh_dport :〈destination_port〉, 
    uh_ulen :〈length〉, 
    [uh_sum :〈checksum〉,] 
    [data :〈data〉]); 

  而set_udp_elements()和get_udp_elements()函数和TCP报文对应的处理函数用法也相同。 

  3.2.4.构造ICMP报文 
  3.2.5.构造IGMP报文 
  3.2.6.发送报文 

  构造报文的操作完成之后,你可以使用send_packet()函数将它们发送出去,其原型如下: 

   reply = send_packet(packet1,packet2,....,packetN, 
    pcap_active:〈TRUE│FALSE〉, 
    pcap_filter:〈pcap_filter〉); 

  如果pcap_active参数为TRUE,这个函数就会等待目标的回应。pcap_filter用来设置你需要得到的报文类型,详情请参考pcap或者tcpdump的手册页。 

  3.2.7.读取报文 

  你可以使用pcap_next()函数读取一个报文,其原型如下: 

   reply = pcap_next(); 

  这个函数将从你使用的最后一个接口读取一个报文,报文的类型取决于最后设置的pcap类型。 

  3.3.工具函数 

  NASL还提供了一些工具函数以简化你的编程。 

   this_host() 

  获得运行脚本的主机IP地址,没有参数。 

   get_host_name() 

  返回当前被测试主机的主机名,没有参数。 

   get_host_ip() 

  返回当前被测试主机的IP地址,没有参数。 

   get_host_open_port() 

  获得远程主机打开的第一个端口号,没有参数。这个函数对于某些脚本(例如:land)非常有用,有些TCP序列号分析程序需要通过这个函数获得远程主机一个打开的端口。 

   get_port_stat(〈portnum〉) 

  如果TCP端口〈portnum〉打开或者其状态是未知,就返回TRUE。 

   telnet_init(〈soc〉) 

  在一个打开的套接字上初始化一个telnet会话,并且返回telnet数据的第一行。例如: 

   soc = open_sock_tcp(23); 
   buffer = telnet_init(soc); 
   display("The remote telnet banner is ",buffer,"\n"); 
   tcp_ping() 

  如果远程主机应答TCP ping请求(发送一个设置ACK标志的TCP报文),本函数就返回TRUE,没有参数。 

   getrpcport() 

  获得远程主机的RPC端口号,原型为: 

   result = getrpcport(program :〈program_number), 
    protocol :〈IPPROTO_TCP│IPPROTO_UDP, 
    [version :〈version〉]); 

  如果远程主机的〈program_number〉程序没有在RPC portmap监控进程中注册就返回0。 

4.字符串处理函数 

  NASL允许你象处理数字一样处理字符串。因此,你能够安全地使用==、〈和〉等操作符。 

  例如: 
    
   a = "version 1.2.3"; 
   b = "version 1.4.1"; 
   if(a〈b) 
    { 
     #因为version 1.2.3比version 1.4.1低 
     #因此,开始执行这里的代码 
    } 
   c = "version 1.2.3"; 
   if(a == c) 
    { 
     #两个字符串相等 
     #因此执行这里的代码 
    } 

  在NASL中,也可以获得一个字符串的某个字符,和C语言完全相同,例如: 

   a = "test"; 
   b = a[1]; #b等于"e" 

  你也可以在一个字符串中加、减一个字符串,例如: 

   a = "version 1.2.3"; 
   b = a - "version"; #b等于"1.2.3" 
   a = "this is a test"; 
   b = "is a "; 
   c = a - b; #c等于"this test" 
   a = "test"; 
   c = " is a "; 
   c = a - b; #a等于"testtest" 

  除此之外,〉〈也可以用于字符串的处理。NASL有很多函数来构造或者修改字符串: 

  4.1.处理正则表达式的ereg()函数 

  在NASL中,模式匹配是由ereg()函数完成的。原型如下: 

   result = ereg(pattern:〈pattern,string:〈string〉) 

  正则表达式的语法是egrep风格的。细节请参考egrep的手册页。例如: 

   if(ereg(pattern:".*",string:"test")) 
    { 
     display("Always execute\n"); 
    } 

   mystring=recv(socket:soc,length:1024); 
   if(ereg(pattern:"SSH-.*-1\..*",string:mysting)) 
    { 
     display("SSH 1.x is running on this host"); 
    } 

  4.2.egrep()函数 

  egrep()函数返回一个多行文本中,匹配〈pattern〉的第一行。如果对单行文本使用这个函数,它就相当于ereg()。如果没有匹配的行,它就返回FALSE。其原型如下: 

   str=egrep(pattern:〈pattern〉,string:〈string〉) 

  示例: 

   soc=open_soc_tcp(80); 
   str=string("HEAD / HTTP/1.0\r\n\r\n"); 
   sen(socket:soc,data:str); 
   r=recv(socket:soc,length:1024); 
   server=egrep(pattern:"^Server.*",string:r); 
   if(server)display(server); 

  4.3.crap()函数 

  crap()函数非常便于测试缓冲区溢出,有两种原型: 

   crap(〈length〉) 

  获得一个以'X'填充的长度为〈length〉的字符串。 

   crap(length:〈length〉,data:〈data〉) 

  高一个长度为〈length〉的字符串,并使用〈data〉填充字符串。例如: 

   a=crap(5); #a="XXXXX" 
   b=crap(4096); #b="XXX...XXX"(4096个X) 
   c=crap(length:12,data:"hello"); #c="hellohellohe" 

  4.4.string()函数 

  这个函数用来定制字符串。其原型为: 

   string(〈string1〉,[〈string2〉,...,〈stringN〉]); 

  它能够解释字符串中\n、\t等特殊字符。例如: 

   name="Renand"; 
   a=string("Hello,I am ",name,"\n"_; #a等于"Hello,I am Renaud" 
   #末尾回行 
   b=string(1," and "m",2," make ",1+2); #b等于"1 and 2 make 3" 
   c=string("MKD ",crap(4096),"\r\n"); #c等于"MKD XXX...XXXXX"(4096个X) 
   #后面是一个回车和一个回行 

  4.5.strlen()函数 

  strlen()函数返回一个字符串的长度,例如: 

  a==strlen("abcd"); #a等于4 

  4.6.raw_string()函数 

  这个函数能够把数字转换为对应的字符,例如: 

   a=raw_string(80,81,82); #80、81、82分别对应ASCII字符的PQR 

  4.7.strtoint()函数 

  这个函数把一个NASL整数转换为一个二进制整数。原型为: 

   value=strtolen(number:〈nasl_integer〉,size:〈number_of_byte〉); 

  这个函数比较适合于和raw_string()函数一块使用。size参数是NASL整数的字节数,可以是:1、2、4。 

  4.8.tolower()函数 

  这个函数能够把一个字符串中的所有大写字符转换为小写字符。原型为: 

   string2=tolower(〈string〉); 

  例如: 

   a="Hello,World" 
   b=tolower(a); #b等于"hello,world" 
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值