Ruby——Metasploit的核心
Ruby编程语言可以说是Metasploit框架的核心。不过Ruby到底是什么呢?根据Ruby官方网站的说法,Ruby是一种简单而强大的编程语言。日本的松本行弘在1995年设计并实现了Ruby语言。后来它被进一步定义为功能类似于Perl语言的、具有动态特性和反射机制的、通用的面向对象
(Object-Oriented Programming,OOP)的程序设计语言。
可以从http://Rubyinstaller.org/downloads/
下载Windows/Linux版本的Ruby。
也可以通过下面的网页获得优秀的Ruby学习资源:http://tryruby.org/levels/1/challenges/ 。
1.1 创建你的第一个Ruby程序
Ruby是一种十分简单易学的编程语言。首先了解一下Ruby语言的基础知识。但是请记住,Ruby是一种内容十分丰富的编程语言。如果讲解Ruby的所有知识将会远远超出本书的范围,因此我们将只涉及编写Metasploit模块所必需的Ruby知识。
1.Ruby的交互式命令行
Ruby语言提供了一个可以进行交互的命令行。在交互式命令行上进行工作可以使我们更清楚地理解Ruby的基础知识。好的,现在就要开始了。首先打开你的CMD命令行或者终端窗口,然后在其中输入命令irb
来启动Ruby的交互式命令行。
先在Ruby交互式命令行中输入一些内容,然后查看发生的变化;假设如下图所示输入数字2
:
irb(main):001:0> 2
=> 2
交互式命令行返回并输出了刚刚输入的值。现在,来进行另一个操作,例如一个如下图所示的加法运算:
irb(main):002:0> 2+3
=> 5
可以看到,如果输入的内容是一个表达式的话,交互式命令行会返回并输出表达式的结果。
现在来执行一些对字符串的操作,例如将一个字符串类型的值保存到一个变量中。过程如下所示:
irb(main):005:0> a= "nipun"
=> "nipun"irb(main):006:0> b= "loves
Metasploit"
=> "loves metasploit"
当对变量a和b赋值结束后,我们来查看一下当在交互式命令行中输入a和a+b时,交互式命令行是如何反应的:
irb(main):014:0> a
=> "nipun"irb(main):015:0> a
+b=> "nipun loves me
tasploit"
可以看到,当将a作为一个输入时,交互式命令行返回并输出了它保存的名为a的变量的值。类似地,输入a+b
返回并输出的结果为变量a和b的连接。
2.在命令行中定义方法
方法或者函数是一组语句,当我们调用它们时会开始执行。可以简单地在Ruby交互命令行中声明一个方法,也可以在脚本中对它们进行声明。在使用Metasploit模块时,Ruby的方法是一个很重要的部分。来看看它的语法格式:
def method_name [( [arg [= default]]...[, * arg [, &expr ]])]
exprend
要定义一个方法,首先以def
开始,紧随其后的是方法的名称,然后是包含在括号中的参数和表达式。我们还将一个end
声明放在所有表达式的最后来结束对方法的定义。这里,arg
指的是方法所接收的参数,expr
指的是方法用来接受并计算的表达式。来看一个例子:
irb(main):002:0> def xorops(a,b)
irb(main):003:1> res = a ^ birb(main):004:1> return resirb(main):005:1> end=> :xorops
我们定义了一个名为xorops的方法,它接收a和b两个参数。接着将接收到的参数进行异或运算,并将结果保存到一个名为res的新变量中。最后使用return语句来返回结果。
irb(main):006:0> xorops(90,147)
=> 201
可以看到,函数通过异或运算打印出了正确的结果。Ruby语言提供了puts
和print这两种输出打印函数。当涉及Metasploit框架时,将使用print_line
函数。我们可以分别使用print_good、print_status和print_error
语句来表示成功执行、状态和错误。下面给出了具体的示例:
print_good("Example of Print Good")
print_status("Example of Print Stat
us")print_error("Example of Print Error
")
当你在Metasploit模块下运行这些命令时会产生如下输出,+
符号并绿色显示表示正常,*
符号并蓝色显示表示状态信息,-
符号并红色显示表示错误信息。
[+] Example of Print Good
[*] Example of Print Stat
us[-] Example of Print Error
我们将会在本章的后半部分学习各种类型的输出语句的作用。
1.2 Ruby中的变量和数据类型
变量是指一个值随时可以改变的占位符。在Ruby中,我们只有在需要使用一个变量的时候才对其进行声明。Ruby语言支持数目众多的变量数据类型,但是我们只讨论与Metasploit相关的数据类型。下面来看看这些数据类型以及它们的操作。
1.字符串的处理
字符串是表示一个流
或字符序列的对象。在Ruby中,可以像上一个例子中那样轻松地将一个字符串类型的值赋给一个变量。通过简单地使用双引号或者单引号标记一个值,就可以将这个值定义为字符串。
这里推荐尽量使用双引号标记,因为单引号标记可能会引发问题。看一下可能引发的问题:
irb(main):005:0> name = 'Msf Book'
=> "Msf Book"irb(main):006:0> name = 'Msf's Boo
k'irb(main):007:0' '
可以看到,当使用一对单括号标记时,它们工作了。然而当试图使用Msf's代替Msf时,错误却出现了。这是因为在程序执行时,系统误将Msf's中的单引号当成了字符串结束的单引号,这显然并非我们所愿。而这种情况导致程序出现了语法错误。
1)字符串连接
在使用Metasploit模块的时候,会用到字符串连接功能——我们有好几个实例都需要将两个不同的结果连接成一个字符串。可以使用+
运算符来实现字符串链接;另外,当需要在一个变量后面追加数据的时候,也可以使用<<
运算符:
irb(main):007:0> a = "Nipun"
=> "Nipun"irb(main):008:0> a << " love
s"=> "Nipun loves"irb(main):009:0> a << " Meta
sploit"=> "Nipun loves Metasploit"irb(main):010:0> a=> "Nipun loves Metasploit"irb(main):011:0> b = " and p
lays counte
r strike"=> " and plays counter strik
e"irb(main):012:0> a+b=> "Nipun loves Metasploit a
nd plays co
unter strike"
这里先将"Nipun"赋值给变量a,然后再使用<<运算符在它的后面追加了"loves"和"Metasploit"。使用另一个变量b保存了值"and plays counter strike"。接下来,简单地使用+运算符将这两个变量连接起来,得到了一个完整的输出"Nipun loves Metasploit and plays counter strike"。
2)子字符串(substring)函数
在Ruby中可以轻松地使用substring函数来获取子字符串——只需要指明子字符串在字符串中的起始位置和长度,就可以获得它,如下所示:
irb(main):001:0> a= "12345678"
=> "12345678"irb(main):002:0> a[0,2]=> "12"irb(main):003:0> a[2,2]=> "34"
3)split函数
可以使用split函数将一个字符串类型的值分割为一个变量数组。用一个简单的例子来说明这一点:
irb(main):001:0> a = "mastering,metasploit"
=> "mastering,metasploit"irb(main):002:0> b = a.split(",")=> ["mastering", "metasploit"]irb(main):003:0> b[0]=> "mastering"irb(main):004:0> b[1]=> "metasploit"
可以看到,现在已经将字符串转换成了一个新的数组b。这个数组b中包含了b[0]和b[1]两个元素,分别是"mastering"和"metasploit"。
2.Ruby中的数字和转换
我们可以直接在算术运算中使用数字。在处理用户的输入时,可以用to_i函数将字符串类型的输入转换成数字。另一方面,也可以使用to_s函数将一个数字转换成字符串。来看一个简单的例子以及它的输出:
irb(main):006:0> b="55"
=> "55"irb(main):007:0> b+10TypeError: no implicit
conversi
on of Fixnum into Stri
ng from (irb):7:in `+'
from (irb):7 from C:/Ruby200/bin
/irb:12:
in `<main>'irb(main):008:0> b.to_i
+10=> 65irb(main):009:0> a=10=> 10irb(main):010:0> b="hel
lo"=> "hello"irb(main):011:0> a+bTypeError: String can't
be coer
ced into Fixnum from (irb):11:in `+
' from (irb):11 from C:/Ruby200/bin
/irb:12:
in `<main>'irb(main):012:0> a.to_s
+b=> "10hello"
可以看到,当将一个用引号标记的值赋给变量b时,这个变量会被当作一个字符串处理。当使用这个变量进行加法运算时就会出现错误。但是,对其使用了to_i函数以后,这个变量就会从字符串类型转换成整型,从而可以正常地执行加法运算。同样,对于字符串,当我们试图将一个整数和一个字符串连接到一起时,错误就出现了。不过,当进行了类型转换后,一切就正常了。
Ruby中的数制转换
在使用渗透模块和其他模块时,都将使用到各种转换机制。现在来看一些之后会用到的数制转换。
16进制到10进制的转换在Ruby中使用hex函数对一个数值进行从16进制到10进制的转换是十分简单的,下面给出了一个示例:
irb(main):021:0> a= "10
=> "10"irb(main):022:0> a.hex=> 16
可以看出,16进制下的10对应10进制下的16。10进制到16进制的转换和上例中相反的操作可以使用to_s
函数来实现:
irb(main):028:0> 16.to_s(16)
=> "10"
3.Ruby中的范围
范围
(range)是一个很重要的内容,广泛应用在Metasploit的辅助模块中,例如扫描模块和测试模块。
让我们定义一个范围,并且查看一下可以对这种数据类型进行哪些操作:
irb(main):028:0> zero_to_nine= 0..9
=> 0..9irb(main):031:0> zero_to_nine.inclu
de?(4)=> trueirb(main):032:0> zero_to_nine.inclu
de?(11)=> falseirb(main):002:0> zero_to_nine.each{
|zero_to
_nine| print(zero_to_nine)}0123456789=> 0..9irb(main):003:0> zero_to_nine.min=> 0irb(main):004:0> zero_to_nine.max=> 9
我们可以看到一个范围对象提供的多种操作,例如搜索、查找最小值和最大值和显示范围中的所有数据。这里的include?函数可以检查范围中是否包含某一个特定的值。此外,min和max函数可以显示出范围中的最小值和最大值。
4.Ruby中的数组
我们可以简单地将数组定义为一系列的元素集合。来看一个例子:
irb(main):005:0> name = ["nipun","metasploit"]
=> ["nipun", "metasploit"]irb(main):006:0> name[0]=> "nipun"irb(main):007:0> name[1]=> "metasploit"
到现在为止,已经介绍了所有编写Metasploit模块必需的变量和数据类型的相关知识。
有关变量和数据类型的更多信息,请访问http://www.tutorialspoint.com/ruby/
。
有关使用Ruby编程的速查表,请参考https://github.com/savini/cheatsheets/raw/master/ruby/RubyCheat.pdf。
1.3 Ruby中的方法
方法是函数的另一个说法。除了Ruby程序员以外,其他背景的程序员可能经常使用这两种叫法。方法就是指能执行特定操作的子程序。方法的使用实现了代码的重用,大大减短了程序的长度。定义一个方法很容易,在定义开始的地方使用def关键字,在结束的地方使用end关键字。让我们通过一个简单的程序来了解它们的工作方式,例如打印出50个空格。
def print_data(par1)
square = par1*par1return squareendanswer = print_data(
50)print(answer)
这里的print_data方法接收主函数发送过来的参数,然后让其乘以自身,再将结果使用return返回。这个程序将返回的值放到了一个名为answer的变量中,随后输出了这个值。我们将在本章的后面和接下来的几章中频繁地使用Ruby中的方法。
1.4 决策运算符
与其他任何编程语言一样,决策在Ruby中也是一个简单的概念。看一个例子:
irb(main):001:0> 1 > 2
=> false
同样,再来查看一个字符串数据的例子:
irb(main):005:0> "Nipun" == "nipun"
=> falseirb(main):006:0> "Nipun" == "Nipun"
=> true
来看一个使用决策运算符的简单程序:
def find_match(a)
if a =~ /Metasplo
it/return trueelsereturn falseendend# 主函数从这里开始a = "1238924983Me
tasploitduidisdid"bool_b=find_match
(a)print bool_b.to_s
在上面的这个程序中,我们使用了一个包含有"Metasploit"的字符串,这个字符串中的"Metasploit"
前后都添加了一些无用字符。然后将这个字符串赋值给变量a。接下来,将该变量传递给函数find_match()
,这个函数的作用是检查该变量是否可以匹配正则表达式/Metasploit/。
如果这个变量中包含了"Metasploit"的话,函数的返回值就是true,否则就会将false赋值给bool_b变量。运行上面这个方法将会产生一个true,这是因为按照决策运算符=~的计算,这两个值是匹配的。
前面的程序在Windows系统环境中执行完成后输出的结果如下面的屏幕截图所示。
C:\Ruby23-x64\bin>ruby.exe a.rb
true
1.5 Ruby中的循环
迭代语句被称为循环。正如任何其他编程语言一样,Ruby编程中也包含循环结构。接下来让我们来使用一下这种结构,看看它的语法和其他编程语言的不同之处:
def forl(a)
for i in 0.
.aprint("Numb
er #{i}\n")endendforl(10)
上面的代码按照定义的范围从0遍历到10,实现了循环打印输出当前的值。在这里我们使用#{i}去打印输出变量i的值。关键字\n指定开始新的一行。因此,每一次打印输出变量时,都会自动占用新的一行。迭代循环是通过each
实现的。这是一种十分常见的做法,在Metasploit模块中被广泛使用。下面是一个示例:
def each_example(a)a.each do |i|print i.to_s + "\t"endend# 主函数从这里开始
a = Array.new(5)a=[10,20,30,40,50
]each_example(a)
在上面的代码中,我们定义了一个方法,这个方法接收一个数组a,然后将数组a中的所有元素用each
循环打印出来。使用each方法完成循环会将数组a中的元素临时保存到i中,一直到下一个循环时再重写这个变量的值。输出语句中的\t表示一个制表位(tab)。有关循环的更多信息,请访问http://www.tutorialspoint.com/Ruby/Ruby_loops.htm。
1.6 正则表达式
正则表达式用来匹配一个字符串或者获取字符串在一组给定的字符串或句子中出现的次数。在Metasploit中,正则表达式是十分关键的。在编写漏洞检查工具和扫描工具以及分析某个给定端口的响应时,总会需要使用正则表达式。
让我们看一个例子,这里的程序演示了正则表达式的使用。设想这样一个场景:我们有一个变量n,它的值是Hello world,我们需要为它设计一个正则表达式。来看看下面的这部分代码:
irb(main):001:0> n = "Hello world"
=> "Hello world"irb(main):004:0> r = /world/=> /world/irb(main):005:0> r.match n=> #<MatchData "world">irb(main):006:0> n =~ r=> 6
我们创建另一个名为r的变量,并把正则表达式内容——/world/保存在其中。在下一行,我们用MatchData
类的match对象将这个字符串和正则表达式进行匹配。命令行返回了一个匹配成功的信息MatchData "world"
。接下来我们使用另一个运算符=~来完成字符串的匹配操作和匹配的具体位置。让我们看一个这样的例子:
irb(main):007:0> r = /^world/
=> /^world/irb(main):008:0> n =~ r=> nilirb(main):009:0> r = /^Hello/
=> /^Hello/irb(main):010:0> n =~ r=> 0irb(main):014:0> r= /world$/=> /world$/irb(main):015:0> n=~ r=> 6
分配一个新的值/^world/给r,这里^运算符表示要匹配字符串的开始位置。我们得到了输出nil,这说明并没有匹配成功。我们重新修改这个表达式以匹配单词Hello开始的字符串。这一次,系统的输出为数字0,这意味着在最开始的位置匹配成功。下一步,我们将正则表达式修改为/world$/,这意味着只有一个以单词world
结尾的字符串才会匹配。
有关Ruby中的正则表达式的更多信息,请访问http://www.tutorialspoint.com/Ruby/Ruby_regular_expressions.htm。。
有关如何构建正确的正则表达式的更多信息,请访问http://rubular.com/
网友评论