大家好,我是小编 今天带来一篇关于注入工具开发的文章 来自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 |
|
来自: 首家i55ryzehof > 《上网》