@author : Dlive
在對Android應用進行Web漏洞測試時,經常遇到一種情況:HTTP傳輸的數據帶有簽名字段
處理這種情況的方法通常是逆向簽名算法,但是如果算法在so中,而且so加殼了,想要逆向出算法也要花很大一番功夫
還有就是可以自己編寫app調用so里的簽名算法,然后對HTTP傳輸的數據進行測試
這兩種方法都挺麻煩的,並且如果一個app中多處使用了不同的簽名/加密算法就更麻煩了
曾經想寫一個Android上的代理軟件,在Android手機上開啟HTTP/HTTPS代理,在PC端將HTTP/HTTPS流量交給代理,代理軟件調用so里的加密/簽名算法,
最后代理軟件將經簽名/加密后的數據提交給服務端。這樣的話就可以直接用SQLmap之類的工具進行測試了。
但是在我准備着手寫這么個東西之前,我發現了個更方便的東西:Frida,使用Frida我們可以較簡便地解決上面所說的問題。
這里以一些Demo為例講解Frida如何簡化Android端應用的安全測試。
同時2017 TSCTF的一道Web+Android APP題目為例,講解如何使用Firda簡化移動端的Web安全測試。(畢竟Web🐶,關注點主要在Web...
0x01 Frida介紹
Frida是一個動態代碼插樁工具,它可以讓你向多種平台(Windows, Linux, macOS, IOS, Android, QUX)的App插入自定義Javascript代碼片段
它可以做什么
- Access process memory
- Overwrite functions while the application is running
- Call functions from imported classes
- Find object instances on the heap and use them
- Hook, trace and intercept functions etc.
0x02 安裝Firda
以Mac為例,其他系統請自行查看Firda官方文檔
環境:Python3 ,Root過的Nexus 4(Android 4.4)
Frida官方文檔說需要Python3.x的環境,因為Firda最開始是基於Android 4.4開發的,所以建議使用4.4或4.4以上版本的系統
sudo pip3 install frida
驗證是否安裝成功
➜ ~ frida --version
9.1.20
➜ ~ python3
Python 3.6.0 (default, Dec 24 2016, 08:01:42)
[GCC 4.2.1 Compatible Apple LLVM 8.0.0 (clang-800.0.42.1)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import frida
>>>
下載和frida對應版本的frida-server (https://github.com/frida/frida/releases ),解壓后將frida-server push到Android中
➜ ~ adb push ~/0Android/frida/frida-server-9.1.20-android-arm /data/local/tmp/frida-server
/Users/dlive/0Android/frida/frida-serv...d. 3.5 MB/s (21555488 bytes in 5.948s)
在adb shell中運行frida-server
root@android:/data/local/tmp # chmod 755 frida-server
root@android:/data/local/tmp # ./frida-server &
0x03 Frida相關命令的基本使用
經測試發現很多情況下frida非常不穩定,可以選擇重啟frida-server后重新執行命令
開啟端口轉發
adb forward tcp:27042 tcp:27042
adb forward tcp:27043 tcp:27043
1.frida-ps
查看正在運行的進程
# Connect Frida to an iPad over USB and list running processes
# -U connect to USB device
$ frida-ps -U
# List running applications
$ frida-ps -Ua
# List installed applications
$ frida-ps -Uai
2.frida-trace
# 顯示open()函數的調用情況
frida-trace -i "open" -U com.android.chrome
# -f 讓Frida啟動chrome app (let Frida spawn the process)
frida-trace -i "open" -U -f com.android.chrome
3.frida
frida交互式命令行界面(詳細請參考官方文檔)
# Unfortunately, in my case it always lead to getting the app killed automatically after 2 seconds.
# This is not what we want. You can either use these 2 seconds to type %resume
frida -U -f com.android.chrome
# better command
# --no-pause automatically start main thread after startup
frida -U --no-pause -f com.android.chrome
# pass the -f option to Frida to let it spawn the process itself
frida -U --no-pause -f com.android.chrome
# 向app注入JS
frida -U -l example.js com.example.dlive
注入的JS和之后Python中用到的JS的用法相同
console.log("[*] Starting script");
Java.perform(function() {
var Activity = Java.use("android.app.Activity");
Activity.onResume.implementation = function () {
console.log("[*] onResume() got called!");
this.onResume();
};
});
0x04 使用Frida進行Hook
1. Hook Native層
import frida
import sys
rdev = frida.get_remote_device()
session = rdev.attach("com.tencent.mm")
scr = """
Interceptor.attach(Module.findExportByName("libc.so" , "open"), {
onEnter: function(args) {
send("open("+Memory.readCString(args[0])+","+args[1]+")");
},
onLeave:function(retval){
}
});
"""
script = session.create_script(scr)
def on_message(message ,data):
print message
script.on("message" , on_message)
script.load()
sys.stdin.read()
2. Hook Java層
import frida
import sys
rdev = frida.get_remote_device()
session = rdev.attach("com.tencent.mm")
scr = """
Java.perform(function () {
var ay = Java.use("com.tencent.mm.sdk.platformtools.ay");
ay.pu.implementation = function(){
var type = arguments[0];
send("type="+type);
if (type == 2)
{
return this.pu(type);
}
else
{
return 5;
}
};
});
"""
script = session.create_script(scr)
def on_message(message ,data):
print message
script.on("message" , on_message)
script.load()
sys.stdin.read()
0x05 使用Frida Python接口結合Flask實現APP中轉注入
apk只有一個登陸功能,該功能的username字段存在注入
apk中調用了native方法對username和password簽名, 簽名之后得到的sign和username, password一起發往服務端
使用Flask寫如下中轉腳本,接收username和password, 計算sign
經測試Frida頻繁向app進程注入JS容易掛掉。。。如果掛掉重啟app就好,然后讓sqlmap繼續原來的session
from flask import Flask
from flask import request
import frida
import hashlib
import requests
import time
app = Flask(__name__)
sign_result = ''
jscode = """
Java.perform(function () {
var sign = Java.use("com.example.dlive.tsctf2017.Sign");
var result = sign.sign("%s", "%s");
send(result);
});
"""
frida_session = frida.get_device_manager().enumerate_devices()[-1].attach("com.example.dlive.tsctf2017")
def on_message(message, data):
global sign_result
sign_result = hashlib.md5(message['payload']).hexdigest()
# print sign_result
def sign(username, password):
global frida_session
global jscode
username = username.replace('"', '\\"')
script = frida_session.create_script(jscode % (username, password))
script.on('message', on_message)
script.load()
@app.route('/forward', methods=['POST'])
def login():
url = 'http://10.101.162.128/sign.php'
username = request.form['username']
password = request.form['password']
session = requests.session()
sign(username, password)
http = session.post(url, data={'username': username, 'password': password, 'sign': sign_result}, timeout=5, allow_redirects=False)
return http.content
if __name__ == "__main__":
app.run()
使用sqlmap注入,目標url是該中轉腳本
中轉注入是稍微方便了不少,但是在注入的時候frida特別容易掛掉QAQ
0x06 參考
https://sec.xiaomi.com/article/23
https://github.com/dweinstein/awesome-frida
https://www.notsosecure.com/pentesting-android-apps-using-frida/
https://www.codemetrix.net/hacking-android-apps-with-frida-1/
https://www.codemetrix.net/hacking-android-apps-with-frida-2/
https://www.frida.re/
http://www.jianshu.com/p/ca8381d3e094
http://www.voidcn.com/blog/asmcvc/article/p-6240248.html
http://wooyun.jozxing.cc/static/drops/tools-5602.html