记一次PHP渗透测试实战教程
在渗透测试过程中,开发不可能每一次都将结果输出到页面上,也就是漏洞无回显的情况,那么在这种情况下,我们可以通过dnslog判断漏洞存在,或者通过起一个python的http服务来判断,方法很多,下面主要进行一些情况的分析。
无回显,即执行的payload在站点没有输出,无法进行进一步操作。在渗透测试过程中,漏洞点不可能总是能够在返回页面进行输出,那么这时候就需要进行一些无回显利用了。
SQL注入,作为OWASP常年占据榜首位置的漏洞,在无回显中也是常见的。当然SQL注入在无回显上已经具有了一定的解决措施。无回显我将其定义为页面没有输出我们想要得到的内容,下面以sqli-labs为例进行讲解。
布尔盲注,盲注的一种,当网站通过查询语句的布尔值返回真假来输出页面信息的时候,查询语句为真,页面输出内容;查询语句为假,页面不输出内容。那么这里就可以通过构造等号判断,获取相应的字符的ascii码,最后还原出数据。具体测试过程如下:1、id传参1之后,页面返回有数据,这里明显不能进行显错注入了。
2、在传参后面加个单引号,页面返回空,不显示错误信息,不能使用报错注入。
3、通过拼接and 1=1和and 1=2,发现页面对于布尔值的真与假返回的页面结果也不同。
4、通过length()函数判断数据库库名的长度大于1。?id=1’ and length(database())>1 %23
5、在大于8的时候页面返回空,所以数据库库名长度等于8。
6、通过ascii()函数和substr ()截取函数获取数据库库名的第一个字符的ascii码?id=1’ and ascii(substr((select database()),1,1))>97 %23?id=1’ and ascii(substr((select database()),1,1))=101 %23首先用大于号判断出大概所处的值,最后使用等于号验证ascii码的值。此处得出数据库库名的第一个字符的ascii码值为115,对应字符为s。
7、更改截取的位置,判断后面的字符对应的ascii码值。?id=1’ and ascii(substr((select database()),2,1))=101 %23
延时盲注,一种盲注的手法。在渗透测试过程中当我们不能使用显错注入、报错注入以及布尔盲注无论布尔值为真还是为假,页面都返回一样之后,我们可以尝试使用延时盲注,通过加载页面的时间长度来判断数据是否成功。在PHP中有一个if()函数,语法为if(exp1,exp2,exp3),当exp1返回为真时,执行exp2,返回为假时,执行exp3。配合延时函数sleep()来获取相应数据的ascii码,最后还原成数据。下面我将通过实例来介绍如今进行延时盲注。1、首先获取的页面如下,后面不论接上布尔值为真还是为假的,页面都返回一样,此时将不能使用布尔盲注。
2、通过and拼接延时函数查看页面是否有延时回显。首先记录没有使用延时函数的页面返回时间,为4.*秒;使用sleep(5)延时5秒之后,页面响应时间为9.*秒,说明对于我们输入的sleep()函数进行了延时处理,此处存在延时盲注。
3、通过延时注入判断数据库库名的长度。一个个测试发现当长度等于8时页面延时返回了,说明数据库库名长度为8。?id=2’ and if((length(database())=8),sleep(5),1) %23
4、与布尔盲注一样,将子查询的数据截断之后判断ascii码,相等时延时5秒。最后得到第一个字符的ascii码为115。?id=2’ and if((ascii(substr((select database()),1,1))=115),sleep(5),1) %23
5、后面替换截断的位置,测试后面的字符的ascii码值。最后得到对应的ascii码值为115 101 99 117 114 105 116 121。通过ascii解码工具解得数据库库名为security。
前面介绍了SQL注入中的盲注,通过布尔盲注或者延时盲注来获取数据需要的步骤非常繁琐,不仅需要一个一个字符的获取,最后还需要进行ascii解码,这需要花费大量的时间与精力。为了加快渗透进程,以及降低获取数据的难度,这里介绍如何通过dnslog进行SQL注入。
dnslog,即dns日志,会解析访问dns服务的记录并显示出来,常被用来测试漏洞是否存在以及无法获取数据的时候进行外带数据。简单来说,dnslog就是一个服务器,会记录所有访问它的记录,包括访问的域名、访问的IP以及时间。那么我们就可以通过子查询,拼接dnslog的域名,最后通过dns日志得到需要的数据。
数据库中的load_file()函数,可以加载服务器中的内容。load_file(‘c:/1.txt’),读取文件并返回内容为字符串,使用load_file()函数获取数据需要有以下几个条件:1.文件在服务器上2.指定完整路径的文件3.必须有FILE权限
UNC路径就是类似\\softer这样的形式的网络路径。它符合 \\服务器名\\服务器资源的格式。在Windows系统中常用于共享文件。如\\192.168.1.1\\共享文件夹名。
1、打开实例站点,很明显这里是只能使用盲注的站点。
2、通过order by判断出字段数为3。
3、在dnslog网站申请一个dnslog域名:pcijrt.dnslog.cn
4、通过load_file函数拼接查询数据库库名的子查询到dnslog的域名上,后面任意接一个不存在的文件夹名。最后将这个查询放到联合查询中,构造的payload如下:
5、执行语句之后在dnslog日志中获取到数据库库名为security。
6、修改子查询里的内容,获取其他数据。
XSS无回显比较特殊,一般XSS漏洞的判断标准为弹框,但是有这样一种情况,在一个表单提交处,内容提交之后只会在页面显示提交成功与否,不会输出提交的内容,那么我们也就无法通过弹框来判断XSS漏洞存在与否。这时候就需要通过XSS盲打来进行攻击。下面通过Pikachu漏洞练习平台来进行实例讲解:
1、如图这里是一个提交看法的功能
2、随便输入内容提交,告诉我们提交成功,没有将我输入的内容返回到页面中
3、登录后台可以看到确实有数据回显
4、输入弹框语句会在后台成功执行
5、在渗透测试过程中我们无法登录后台进行查看,那么就需要盲打XSS,输入XSS平台的payload,坐等管理员查看内容后上钩。
SSRF即服务端请求伪造,一种由攻击者构造的通过服务器发起请求的攻击。测试代码如下:
首先通过访问百度可以验证漏洞存在
无回显情况即不进行输出,页面返回空
这种情况可以通过dnslog或者python搭建http服务验证1、DNSLOGhttp://172.16.29.2/ssrf_test.php?url=http://ssrf.02c6ot.dnslog.cn
2、python起的http服务
因为XML是用来存储传输数据的,除了确实是业务需要,否则开发不可能会输出内容,也就是说你确实读取到了文件内容,但是没办法看到。XXE无回显问题当然也是可以通过在域名前面放入查询出的内容,将数据通过dns日志记录下来。XXE虽然不是通过DNSlog,但是也同样是外带数据。流程如下:在受害者网站中,我们通过请求攻击者VPS上的1.xml文件,文件内容为将某数据放在GET传参中去访问2.php。然后2.php中的内容为保存GET传参的数据,将数据放入到3.txt中。具体文件内容放在下面,里面的IP地址应该为攻击者的IP地址,这3个文件也是放在攻击者VPS上。1.xml
2.php
3.txt
简单的命令执行站点
输入任何命令都无回显
通过POST传参测试
传参的内容需要进行url编码
Post传参
Dnslog获取结果
Base64解码获取内容
在渗透测试过程中,无回显是很常见的,程序不可能将一些操作都回显到页面中,那么这种时候我们就需要外带数据来获取想要的内容。当然最好就是能够反弹shell,通过获取shell来执行命令,这样会舒服很多。
无回显的情况还有很多很多,这里简单介绍了几种,希望读者朋友们能够从中学到对于无回显的情况下如何进行渗透测试,方法很多,不固定,学习思路即可。
php分享之trie_filter扩展模块安装
一 安装libiconv,这个是libdatrie的依赖项
wget http://ftp.gnu.org/pub/gnu/libiconv/libiconv-1.14.tar.gz
tar zxvf libiconv-1.14.tar.gz
cd libiconv-1.14
./configure
make
make install
二 安装:libdatrie (http://linux.thai.net/~thep/datrie/datrie.html#Download)
tar zxf libdatrie-0.2.4.tar.gz
cd libdatrie-0.2.4
./configure –prefix=/usr/local
make
make install
编辑过程中的问题汇总
1编译出现错误 trietool.c:125: undefined reference to `libiconv\’
[sourcecode language=\”plain\”]./configure LDFLAGS=-L/usr/local/lib LIBS=-libiconv 这个目前在虚拟机上不好用(真实服务器不存在)[/sourcecode]
2 configure: error: C compiler cannot create executable 这个错误一般没有安装gcc
yum install gcc gcc-c++
3 libiconv.so.2: cannot open shared object file 代表找不到libiconv.so.2 解决方案
在/etc/ld.so.conf中加一行/usr/local/lib,
然后运行/sbin/ldconfig,文件解决,没有报错了~~
到此位置trie_filter安装陈功
三 安装PHP扩展
tar xvf trie_filter-2011-03-21.tar
cd trie
/usr/local/php/bin/phpize
./configure –with-php-config=/usr/local/php/bin/php-config
make
make install
四 生成敏感词词典
首先你需要把需要检测的敏感词写入到一个文本文件中(如:minganci.txt),每行一个敏感词,然后使用上一步生成的 dpp 程序处理这个文本文件来生成词典
./dpp txt_file_path dict_file_path
(例:./dpp /home/like/software/minganci.txt minganci.dic)
生成过程中出现的问题
1./dpp: error while loading shared libraries: libdatrie.so.1: cannot open shared object file: No such file or directory
#vi /etc/ld.so.conf 在里面加入:/usr/local/lib
然后运行:#/sbin/ldconfig,即解决
最后再:./dpp /home/like/software/minganci.txt minganci )
备注:如果需要支持中文的话 则替换扩展包的内容php-ext-trie-filter-maste_support_ch
PHP高级编程-回归原生态-函数式编程与数组
4.2.4 函数式编程与数组
在函数式编程的世界里,针对集合的操作有三大类,分别是:映射、过滤和归约。
虽然PHP是一门解释性脚本语言,并且支持面向过程编程和面向对象编程,但与函数式编程还是有很大区别的。PHP也为映射、过滤和归约提供了对应的函数。它们分别是:
- 映射:array_map()
- 过滤:array_filter()
- 归纳:array_reduce()
下面可以通过一个简单的例子来快速认识这三大类的操作。假设我们有1、2、3、4、……、9、10这样十个数字,作为最初的集合元素。则有:
如果我们想让每个数字都翻N倍,即对原来每个元素,通过一个规则映射到一个新的集合,那么这就是映射。使用array_map()函数可轻松实现这一点。
通过映射后,新集合与旧集合的元素是一一对应的,数量不会少也不会多。这就和投影一样。这里的执行结果会输出:
而过滤操作,显然会对集合的元素数量有影响,通常会根据条件过滤移除部分元素,所以执行过滤后,元素个数会减少。继续前面的示例,如果要找出全部的奇数,可以:
输出结果是:
最后,是集合的归作,即把全部的元素通过某个规则全部合成一个新东西。注意,映射和过滤后的新元素的类型,和原来元素的类型是一样的。即原来是整型的元素,操作后还会是整型的元素,虽然数量上会有所变化。而归纳则是完全不同的操作,除了最后元素个数变成只有一个外,新元素的类型极大可能会是新的类型。
拿这里的例子来说,假设我们要把全部的数字按字符串连接起来,那么最后就会形成一个字符串:12345678910。使用array_reduce()的实现代码是:
在函数式编程的世界里,函数是“一等公民”。而在OOP世界里,类才是“一等公民”。在最开始时,我们需要对原来的数值翻N倍,这个N倍暂时是通过参数来传递的。又如,在过滤奇数时,是直接硬编程在代码里的,如果我要改成过滤偶数呢,怎么办?又假设我会动态传入过滤条件呢,又怎么办?大家可以回想一下,在面向过程编程和面向对象编程里,我们都是怎样解决类似这样的需求的。
这里简单分享一下,在函数式编程世界里巧妙的做法。因为函数是它们的“一等公民”,函数可以作为函数的参数也可以作为函数的返回值,甚至还可以作为变量存储起来,这叫做高阶函数。通过原子的操作,再结合部分施用或柯里化,就能灵活组合成复杂的功能。和面向对象编程世界的自顶而下的封装不同,函数式编程则是自底而上的组合形式。
初次接触函数式编程的同学,对于柯里化这个概念有点陌生。这里稍微解释一下,简单地理解,可以看成一开始某个函数需要两个参数的,但我先提供一个参数,然后返回一个半成品函数。剩下的另外一个参数,再作为参数传给这个新的函数。打个比方,就类似分期付款一样,一开始钱不够,先给部分,后面再分期支付。以翻N倍为例,这里有两个参数,一个是原始的数值,另一个参数是翻多少倍。但再一推导,实际上就是两个数相乘。
先睹为快,使用Scala函数式编程语言实现上面同样功能的完整代码。将下面Scala代码保存到ArrayCurry.scala文件,位置目录任意。
在安装了Scala的情况下,可以执行以下命令:
$ scalac ./ArrayCurry.scala && scala ArrayCurry
然后就可能看到输出:
2 4 6 8 10 12 14 16 18 201 3 5 7 912345678910
除了输出格式外,效果和前面是一样的。但Scala的代码更简洁、更优雅。
再来稍后看一下柯里化的应用。先添加一个柯里化实现的类成员函数:
然后在main()函数最后追加以下代码,就可以应用柯里化实现对不同倍数的相乘。
从这里可以窥探到函数式编程的思想。即找出原子性的操作,再基于此基础推导出更多衍生的操作。例如这里的,两数相乘multi是最基本的操作,其次再到翻2倍的multi2,当然基于multi我们可以快速创建翻3倍、翻10倍、翻N倍的函数——只需要传一个参数即可。最后,把这个翻2倍的因子传递给映射操作,就可以完成对整个集合的映射操作。多么微妙!
至此,我们简单回顾一下。一开始,我们学习了PHP数组关于映射、过滤和归约的三大类操作。然后使用函数式编程语言Scala同样实现了一遍,还稍微领略了函数式编程的魅力和思想。但这本书更多是关于PHP的书,这里要告诫各位开发同学的是,虽然函数式编程的魅力很大,但PHP语言更多是简单、实用、方便。如果没有必要,建议不要采用array_map()、array_filter()、array_reduce()这些函数。
有同学开始感到困惑了,讲了那么多,最后是为了让我们不要使用?为什么呢?因为匿名函数会增加代码的复杂度,增加代码的嵌套层级,不容易理解,更不容易维护。现在的时代不再是以前写出别人看不懂的代码就是高手,而是如何写出连实习生都能快速理解的代码才是专家。毕竟PHP没有Scala那么强悍的语法糖,也没有像Javascript的上下文,过度使用这类数组的函数,反而会适得其反。
最后,我们来看下,PHP回归到简单版的实现方式。其实很简单,改用foreach进行循环处理即可。不需要花俏、华而不实的外表。以下代码,想必连刚学PHP的同学也能快速理解,并且维护起来成本更低。
如果非得要用一句话来总结,那就是:不要让事情变得更复杂,不要增加人为的偶然复杂性。
4.2.5 数组类
前面介绍的关于数组的排序、集合的三大操作,都是使用函数的,是面向过程的。接下来,了解一下面向对象编程相关的知识。数组类是什么意思呢?不难理解,数组类就是具体数组特性的类。
对于一个数组,可以获取和修改某个键的值,也可以进行删除、判断键是否存在。如果一个类想实现具有数组的访问特性,就需要实现ArrayAccess(数组式访问)接口,并且需要实现以下四个方法:
- ArrayAccess::offsetExists — 检查一个偏移位置是否存在
- ArrayAccess::offsetGet — 获取一个偏移位置的值
- ArrayAccess::offsetSet — 设置一个偏移位置的值
- ArrayAccess::offsetUnset — 复位一个偏移位置的值
结合下面示例,可以看更好地理解这四个方法的用处。
那什么时候会用到数组类呢?这里先简单抛个砖,后面会继续深入讨论。在PHP开源框架或开源类库里,会用到这个ArrayAccess接口实现一些高级的功能操作。以流行的Phalcon框架为例,它的DI容器,以及它的依赖注入都是设计得非常巧妙且强大的。其中就可以通过数组的方式来访问DI容器。例如:
PhalApi开源接口框架受此启发,也引入了DI依赖注入,同时也实现了ArrayAccess接口。在PhalApi的PHP源代码里,我们可以找到对应的实现代码。
当开发工程师需要使用DI容器时,就可以像Phalcon那样,使用数组的方式来操作。例如和前面类似的实现:
这里关于数组的访问接口,以及DI容器的介绍,先到这里。后面讲魔术方法时,我们再来一起深入探讨。
本文作者及来源:Renderbus瑞云渲染农场https://www.renderbus.com
文章为作者独立观点不代本网立场,未经允许不得转载。