查看原文
其他

OneFuzz踩坑教程

MinGW 看雪学苑 2022-07-01

本文为看雪论坛优秀文章

看雪论坛作者ID:MinGW





0x00 写在前面


1. 微软最近开源了一个叫OneFuzz的fuzz平台,表面上讲是内部工具开源使用,实际上是推广微软的Azure云产品和服务……因此,大家不要期望OneFuzz自己真的有自己的fuzz算法。当然这些只是我个人想法。

2. 整个过程坑会比较多,我会带大家把我遇到的坑踩一遍(那是不可能的,我会把我踩的坑给大家看一下,让大家不要踩),最终实现跑出结果,同时我也会对我自己遇到的问题给出答案;同学们要是遇到了我没遇到的问题,评论区帮忙留下言,我看看能不能尽量帮上忙。

3. OneFuzz调研的整个周,我被它折腾的焦头烂额,整个过程是我实地踩出来的。但限于个人能力,整个教程会有很多不足之处,也会夹杂着一些个人短浅的见解,我只希望能帮上大家的忙,请大家轻点喷……




0x01 官方链接


1. 微软官方公布链接:https://www.microsoft.com/security/blog/2020/09/15/microsoft-onefuzz-framework-open-source-developer-tool-fix-bugs/

2. GitHub链接:
https://github.com/microsoft/onefuzz

3. GitHub例子链接:
https://github.com/microsoft/onefuzz-samples




0x02
特色功能和作用



整理+翻译自微软官方链接资料,可能会有偏差。

1. 开源,用户可以根据需要自定义OneFuzz,更换插桩代码和管理种子输入
2. 跨平台,支持windows和linux平台(需要在各个平台重新编译)
3. 内置集成模糊测试流程,默认支持多个Fuzzer协同进行工作,Fuzzer之间共享数据
4. 提供(对样本、crash或hang的)程序化分类和去重,保留独特案例
5. 透明设计使得使用者可以监视运行情况
6. 提供live调试会话
7. 通过Azure DevOps或Microsoft Team Message向使用者发送通知和crash报告
8. 提供python SDK来调用OneFuzz功能





0x10 正文-
本地环境安装



0x11 所需下载资料(Windows环境)



0x12 环境安装


1. Python 3

这个不用我多讲了吧。OneFuzz的python脚本是用Python 3 写的,而且最好把Python 3加到环境变量里面,方便以后用。

2. func-cli-x64.msi(Azure云需要用到的东西)

下载链接:
https://functionscdn.azureedge.net/public/artifacts/v3/latest/func-cli-x64.msi

下载完成之后运行,下面是我下的3.0.2912版本。

然后按照提示安装吧。

3. release-artifacts.zip

下载链接:
https://github.com/microsoft/onefuzz/releases

下载release-artifacts.zip,不要想着去下载源码(Source Code(zip))然后编译,因为源码非常小(<10M),里面很可能没什么核心的东西。

下载完成之后解压,里面有几个文件,如下所示:

其中,onefuzz-cli-1.0.0.exe是一个需要有命令行启动的程序,里面包含了onefuzz几乎所有的命令。

这个程序起的作用和./sdk/里面的两个Python包作用是一样的,不过自从我安装了./sdk/里面的Python包之后,我就可以直接在控制台敲onefuzz 就可以使用onefuzz的命令了,所以基本上没用这个程序了。如果安装完Python包不能像我一样的话这个程序也是一个很好的后备工具。

./sdk/里面实际上是2个Python SDK包,2个对应的压缩包,压缩包里面是setup.py形式的安装,SDK包是.whl格式的。如果你想用OneFuzz来进行二次开发,建议你安装上。里面一共有两个文件,建议先安装名字长的那个(onefuzztypes-1.0.0-py3-none-any.whl),再安装名字短的那个(onefuzz-1.0.0-py3-none-any.whl)。别问我为什么。
还有一个onefuzz-deployment-1.0.0.zip的包,必须解压出来,解压完成之后里面是这样子的:


这里面的东西先不要动,以后会有用的。不过你需要执行一下命令,安装一下requirements.txt里面的依赖包。注意,这一步可能花的时间比较长。


pip install -r requirements.txt

你如果打开requirements.txt看一下里面的依赖包,会发现里面大部分都是以azure开头的,这个时候你就应该有一个预感,这个东西如此依赖azure,说不定就是来推销azure的。

上面的步骤都完成之后,下面就开始踩坑之旅吧。





0x20 正文-
Azure环境配置



