基于AFL对Linux内核隐约测试的历程详述 | 申博官网
登录
  • 欢迎进入申博官网!
  • 如果您觉得申博官网对你有帮助,那么赶紧使用Ctrl+D 收藏申博官网并分享出去吧
  • 这里是申博官方网!
  • 申博官网是菲律宾sunbet官网品牌平台!
  • 申博开户专业品牌平台!

基于AFL对Linux内核隐约测试的历程详述

申博_安全防护 申博 53次浏览 已收录 0个评论

coverage-guided fuzzing是一种壮大的隐约测试手艺,由于代码掩盖率(Code Coverage)是反应测试用例对被测软件掩盖顺序的重要目的,自动化顺序将半随机输入注入到测试顺序中,如许做的目的是找到触发破绽的输入,隐约测试在查找C或c++顺序中的内存破坏破绽时迥殊有用。一般情况下,发起挑选一个异常熟习但很少触及的、大批剖析的库。根据经验看,libjpeg、libpng和libyaml都是圆满的进击目的。不过如今很难找到一个好的目的,不过从别的一个角度来讲,这也申明软件愈来愈平安了!不过我照样决议尝试一下Linux内核的netlink机制。

Netlink是linux供应的用于内核和用户态历程之间的通讯体式格局。然则注重虽然Netlink重要用于用户空间和内核空间的通讯,然则也能用于用户空间的两个历程通讯。只是历程间通讯有其他许多体式格局,平常没必要Netlink。除非须要用到Netlink的播送特征时。

从道理上来讲,Netlink是供“ ss”,“ ip”,“ netstat”之类的东西运用的内部Linux东西。它用于低层网络使命——设置网络接口、IP地点、路由表等。所以,这是一个很好的渗入测试目的,由于它是内核中一个不为人知的部份,而且自动编写有用的音讯相对轻易。最重要的是,在这个历程当中我们可以学到许多关于Linux内部的东西。不过,netlink中的破绽不会对平安形成影响,由于netlink套接字一般须要特权接见。

在这篇文章中,我们将运转AFL代码掩盖率东西,在一个定制的Linux内核上驱动我们的netlink shim顺序,一切这些都在KVM假造化中运转。

一般,在运用AFL时,我们须要检测目的代码,以便以AFL兼容的体式格局报告代码掩盖率。然则我们想要隐约内核!我们不能只是用“afl-gcc(AFL的编译器)”从新编译它。相反,我们将运用一个技能。我们将预备一个二进制文件,它会诳骗AFL,让它认为是用它的东西编译的。这个二进制文件将报告从内核中提取的代码掩盖率。

内核代码的代码掩盖率

内核至少有两个内置的代码掩盖率机制- GCOV和KCOV:

1. 在Linux内核中运用gcov;

2. KCOV:隐约的代码掩盖率。

KCOV在设想时斟酌到了隐约性测试,因而我们将运用它。

Kcov是一个代码掩盖测试东西,最初基于Bcov,它可在FreeBSD、Linux、OSX体系中运用,支撑的言语包括编译言语(compiled languages)、Python和Bash。与Bcov一样,Kcov对编译的顺序运用DWARF调试信息,以便无需特别编译器开关即可网络掩盖信息。

KCOV运用起来异常简朴,我们必需运用准确的设置来编译Linux内核。起首,启用KCOV内核设置选项:

cd linux
./scripts/config \
    -e KCOV \
    -d KCOV_INSTRUMENT_ALL

KCOV可以纪录全部内核的代码掩盖率,可以运用KCOV_INSTRUMENT_ALL选项举行设置。然则,如许做也有瑕玷,会减慢我们不想剖析的内核部份,而且会在我们的丈量中引入噪音下降丈量的准确性。起首,让我们禁用KCOV_INSTRUMENT_ALL并有挑选地在我们现实要剖析的代码上启用KCOV。在这篇文章中,我们只关注netlink机制,因而我们会在全部“ net”目次树上启用KCOV:

find net -name Makefile | xargs -L1 -I {} bash -c 'echo "KCOV_INSTRUMENT := y" >> {}'

在抱负的情况下,我们只对我们真正感兴趣的几个文件启用KCOV。然则netlink处置惩罚普及全部网络客栈代码,因而我们在这篇文章中没有时候对其举行微调。

运用KCOV后,就有必要增添“内核黑客”选项,以增添报告内存破坏破绽的可能性。关于Syzkaller发起的选项列表,请参阅自述,个中最重要的是KASAN。

