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)