0x21 注册Azure云账号


这一步里面需要注册一个微软邮箱账号,直接去微软国际官网注册就好了。链接不用给了吧,算了,还是给一下吧,免得走到国区。(原因在后面的答疑0x61)

https://www.microsoft.com/zh-cn

注册完成之后就可以去Azure登录了,链接:
https://azure.microsoft.com/zh-cn/

好的,看见免费试用Azure了吗?点进去。


然后就可以用你注册的账号登录了。

如果网站加载的慢,请记住这个是国外的,访问国外的网站怎么样快这件事我就不用说了吧。

登录好了之后,Azure会要求你验证一系列的东西,比如绑定手机号之类的。不过最重要的就是绑定一张银行卡,如下图:

这里要求你有一张支持VISA的卡,或者是MasterCard(万事达卡)。这里面,我国不少银行有能刷国外的信用卡,像招行的全币种卡等等都能用。一般卡片上有VISA标志或者万事达的标志,这种卡是可以用的。这里面地址是可以随便填的,但是微软要给你发账单,就会发到这个地址去。持卡人姓名里面就开始踩到坑了……

坑:这个地方要求和卡片上的名字一样,但是我当时填的一样,结果还是提示我信息不对。

填坑:我的名字是三个字的,持卡人姓名要求拼音全大写,即假如我叫单身狗,那我应该在这填DAN SHEN-GOU;假如我的名字叫社畜(瞎说什么实话),那我应该填SHE CHU,注意中间的空格是英文字符(也可能是中文字符,我忘了)。但是我当时填了卡上的名字DAN SHEN GOU就没过去……不知道大家会不会遇到和我一样的情况,如果遇到了只能各种情况试一试,最好遇不到。我就在这个地方猜了两天的名字。
 
继续流程。

好了,现在你的信息已经都给了Azure了,你的注册步骤已经完成了。

如果一切无误的话你应该可以回到Azure登录,链接在0x21中,然后JMP 踩坑教程00+0x21,继续点击免费试用。

在使用过程中如果发现微软扣掉了卡里面的$1,这个是微软来检测你的卡是否可用的,为以后的充值做准备。

0x22 进入网页版Azure云平台


链接:https://portal.azure.com/#home
在这里面就可以通过平台方便地管理Azure云里面的内容了。


然后在云平台创建一个资源组,具体方式:


1. 在最上方搜索框里面输入“资源组”,就会出现资源组选项。

2.点击资源组选项,进入资源组界面。

3. 点击左上角的“添加”按钮,进入添加资源组界面。

不建议起中文名字,建议使用英文字母和数字。区域建议选美国东部。(原因在后面的答疑0x61)

4. 下一步是填写标记,在这里面你可以设置一些宏,从而可以实现一些功能,但是我是没用过这个,我都直接跳过了。


5. 下一步就直接创建吧。然后你就能看到资源组列表里面多出来了一个。

0x23 使用命令行进行Azure操作


在整个OneFuzz教程里面,用到的Azure命令并不是很多。如果你准确无误地完成了前面所有步骤的话,那你可以进行以下步骤:


1. 通过管理员命令行输入以下命令(原因在后面的答疑0x62)


az login


这条命令会调用本地Azure端,触发登录,以后就不需要再次登录了,除非更换账号。


执行之后会弹出一个网页,需要你输入账号密码。如果你前面登陆了网页版的Azure云,弹出的网页可能直接会提示你已经登录,只需要点一下自己的账号,就会直接登录,并弹出10秒后跳转Azure CLI帮助文档。

同时,命令行也会返回你账号的json数据。

2. 由于缺少订阅,现在还不能算完成,还需要订阅以下内容:

  • Microsoft.EventGrid

  • Microsoft.Network

  • Microsoft.Compute


因此,继续在命令行输入查询命令:

az provider show -n Microsoft.EventGrid -o table

然后会返回EventGrid(事件网格,Azure云的一个服务)的订阅状态,如果显示没有订阅,则需要以下命令:


az provider register --namespace Microsoft.EventGrid


然后过一会再输入一遍查询命令,就会返回状态。


同理,对后面的两个订阅内容采用相同的方式订阅。


全部订阅完成之后,Azure云的命令行操作就基本上结束了。





0x30
OneFuzz 环境配置



0x31 OneFuzz deployment


注意:从这一步开始,Azure开始扣你的免费额度了。