有了这个设置,我们就可以编译启用KCOV和KASAN的内核。哦,另有一件事,我们将在kvm中运转内核。我们将运用“virtme”,所以我们须要一些切换:

./scripts/config \
    -e VIRTIO -e VIRTIO_PCI -e NET_9P -e NET_9P_VIRTIO -e 9P_FS \
    -e VIRTIO_NET -e VIRTIO_CONSOLE  -e DEVTMPFS ...

怎样运用KCOV

KCOV异常轻易运用,起首,请注重,代码掩盖率纪录在每一个历程的数据结构中。这意味着你必需在用户空间历程中启用和禁用KCOV,而且不可能纪录诸如中断处置惩罚之类的非使命内容的掩盖局限,这完整符合我们的须要。

KCOV将数据报告到一个环形缓冲区,设置异常简朴,细致请参阅此代码,然后,你可以运用简朴的ioctl启用和禁用它。

ioctl(kcov_fd, KCOV_ENABLE, KCOV_TRACE_PC);
/* profiled code */
ioctl(kcov_fd, KCOV_DISABLE, 0);

在这个序列以后,轮回缓冲区包括一切启用kcov的内核代码的基础块的%rip值的列表。要读取缓冲区,只需运转以下代码即可:

n = __atomic_load_n(&kcov_ring[0], __ATOMIC_RELAXED);
for (i = 0; i < n; i++) {
    printf("0x%lx\n", kcov_ring[i + 1]);
}

运用addr2line如许的东西,可以将%rip剖析为特定的代码行。虽然我们不须要它,原始的%rip值对我们来讲已足够了。

将KCOV注入AFL

下一步是进修怎样诳骗AFL,请记着,AFL须要一个特地设想的可执行文件,然则我们愿望供应内核代码掩盖率。起首,我们须要相识AFL是怎样事情的。

AFL设置一个64K的8位数字数组,这个内存地区称为“shared_mem”或“trace_bits”,与跟踪顺序同享。可以将数组中的每一个字节看做插装代码中特定(branch_src、branch_dst)对的掷中计数器。

须要注重的是,AFL更喜好运用随机的分支标签,而不是重用%rip值来标识基础块。这是为了增添熵,我们愿望数组中的掷中计数器是均匀分布的。AFL运用的算法为:

cur_location = <COMPILE_TIME_RANDOM>;
shared_mem[cur_location ^ prev_location]++; 
prev_location = cur_location >> 1;

在运用KCOV的情况下,我们没有为每一个分支供应编译时随机值。相反,我们将运用哈希函数从KCOV纪录的%rip生成一致的16位数字。这是将KCOV报告送入AFL“shared_mem”数组的要领:

n = __atomic_load_n(&kcov_ring[0], __ATOMIC_RELAXED);
uint16_t prev_location = 0;
for (i = 0; i < n; i++) {
        uint16_t cur_location = hash_function(kcov_ring[i + 1]);
        shared_mem[cur_location ^ prev_location]++;
        prev_location = cur_location >> 1;
}

从AFL读取测试数据

卡巴斯基实验室:2019Q3钓鱼及垃圾邮件报告

一、本季度重点关注 1.1 Amazon Prime 在第三季度,我们发现了许多与Amazon Prime相关的欺诈邮件。其中,大部分网络钓鱼邮件都包含一个伪造的Amazon登录页面链接,声称提供更低的价格、提供购买商品的奖励或通知会员相关的信息等。9月是网络购物的旺季,在这样的背景下,我们看到钓鱼邮件呈现出这样的趋势,也是非常正常的。 除此之外,诈骗者还使用了另外一种欺诈手段,他们发送一封电子邮件告知受害者说其取消Amazon Prime的请求已经通过,但如果用户改变主意,可以拨打某个号码。不知情的用户在收到

末了,我们须要现实编写测试代码来进击内核netlink接口!起首,我们须要从AFL读取输入数据。默许情况下,AFL将测试用例发送到stdin:

/* read AFL test data */
char buf[512*1024];
int buf_len = read(0, buf, sizeof(buf));

Netlink的隐约测试

然后我们须要将这个缓冲区发送到一个netlink套接字。然则我们对netlink的事情道理一窍不通!好的,让我们运用前5个字节的输入作为netlink协媾和组id字段。这将许可AFL盘算并猜想这些字段的准确值。代码测试netlink(简化):

struct sockaddr_nl sa = {
        .nl_family = AF_NETLINK,
        .nl_groups = (buf[1] <<24) | (buf[2]<<16) | (buf[3]<<8) | buf[4],
};

bind(netlink_fd, (struct sockaddr *) &sa, sizeof(sa));

