Autoit辅助winafl对GUI程序fuzz
2019-10-26 22:48:49 Author: forum.90sec.com(查看原文) 阅读量:240 收藏

前言

对图形界面程序的模糊测试无外乎以下这三种方法(以下为仅使用afl/winafl的):

1.针对有源码的可以进行patch使其跳过界面显示阶段直接结束。(可参考:Fuzzing Linux GUI/GTK Programs With American Fuzzy Lop )

2.针对无源码的可以写harness。(可参考:50 CVEs in 50 Days: Fuzzing Adobe Reader)

3.通过监控被fuzz的GUI程序在一定时间内将其kill掉。

本文属于第三种方法,但通过Autoit进行辅助可以拓展出更加丰富的功能而不局限于仅仅将被fuzz程序关闭。

Autoit简介

AutoIt是一个用于Windows的自动化语言。它兼容于Windows 95,98,ME,NT4,2000,XP,2003,Vista以及Windows 7。AutoIt自动化脚本可以编译成压缩、单一的可执行文件,这样的文件可以运行在没有安装AutoIt解释器的计算机上。

部分功能:调用Win32 DLL中的函数、模拟鼠标移动、操作窗口和进程、自动发送用户输入和键击到应用程序以及程序中的单个控件、运行控制台应用程序和访问标准流、包含文件在编译文件中以便在运行时提取、GUI接口,创建消息和输入框、支持COM。

最初的思路

一开始的思路是使用Autoit的Run或者ShellExecute函数执行被fuzz函数通过发送快捷键或者结束进程的方式将其关闭,将脚本打包成exe,这样用winafl去fuzz被打包过的exe。但实际测试过程中发现winafl只会记录打包的exe的代码覆盖率。被fuzz程序实际上是以子进程的形式去运行。翻看winafl的issue发现作者的这样一段话

DynamoRIO does indeed instrument child processes by default, but this is disabled in WinAFL here: https://github.com/ivanfratric/winafl/blob/master/afl-fuzz.c#L2089
(note the -no_follow_children flag).

The main reason is communication of target process and afl-fuzz: Target process needs to connect to a pipe and shared memory exposed by afl-fuzz. IIRC this led to problems in the past when multiple processes attempted to connect to the same pipe/shared memory and I put -no_follow_children to fix that.

A possible alternative could be to only connect to pipe/shm once the target function is reached (and hope it's only going to get reached in 1 process). Not sure if this would result in some other problems, difficult to say off the top of my head.

由于winafl使用管道与目标进程进行通信,多个进程同时连接同一管道会出现问题。

最后实现的方法

使用Autoit的 WinWait 函数监控被fuzz程序的主窗口类,捕获主窗口类后可以对其发送快捷键或鼠标点击事件,之后再对其关闭。实现脚本如下:

#include <Constants.au3>
While True
   Local $hWnd = WinWait("[CLASS:Notepad]")
   If WinActive($hWnd) Then
	  Sleep(1000)
	  Send("{ESC}")
	  WinClose($hWnd)
   EndIf
WEnd

但这个脚本存在一个问题,若其他程序主窗口类名和其相同也会被捕获从而造成干扰,在查阅autoit文档后改进如下:

#cs ----------------------------------------------------------------------------

 AutoIt Version: 3.3.14.5
 Author:         1vanChen
 Name:           fuzzHelper

 Script Function:
	Get target program window class
	Open target program and close it automatically
 Usage:
    Find target program window class (make sure the program is running): 	fuzzHelper.exe programName.exe
	Open target program and close it automatically:							fuzzHelper.exe ProgramName.exe WindowClsName

#ce ----------------------------------------------------------------------------

#include <Constants.au3>
#include <MsgBoxConstants.au3>
#include <WindowsConstants.au3>
#include <WinAPI.au3>

#pragma compile(Console, True)

If $CmdLine[0]==2 Then
   While True
	  Local $hWnd = _WinGetHandleByPnmAndCls($CmdLine[1],$CmdLine[2])
	  If WinActive($hWnd) Then
		 Sleep(500)
		 ;此处只是发送"关闭"这个快捷键,
		 ;还可以根据需要添加其他要发送的快捷键
		 Send("{ESC}")
		 WinClose($hWnd)
	  EndIf
   WEnd
ElseIf $CmdLine[0]==1 Then
   Local $pid = ProcessExists($CmdLine[1])
   If $pid Then
       _WinGetWindowClsByPid($pid)
   Else
      MsgBox($MB_SYSTEMMODAL, "", "程序未找到")
   EndIf

EndIf

; 根据pid打印该程序所有窗口类
Func _WinGetWindowClsByPid ($pid )
   Local $winArr = _WinAPI_EnumWindowsTop()
   For $i=1 To $winArr[0][0]
	  If $pid=WinGetProcess($winArr[$i][0])Then
		 ConsoleWrite($winArr[$i][1] & @CRLF)
	  EndIf
   Next

EndFunc

; 根据pname和class获取窗口句柄,找不到则返回0
Func _WinGetHandleByPnmAndCls($pname, $class)
   Local $pid = ProcessExists($pname)
   If $pid Then
      return _WinGetHandleByPidAndCls($pid, $class)
   Else
      Return 0
   EndIf
EndFunc

; 根据pid和class获取窗口句柄,找不到则返回0
Func _WinGetHandleByPidAndCls($pid, $class)
   Local $winArr = _WinAPI_EnumWindowsTop()
   For $i=1 To $winArr[0][0]
      If $pid=WinGetProcess($winArr[$i][0]) And $winArr[$i][1]=$class Then
         return $winArr[$i][0]
      EndIf
   Next
   Return 0
EndFunc

该脚本可以直接运行也可以打包成exe,有两个功能:

1.在打开被fuzz程序的形况下运行:fuzzHelper.exe programName.exe列出被fuzz程序窗口类。

2.在启动winafl前运行: fuzzHelper.exe ProgramName.exe WindowClsName捕获被fuzz程序窗口类并执行相应操作。

总结

这种方式最大的优势在于不需要对程序进行任何前期逆向工作,无脑fuzz。缺点在于由于需要加载图形界面或者执行相应操作,fuzz过程会变得异常缓慢,我在测试的时候一个test case大约需要2秒。目前可以想到的提升速度的方法有:多核fuzz、虚拟机cpu加速、移植论文中改进的变异算法...但终究和写harness这种在速度上不是一个数量级的。

在fuzz中减少人工投入还是有很长的路要走...

参考链接

https://www.autoitscript.com/autoit3/docs/

https://autoit8.com/Doc/

https://blog.csdn.net/moonshine_1988/article/details/48006043


文章来源: https://forum.90sec.com/t/topic/560/1
如有侵权请联系:admin#unsafe.sh