C#灰帽子:设计安全测试工具(txt+pdf+epub+mobi电子书下载)


发布时间:2021-03-08 10:28:16

点击下载

作者:(美)布兰德·佩里(Brandon Perry),王自亮,侯敬宜,李伟

出版社:机械工业出版社

格式: AZW3, DOCX, EPUB, MOBI, PDF, TXT

C#灰帽子:设计安全测试工具

C#灰帽子:设计安全测试工具试读:

前言

很多人问我为什么喜欢C#。我原本是一个开源软件的支持者、忠实的Linux用户和Metasploit的贡献者(主要使用Ruby编写),然而我却把C#当作我最喜欢的语言,这似乎很奇怪。这是为什么呢?许多年前,当我开始使用C#的时候,Miguel de Icaza(因GNOME出名)开始了一个叫作Mono的小项目。在本质上,Mono是一个Microsoft.NET框架的开源实现。C#被提交为ECMA标准,微软将其吹捧为替代Java的框架(因为C#代码可以在一个系统或平台上编译并在其他地方运行),唯一的问题是微软只为Windows操作系统发布了.NET框架。Miguel和一小群核心贡献者接受了使Mono项目成为.NET到达Linux社区的桥梁的重任。幸运的是,我的一个朋友建议我学习C#,但是他也知道我对Linux很感兴趣,他为我指明了这个刚刚起步的项目的方向,看看我是否可以同时使用C#和Linux。之后,我被C#深深吸引了。

C#是一种优雅的语言,C#的发明者和主要架构师Anders Hejlsberg曾经为Pascal编写编译器,然后为Delphi编写编译器,这些经历使他对各种编程语言的真正特点有深刻的理解。Hejlsberg加入微软之后,于2000年左右推出了C#。早年,C#与Java共享了很多语言特性,比如Java的语法细节,但是随着时间的推移,C#自成一派,并早于Java引入了一大堆功能,例如LINQ、代理和匿名方法。使用C#,你可以使用许多C和C++的强大特性,可以使用ASP.NET栈或丰富的桌面应用程序编写完整的Web应用程序。在Windows上,WinForms是UI库的首选,但对于Linux来说,GTK和QT库更易于使用。最近,Mono已经可以在OS X平台上支持Cocoa工具包,甚至支持iPhone和Android。

为什么信任Mono

贬低Mono项目和C#语言的人声称,Mono等技术如果在非Windows的任何平台上使用都是不安全的。他们认为微软将会停止开发Mono,使Mono被遗忘到许多人都不会严肃谈论这个项目的程度。我不认为这是一个风险。在撰写本书时,微软不仅收购了Xamarin公司(该公司由Miguel de Icaza创建以支持Mono框架),而且微软拥有大量的开源的核心.NET框架。在Steve Ballmer的领导下,微软还以许多令人难以想象的方式接受了开源软件。新任首席执行官Satya Nadella表示,微软与开源软件对接根本没有任何问题,建议各种公司要积极参与Mono社区,以便使用微软的技术来进行移动开发。

本书的读者对象

