逻辑漏洞
- 越权漏洞
- 支付漏洞
- 暴力破解
- 密码找回漏洞
- 轰炸漏洞
越权漏洞
1.概述
多数WEB应用都具备权限划分和控制,但是如果权限控制功能设计存在缺陷,那么攻击者就可以通过这些缺陷来访问未经授权的功能或数据,这就是我们通常说的越权漏洞。
简单来说就是用户拥有不属于它本身的权限,可以执行不能执行的操作。
2.产生原因
开发人员在对数据进行操作时对客户端请求的数据过分相信,遗漏了对于客户端权限的仔细判定。
3.分类
水平越权:权限不变,身份改变(攻击者可以访问与他拥有相同权限的用户的资源)。
普通用户A越权查看用户B的信息
垂直越权:身份不变,权限改变(低级别攻击者可以访问高级别用户的资源)。
普通用户C越权执行超级管理员权限,对用户B进行禁言
交叉越权:既可以水平越权又可以垂直越权。基本上只要垂直越权能做,水平越权也能做。
3.水平越权演示
海洋 cms v9越权漏洞
注册用户:
1.fuming-1 123456
2.fuming-2 654321
分别用2个浏览器登录这2个用户,这里我直接复制了一个burp,然后使用burp自带的浏览器。
此网站功能:


这些功能都可以进行越权测试,如:
1.查看他人历史记录
2.代替他人留言
3.查看他人会员资料
4.代替签到
5.修改他人密码,资料
6.查看他人收藏,购买记录
这里有很多功能不能用,就修改信息功能块进行水平越权测试。
身份凭证:
fuming-1 :Cookie: PHPSESSID=5f09f59330c679436dc5f255058fd809
fuming-2 :Cookie: PHPSESSID=b33aad69ca85ac35beb9dc685a4f805a
测试过程:
fuming-1提交修改联系方式为000000@qq.com,抓包修改Cookie为fuming-2,登录fuming-2查看信息是否修改成功

修改ID:

查看fuming-2信息:

