Trinity를 활용한 System call Fuzzing
취약점을 찾기 위해 하는 작업 중 큰 부분을 차지하는것이 바로 Fuzzing 입니다. Fuzzing 을 돕는 프로그램을 Fuzzer라고 부르는데, Fuzzer 중 Linux 시스템에서 Syscall에 대한 Fuzzing 작업을 수행할 수 있는 “Trinity” 라는 툴에 대한 이야기를 할까 합니다.
Trinity란?
Trinity는 Kernelslaker(Dave Jones)가 개발 및 github를 통해 배포되고 있는 Open source Fuzzing Framework 입니다. 리눅스 시스템에서 System call에 대해 반복적인 작업으로 에러를 유발하여 분석가들이 분석할 수 있는 포인트를 제공해 줄 수 있습니다.
Install Trinity
Trinity는 리눅스 시스템에서 쉽게 설치할 수 있습니다. 일단 apt 저장소를 통해 패키지로 배포되고 있고 github를 통해서도 배포되고 있어 다운로드하여 컴파일 후 사용이 가능합니다.
git clone 명령을 통해 github에서 trinity 다운로드
git clone https://github.com/kernelslacker/trinity.git
cd trinity
./configure.sh
make
make install
or
apt 패키지 관리자를 이용하여 설치
apt-get install trinity
설치 후 실행하여 옵션을 확인하면 아래와 같습니다.
trinity -h
--arch, -a: selects syscalls for the specified architecture (32 or 64). Both by default.
--children,-C: specify number of child processes
--debug,-D: enable debug
--exclude,-x: don't call a specific syscall
--group,-g: only run syscalls from a certain group (So far just 'vm').
--ioctls,-I: list all ioctls.
--kernel_taint, -T: controls which kernel taint flags should be considered, for more details refer to README file.
--list,-L: list all syscalls known on this architecture.
--logging,-l: (off=disable logging).
--monochrome,-m: don't output ANSI codes
--no_files,-n: Only pass sockets as fd's, not files
--proto,-P: specify specific network protocol for sockets.
--no_proto,-E: specify network protocols to be excluded from testing.
--quiet,-q: less output.
--random,-r#: pick N syscalls at random and just fuzz those
--syslog,-S: log important info to syslog. (useful if syslog is remote)
--verbose,-v: increase output verbosity.
--victims,-V: path to victim files.
-c#,@: target specific syscall (takes syscall name as parameter and optionally 32 or 64 as bit-width. Default:both).
-N#: do # syscalls then exit.
-p: pause after syscall.
-s#: use # as random seed.
System Call Fuzzing
trinity 를 통해서 간단하게 sploice syscall 에 대해 테스트가 가능합니다.
trinity -x splice
..snip..
child3:17903] [128] truncate(path="/proc/1242/task/1271/net/stat/ndisc_cache", length=133) = -1 (Permission denied)
[child3:17903] [129] lsetxattr(pathname="%d%s%d%s%s%d%s%s%s%d%s%d%d%s%d%s%s%d%d%d%d%d%d%s%s%d%s%d%s%s%d%d%d%d%s%s%d%d%s%d%s%d%d%s%s%d%d%d%s%s%d%s%s%d%d%s%d%d%s%d%s%s%d%s%d%s%s%d%s%d%d%d%d%d%d%s%s
..snip..
page_rand], len=0x709cf5e, flags=2) = -1 (Invalid argument)
[child1:17798] [1152] splice(fd_in=8, off_in=0, fd_out=386, off_out=0, len=4096, flags=13) ^C[child3:17800] <timed out>
[child3:17800] child exiting.
[child0:17797] <timed out>
[child0:17797] child exiting.
[child2:17799] <timed out>
[child2:17799] child exiting.
[child1:17798] <timed out>
[child1:17798] child exiting.
Bailing main loop. Exit reason: ctrl-c
^C
[watchdog] [16190] Watchdog exiting
[init]
Ran 5009 syscalls. Successes: 989 Failures: 3992
Report
Fuzzing 이 끝난 후 Trinity 는 실행된 디렉토리에 각종 파일과 log 를 남깁니다.
...
trinity-child0.log
trinity-child1.log
trinity-child2.log
trinity-child3.log
trinity.log
trinity.socketcache
여기서 log 파일 구성을 보자면
- trinity.log
- trinity-child0.log
- trinity-child1.log
- trinity-child2.log
- trinity-child3.log
위와 같은 형태로 볼 수 있습니다.
실행이 가능한 임의의 프로그램에 대해 Fuzzing 을 수행하고 결과를 봅시다.
trinity -V /bin -c execve
[init] Parsed 35 char devices, 24 block devices, 23 misc devices.
[init] Using pid_max = 32768
[init] Started watchdog process, PID is 21948
[main] Main thread is alive.
..snip..
[main] fd[42] = /bin/fgconsole (read-only)
[main] fd[43] = /bin/mountpoint (read-only)
[main] fd[44] = /bin/rmdir (read-only)
[main] fd[45] = /bin/ln (read-only)
[main] fd[46] = /bin/ntfsfix (read-only)
[main] fd[47] = /bin/ntfs-3g (read-only)
[main] fd[48] = /bin/chvt (read-only)
[main] fd[49] = /bin/su (read-only)
[main] fd[50] = /bin/mknod (read-only)
위 명령을 통해 /bin 하위의 프로그램에 대해 랜덤으로 테스트를 진행하고, 발견된 사항에 대해서는 trinity.log 와 각 child log 를 통해서 확인이 가능합니다.
cat trinity-child0.log
[child0:22840] [0] execve(name="/bin/setfacl", argv=0x171ec30, envp=0x171ed30) = -1 (Bad address)
[child0:22840] [1] execve(name=".//bin/pidof ", argv=0x171ed80, envp=0x171ede0) = -1 (No such file or directory)
[child0:22840] [2] execve(name="/bin/mv", argv=0x1439290, envp=0x171ee20) = -1 (Bad address)
[child0:22840] [3] execve(name="/bin/loadkeys", argv=0x171ef10, envp=0x171ef80) = -1 (Bad address)
[child0:22840] [4] execve(name="/bin/nisdomainname", argv=0x171efa0, envp=0x171efc0) = -1 (Bad address)
[child0:22840] [5] [32BIT] execve(name="/bin/systemctl", argv=0x171f000, envp=0x171f100)