现在我们要将OneFuzz部署在云上,如果你前面的步骤都正确无误的话,这一步应该也对你不是问题。这里喜欢探索的同学可能发现了,在onefuzz的github中,./docs/里面好像有一个文件叫做getting-started.md,那里面好像讲了怎么做。


说起来,OneFuzz刚出的那几天,全网没什么教程,我就是仰仗那篇文档踩了一周的坑。因此我决定在我踩完坑之后自己整理一个详细文档,让大家别像我一样踩坑了。


1.  管理员启动控制台,切换到当时解压的/onefuzz-deployment-1.0.0/文件夹中,运行deploy.py。这里会提示输入必要的参数。

注意:以后的OneFuzz命令最好都要在管理员权限的控制台运行。(原因在后面的答疑0x62)

这里需要location,resource_froup,application_name,owner四个参数,分别讲一下。

resource_group为我们前面讲的资源组名称;location为资源组所在地区,例如美国东部为eastus,东南亚为southeastasia,美国东部2为eastus2,当然Azure在全球都有服务器;application_name为你为OneFuzz项目起的名字,会出现在资源组里面;owner即为你自己的邮箱,如果拥有者是你自己的话。

因此,我这里给出的命令为:.

deploy.py eastus caikeng onefuzztutorial 我的邮箱

2.正常执行的时候会输出一大堆的东西,你可以看出OneFuzz读取了autodeploy.json,然后在Azure云上创建各种的东西,剩下的就是等会,等待命令返回。


这段时间你可以去网页版Azure云中进入你自己创建的资源组,右上角会有一个日志,显示正在部署,你可以在里面观察进度。


后来就会看到,OneFuzz正在把自己带的工具上传到云端,并创建很多的东西,比如存储账户,事件网格,函数应用等等。

3. 完成了,会提示你OneFuzz会自动收集数据并上传,需要在项目对应的函数应用中删除一个字段。然后提示你更新Azure CLI的配置,命令已经给你了,只需要复制一下,管理员控制台运行一下就可以了。这里链接可能不和我的一样,但是大家照做就是了。


4.运行完成之后,管理员运行以下命令:

onefuzz versions check --exact

如果能正常返回,那说明OneFuzz的部署已经成功了。

坑:为什么我部署的时候总是出现urllib3报错无法建立连接或者一直Timeout Retrying呢?

填坑:你也许忘了你的资源组在美国了,懂我的意思吗?(梯子啊兄弟,梯
子)


0x32 OneFuzz测试实例准备


1. 在0x01中的例子链接中,我们git clone一下,然后去找/onefuzz-samples/examples/simple-libfuzzer/里面的文件。解压出来之后是这个样子的。
2. 如果你能make,那就make一下,不然就请到linux 64位环境下make一下。后面我们做的实验是linux环境编译出来的。编译完之后你应该能拿到一个叫做fuzz.exe的elf文件。如果拿到的没有.exe后缀,那也没关系,这里的名字最好自己改一个其他的,免得以后生是非。

我修改了一下名字,改成了testprogram,这样会更有辨识度一些。

0x33 OneFuzz的Fuzz环境准备


1. 创建工作池

管理员命令行切到刚刚编译完的文件所在的文件夹,然后执行:

onefuzz pools create 工作池名称 系统类型

工作池名称是自己定的,系统类型有linux和windows,只能填这两种。因此,我的命令:

onefuzz pools create my-pool linux

会返回JSON数据,来显示状态:

可以通过以下命令来查询状态:

onefuzz pools list

大家可以试一下,onefuzz的命令还有很多,我就不一一展开讲了。

创建好之后,过不一会查询一下状态,会显示state:running,那说明完成了。

2.创建虚拟机集群

这个是非常重要的,OneFuzz利用Azure的云计算能力和负载均衡能力,在集群上部署fuzz任务,集群则将任务分配给各个虚拟机,由虚拟机执行fuzz任务。

参考gettting-started.md,命令如下:

onefuzz scalesets create 工作池名称 虚拟机数量 可选参数

实际上这里的可选参数支持很多,你可以看到:

-h帮助,-v版本/冗余(version/verbosity,用不着),--format输出格式,--query输出筛选 --image指定虚拟机使用的镜像 --vm_sku指定虚拟机的配置,--region创建的虚拟机所在地区,--spot_instance是否创建spot实例(这个具体是什么我也不太清楚),--tags创建标记。

这里面,特别要注意的是--vm_sku,这个参数可以在自己购买虚拟机的时候查到;--spot_instance,这个一般用不到,因为很多虚拟机配置不支持这个功能。

