自定义提取Merlin Agent样本配置信息
根据上述结论,我们发现,只要使用官方提供的编译方式,即会导致配置信息直接暴露于样本文件中。
因此,针对此类样本,我们即可编写自动化程序实现自动化提取配置信息。
自动化程序提取配置信息
自动化提取配置信息的脚本代码如下:
package main
import (
"bytes"
"fmt"
"io/ioutil"
"os"
"strings"
)
func main() {
filename := os.Args[1]
data, _ := ioutil.ReadFile(filename)
if strings.Contains(string(data),
index := strings.Index(string(data),
offset := bytes.Index(data[index:index+0x1000], []byte{0xA})
configdata := strings.ReplaceAll(strings.TrimSuffix(strings.TrimPrefix(string(data[index:index+offset]),
fmt.Println(strings.ReplaceAll(configdata,
}
}
根据上述结论,我们发现,只要使用官方提供的编译方式,即会导致配置信息直接暴露于样本文件中。
因此,针对此类样本,我们即可编写自动化程序实现自动化提取配置信息。
自动化程序提取配置信息
自动化提取配置信息的脚本代码如下:
package main
import (
"bytes"
"fmt"
"io/ioutil"
"os"
"strings"
)
func main() {
filename := os.Args[1]
data, _ := ioutil.ReadFile(filename)
if strings.Contains(string(data),
-ldflags=") {index := strings.Index(string(data),
-ldflags=")offset := bytes.Index(data[index:index+0x1000], []byte{0xA})
configdata := strings.ReplaceAll(strings.TrimSuffix(strings.TrimPrefix(string(data[index:index+offset]),
-ldflags="), "), \", ")fmt.Println(strings.ReplaceAll(configdata,
-, string([]byte{0xA})+-))}
}
检测Merlin Agent木马
为了实现Merlin Agent木马的自动化检测,笔者尝试在网络中搜索了一番,在/Neo23x0/signature-base/blob/38d1f4f0f87c009289a1aef111af9d89d75ed260/yara/gen_merlin_agent.yar地址中找到了针对Merlin Agent木马的yara规则。
虽然此yara规则的时间确实还是比较久了,不过还是能成功检测当前最新版本的Merlin Agent木马了。
yara规则扫描结果如下:(笔者抽选了多个版本的Merlin Agent木马,发现都能成功扫描)
为了实现Merlin Agent木马的自动化检测,笔者尝试在网络中搜索了一番,在/Neo23x0/signature-base/blob/38d1f4f0f87c009289a1aef111af9d89d75ed260/yara/gen_merlin_agent.yar地址中找到了针对Merlin Agent木马的yara规则。
虽然此yara规则的时间确实还是比较久了,不过还是能成功检测当前最新版本的Merlin Agent木马了。
yara规则扫描结果如下:(笔者抽选了多个版本的Merlin Agent木马,发现都能成功扫描)
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虚拟环境。下载镜像需要十到十五分钟。
步骤:
安装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重定向漏洞
在虚拟机上部署一个简单的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连接。
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传出。
在构造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的权限。
如此便构造了一个嵌套的Intent。
通过嵌套的Intent以及Vulnerable中的重定向漏洞,从pwn跳转到Vulnerable,再从Vulnerable把intent的Extra反序列化为Intent类跳转到pwn。使pwn获得临时读写com.bytectf.babydroid的权限。
TestActivity中Webview的setAllowFileAccess和setJavaScriptEnable都已经打开,所以Webview可以渲染文件因为之前建立好了软链接,通过跳转TestActivity渲染file:///data/data/com.bytectf.pwneasydroid/symlink.html即是渲染/data/data/com.bytectf.easydroid/Cookies。
将Cookies文件中的全部内容作为文本,通过http传出来。
将Cookies文件中的全部内容作为文本,通过http传出来。