struct iovec iov = { &buf[5], buf_len - 5 };
struct sockaddr_nl sax = {
      .nl_family = AF_NETLINK,
};

struct msghdr msg = { &sax, sizeof(sax), &iov, 1, NULL, 0, 0 };
r = sendmsg(netlink_fd, &msg, 0);
if (r != -1) {
      /* sendmsg succeeded! great I guess... */
}

基础上就是如许!为了进步速率,我们将其包装在一个简短的轮回中,该轮回模拟AFL的“fork服务器”逻辑。我将在此处跳过申明,有关细致信息,请拜见我们的代码。我们的AFL-to-KCOV shim的效果代码以下:

forksrv_welcome();
while(1) {
    forksrv_cycle();
    test_data = afl_read_input();
    kcov_enable();
    /* netlink magic */
    kcov_disable();
    /* fill in shared_map with tuples recorded by kcov */
    if (new_crash_in_dmesg) {
         forksrv_status(1);
    } else {
         forksrv_status(0);
    }
}

点此,拜见完整的源代码。

怎样运转自定义内核

如今来讲说,怎样现实运转我们构建的自定义内核,现在共有三个选项:

“当地”选项:你可以完整在你的服务器上启动构建的内核,并在当地对其举行隐约处置惩罚。这是最快的手艺,然则问题许多。假如隐约测试成功地找到了一个破绽,你的装备很可能会崩溃,从而丧失测试数据。

“uml” :我们可以将内核设置为以用户形式Linux运转,运转UML内核不须要任何特权。内核只运转一个用户空间历程。UML异常酷,但遗憾的是,它不支撑KASAN,因而发明内存破坏破绽的时机减少了。末了,UML是一个异常奇异的特别环境,在UML中发明的破绽可能与现实环境无关。风趣的是,Android network_tests框架运用了UML。

“kvm”:我们可以运用kvm在假造环境中运转自定义内核。

在KVM环境中运转自定义内核的最简朴要领之一是运用“virtme”剧本。有了它们,我们就没必要竖立专用的磁盘映像或分区,只需同享主机文件体系。以下是我们运转代码的体式格局:

virtme-run \
    --kimg bzImage \
    --rw --pwd --memory 512M \
    --script-sh "<what to run inside kvm>"

不过症结的一步好像忘了,就是为我们的隐约器预备输入语料库数据!

竖立输入语料库

每一个隐约测试都采用了一个精心设想的测试用例作为输入,以指导第一个突变。测试用例应该是简短的,并掩盖尽量多的代码。遗憾的是,我对netlink一窍不通。

因而,我就让AFL“找出”哪些输入是有意义的,以下就是我们的输入语料库:

mkdir inp
echo "hello world" > inp/01.txt

编译和运转全部顺序的历程,请拜见github上的README.md ,简朴来讲,以下所示:

virtme-run \
    --kimg bzImage \
    --rw --pwd --memory 512M \
    --script-sh "./afl-fuzz -i inp -o out -- fuzznetlink"

运转此敕令,你将看到熟习的AFL状况屏幕:

基于AFL对Linux内核隐约测试的历程详述

如今,你就有了一个自定义的强化内核,该内核会运转一个以代码掩盖率为测试标识的隐约测试历程。

如许的勤奋值得吗?纵然有了这个基础的隐约测试器,也没有输入语料库。不在两三天后,该隐约器照样找到了一条风趣的代码途径:NEIGH:BUG,双计时器加法,状况为8。运用更专业的隐约器,可以举行一些改良“稳固性”的事情目的和像样的输入语料库,我们可以期待更好的测试效果。

假如你想相识更多有关netlink套接字现实功用的信息,请参阅此文。

不过在这篇文章中,我们没有提到:

1. 细致的AFL shared_memory设置;

2. AFL的耐久形式是怎样完成的;

3. 怎样竖立一个网络称号空间来断绝新鲜的netlink敕令的影响,并进步AFL的“稳固性”;

4. 怎样读取dmesg (/dev/kmsg) 来查找内核崩溃;

5. 在KVM以外运转AFL的主意,为了速率和稳固性,现在的测试在发明崩溃后还不稳固。

本文翻译自:https://blog.cloudflare.com/a-gentle-introduction-to-linux-kernel-fuzzing/


申博|网络安全巴士站声明:该文看法仅代表作者自己,与本平台无关。版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权
转载请注明基于AFL对Linux内核隐约测试的历程详述
喜欢 (0)
[]
分享 (0)
发表我的评论
取消评论
表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址