下面是虚拟机的配置,可以在购买虚拟机的地方看见,而且每个地区支持的虚拟机配置不尽相同。


这里我选择1核2G的配置,编号是Standard_B1ms,因此,我的命令是:

onefuzz scalesets create my-pool 4 --vm_sku Standard_B1ms

输入命令后,控制台会返回集群状态的json文件。
你可以随时输入查询命令来查询虚拟机集群的状态:

onefuzz scalesets list


可以看见state字段对应的值是setup,说明集群正在自动配置。配置好了之后state字段的值就会变成running,说明集群已经跑起来了。

跑起来之后,我们再进行下一步的操作。(原因在后面的答疑0x63)

坑:为什么我查询之后发现状态是creation_failed呢?

填坑:我遇到的情况是Azure免费使用套餐里面限制总共虚拟机最多创建4台,创建多了就会失败,查询返回的JSON提示升级套餐或者充值。集群之外创建的虚拟机也会算在里面,所以注意虚拟机的数量。还有可能是虚拟机的配置比较高,导致试用套餐$200 额度不够,这种情况由于我没有选这么好的,暂时没遇到过。如果还有其他情况方便留下言,一起讨论下。

现在就是跑起来了的状态。




0x40 运行OneFuzz


0x41 创建libfuzzer的工作


我们前面通过命令行已经到了fuzz的目标程序所在的目录,我的目录是这样的:

现在我们可以通过OneFuzz创建工作了,命令是这样的:

onefuzz template libfuzzer basic libfuzzer项目名称 工作名称 build名 工作池名 参数

在这条命令里面,libfuzzer项目名称、工作名称、build名是自己取的,工作池名就是前面定义的工作池。libfuzzer是OneFuzz包含的一个开源fuzz工具,OneFuzz还包含afl,ossfuzz,radamsa。basic是fuzz的模板名,用户可以创建自己的模板,但是现在OneFuzz还没有支持这种功能,所以默认使用OneFuzz内置的basic模板。


参数有很多,具体如下:

这些参数里面讲一下用到的。--target_exe使我们必须用的,它用来指定要上传到云上的目标程序;--inputs是我们输入的种子目录,OneFuzz会自动上传目录里面的文件;--dryrun为初始输入测试用例执行一次,这个命令应该是在本地执行的,其他的fuzz操作会放在云上面跑;--notification_config用来配置通知,当出现crash结果或者报告的时候会通知用户;--reboot_after_setup设置好后重启虚拟机;--vm_count确定运行此工作的虚拟机数,默认为集群中的全部虚拟机;--duration整个工作运行时间,由于fuzz过程是不会自动停下来的,指定这个参数可以控制运行时间,单位是小时。


所以这里我的命令是:

onefuzz template libfuzzer basic my-project my-target build_1 my-pool --duration 1 --reboot_after_setup --target_exe ./testprogram --inputs ./seeds/

这里要注意的是使用linux的目录格式(.和/),不能用Windows的目录格式(\),因为我们的虚拟机是Ubuntu系统的。

输入之后就会看到OneFuzz正在根据工作创建blob以及各种各样的任务和容器,然后会上传目标程序和测试用的种子文件。

坑:为什么我会遇到Timeout,retrying的错误?

填坑:这个时候就应该是网络的问题。我当初挂着梯子就总是遇到上传失败的问题,后来我把梯子关了,等了一小会就上传好了,当然这是我自己的情况,毕竟服务器在国外,网络不稳定或者网速慢都是正常现象。

0x42 上传完成的状态查询


上传完成的提示应该是这样的(由于我为了调试错误信息而修改了代码,中间有些地方的输出是本来没有的):

看出OneFuzz根据工作创建了3个任务,给虚拟机集群执行,并返回了job_id,这个时候可以使用下面的命令查看工作对应任务的状态,返回的是JSON格式:

onefuzz tasks list --job_id 返回的job_id

这个是部分任务的JSON,可以看出来已经在running(运行)状态了。

0x43 查看fuzz的输出结果


我们只需要等待工作运行时间结束,就可以拿结果了。运行过程中,可以去Azure云上面进入资源组,找一个fuzz开头的存储账户,进入里面,选择在资源管理器中打开(预览)就可以看到里面的容器,如果不选预览就得下载一个Azure的Storage Explorer才能看。


可以看出来已经跑出来了不少的crash:

也可以看到产生了一些unique-reports:

里面的数据都是JSON格式,都是可以下载的。




0x50 OneFuzz
远程调试目标程序