4.代码分析
就修改信息进行分析:seacms-v9-master/member.php
if($action=='chgpwdsubmit')
{
//判断两次密码是否相同
if(trim($newpwd)<>trim($newpwd2))
{
ShowMsg('两次输入密码不一致','-1');
exit();
}
//判断密码,邮箱,联系方式
if(!empty($newpwd)||!empty($email)||!empty($nickname))
{
//判断密码是否为空
if(empty($newpwd))
{
//新密码为空的话就将旧密码赋值给$pwd,即密码不变
$pwd = $oldpwd;
}
else
{
$pwd = substr(md5($newpwd),5,20);
};
//更新数据库中存储的信息
$dsql->ExecuteNoneQuery("update `sea_member` set password = '$pwd',email = '$email',nickname = '$nickname' where id= '$uid'");
ShowMsg('资料修改成功','-1');
exit();
}
修改信息的代码流程:判断两次密码是否相同,判断密码是否为空,更新数据库信息。
这就是越权的产生原因:对客户端数据过于相信(只判断密码),但没有判断客户端用户权限。
5.垂直越权演示
pikachu靶场
管理员:admin 123456
普通用户:pikachu 000000
分别登录,查看各自权限:
admin:创建,删除,查看用户信息
pikachu:查看用户信息
垂直越权:身份不变.权限改变.那么在这里的越权就是:以pikachu用户的身份,执行创建、删除功能
越权过程:admin创建用户,抓包,修改cooike信息为pikachu
admin:Cookie: PHPSESSID=1ab15e257309746e7133f4b687633e13
pikachu:Cookie: PHPSESSID=cba862a79b33c2bc63942a4ca51557f0
抓admin的创建包,修改cookie:

创建成功:

6.代码分析
$link=connect();
// 判断是否登录,没有登录不能访问
//这里只是验证了登录状态,并没有验证级别,所以存在越权问题。
if(!check_op2_login($link))
{
header("location:op2_login.php");
exit();
}
if(isset($_POST['submit']))
{
if($_POST['username']!=null && $_POST['password']!=null){//用户名密码必填
$getdata=escape($link, $_POST);//转义
$query="insert into member(username,pw,sex,phonenum,email,address) values('{$getdata['username']}',md5('{$getdata['password']}'),'{$getdata['sex']}','{$getdata['phonenum']}','{$getdata['email']}','{$getdata['address']}')";
$result=execute($link, $query);
if(mysqli_affected_rows($link)==1){//判断是否插入
header("location:op2_admin.php");
}else {
$html.="<p>修改失败,请检查下数据库是不是还是活着的</p>";
}
}
}
只是判断是否登录,并没有对用户权限进行验证,只要是登录就能往下操作,这个页面的添加账号信息。所以登录的任何用户只要提交参数即可创建用户。
7.测试思路
注册2个账号,看到身份凭证之类(用户id,vip,手机号...)的就换。
8.修复
1.鉴权,服务端对请求的数据和当前用户身份做校验
2.对于可控参数进行严格的检查与过滤
支付漏洞
1.快捷支付原理
商户网站接入支付结果有两种方式,一种是通过浏览器进行跳转通知,另一种是服务器端异步通知。
浏览器跳转通知:
基于用户访问的浏览器,如果用户在银行页面支付成功后,直接关闭了页面,并未等待银行跳转到支付结果页面,那么商户网站就收不到支付结果的通知,导致支付结果难以处理。而且浏览器端数据很容易被篡改而降低安全性.(这种方式已经很少了,因为这种方式相当于是:支付宝 给了你一个数据,然后你告诉商家你付了钱,而不是由支付宝直接告诉商家你付了钱)
服务器端异步通知:
该方式是支付公司服务器后台直接向用户指定的异步通知URL发送参数,采用POST或GET的方式。商户网站接收异步参数的URL对应的程序中,要对支付公司返回的支付结果进行签名验证,成功后进行支付逻辑处理,如验证金额、订单信息是否与发起支付时一致,验证正常则对订单进行状态处理或为用户进行网站内入账等。(商家计算出金额–>用户传参-> >支付宝、微信 -> 商家 ->用户)
2.修改金额
支付三步曲——订购、订单、付款,在这三个环节中进行价格修改测试即可。
案例:
中国国旅一元买任意张数旅游票
淘宝网某处存在严重支付漏洞
看我如何1块钱买价值3999块钱的嗨镜(京东众筹破2百万)支付漏洞
3.修改支付状态
没有对支付状态的值跟实际订单支付状态进行校验,导致点击支付时抓包修改决定支付或未支付的参数为支付状态的值从而达到支付成功。
案例:
同程旅交汇低价支付高价订单订单随意修改(另种支付漏洞隐患)
4.修改数量
没有对购买的数量参数进行限制,导致可随意修改,最常见的修改方式是改成负数,小数,突破最大限制数。
案例:
同程旅游网某处支付漏洞
国美网上商城支付漏洞1元订购Iphone 4S!
新蛋中国支付漏洞
5.修改附属值
1.修改优惠劵金额/数量
2.修改积分金额
3.修改运费金额
案例:
东吴人寿商城积分支付漏洞(一秒成就中东大土豪)
锦江之星积分兑换逻辑错误(支付漏洞)
新东方逻辑支付漏洞
6.越权支付
通过修改一些 特殊传参(如:id,username,openid) 来达到用他人的资金来干购买自己的商品。
实例:
一次信息泄露到越权支付的实战
7.跳过支付
这种方式需要依靠前面说的浏览器跳转。首先抓包找到支付成功访问的页面,然后直接下个单子,复制订单号,然后拼接成功访问的页面
8.并发支付
有任何能对我们有益的功能都可以进行并发测试。
在支付中:
1.并发提现
2.并发领取优惠券
3.并发生成新人福利,首单优惠订单
9.交易重放
购买成功后,重放其中的请求,竟然可以多次购买商品。
实例:
豆丁网购买豆元后可以将豆元倍增
阿里云0元订单,服务器随便买
10.订单替换
首先去产生两个订单,这两个订单商品是不一样的,其价格不一样,如果服务端没有做好这相关的验证,那么在支付的过程当中抓包,修改其订单值为另一个订单值,最后支付,这时就可以用订单1的支付价格买到订单2的商品。
11."四舍五入"
充值:
用余额充值为例,余额都是保留到分(也就是0.00),但是当我们充值0.019时,网站系统可能直接将0.016四舍五入为0.02,而我们在支付的时候则可以支付0.016,那么就成功成功重置0.02了。
提现:
余额精确到分(1.00),我们提现的时候提交1.001,如果系统逻辑错误,那么就能成功提现到1.001,因为银行,第三方支付都是可以精确很多的。
12.突破购买限制
比如新人福利,可以以很便宜的价格购买商品,但是只能购买一次。
我们可以无限次生成那个以优惠价购买商品的订单,只要不支付,优惠就会一直存在,等到有优惠的订单生成完毕,我们再进行支付。
13.演示
1.大米CMS_v5.4演示
首页:http://localhost/damicms/index.php
后台:http://localhost/damicms/admin.php?s=/Public/login
1.分析网站支付功能
先对网站购买商品功能进行分析:
1.产品信息:

产品详情:

2.商品购买
选择商品及数量时:
数据包:

分析参数(和页面信息结合着看就行):
m=Member 成员,会员 购买者身份信息
a=gobuy 去买 传递功能
id=69 可能是商品编号或者订单编号
name=大米CMSææºå¼åä¸ç 购买商品的名字
qty=1 购买数量
price=5400 商品价格
gtype=ç°è² 未知
pic=/damicms/Public/Uploads/thumb/thumb_1393206337.jpg 此商品的图片
生成订单:

通过生成的订单可知:
id=69 确定为商品编号
gtype=ç°è² 型号
在生成订单时填写地址(这里可以进行XSS测试)
那么在生成订单时可能存在漏洞有:
1.直接修改价格,数量
2.修改价格高的商品编号为价格低的(这个还得看商品变了没,变了那么就没用)
提交订单:
数据包参数分析:

id这些已经知道的就不在说了,看下新增加的:
realname=å¼ 姓名
tel=15004983328 手机
province=å®å¾½ 省
city=åè¥å¸ 市
area=è¥è¥¿å¿ 县
address=fuming 详细地址
trade_type=1 付款方式
iscart=0 未知

input_charset=utf-8 输入字符编码类型
logistics_fee=0.00 运费金额
logistics_payment=SELLER_PAY 运费支付方式
logistics_type=EXPRESS 物流类型
notify_url=http://www.myweb.com/index.php/Public/shouquan(授权) 访问后是"失败"
out_trade_no=GB1660049308-9 贸易号(可能时订单编号)
partner=2088002530455064 伙伴???暂时未知
return_url=http://www.myweb.com/Trade/ap_danbao/return_url.php 访问后是"验证失败"
seller_email=admin@126.com 卖家邮箱
service=create_partner_trade_by_buyer 贸易伙伴??
show_url=http://www.damicms.com/Public/donate ??
subject=?�è¡ì?¡Ã?CMS????????????????? 主题
sign_type=MD5 字符类型
提交订单后应该开始支付了,但是由于网站原因啊,没办法出来。
那么就在这里将提交订单后出现的数据包参数猜测下存在那些漏洞:
1.修改商品金额,数量
2.修改运费金额
3.物流类型,商品/运费支付方式修改为一个未知的,可能会成功
4.获取到了卖家邮箱
5.那两个网址可能有问题:一个是授权,一个是验证失败
6.out_trade_no,订单编号替换??
3.会员中心-我的订单

在这里确定了参数out_trade_nojiu的确是订单编号,那么可以进行的操作
1.将价格高的订单替换为价格第的订单编号
2.发现这里有"等待支付"的状态,那么是否可以替换订单编号达到替换支付状态?将"等待支付"替换为"已支付"状态呢?
3.在之前的流程中也存在订单编号,那么能否通过替换订单编号来查看其他人的收获信息呢?
4.在这里存在"删除,评价"操作,是否存在越权漏洞?(这里只讲支付哈)
4.会员中心-我的充值


可能存在的漏洞:
1."四舍五入"的充值与提现
2.这里提现没有验证,能否越权提现
5.总结此网站支付流程,可能存在的漏洞
支付流程:选择商品->生成订单(填写收货地址)->支付(这里不能测试,坏了)
此cms可测试的支付漏洞:生成订单时修改商品价格,数量.修改商品编号(这里有关付款类的功能都不能使用,能测试的只有这个了)
2.漏洞测试
1.修改价格


注意:在测试支付漏洞时,要成功支付才算漏洞存在。这里是因为不可支付,所以就不演示。
2.修改数量
3.修改产品id
测试产品:4000 id=66
大米CMS手机开发专版:5400 id=69
这里购买 5400 的手机,替换id为4000的,看价格是否变化。
失败,证明生成订单时,商品的价格仅有数据包参数price所影响。
2.niushop v1.11
首页 http://localhost/niushop_b2c_release/index.php
后台 http://localhost/niushop_b2c_release/index.php?s=/admin/login
1.分析网站支付功能
产品:


存在限购商品,可尝试突破购买限制,多次购买商品。
网站存在优惠券领取,可尝试并发领取优惠券/修改优惠券金额,数量
生成订单:
第一个数据包:

tag=buy_now 立即购买,应该是表行为(立即购买/加入购物车)
sku_id=3 商品/订单id
num=1 数量
第三个数据包:

ap_id=1052 商品/订单id
订单页面:
购物流程:

可测试跳过支付,再生成订单后,直接跳转到支付成功页面
收货人信息:

越权查看他人收货地址。
越权修改他人收货地址为自己的。
使用优惠券:

可在此处修改优惠券金额,数量
结算信息:

待会可以测试越权使用他人余额支付,修改余额数量
提交订单-使用第三方支付(使用优惠券):


goods_sku_list= 商品清单
leavemessage= 留言
use_coupon= 使用优惠券
integral=
account_balance= 余额支付金额
pay_type= 支付类型
buyer_invoice= 发票
pick_up_id= 领取id???
express_company_id= 快递公司id

out_trade_no=1661243158989 贸易号
分析:
1.优惠券金额无法修改
2.可修改贸易号测试
支付页面:

发现url上的参数,也就是提交订单第3个数据包的参数,确定为"支付流水号",那么是否存在替换流水号达到修改支付状态?
提交订单-使用余额支付


交易成功的参数:

是否可以替换掉参数以达到跳过支付?

总结:
可进行测试的漏洞点:
1.多次创建订单,达到突破购买限制
2.并发领取优惠券
3.修改商品数量,id
4.修改out_trade_no交易流水号达到支付状态修改
5.修改余额测试??
6.跳过支付
2.漏洞测试
1.突破限制
1.购买限制设置:

2.这里可以生成多个个订单,再进行支付,以突破限制(这里无法支付,暂时无法测试):

3.这里经过测试使用余额支付时,并不会有购买限制,所以也能绕过。

2.并发领取优惠券
这里的优惠券是有限制的,一个人只能领取一次:

1.并发
使用并发插件 Turbo intruder
安装

使用


2.并发测试
换个新的账号去测试:

抓包:

发送到 Turbo intruder模块:

结果:



3.修改商品数量id


订单信息显示修改成功了啊,付款看看


4.修改商品id(sku_id)
sku_id=3 ¥5099.00
sku_id=4 ¥2999.00
在这里我们购买5099的手机,然后抓包替换成2999的id


这里是失败了,商品id发生变化,商品也变了,没用。
替换商品ID,结果应该是只变化价格,但不变化商品,才算成功。
这种情况可能是因为商品信息和价格不绑定,而价格由商品ID决定。
5.修改支付状态
支付成功的订单号:
&out_trade_no=1661248847118
购买商品,修改

这里是失败了,出现支付错误

6.跳过支付
交易成功URL:
未支付URL:
支付成功和未支付的区别:s=/wap/pay/paycallback&msg=1
前端显示支付成功:


看下订单,失败了,只是前端显示了,并没有成功。也就证明了这个不是基于浏览器跳转的快捷支付。
7.修改余额测试
在提交订单的数据包中有余额大小的参数(account_balance),那么余额不足是否只是前端检测?
修改余额:

改大,失败
改小
成功,可以给商家多送钱....
8.总结
存在漏洞:
1.优惠券并发领取
2.商品数量更改
暴力破解
使用pikachu靶场的暴力破解模块进行学习
基于表单的暴力破解
1.将数据包发送到Intruder模块

2.添加变量

3.选择字典,开始爆破

4.结果

验证码绕过(on server)
$html="";
if(isset($_POST['submit'])) {
if (empty($_POST['username'])) {
$html .= "<p class='notice'>用户名不能为空</p>";
} else {
if (empty($_POST['password'])) {
$html .= "<p class='notice'>密码不能为空</p>";
} else {
if (empty($_POST['vcode'])) {
$html .= "<p class='notice'>验证码不能为空哦!</p>";
} else {
// 验证验证码是否正确
if (strtolower($_POST['vcode']) != strtolower($_SESSION['vcode'])) {
$html .= "<p class='notice'>验证码输入错误哦!</p>";
//应该在验证完成后,销毁该$_SESSION['vcode']
}else{
$username = $_POST['username'];
$password = $_POST['password'];
$vcode = $_POST['vcode'];
$sql = "select * from users where username=? and password=md5(?)";
$line_pre = $link->prepare($sql);
$line_pre->bind_param('ss',$username,$password);
if($line_pre->execute()){
$line_pre->store_result();
//虽然前面做了为空判断,但最后,却没有验证验证码!!!
if($line_pre->num_rows()==1){
$html.='<p> login success</p>';
}else{
$html.= '<p> username or password is not exists~</p>';
}
}
else{
$html.= '<p>执行错误:'.$line_pre->errno.'错误信息:'.$line_pre->error.'</p>';
}
}
}
}
}
}
这里对验证码的检测:判断是否为空,判断是否正确,错误就提示"验证码输入错误哦!"。但是没有在账号密码错误一次时,
就更换新的验证码。
测试流程:
填写一次正确的验证码,抓取的数据包就可以一直使用。
验证码绕过(on client)
服务端代码:
if(isset($_POST['submit'])){
if($_POST['username'] && $_POST['password']) {
$username = $_POST['username'];
$password = $_POST['password'];
$sql = "select * from users where username=? and password=md5(?)";
$line_pre = $link->prepare($sql);
$line_pre->bind_param('ss', $username, $password);
if ($line_pre->execute()) {
$line_pre->store_result();
if ($line_pre->num_rows > 0) {
$html .= '<p> login success</p>';
} else {
$html .= '<p> username or password is not exists~</p>';
}
} else {
$html .= '<p>执行错误:' . $line_pre->errno . '错误信息:' . $line_pre->error . '</p>';
}
}else{
$html .= '<p> please input username and password~</p>';
}
}
客户端:
<script language="javascript" type="text/javascript">
var code; //在全局 定义验证码
function createCode() {
code = "";
var codeLength = 5;//验证码的长度
var checkCode = document.getElementById("checkCode");
var selectChar = new Array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9,'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z');//所有候选组成验证码的字符,当然也可以用中文的
for (var i = 0; i < codeLength; i++) {
var charIndex = Math.floor(Math.random() * 36);
code += selectChar[charIndex];
}
//alert(code);
if (checkCode) {
checkCode.className = "code";
checkCode.value = code;
}
}
function validate() {
var inputCode = document.querySelector('#bf_client .vcode').value;
if (inputCode.length <= 0) {
alert("请输入验证码!");
return false;
} else if (inputCode != code) {
alert("验证码输入错误!");
createCode();//刷新验证码
return false;
}
else {
return true;
}
}
createCode();
</script>
这里只在客户端对验证码检测,但是服务端没有关于验证码的检测。
所以输入正确验证码后,正常爆破即可。
token防爆破?
有的网站后台存在 token 值,这个 token 通俗的名字叫令牌,每次刷新页面都会随机变化。提交请求时必须携带这个 token 值,可以利用这点避免后台进行直接穷举和防止 csrf 攻击。
在服务端会返回 token 给前端,前端在每次请求时会带上服务端发来的 token 来证明自己的合法性.
前次返回包:

下次请求包:

那么如何使用 burpsuite 爆破呢?
爆破token之前,要先抓一次包,token爆破是根据返回包进行的。
- attack type选择pitchfork,添加password,token为变量

- 在 Option 中的 Grep Extract 中点击 Add,在点击 Refetch response,找到返回的包,找到来自服务器返回的 token,为了便于查找可以在最下方的输入栏输入 token 直接找到 token 的值


- 在 Option 中的最下方勾选 always,并将线程设置为 1 ,如果不将线程设为1会出现报错


- 为变量1password设置爆破字典,对 token 的 Payloads 的参数设置为 Recursive grep,同时在 Payload Options 选中第一项,并将之前复制的 token 值输入到下面的输入栏中.开始爆破.



识别验证码
在验证码不可绕过的情况下,就需要我们自动化的识别验证码进行爆破。这里使用BurpSuite的captcha-killer插件进行识别。
1.插件安装




2.演示
密码找回漏洞

密码重置流程:

1.用户凭证暴力破解
密码找回的凭证太弱,当验证码为4位数字且验证码时效很长时,可通过暴力破解验证码进行密码找回。
当当网任意用户密码修改漏洞
2.返回凭证
1.url返回验证码及token
找回密码凭证发到邮箱中,url中包含用户信息以及凭证,但是这个凭证可以重置任何用户
2.密码找回凭证在页面中
通过密保问题找回密码、找回密码的答案在网页的源代码中
走秀网秀团任意密码修改缺陷
3.短信/邮箱验证码返回到页面源代码,数据包中(验证码可控)
3.跳过验证
修改数据包中的步骤参数,如step=1,修改参数,使其跳过验证码验证。
修改响应数据包,如false改成true,0改成1等,修改后前端认为验证正确,即跳过验证。
4.验证信息未绑定
在重置密码时,抓包,修改手机号/邮箱为自己的,然后输入验证码,看能否成功。
5.密码找回验证条件可社工
- 只验证帐号是否存在即可修改密码
- 只验证帐号与邮箱地址是否匹配即可修改密码
- 只验证帐号与手机号是否匹配即可修改密码
信息轰炸
短信/邮箱轰炸
绕过手法:
- 修改Cookie值绕过
- 修改IP值绕过~XXF
- 修改返回值绕过
- 编码
- 添加字符:
00,0086,+86,空格,\n - 多次叠加参数
- 大小写英文:
@qQ.Com