在网络和应用安全工程师中,许多人在一定程度上依赖自动化地扫描漏洞或分析恶意软件。因为有很多安全专业人员喜欢使用各种操作系统,所以编写每个人都可以轻松运行的工具可能很困难。Mono是一个不错的选择,因为它是跨平台的,并且有一个优秀的核心库集合,使安全专业人员将各种工作自动化变得简单。如果你有兴趣学习如何编写攻击性的Exploit、自动扫描基础设施的漏洞、反编译其他.NET应用程序、读取离线注册表配置单元、创建自定义跨平台载荷,那么本书涵盖的许多内容都会让你快速入门(即使你没有C#的使用背景)。

本书的主要内容

在本书中,我们将介绍C#的基础知识,然后使用合适的、丰富的库快速实现实际能用的安全工具。在应用程序之外,我们会编写模糊工具来找到可能的漏洞,并编写代码对发现的任何漏洞进行全面利用。你将看到C#语言特性和核心库的强大功能。一旦学习了基础知识,我们将自动化目前流行的安全工具,比如Nessus、Sqlmap和Cuckoo Sandbox。总之,在读完本书后,你将有一个包含库的执行方案列表,将许多安全专业人员经常执行的工作自动化。

第1章:C#基础知识速成

在这一章中,我们通过简单的例子介绍C#面向对象编程的基础知识,但同时覆盖了各种各样的C#特性。我们从一个Hello World程序开始,然后构建小的类,以便更好地了解面向对象的概念,然后介绍更高级的C#特性,例如匿名方法和P/Invoke。

第2章:模糊测试和漏洞利用技术

在这一章中,我们使用各种数据类型编写了一个寻找XSS和SQL注入的小型HTTP请求模糊工具(通过HTTP库与Web服务器通信)。

第3章:对SOAP终端进行模糊测试

在这一章中,我们采用前几章介绍的模糊测试工具概念,编写了另一个小型模糊测试工具,通过自动生成HTTP请求来检索和解析SOAP WSDL,以查找潜在的SQL注入。

同时该章也会介绍如何从标准库中获得优秀XML库。

第4章:编写有效载荷

在这一章中,我们将重点放在HTTP上,继续编写有效载荷。我们首先创建几个简单的有效载荷——一个通过TCP,另一个通过UDP。然后学习如何在Metasploit中生成x86/x86-64shellcode来创建跨平台和跨架构的有效载荷。

第5章:自动化运行Nessus

在这一章中,为了将几个漏洞扫描程序自动化,我们回到HTTP(第一个是Nessus),通过编程了解如何创建、观察和报告CIDR扫描的范围。

第6章:自动化运行Nexpose

在这一章中,我们继续专注于工具自动化,只不过转到Nexpose漏洞扫描器上。Nexpose的API也是基于HTTP的,可以自动化扫描漏洞并创建报告。Rapid7是Nexpose的创始人,为其社区产品提供一年免费的许可证,这对业余爱好者非常有用。

第7章:自动化运行OpenVAS

在这一章中,我们专注于使用开源的OpenVAS使漏洞扫描自动化。OpenVAS的API仅使用TCP套接字和XML实现通信协议,从根本上与Nessus和Nexpose不同。因为它也是免费的,所以对于希望通过有限的预算获得更多的漏洞扫描经验的爱好者来说很有用。

第8章:自动化运行Cuckoo Sandbox

在这一章中,我们将使用Cuckoo Sandbox进行数字取证。使用易用的REST JSON API自动提交潜在的恶意软件样本,然后报告结果。

第9章:自动化运行sqlmap

在这一章中,我们通过自动化执行sqlmap,最大限度地发挥SQL注入的危害。首先编写一些小工具,使用与sqlmap一起发送的易用的JSON API提交单个URL。一旦熟悉了sqlmap,我们会将其集成到第3章介绍的SOAP WSDL模糊测试工具中,自动利用和验证任何潜在的SQL注入漏洞。

第10章:自动化运行ClamAV

在这一章中,我们开始关注与本机的非托管库进行交互。ClamAV是一个受欢迎的开源反病毒项目,虽然不是用.NET语言编写的,但是我们仍然可以与其核心库以及TCP守护进程交互,这将允许远程使用。我们会在这两种情况下介绍如何将ClamAV自动化。

第11章:自动化运行Metasploit

在这一章中,我们重点介绍Metasploit,学习如何通过配有核心框架的MSGPACK RPC以编程的方式利用和报告植入shell的主机。

第12章:自动化运行Arachni

在这一章中,我们关注通过双重许可配置黑盒Web应用程序扫描器Arachni,这是一个免费开源的项目。使用更简单的REST HTTP API和随附项目更强大的MSGPACK RPC,编写一些在扫描URL时自动报告调查结果的小工具。

第13章:反编译和逆向分析托管程序集

在这一章中,我们进行逆向工程。在Windows上有易于使用的.NET反编译器,但不适用于Mac或Linux,所以我们自己写一个小的反编译器。

第14章:读取离线注册表项

在这一章中,我们通过检查二进制结构的Windows注册表,将注意力集中在注册表项上,从而转向事件响应。学习如何解析和读取离线注册表项,可以检索系统启动密码,它存储在注册表中,用于加密密码的散列。

致谢

可以说,写这本书花了10年时间!虽然在电脑上我只写了3年。我的家人和朋友肯定注意到我一直在不断地谈论C#,但是他们非常宽容并理解我,成为我的超级耐心的听众。AHA的兄弟姐妹们给了我这本书中许多项目的灵感,是本书的重要支柱。非常感谢John Eldridge,一位亲密的朋友,是他带我进入C#世界,激发了我对编程的兴趣。Brian Rogers一直是我最好的技术资源之一,在本书的编写过程中,我们的思想产生了许多碰撞,并得到很多启发,他也是一个拥有敏锐眼光和见解的优秀的技术编辑。我的产品经理Serena Yang和Alison Law减轻了我反复修改书稿的痛苦。当然,Bill Pollock和Jan Cash把我模糊的表述变成了每个人都可以读懂的清晰的句子。非常感谢No Starch的全体工作人员!

最后的说明

本书所介绍的内容远远不能反映C#的强大功能和构建自动化工具的潜力,特别是因为我们创建的许多库是灵活的、可扩展的。我希望这本书展示了将常用的或烦琐的任务自动化是多么简单,并鼓励你继续完善我们创造的工具。可以在https://www.nostarch.com/grayhatcsharp找到本书的源代码和更新。第1章C#基础知识速成

与Ruby、Python、Perl等语言不同,C#程序默认可以在所有Windows操作系统上运行。另外,在如Ubuntu、Fedora或其他Linux系统上运行C#编写的程序也很简单,特别是自从可以通过如apt或yum的大多数的Linux包管理器安装Mono之后更是如此。这使得C#与大多数语言相比能够更好地满足跨平台的需求,因为C#拥有易于获取的简单而强大的标准库。总而言之,C#和Mono/.NET库为任何想要快速轻松地编写跨平台工具的人创建了一个不能拒绝的框架。1.1 选择IDE

大多数想要学习C#的人将使用Visual Studio这样的IDE(Integrated Development Environment,集成开发环境)编写和编译代码。微软的Visual Studio在全球是C#开发的事实上的标准。如Visual Studio社区版这样的免费版本可供个人使用,可以从微软的网站https://www.visualstudio.com/downloads/上下载。

在这本书的写作过程中,我使用了MonoDevelop和Xamarin Studio,这取决于我是用Ubuntu还是OS X。在Ubuntu上,可以使用apt包管理器轻松安装MonoDevelop。MonoDevelop由Xamarin维护,该公司也维护Mono。要安装它,请使用以下命令:

Xamarin Studio是MonoDevelop IDE的OS X版。Xamarin Studio和MonoDevelop具有相同的功能,但用户界面稍有不同。你可以从Xamarin的网站https://www.xamarin.com/download-it/上下载Xamarin Studio IDE安装程序。

这两个IDE中的任何一个都能满足我们在本书中的需求。其实如果你只想用vim,你甚至不需要一个IDE!我们也将尽快介绍如何使用Mono附带的命令行C#编译器而不是IDE编译一个简单的示例程序。1.2 一个简单的例子

对于使用过C或Java的人来说,C#的语法看起来似乎非常熟悉。与C和Java一样,C#是一个强类型的语言,这意味着一个变量在代码中的声明只能有一种类型(整型、字符串或者Dog类)并且永远是那种类型,不管那种类型是什么。我们先来快速看看清单1-1中的Hello World示例,该示例展示了一些C#基本的类型和语法。

清单1-1:一个基础的Hello World程序

一开始就需要导入将要使用的命名空间①,即用using声明导入System命名空间。类似于C中的#include,Java和Python中的import,Ruby和Perl中的require,这能允许我们访问程序中的库。声明要使用的库之后,应声明类存在的命名空间②。

与C(以及较旧版本的Perl)不同,C#是面向对象的语言,类似于Ruby、Python和Java。这意味着我们可以在编写代码的同时编写复杂的类来表示数据结构以及数据结构的方法。命名空间让我们的类和代码组织起来并且防止潜在的名称冲突,比如两个程序员创建了具有相同名称的两个类。如果两个具有相同名称的类在不同的命名空间中,那就不会有什么问题了。每个类都需要有一个命名空间。

有了命名空间,我们可以声明一个类③实现Main()方法④。如前所述,通过类可以创造复杂的数据类型以及与真实世界中的对象更匹配的数据结构。在这个例子中,类的名字并不重要,它只是用来包含Main()方法,Main()方法才是重点。因为在运行示例应用程序时要执行Main()方法。每个C#应用程序都需要一个Main()方法,就像C和Java一样。如果你的C#应用程序接受命令行参数,可以使用args变量⑤访问传递给应用程序的参数。

C#中存在如字符串⑥这样的简单数据结构,也能创建诸如表示日期和时间⑦的类的更复杂的数据结构。DateTime类是处理日期的核心C#类。在我们的例子中,使用它把当前的日期和时间(DateTime.Now)存储在变量now中。最后,使用声明的变量和Console类的Write()⑧和WriteLine()⑨方法可以输出一条友好的信息(后者末尾包括换行符)。

如果你使用的是IDE,则可以通过单击运行按钮编译并运行代码,它位于IDE的左上角,看起来像一个播放按钮。按F5键也可以运行代码。但是,如果你想使用Mono编译器从命令行将源代码编译,也可以很容易地实现。从你的C#类的代码的目录中,使用Mono附带的mcs工具将类编译成可执行文件,如下代码所示:

运行清单1-1中的代码应该在同一行打印字符串“Hello World!”和当前日期,如清单1-2所示。在一些Unix系统上,你可能需要运行mono ch1_hello_world.exe。

清单1-2:运行Hello World应用程序

祝贺你成功编写运行了第一个C#程序!1.3 类和接口

类和接口用于创建只用内置的结构难以表示的复杂的数据结构。类和接口可以有属性,它们是获取或设置类或接口的值的变量;也可以有方法,它们类似于在类(或子类)或接口上执行的函数,并且是唯一的。属性和方法用于表示关于对象的数据。例如,一个Firefighter类可能需要一个int类型的属性代表消防员的养老金或一个告诉消防员前往火灾发生地点的方法。

类可以用作蓝图来创建其他类,这种技术称为子类化。当一个类对另一个类进行子类化时,它会继承该类的属性和方法(该类称为父类)。接口也被用作新类的蓝图,但与类不同,它们没有继承。因此,实现接口的基类子类化之后不会给子类传递接口的属性和方法。1.3.1 创建一个类

我们将创建如清单1-3所示的简单的类作为一个表示公务员的数据结构的例子,它们使我们的生活更轻松美好。

清单1-3:PublicServant抽象类

PublicServant类是一种特殊的类。这是一个抽象类①。一般来说,可以像创建任何其他类型的变量一样创建一个类,这称为实例或对象。但是抽象类不能像其他类一样实例化,只能通过子类化继承。有很多类型的公务员,例如警察和消防员。编写一个这两类公务员继承的基础类是很有道理的。在这种情况下,如果这两个类是PublicServant的子类,则会继承一个PensionAmount属性②和一个必须由PublicServant的子类实现的DriveToPlaceOfInterest代理③。没有普遍意义上的某个人可以申请的“公务员”的工作,所以没有理由创建一个PublicServant的实例。1.3.2 创建接口

C#中的接口是对类的补充。接口允许程序员强制类实现某些没有继承的属性或方法。我们来创建一个简单的接口,如清单1-4所示。这个接口叫作IPerson,并且会声明几个人类具备的属性。

清单1-4:IPerson接口

注意:C#中的接口通常以I为前缀,以区别于可能实现它们的类。这个I不是必须的,但它是主流C#开发中一个非常常用的模式。

如果一个类实现IPerson接口①,那个类就需要自己实现Name②和Age③属性,否则不会通过编译。接下来在实现Firefighter类来实现Iperson接口时,我会准确地说明这是什么意思。现在,只需要知道接口是C#的一个重要而有用的功能。熟悉Java中接口的程序员对此会感到非常轻松自如。C程序员可以将它们视为具有函数声明的头文件,需要.c文件实现该函数。熟悉Perl、Ruby或Python的人刚开始可能会觉得接口很奇怪,因为那些语言中没有类似的功能。1.3.3 从抽象类中子类化并实现接口

让我们来使用PublicServant类和IPerson接口,消化刚刚所讲的内容。可以创建一个代表消防员的类,继承自PublicServant类并实现IPerson接口,如清单1-5所示。

清单1-5:Firefighter类

Firefighter类①比我们之前写的代码复杂了一些。首先请注意,Firefighter类通过冒号之后列出逗号分隔的类和接口继承了PublicServant类②并实现了IPerson接口③。然后我们创建一个新的构造函数④,当创建一个新的类的实例时设置类的属性。新的构造函数将接受消防员的名称和年龄作为参数,这将使用传递的值设置IPerson接口所需的Name⑤和Age⑥属性。然后我们用自己的方法重写继承自PublicServant类的DriveToPlaceOfInterest()方法⑦,调用一些我们声明的空的方法。我们需要实现DriveToPlaceOfInterest()方法,因为它在PublicServant类中被标记为抽象的,子类必须重写抽象方法。

注意:类具有默认构造函数,它没有创建实例的参数。创建一个新的构造函数实际上覆写了默认构造函数。

PublicServant类和IPerson接口非常灵活,可以用于创建具有不同用途的类。我们会使用PublicServant和IPerson实现另一个PoliceOfficer类,如清单1-6所示。

清单1-6:PoliceOfficer类

PoliceOfficer类①类似于Firefighter类,但有几个区别。最值得注意的是,在构造函数②中设置了一个名为HasEmergency的新属性③。我们还覆写了以前的Firefighter类中的DriveToPlaceOfInterest()方法④。但是这次,我们使用了HasEmergency属性⑤确定警察驾驶汽车时是否应该使用警笛。可以使用父类和接口的相同组合来创建其中的函数完全不同的类。1.3.4 将所有内容与Main()方法结合到一起

可以使用新类来测试一些C#的更多功能。写一个新的Main()方法来显示这些新类,如清单1-7所示。

清单1-7:在Main()方法中同时创建PoliceOfficer类和Firefighter类

要使用PoliceOfficer类和Firefighter类,必须使用我们在各自的类中定义的构造函数将其实例化。首先实例化Firefighter类①,传递姓名为Joe Carrington和年龄为35的参数给类构造函数并将新类分配给firefighter变量。我们还将消防员的PensionAmount属性②设置为5000。在设置firefghter之后,我们将对象传递给PrintNameAndAge()和PrintPension()方法。

请注意,PrintNameAndAge()方法将IPerson接口⑥作为一个参数,而不是一个Fire-fighter类、PoliceOfficer类或PublicServant类。当一个类实现了一个接口,你可以创建接受这个接口作为参数(在我们的例子中是IPerson)的方法。如果你给方法传递IPerson,该方法只能访问接口需要的属性或方法而不是整个类的。在我们的例子中,只有Name和Age属性可访问,这就是我们的方法所需要的全部了。

同样,PrintPensionAmount()方法接受PublicServant⑦作为参数,因此它只能访问PublicServant的属性和方法。C#中的is关键字可用于检查对象是否是某种类型或类,所以我们可用这个方法来检查公务员是否是Firefighter⑧或者PoliceOfficer⑨,然后据此打印一条消息。

对PoliceOfficer类我们也做和Firefighter类同样的操作,创建一个name为Jane Hope、age为32的新类,然后我们将她的退休金设置为5500,HasEmergency属性③设置为true。打印name、age和pension④之后,我们调用officer的DriveToPlaceOfInterest()方法⑤。1.3.5 运行Main()方法

运行应用程序展示类和方法是怎么互相交互的,如清单1-8所示。

清单1-8:运行基础程序的Main()方法

正如你所看到的,公务员的姓名、年龄和养老金打印到屏幕上,正如预期的那样!1.4 匿名方法

到目前为止,我们使用的方法是类方法,但是我们也可以使用匿名方法。C#的强大功能使我们能够使用委托动态传递和分配方法。使用委托,可在创建一个委托对象后保存对将要调用的方法的引用。我们在父类中创建这个委托,然后把委托的引用分配给子类中的匿名方法。用这种方法可以动态地把子类中的代码分配给代理,而不是覆盖父类的方法。为了演示如何使用代理和匿名方法,可以在已经构建的类上编写代码。1.4.1 在方法中使用委托

让我们更新PublicServant类,在DriveToPlaceOfInterest()方法中使用委托,如清单1-9所示。

清单1-9:带有委托的PublicServant类

在以前的PublicServant类中,如果我们想改变DriveToPlaceOfInterest()方法就需要重写它。在新的PublicServant类中,DriveToPlaceOfInterest()被替换为委托①和一个允许我们调用并分配DriveToPlaceOfInterest()的属性②。现在,继承自PublicServant类的任何类都有一个可以用来为DriveToPlaceOfInterest()设置自己的匿名方法的委托,而不需要在每个类中都重写这个方法。因为Firefighter类和PoliceOfficer类继承自PublicServant,我们需要相应地更新Firefighter类和PoliceOfficer类的构造函数。1.4.2 更新Firefighter类

我们将首先使用新的委托属性来更新Firefighter类。该构造函数如清单1-10所示,这是我们在该类中唯一改动的地方。

清单1-10:FireFighter类使用DriveToPlaceOfInterest()方法的委托

在新的Firefighter类构造函数中①,我们像以前一样分配Name②和Age③。接下来,我们创建匿名方法并使用+=运算符④把它分配给DriveToPlaceOfInterest委托属性,所以调用DriveToPlaceOfInterest()将调用匿名方法。这个匿名方法打印“Driving the firetruck”,然后运行原来的类中的空方法。这样,我们可以向一个类中的每个方法添加自定义代码而不必重写它。1.4.3 创建可选参数

PoliceOfficer类需要进行类似的改变,我们更新构造函数如清单1-11所示。也可以使用一个可选参数,这是构造函数中的一个参数,在创建新实例时不必包括它。我们将创建两个匿名方法并使用可选参数来确定要分配给代理的方法。

清单1-11:新的PoliceOfficer构造函数

在新的PoliceOfficer构造函数中①,与原来一样设置Name③和Age④属性。但是这一次,使用了一个可选的第三个参数②分配给HasEmergency属性⑤。第三个参数是可选的,因为它不需要被指定,当构造函数只提供前两个参数时使用默认值(false)。我们将根据HasEmergency是否为true⑥使用新的匿名方法设置DriveToPlaceOfInterest委托属性。1.4.4 更新Main()方法

使用新的构造函数,我们可以运行更新过的Main()方法,几乎与第一个相同,详见清单1-12。

清单1-12:更新的Main()方法使用我们的使用代理的类开车去感兴趣的地方

唯一的区别是在最后三行,这表明创建了一个新的有紧急情况的PoliceOfficer类②(构造函数的第三个参数是true),与Jane Hope相反①,它没有第三个参数。然后在John Valor officer③中调用DriveToPlaceOfInterest()。1.4.5 运行更新的Main()方法

运行新的方法展示如何创建两个PoliceOfficer类——一个有紧急情况,一个没有。会打印两份不同的内容,如清单1-13所示。

清单1-13:用使用代理的类运行新的Main()方法

正如你所看到的那样,创建一个具有紧急事件的PoliceOfficer类会使得警察开车时开启警笛②。另一方面,Jane Hope开车时并没有开启她的警笛①,因为没有紧急情况。1.5 与本地库整合

有时你需要使用仅在标准操作系统库提供的库,如Linux上的libc和Windows中的user32.dll。如果你打算使用C、C++或另一种被编译为本机程序集的语言编写的库中的代码,在C#中使用这些本地库很容易,第4章将使用这种技术制作跨平台的Metasploit有效载荷。这个功能称为平台调用,简称P/Invoke。程序员经常需要使用本地库,因为它们比.NET或Java所使用的虚拟机更快。从事财务或科学专业方面的程序员需要使用代码做大量数学计算,可能会使用C语言编写他们需要的运行更快的代码(例如直接与硬件交互的代码),但是使用C#来处理代码速度较慢。

清单1-14展示了一个简单的应用程序,使用P/Invoke在Linux中调用标准C函数printf()或者使用Windows上的user32.dll弹出一个消息框。

清单1-14:用一个简单的例子演示P/Invoke

这个例子并不简单。我们首先使用DllImport属性①声明两个函数,在代码外部它们将在不同的库中被查找。属性允许你向运行时由.NET或Mono虚拟机使用的方法中添加额外的信息。在我们的例子中,DllImport属性告诉运行时查看我们在另一个DLL中声明的方法,而不是期待我们实现这个方法。

我们还声明了函数所期望的函数名和参数。对于Windows,可以使用MessageBox()函数,该函数需要一些如弹出窗口标题和显示文本的参数。对于Linux,printf()函数打印一个字符串。两者的这些函数在运行时查找,这意味着我们可以在任何操作系统上编译这个程序而不管该系统是否具有这两个库或其中之一。

声明本地函数之后可以写一个Main()方法②通过使用os.Platform③的if语句检查当前的操作系统。使用Platform属性映射到枚举类型的PlatformID④,它存储程序可以运行的操作系统。使用枚举类型的PlatformID,可以测试程序是否运行在Windows上,然后调用相应的方法:Windows上的MessageBox()⑤或Unix上的printf()⑥。无论这个应用程序是在什么操作系统上编译的,编译好之后都可以在Windows系统或Linux系统上运行。1.6 本章小结

C#语言有许多现代功能,使其成为一种可处理复杂数据和应用的伟大语言。我们只接触了表面的几个功能,如匿名方法和P/Invoke。在接下来的章节中我们将介绍类和接口的概念以及许多其他高级功能,包括可用的核心库,例如HTTP和TCP客户端等。

当我们在本书中开发自己的定制安全工具时,还将了解一般编程模式,这是有用的轻松快捷地创建类的惯例。第5章和第11章中有编程模式的经典示例,我们会使用Nessus和Metasploit等第三方工具的API和RPC接口。

在本书末尾,我们将介绍如何将C#用于每个安全从业者经典示例(从安全分析师到工程师,甚至在家的爱好者)的日常工作。C#是优美且强大的语言,Mono带来的跨平台的支持使得C#可用于手机和嵌入式设备开发,它与Java和其他语言一样功能强大易学易用。第2章模糊测试和漏洞利用技术

在本章中,我们将介绍如何编写简单优美的跨站脚本攻击(cross-site scripting,XSS)和SQL注入模糊测试工具。模糊测试工具是试图发现其他软件错误的软件,例如通过给服务器发送恶意的或格式不正确的数据。模糊测试工具一般的两种类型是基于突变的测试和基于生成的测试。一个基于突变的模糊测试工具试图通过改变已知的良好的数据样本去生成测试数据而不考虑协议或数据结构。相比之下,基于生成的模糊测试工具会考虑到服务器通信协议的细微差别,并使用这些细微差别来生成严格说来有效的数据并发送到服务器。这两种类型的模糊测试工具目标都是获得服务器返回的错误。

我们将编写一个基于突变的模糊测试工具,当你拥有URL或HTTP请求形式的已知的良好的输入时可以使用它(我们将在第3章中编写基于生成的模糊测试工具)。一旦能够使用模糊测试工具来发现XSS和SQL注入漏洞,则可以利用SQL注入漏洞从数据库中检索用户名和密码散列。

为了发掘和利用XSS和SQL注入漏洞,我们将在C#中使用核心HTTP库构建HTTP请求。我们会编写一个简单的模糊测试工具来解析URL并开始对使用GET和POST请求的HTTP参数进行模糊测试。接下来,我们将使用精心制作的从数据库中提取用户信息的HTTP请求来充分利用SQL注入漏洞。

我们将在本章中针对一个称为BadStore的小型Linux发行版测试我们的工具(可在VulnHub网站https://www.vulnhub.com/下载)。BadStore被设计成存在诸如SQL注入和XSS漏洞(还有其他很多漏洞)。从VulnHub下载BadStore ISO后,我们将使用免费的VirtualBox虚拟化软件创建一个虚拟机并在其中启动BadStore ISO,以确保我们的攻击不会危及主机系统。2.1 设置虚拟机

要在Linux、Windows或OS X上安装VirtualBox,请在https://www.virtualbox.org/下载VirtualBox软件。(安装应该很简单,只需要在下载软件时按照网站上最新的提示即可。)虚拟机(VM)允许我们使用物理机来模拟计算机系统。可以使用虚拟机轻松创建和管理易受攻击的软件系统(例如,本书中使用的系统)。2.1.1 添加仅主机虚拟网络

在实际建立虚拟机之前,你可能需要为虚拟机创建仅主机的虚拟网络。仅主机的网络仅允许在虚拟机和主机系统之间进行通信。以下是执行的步骤:

1.单击File->Preferences打开VirtualBox-preferences对话框。在OS X上选择Virtual-Box->Preferences。

2.单击左侧的Network部分。你应该看到两个选项卡:NAT网络和仅主机网络。在OS X上,在设置对话框的顶部单击Network选项卡。

3.单击Host-only Networks选项卡,然后单击Add host-only network(Ins)按钮。此按钮是网卡的图标上覆盖了一个加号。这应该创建一个名为vboxnet0的网络。

4.单击右侧Edit host-only network(Space)按钮,这个按钮是螺丝刀的图标。

5.在打开的对话框中单击DHCP Server选项卡,选择Enable Server框。输入服务器IP地址192.168.56.2,输入服务器掩码255.255.255.0。下面的地址绑定输入192.168.56.100,上面的地址绑定输入192.168.56.199。

6.单击OK将更改保存到仅主机网络。

7.再次单击OK关闭设置对话框。2.1.2 创建虚拟机

一旦安装了VirtualBox并且设置了仅主机网络就可以按照下面的步骤设置虚拟机:

1.点击左上角的New图标,如图2-1所示。

2.当提供一个对话框来选择操作系统的名称和类型时,选择Other Linux(32-bit)选项。图2-1 VirtualBox中的BadStore VM

3.点击Continue,你应该看到一个屏幕给出虚拟机的RAM。将RAM的值设置为512MB并单击Continue(模糊测试和漏洞利用可能需要Web服务器使用虚拟机上大量的RAM)。

4.当被要求创建一个新的虚拟硬盘驱动器时,选择Do not add a virtual hard drive,然后单击Create(我们将从ISO镜像运行BadStore)。现在你应该在VirtualBox的左窗格中看到VM管理窗口,如图2-1所示。2.1.3 从BadStore ISO启动虚拟机

虚拟机创建完成后,使用以下步骤将其设置为从BadStore ISO启动:

1.右键单击VirtualBox管理器左窗格中的VM,单击Settings应该会出现一个显示当前网卡、CD-ROM和其他杂项配置的对话框。

2.在设置对话框中选择Network选项卡,应该看到上面的七种网卡设置,包括NAT(网络地址转换),仅主机和桥接。选择仅主机的网络来分配一个只能从主机访问而不能从互联网的其余部分访问的IP地址。

3.需要在高级设置中将网卡类型设置为一个较旧的芯片组,因为BadStore是基于一个旧的Linux内核,一些较新的芯片组不受支持。选择PCnet-FAST III。

现在执行以下步骤设置CD-ROM以从硬盘驱动器上的ISO启动:

1.在设置对话框中选择Storage选项卡。单击要显示的CD图标会展示一个选择虚拟CD/DVD磁盘的菜单。

2.单击Choose a virtual CD/DVD disk file选项以查找保存到文件系统的BadStore ISO,并将其设置为可启动介质。虚拟机现在应该可以开机了。

3.通过单击设置标签右下角的OK保存设置。然后点击VirtualBox管理器左上角的Start按钮(它在设置齿轮按钮旁边),启动虚拟机。

4.一旦机器启动,你应该看到一条消息——“请按Enter键激活此控制台。”按Enter键并输入ifconfig查看应该获得的IP配置。

5.拥有虚拟机的IP地址后,将其输入你的浏览器,应该会看到如图2-2所示的主页。图2-2 BadStore网络应用程序的主页2.2 SQL注入

在当今丰富的Web应用程序中,程序员需要能够存储并在后台查询信息以提供高品质的用户体验。这通常使用如MySQL、PostgreSQL或Microsoft SQL Server这样的结构化查询语言(Structrued Query Language)数据库来完成。

SQL允许程序员使用SQL语句(根据一些提供的信息或标准告诉数据库如何创建、读取、更新或删除数据)编程与数据库进行交互。例如,查询数据库中用户数的一条SELECT语句如清单2-1所示。

清单2-1:简单的SQL SELECT语句

有时程序员需要动态的SQL语句(也就是说,根据用户与Web应用程序的交互进行更改)。例如,程序员可能需要基于一个特定用户的ID从数据库中选择信息。

但是,当程序员使用一个来自不可信的客户端(如Web浏览器)的用户提供的值构建SQL语句时,如果这个值没有经过适当的检查可能会引发SQL注入漏洞。例如,清单2-2所示的C#SOAP方法可能用于将用户插入到托管在Web服务器上的数据库。(Simple Object Access Protocol,SOAP,是一种基于XML的在Web应用程序上快速创建API的Web技术,它在C#和Java等在企业中常用的编程语言中很受欢迎)。

清单2-2:易受SQL注入攻击的C#SOAP方法

在这种情况下,程序员没有在创建①并执行②SQL语句之前检查用户名和密码。因此,攻击者可以构造用户名或密码字符串使得数据库运行精心制作的能让他们执行远程命令和完全控制数据库的SQL代码。

如果你要给其中一个参数传递一个单引号(比如user'name而不是username),Execute-NonQuery()方法会尝试运行一个无效的SQL查询(如清单2-3所示)。那么攻击者将在HTTP响应中看到方法抛出的异常。

清单2-3:用户提供的未经检查的数据导致SQL查询无效

许多启用数据库访问的软件库通过参数化查询允许程序安全地使用如Web浏览器这种不受信任的客户端提供的值。这些库通过转义字符自动清除任何不受信任的传递给SQL查询的值(例如单引号、括号和SQL语法中使用的其他特殊字符)。参数化查询和其他像NHibernate这样的对象关系映射(Object Relational Mapping,ORM)库有助于防止这些SQL注入问题。

这些用户提供的值倾向于在WHERE子句中使用SQL查询,如清单2-4所示。

清单2-4:根据特定的user_id从数据库中选择一行的SQL SELECT语句示例

如清单2-3所示,将单引号放在用于构建动态SQL查询之前没有被适当检查的HTTP参数中可能会导致Web应用程序抛出一个错误(比如HTTP返回码为500),因为SQL中的单引号表示字符串的开头或结尾。单引号通过过早地结束一个字符串或者通过开始一个没有结尾的字符串使得SQL语句无效。通过解析这样请求的HTTP响应,我们可以对这些Web应用程序进行模糊测试并搜索用户提供HTTP参数。当参数被篡改时,会造成响应中的SQL错误。2.3 跨站脚本攻击

像SQL注入一样,跨站脚本攻击利用程序员使用从Web浏览器传递到服务器的数据,构建要在Web浏览器呈现的HTML代码中的漏洞。

有时,由不受信任的客户端(如Web浏览器)提供的数据到达服务器时可能包含如JavaScript的HTML代码,允许攻击者窃取cookies或者使用未经检查的HTML将用户重定向到恶意网站。

例如,允许发表评论的博客可能会在向站点的服务器发送HTTP请求时携带评论中的数据。如果攻击者使用嵌入式HTML或JavaScript创建恶意评论并且在浏览器中提交评论时博客软件没有进行相应的检查,那么攻击者可以使用他们加载的恶意评论用自己的HTML代码破坏网站或者将任何博客的访问者重定向到攻击者自己的网站。之后攻击者可能会在访问者的机器上安装恶意软件。

一般来说,一种快速检测网站中的代码是否容易受到XSS攻击的方法是使用一个被污染的参数向网站发出一个请求。如果污染的数据出现在响应中而没有更改,那么你可能已经找到了一个XSS向量。例如,假设你给HTTP请求的参数传递了,如清单2-5所示。

清单2-5:使用查询字符串参数向PHP脚本发送Get请求的例子

服务器返回类似清单2-6中HTTP响应的内容。

清单2-6:来自PHP脚本检查name查询字符串参数的响应示例

如果代码被替换为具有HTML实体的版本,你应该知道该网站使用例如html-specialchars()这样的PHP函数或类似的方法。但是如果网站在响应中返回,你就知道它不执行任何过滤或检查,如清单2-7所示的HTTP name参数。

清单2-7:易受XSS攻击的PHP代码

与代码清单2-1中易受SQL注入的代码一样,在呈现HTML代码①之前没有对参数进行过滤或替换任何潜在的坏字符。通过将精心制作的name参数传递给Web应用程序,我们可以把HTML代码渲染到屏幕,执行JavaScript代码,甚至运行试图接管计算机的Java小程序。例如,我们可以发送一个如清单2-8所示的精心制作的网址。

清单2-8:具有查询字符串参数的URL,如果该参数易受XSS影响,则会弹出JavaScript警报框

如果PHP脚本使用name参数构建一些最终将在Web浏览器中被渲染的HTML代码则清单2-8中的URL可能会导致JavaScript弹出一个窗口显示数字1。2.4 使用基于突变的模糊测试工具对GET参数进行模糊测试

既然你了解了SQL注入和XSS漏洞的基础知识,让我们实现一个快速的模糊测试工具在查询字符串参数中挖掘潜在的SQL注入或XSS漏洞。查询字符串参数是URL中?后面的参数,格式为key=value。我们会专注于GET请求中的HTTP参数,但是首先我们将分解一个URL以循环遍历任何HTTP查询字符串参数,如清单2-9所示。

清单2-9:一个小的分解给定URL中的查询字符串参数Main()方法

在清单2-9中,我们将第一个参数(args[0])传递给模糊测试程

试读结束[说明:试读内容隐藏了图片]

下载完整电子书


相关推荐

最新文章


© 2020 txtepub下载