这一部分我并没有做,因为我可以把报告和测试用例拉下来本地调试,体验要比远程调试好。远程调试就是ssh连接虚拟机调用gdb调试,如果想试一下可以参考链接:
https://github.com/microsoft/onefuzz/blob/main/docs/screencasts/live-debugging.gif





0x60 答疑


0x61 关于国区和国外的问题


国区也是有Azure云的,不过是由世纪互联代理,链接:
https://portal.azure.cn/#home

国内也有区域,如华东1,华东2,华北1等等。但是国区的Azure服务和国外的是不一样的,国外的Azure云有300+种服务,国区的有<200种。可以看一下下面的链接:
https://www.cnblogs.com/zangdalei/p/7423020.html

OneFuzz依赖的Azure服务在国区和一些国外区可能出现unsupported(所在区域不支持)的情况。而且不建议国区Azure和国外Azure都登录着,否则OneFuzz可能会出现问题。我当时选择了资源组的位置是东南亚(southeastasia),结果就出现了不支持的情况。具体我就不截图了。
 
再者,OneFuzz的register_pool_application.py文件中,开发者将很多的链接写死了,下面是两个例子:

就会导致很多的过程是不会访问国内的Azure云的。(这部分内容我再试试看看能不能用)

0x62 管理员权限问题


Azure的许多操作,包括OneFuzz的都需要管理员权限,否则会出现各种错误,比如访问拒绝,上传失败等等。

所以我建议一直用管理员权限的命令行,来避免这种事情发生。

0x63等待集群跑起来之后


在集群通过命令被创建到完全创建好是有时间的,中间会经历init和setup状态,如果有问题就会进入creation_failed状态(state),失败原因可以通过命令:

onefuzz scalesets list

查询的到。如果在集群进入running状态前就运行了OneFuzz,到时候可能会因为OneFuzz没有办法分配任务到集群中的虚拟机,导致任务(task)停留在waiting(等待)和scheduled(计划中)的状态而不自动开始(running),从而浪费时间。

集群创建失败的原因有很多,比如由于套餐的限制,每个免费套餐最多允许创建4台虚拟机,因而虚拟机集群中如果虚拟机数量大于4,就会提示失败,等等。解决方法就是把多余的虚拟机或者集群全部删除。其他问题我暂时没有遇到。





0x70 写在后面


OneFuzz极度依赖Azure云平台,调用的fuzz工具也不过是网上开源的那些,可以看出它就是一个微软为了推广自己云平台产品的一个幌子。

像OneFuzz调用的那些开源fuzz工具(afl,libfuzzer之类的),它们的工作方式也不过是对测试用例进行各种各样的随机变异,喂给目标程序,统计代码覆盖率罢了。然而测试用例的变异结果无穷无尽,导致整个fuzz过程变成了无限随缘过程,真正能够量化的标准也就只有单位时间内变异的次数(或者喂给目标程序执行的次数)了

就比如一台机器在单位时间(1小时)内对用例变异了1亿次,另一台机器在单位时间内变异了1万次,很显然变异了1亿次的比1万次的更有可能产生更多的crash,发现更多的漏洞,因为尝试的次数多。

从而在目标程序、测试用例、fuzz工具等其他条件均相同的情况下,整个fuzz的效率只是和单位时间fuzz的次数,也就是主机的计算力有关。计算力高的,就会比计算力低的能有可能发现更多的漏洞或者新漏洞。最终就变成了一个计算力的问题,微软的Azure云恰好卖云计算,OneFuzz也恰好运用了Azure云的云计算。

我想,如果我们在本地有强大的计算力,并且我们要做的fuzz工作也不是很复杂,我们根本不需要耗费财力去使用OneFuzz,我们只需要在本地跑一下fuzz工具就可以了。除非真的有特殊需求,我不太建议用OneFuzz。



- End -



看雪ID:MinGW

https://bbs.pediy.com/user-home-831588.htm

  *本文由看雪论坛 MinGW 原创,转载请注明来自看雪社区。



2.5折优惠票数量有限,先到先得哦!

推荐文章++++

* 简析"千层饼"式伪装方式的病毒

* 浅析一个海莲花样本

* Safe-Linking机制分析及绕过

* 萌新逆向学习笔记——CreateRemoteThread注入Shellcode

* 反汇编代码还原之特殊除法还原







公众号ID:ikanxue
官方微博:看雪安全
商务合作:wsc@kanxue.com



求分享

求点赞

求在看


“阅读原文”一起来充电吧!

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存