黑客网站入侵 编程 搭建 渗透 破解
3.67K subscribers
418 photos
13 links
Download Telegram
ByteCTF2021_mobile 环境搭建

步骤:
安装dokcer。
在虚拟机上,运行flask服务器。将打包好的pwn.apk放在服务器上。一是,在之后运行的脚本中可以在服务器上下载这个apk。二是,做URL参数解析,用来接收传出的flag。
from flask import Flask, request, send_from_directory
import os
app = Flask(name, static_folder='dist')

@app.route("/")
def hello():
return "hello world"
# URL参数解析
@app.route('/getUrlParam')
def getUrlParam():
# name=request.args["name"]
# password=request.args["password"]
flag = request.args["msg"]
with open("./flag.sql",'w') as f:
f.write(flag)
# print("name:"+name)
# print("password:"+password)
s = "flag: %s"%flag
print(s)
return s
@app.route('/test')
def test():
print("test")
return app.send_static_file('test.html')
# easydroid XSS
@app.route('/exp.html')
在~/ByteCTF2021_Android/babydroid/src_babydroid目录下执行run.sh脚本,生成babydroid容器。docker镜像中有Android虚拟环境。下载镜像需要十到十五分钟。
获得flag后,因为安卓不方便控制台输出。所以exp选择用http把flag传出来。

在虚拟机上部署一个简单的flask,用来做url参数解析,即可获得传出的flag。

babydroid
1. 原理
题目漏洞点
babydroid的文件目录
FlagReceiver.java
public void onReceive(Context context, Intent intent) {
String flag = intent.getStringExtra("flag");
if(flag!=null){
File file = new File(context.getFilesDir(), "flag");
writeFile(file, flag);
Log.e("FlagReceiver", "received flag.");
}
}
系统广播flag后,广播接收器接收到flag,将它写入file的位置。我们就知道要想拿到flag,即是要读取/data/user/0/com.bytectf.babydroid/files/flag。

Vulnerable.java中的Intent重定向漏洞
在运行虚拟机是可能会提示无法虚拟化CPU,这种情况一般有以下三种原因:

CPU确实无法虚拟化(无法解决)
BIOS设置中未开启CPU
开启了Hyper-V导致VMware无法直接接触物理层(我就是这个原因,之前使用了WSL,开启了Hyper-V,导致在VMware中无法CPU虚拟化)

在emulator启动时会有如下报错,如果不在启动脚本中修改ADB_PORT会导致之后获得flag后,无法建立HTTP连接。
如何授予文件临时读写权限
在构造Intent组件时,data设置为content://androidx.core.content.FileProvider/root/data/data/com.bytectf.babydroid/files/flag,flag设置为Intent.FLAG_GRANT_READ_URI_PERMISSION|Intent.FLAG_GRANT_WRITE_URI_PERMISSION,赋予临时数据读写权限。
把想赋予的不同临时权限求亦或和,赋给flag,通过Intent打开的组件就可以获得对应的临时权限。

pwn思路
构造一个嵌套的Intent,并借助Vulnerable.java转发。因为fileProvider存在文件临时读写问题,故可在转发的过程中,赋予pwn临时读写flag文件的权限。最后用http传出。
构造需要Vulnerable.java转发的Intent类evil,然后将evil序列化后放入跳转到Vulnerable的intent的Extra属性中。注意,evil的Flags要设置为3,这样被跳转的pwn就获得了文件临时读写权限。
如此便构造了一个嵌套的Intent。

通过嵌套的Intent以及Vulnerable中的重定向漏洞,从pwn跳转到Vulnerable,再从Vulnerable把intent的Extra反序列化为Intent类跳转到pwn。使pwn获得临时读写com.bytectf.babydroid的权限。
把接收到的flag存入到持久化Cookies中。在本类中,Cookies是以.db的形式存储在/data/data/com.bytectf.easydroid/app_webview/Cookies中。所以,我们希望拿到flag就是希望能把Cookies传出来。

第1行的URL验证,使用了contains(),不太严格,很容易被绕过。
第6到17行,重载了shouldOverrideUrlLoading)函数,存在Intent重定向漏洞。在Webview加载URL前,可能会先执行Intent的跳转。注意,这里的URL不一定是Intent传来的,也可能是脚本中需要打开的网页。
pwn思路
使用XSS攻击,通过在Cookies中插入js脚本,当Webview把Cookies当作.html渲染时,将Cookies文件传出来就可以拿到flag。
在pwn中构造一个Intent,通过Intent重定向运行MainActivity,因为Activity中有不严格的URL校验,可以绕过执行脚本easydroid.html。在easydroid.html脚本中,先通过TestActivity渲染exp.html文件,将恶意的<script>保存到Cookies中。再通过TestActivity渲染symlink.html(Cookies),将恶意代码执行。
TestActivity中Webview的setAllowFileAccess和setJavaScriptEnable都已经打开,所以Webview可以渲染文件因为之前建立好了软链接,通过跳转TestActivity渲染file:///data/data/com.bytectf.pwneasydroid/symlink.html即是渲染/data/data/com.bytectf.easydroid/Cookies。

将Cookies文件中的全部内容作为文本,通过http传出来。
Detours hook 流程
Detours hook目标函数的逻辑很简单,就是将目标函数开头的指令换成jmp指令,跳转到我们定义的函数中。主要流程如下,前3步是DetourAttach函数做的事情,第4-5步是DetourCommit做的事情:

计算需要修改目标函数的字节数 n,jmp到新函数地址的指令长度为5个字节,但是目标函数的前5个字节可能不能构成完整的指令。如目标函数的第4个字节到第6个字节构成了一条指令,如果只考虑前5个字节,此条指令将无法正确执行
计算Trampoline(跳板)函数跳转回来的地址:目标函数地址+第1步计算的需要修改的字节数n
构建Trampoline(跳板)函数:找一块空白的内存区域,根据第1步计算的字节数拷贝目标函数的前n个字节,然后加上一条jmp指令,以跳转到第2步所计算出的地址
修改目标函数的前5个字节,以跳转到hook后的函数中。如果第1步计算出来的需要修改的字节数大于5,大于5的部分填上0xCC
会将Trampoline函数的地址addr3 给DetourAttach函数的第一个参数(所以此参数是一个二级指针),因此可以在新函数中通过Trampoline调用原函数
hook代码如下:由于thiscall是由被调用函数清理参数栈,因此将新函数的调用约定为stdcall。这样除了this指针没有通过ecx传递之外,其余的操作与thiscall相同。如果新函数中需要使用this指针(如调用原函数),需要在函数开头push ecx,将this指针保存在栈上。当需要使用时,pop ecx,将this指针传给ecx以模拟thiscall。注意:push ecx之后堆栈会变化,需要自己维护,在函数结束时保持堆栈平衡,编译器优化会将函数调用约定变为__usercall,这种调用约定传参与fastcall一样,但是无论是调用方还是被调用方都没有清理堆栈,程序可能会崩溃。可以禁用优化,不使用这种调用约定