可疑点
- SQL 注入。
- 业务逻辑漏洞。
- 水平越权。
- 图片上传。
- xss(反射、存储)。
- CSRF。
测试
SQL 注入
服务器加载比较慢,而且为了测试安全,从仓库 pull 源代码,在本地跑进行测试。
** 主要采取的方法:代码审计,查看后台报错信息;黑盒测试。 **
- 查看 SQL 语句执行情况。
application.yaml
1 2 3 4
| mybatis: # spring boot集成mybatis的方式打印sql configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
|
- 预编译,先占位解决 SQL 注入
- 原理
mybatis 默认情况下,将对所有的 sql 进行预编译。mybatis 底层使用 PreparedStatement,过程是先将带有占位符(即”?”)的 sql 模板发送至 mysql 服务器,由服务器对此无参数的 sql 进行编译后,将编译结果缓存,然后直接执行带有真实参数的 sql。核心是通过 #{ } 实现的。
在预编译之前,#{ } 解析为一个 JDBC 预编译语句(prepared statement)的参数标记符?
- 分析
UserMapper.xml
(1)#
1 2 3
| <select id="selectUserByAccount" resultMap="userResultMap"> select * from v_user where account = #{account} </select>
|
查看后台处理情况(使用 account 账户 1 和密码 1 进行登录,查看后台 sql 语句)
1 2 3 4 5 6 7
| JDBC Connection [HikariProxyConnection@548761230 wrapping com.mysql.cj.jdbc.ConnectionImpl@29572120] will not be managed by Spring ==> Preparing: select * from v_user where account = ? ==> Parameters: 1(String) <== Columns: id, username, password, account, icon, status, admin <== Row: 14, null, DqFzSl9t27Hf696hBn82SQ==, 1, null, 0, 0 <== Total: 1 Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2b6b45bb]
|

可疑很清晰看到显示有?占位,对指令语句和数据语句分别进行编译,从根源上解决了 SQL 注入。
(2)${account}
一个很有意思的事情出现了!
1)account = 1
1 2 3 4 5 6 7 8 9
| JDBC Connection [HikariProxyConnection@939952256 wrapping com.mysql.cj.jdbc.ConnectionImpl@19df681a] will not be managed by Spring ==> Preparing: select * from v_user where account = 1 ==> Parameters: <== Columns: id, username, password, account, icon, status, admin <== Row: 12, null, J4Hsbg0u8mpD/ZwVmlWr3g==, 1", null, 0, 0 <== Row: 13, null, L62seSBiMkORDq/plPDjWw==, 1', null, 0, 0 <== Row: 14, null, DqFzSl9t27Hf696hBn82SQ==, 1, null, 0, 0 <== Total: 3 Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@57a4e160]
|

select * from v_user where account = 1,出现了三个结果!导致报错。
这是怎么回事呢?我们将命令带入数据库中跑一下看看。

其间还测试了各种情况:1. 1, 1a
1 2 3 4
| 1 = 0 or 1=“1'” 1 = 0 or 'a1'=0 1 = 0 or '2'=2 1 = 0 or 'a'=0
|
以上情况均可查出所有 account 以 1 开头的
这应该是 mysql 的一个特性:转换就是字符中有数字转数字,没数字默认 0,转到字母就停止。
还可以再测试一下’11’=11 和’1a1’=1
可以参考一下 mysql 文档:https://dev.mysql.com/doc/refman/5.7/en/comparison-operators.html
2)account = 1 or 1 = 1

好家伙,全给查出来了,好在没有报错回显。
交易逻辑漏洞
充值提现
- 抓包修改 recharge 参数值


- 抓包修改 cash 参数值
提现和充值也是一样可以抓包修改参数,虽然两者总的价值是 $10000,但是用户如果类似于微信支付逻辑一样链接银行卡等信息,可以无限制提现。
交易买入与卖出
ps:解决 Burp 外网抓包代理问题。

- 买入
代码审计得到获取数据是通过连接火币 api,需要 vpn
抓包快速放掉第 1 个包,修改第二个包参数



- 卖出
和买入一样的思路
水平越权
充值提现
抓包修改 account 参数值
可以随意更改其他用户充值提现情况,同时结合交易逻辑漏洞,可以造成其他用户账户信息混乱。
- admin1 用户(昵称:纯情男中专生)

- 1 用户(昵称:null)

- 抓包修改 1 用户为 admin1 用户
充值 200


推文
- 发布推文
可以更改昵称伪造其他用户发表推文。
- 发布评论
可以更改昵称伪造其他用户发表评论。
- 点赞
可以更改昵称伪造其他用户点赞。
- 交易明细
可以更改 account 参数值伪造其他用户查看用户具体资产信息。

图片上传
- 在头像和推文内容图文上传处,可以上传图片马
- 上传后发现解析不了,蚁剑连接不上,不存在文件包含漏洞。
- 代码审计分析
(1)图片后缀的后端写死,无更改可能
1
| String picUrl = "D:/Trade-main/trade-server/img/icon/" + uuid + ".png";
|
(2)图片解析直接调用对应上传后服务器网址图片,再利用 CSS 调整相应大小尺寸,无上传图片马再解析可能。
1 2 3 4 5 6
| return { user, attachImageUrl: HttpManager.attachImageUrl, ...toRefs(state), ...methods }
|
1 2
| // 获取图片信息 attachImageUrl: (url) => `${getBaseURL()}/${url}
|
1 2 3 4 5 6 7 8 9
| .head-icon { position: relative; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 50%; border-radius: 50%; border: 1px solid #fff; }
|
XSS
- 代码审计
所有参数传值地方都正确使用,从解析方面避免了攻击。
CSRF
- account 获取
利用爆破或者正则表达式抓包解析可以获取当前用户的 cookie.account
- CSRF poc 构造
1 2 3 4 5 6 7 8 9 10 11
| <script src="http://code.jquery.com/jquery-latest.js"></script> <script src="http://cdn.bootcss.com/jquery/1.12.2/jquery.js"></script> <script src="https://cdn.bootcdn.net/ajax/libs/jquery.serializeJSON/2.9.0/jquery.serializejson.js"></script> <form id=payment action="http://124.220.209.244:8005/buy" method=POST> <input type="text" name="bc" value="ht" /> <input type="text" name="qc" value="usdt" /> <input type="text" name="price" value="0.0" /> <input type="text" name="size" value="48" /> <input type="text" name="account" value="1" /> <input type="submit" value="Submit request" /> </form>
|
修复建议
交易逻辑漏洞
- 充值提现
- 对参数(account、recharge、cash)值进行非对称加密,是攻击者无法篡改参数值。
- 对虚拟币 USDT 兑换前进行逻辑判断,兑换后小于 0 不予以兑换(防止连接银行卡长生无限提现情况)
- 交易买入与卖出
- 对参数(bc、qc、price、size、accont)值进行非对称加密,是攻击者无法篡改参数值。这里还看了以下,account 这些是从 cookie 中获取,cookie 一般会进行加密,所以也需要对 cookie 加密。
CSRF
参考:https://blog.csdn.net/allway2/article/details/122786570
- 增加 token 令牌,springboot 框架有防 csrf 的相应包和代码,对应调用即可。