本文介绍一个简便的方法构建自动挖掘chromium 框架。主要的想法是自动去跑生成的testcase ,然后检测结果是否触发了ASAN,触发了的话自动邮件发送符号化的邮件。
单纯的挖chromium,看你怎么挖了,有些漏洞window.close() 再加上一些features 开关,配合用户操作就可以挖到一批,也有些poc 是直接是for 循环几个 js api,在event handler中来个postmessage 来detach 某内存,或者是gc 或者删除某个对象来释放对象。这poc 看起来构造也容易,想着如何fuzz 的话应该比较大概率可以通过fuzz 挖到。
首先需要个asan 编译的chromium 预编译文件,一般的可以从 https://alesandroortiz.com/articles/latest-chromium-asan-builds/ 来下载
或者通过查找chromium base position 然后通过gsutil 来下载
这里祭出本人使用的脚本query.sh
BASE='https://omahaproxy.appspot.com/deps.json?version='
GSUTIL_LINUX='gsutil ls "gs://chromium-browser-asan/linux-release/asan-linux-release-'
if [ $# != 1 ]; then
BASE_VERSION=`curl $BASE 2> /dev/null | jq -r ".chromium_version"`
BASE_POSITION=`curl $BASE 2> /dev/null | jq -r ".chromium_base_position"`
V8_VERSION=`curl $BASE$BASE_VERSION 2> /dev/null | jq -r ".v8_version"`
echo "current stable version: $BASE_VERSION"
echo "v8 version: $V8_VERSION"
# show
exit 1
fi
VERSION="$1"
DOWNLOAD_URL=$BASE$VERSION
BASE_POSITION=`curl $DOWNLOAD_URL 2> /dev/null | jq -r ".chromium_base_position"`
V8_VERSION=`curl $DOWNLOAD_URL 2> /dev/null | jq -r ".v8_version"`
echo ""
echo "chromium base position: $BASE_POSITION"
echo "v8 version: $V8_VERSION"
if [ "$2" = "win" ];
then
echo "yes";
fi
ex:
➜ browser git:(master) query.sh 106.0.5249.119
chromium base position: 1036826
v8 version: 10.6.194.18
^C
➜ browser git:(master) gsutil ls "gs://chromium-browser-asan/linux-release/asan-linux-release-103682*.zip"
gs://chromium-browser-asan/linux-release/asan-linux-release-1036821.zip
gs://chromium-browser-asan/linux-release/asan-linux-release-1036825.zip
gs://chromium-browser-asan/linux-release/asan-linux-release-1036826.zip
之后cp 来下载
➜ browser git:(master) gsutil cp gs://chromium-browser-asan/win32-release_x64/asan-win32-release_x64-1036825.zip .
运行和检测ASAN 信息
asan chromium 在触发漏洞时会打印sanitize 信息来检测,将输出信息不断的进行检测sanitize 标头即可。
可以选择直接使用linux 脚本来跑,然后检测下返回码,最初也是这么跑的
...
export ASAN_OPTIONS=detect_leaks=0
export USE_ZEND_ALLOC=0
while true; do
if [ $(ls $FUZZDIR/$NODE/ | wc -l) -eq 0 ]; then
echo "Waiting for more tests..."
sleep 2
continue
fi
TEST=$(ls $FUZZDIR/$NODE/ | head -n1)
echo -n "Testing $TEST: "
OUTPUT=$(timeout -s SIGTERM $TIMEOUT $CHROMIUM/chrome --user-data-dir=$USERDIR --disable-gpu --headless --no-sandbox --js-flags='--expose_gc' --enable-blink-test-features --disable-popup-blocking --ignore-certificate-errors --enable-experimental-web-platform-features --enable-features=AutofillAddressProfileSavePrompt $FUZZDIR/$NODE/$TEST 2>&1 | $MAIN_CHROMIUM/src/tools/valgrind/asan/asan_symbolize.py > $ASANLOG)
RET=$?
if [ $RET -ne 0 ]; then
...
echo -e "e[31;1mCRASH (ret:$RET)e[0m"
mv $FUZZDIR/$NODE/$TEST /mnt/fuzz/crashes/$TEST$(date)
mv $ASANLOG /mnt/fuzz/crashes/$TEST$(date).asan.log
...
跑起来飞快,1秒可能跑1,2个吧
配合个某个generator,跑了一晚跑出了个asan,最后不出意外的还是出意外了:(
由于不满足测试速度,去寻找其他方案。一般的跑testcase 可以放在iframe 里面不断加载,像fuzz in sixty seconds 那样,也可以使用extensions 来不断开tab 来加载,或者在网页中open 个testcase ,然后关闭。
在github 上搜了一下mozila 开发了ffpuppet 来fuzz 他们的firefox,有现成的我就直接拿来用,这里做了一些修改,来适应chromium,同时添加一些自定义参数。
web server
这里选择使用了web server 来提供testcase ,通过访问一个url 然后返回testcase url 来测试。
直接使用php + redis,从redis 来获取有generator 生成的testcase。这样可以可以实现分布式测试,提高fuzz 效率。
<html>
<head>
<script>
var file = null;
var run_count = 0;
var bFinish = false;
onload = function fLoad() {
var xhr = new XMLHttpRequest();
xhr.onload = function (e) {
console.log(file);
file = JSON.parse(xhr.response).file;
if (bFinish == false)
bFinish = true;
document.title = "Loading " + file;
console.log(">>>>> " + file);
}
xhr.open('GET', '/next.php?action=query');
xhr.send(null);
var oFrame = open("/testcase/" + file + ".html");
console.log("<<<<<<< " + file);
setTimeout(fCleanup, 200);
function fCleanup() {
// setTimeout(function() {
try {
if (bFinish == true) {
bFinish = false;
oFrame.close();
}
} catch (e) { };
// }, 200);
fLoad();
}
}
</script>
</head>
<body>
</body>
</html>%
testcase 生成
你猜
看你想fuzz 哪个组件,然后看规范,收集api,写规则。。。
自动化
开个cron job,自动从github pull写好的generator,以及不断检测是否有crash 文件生成,有的话直接发邮件过去。
最终
不过还是审计吧
原文始发于微信公众号(Exploit10Day):automatic fuzz chromium from a easy way