分享

用世界上最好的语言开发自动化注入工具

 首家i55ryzehof 2018-08-18

大家好,我是小编

今天带来一篇关于注入工具开发的文章

来自Gcow团队的特特

我预感

这是一篇会引来腥风血雨的文章

大家评论区见

前言

“我就说php是世界上最好的语言,不服来投稿打我脸”

本文使用世界上最好的语言(PHP)针对某h站系统而开发的自动化注入工具。

首先来明确工具开发中的几点:

正常页面和错误页面的区别

该工具自动化判断表名以及表中字段的数据长度

使用缓存机制(读取和写入)

使用php cli(命令行)模式

开始分析

可能有人会问了“为何不用python,而用php?”

因为这个注入点比较特殊,是一个302页面跳转处的注入,从数据库中查询到某个域名后会输出到页面后跳转,否则因查询不到某个域名造成死循环。

输出页面的代码如下:

go.click();

Href参数有值的情况下为正常,否则异常

document.write('');

go.click();

异常之后就会存在死循环,因为href都为空

之所以使用php是因为这里是302页面,python获取不到页面内容,而php则可以获取到内容。

对于工具开发,必不可少的是http请求函数,php现成的有file_get_contents相对来说并不好用,如果请求不到,使用就会产生异常,为此将要用的curl封装了一个函数:

先来测试一下,主要还是测试是否能获取到302页面的内容,代码如下:

获取到的内容如下:

使用“------------”分界线,将正确页面和错误页面分割开来。

href参数中有值的是正常页面,否则为异常页面。

我们接下来试着采用接收命令行参数的方式具体实现吧!

具体实现

Php cli模式接收命令行参数的超全局数组为$argv:

首先我们要想到如何实现-u这些内容,所以将获取的东西封装并且命名为GetHostId,这个函数中不需要参数,需要获取全局变量可以使用两种形式:$GLOBALS和global $argv。

这里我们还是使用$GLOBALS的方式获取,因为最后会将这些函数封装在一个类里面,能够更加灵活。

根据上图可知,数组下标为0的数值是无用的,需要删掉$GLOBALS[“argv”][0]:

这里第一行就将下标为0的值删掉了,因为第1个就是执行的文件名,所以直接删掉,然后进行赋值。

接下来,命令行中需要两个参数:一个是--host或-h,另一个为--id,函数已封装完毕:

这里我们当前文件接收命令行参数就有了两种形式:

程序这样做显得不灵活了,为了解决这里位置不能随意调换的问题可以再封装一个函数:

这样获取命令行参数就可以不分先后顺序了!

这里已经获取到了域名以及id,接下来还需要另一个参数--batch:

如果参数存在则默认使用http;

如果参数不存在则在命令行中获取,已将获取这部分封装成了函数;

GetInput函数是获取命令行中的值,而GetHttp是调用GetInput获取用户输入的是http或是http协议:

这里获取到http或者https协议拼接到host后,将拼接的值进行存活的判断。

封装一个is_survival函数:

存活返回true;

否则false;

判断存活本应判断状态码,但判断状态码并不严格,这里使用正则表达式来进行匹配,返回值如下:

正则所匹配的东西应该是href中的值,正则表达式如下:/href=”(.+)”/i

以上就是判断存活的必要条件,接着继续:

这里存活条件为href中有值否则是死亡状态。

死亡状态有两种情况:

一种是无法访问;

另一种是输入的id值不正确

继续往下:

查询不到内容的情况:

函数中同时会自动测试五次,五次过后依就获取不到便自动退出。

验证测试

这里我们验证其是否存活,从字典中获取表名,然后测试取出的表是否存在。

在本地创建一个dictionary目录,并且写入一个名为tables.txt的字典文件:

接下来在此封装两个函数,一是GetContents,另一个是GetTables:

这里我们通过GetTables函数中调用GetContents函数获取字典内容,然后返回到GetTables函数中,将内容以回车分割为数组并且返回数组。

接下来我们还要再接着封装一个名为TablesSurvival的函数,然后返回值为数组,这里我们将查表的SQL :+and+exists(select%20*%20from%20admin)拼接上去

成功测试表名存在后:

再封装一个名为GetColumns的函数;

此函数获取dictionary目录下的columns.txt文件中的内容,并以回车分割具体实现

具体实现:

这里字段名的格式和表名的格式略有不同,格式如下:

到这里为止,我们的程序已经可以自动化测试表名以及字段名,现在可以试着将前面相同功能的函数进行合并:

比如GetColumns和GetTables,这两个函数合并后名称为GetTablesOrColumns。

TablesSurvival和ColumnsSurvival合并为TablesOrColumnsSurvival。

试着运行:

证实代码精简后,还是一样的运行结果。

此时已知表名以及字段名称,既是自动化工具,自然少不了测试字段中内容的长度。

将获取字符长度的代码封装,名为GetStringLength,返回值为数组:

可以看到我们返回的格式为:[表名,字段长度=>字段名,字段长度=>字段名]。

已经得知表名、字段名以及字段内容长度,接着定义一个名为SqlInjection,就不需要返回值了:

到这里基础已经完成了。

缓存机制

虽然基础已经完成了,但还需要一个缓存机制。

我们将获取到的内容写入到文件夹下,我们的缓存目录结构如下:Data目录->域名目录->表名目录->字段文本

现在封装一个名为TextPut函数:

随后在GetStringLength中调用textput函数,将字段中的字符长度及字段名写入到以域名的名称命名的文本中:

写入文本格式如下:

然后在SqlInjection函数中调用并将注入到的数据写入文件中:

成功将获取到的数据写入到文件中,但还要进行一次判断,封装一个名为is_cache函数:

并且将SqlInjection函数增加一个cache形参,方便缓存机制。

最终程序调用如上,还应该写一个名为DumpContent的函数,将注入到的数据打印出来。

程序调用最终如下:

测试一下缓存机制:

username字段测试到第四个字符,退出程序:

程序果断退出了,接着再来运行一次:

还在获取第四个字符是因为我们设置的是:“只有读取到了写入文件之后才会跳到第五个字符”

然而这里还没读取到第四个字符,所以程序还是从第四个字符开始后静静的等待执行完毕。

本次分享就到这里了,感谢大家的阅读!

其实工具开发旨在思路,无论用什么语言只要可以实现便是达到目的。

自动化测试工具地址:https://github.com/only-wait/tools/tree/master/h%E7%AB%99%E8%87%AA%E5%8A%A8%E5%8C%96%E6%B5%8B%E8%AF%95%E5%B7%A5%E5%85%B7

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多