OneShell

I fight for a brighter tomorrow

0%

[afl-training] date

[afl-training] date

date 的这个漏洞也是使用 AFL 发现的。通过查看 date 的 man 手册,可以看到 date 可以从命令行、日期相关系统调用、环境变量和一些文件中读取输入。此次 challenge 是如何对一个程序的环境变量进行 fuzz,个人还是比较重视这个 challenge,因为我的毕业设计是打算对 IoT 固件中的 CGI 程序进行模糊测试,而 CGI 程序大多是从环境变量以及标准输入 STDIN 中获取数据,然后处理完毕后通过标准输出 STDOUT 输出,做完这个 challenge 应该就可以开始进行毕业设计的总体实现了。

编译 date

首先对 date 的源码进行编译,和之前的 challenge 类似,需要使用 afl-clang-fast 以及开启 AFL_USE_ASAN=1 编译选项。

进入 challenge 中的 date 目录,下载源码,并编译时必要的依赖。

1
2
git submodule init && git submodule update
sudo apt install autopoint bison gperf autoconf texinfo

编译 date

1
2
3
4
5
cd coreutils
./bootstrap
patch --follow-symlinks -p1 < ../coreutils-8.29-gnulib-fflush.patch
CC=afl-clang-fast ./configure # 如果是root用户编译加上FORCE_UNSAFE_CONFIGURE=1选项
AFL_USE_ASAN=1 make

运行编译出来的带有 bug 的 date 程序

1
2
./src/date
TZ='Asia/Tokyo' ./src/date # 加上环境变量TZ

undifined

目前是已知 TZ 环境变量存在 bug,那么运行 poc,ASAN 报错发生堆溢出

1
TZ="aaa00000000000000000000aaaaaab00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" ./src/date --date "2017-03-14 15:00 UTC"

undifined

harness

那么问题就是如何对环境变量进行 fuzz。在每一个 challenge 中都有一个 HINT.md 文档,作为对当前挑战的提示。对于如何 fuzz 环境变量,HINT.md 提出了三个方案:

  1. 在源码中找到所有读取环境变量 TZ 的地方,然后替换为从 STDIN 中读取
  2. 修改 main 函数,在运行之初就设置 TZ 环境变量从 STDIN 中读取
  3. 使用 LD_PRELOAD 环境变量对 getenv 函数进行劫持,这样就可以通过标准输入传递到环境变量的值

在 ANSWERS.md 中,推荐使用的是第二个方案,因为第一个方案需要对代码中每一个读取环境变量的地方进行修改,很难确定每个地方都替换了为了 STDIN;第三个方案虽然重用性比较高,但是对于入门而言,需要花费的功夫还是比较多的。我在毕设中应该会使用到第三种方案,因为这样可以最大限度不对 CGI 的程序做出修改。

使用第二个方案的一个原因也是,date.c 代码中,只有一个使用到了 getenv(“TZ”),那么在 main 函数运行之初,就提前设定好 TZ 环境变量从 STDIN 中读取,从而实现 fuzz 环境变量的值从标准输入中读取。在 main 函数中增加如下:

1
2
3
static char val[1024 * 16];
read(0, val, sizeof(val) - 1);
setenv("TZ", val, 1);

undifined

然后重新编译:

1
2
make clean
AFL_USE_ASAN=1 make -j 4

然后重新运行程序,可以看到每次 date 运行前都要从标准输入先获取 TZ 环境变量,修改成功

undifined

开始 fuzz

设置初始种子,可以就用上面的 Europe/London 作为初始种子:

1
2
mkdir input 
echo "Europe/London" >> ./input/london

undifined

fuzz 前需要注意,在教程中使用的是固定日期,并且如果使用 ASAN,需要设置内存限定:

1
afl-fuzz -m none -i ./input -o output -- ./src/date --date "2017-03-14 15:00 UTC"

undifined

运行了 1 个小时,玩了一会儿游戏,一共挖出 30k 个 crash,但是只有 3 个 unique crashes。

将 crash 传入到 date 运行,ASAN 报错如下:

undifined

的确是发生了溢出

参考链接