android cpp获取当前应用包名 c获取当前程序的路径_ubuntu

AFL基于代码插桩来生成测试用例,这样生成的样本就比较的好,而且针对 linux 做了许多性能优化使得速度也非常快。

AFL(American Fuzzy Lop)是由安全研究员Michał Zalewski开发的一款基于覆盖引导(Coverage-guided)的模糊测试工具,它通过记录输入样本的代码覆盖率,从而调整输入样本以提高覆盖率,增加发现漏洞的概率。其工作流程大致如下:

①从源码编译程序时进行插桩,以记录代码覆盖率(Code Coverage);

②选择一些输入文件,作为初始测试集加入输入队列(queue);

③将队列中的文件按一定的策略进行“突变”;

④如果经过变异文件更新了覆盖范围,则将其保留添加到队列中;

⑤上述过程会一直循环进行,期间触发了crash的文件会被记录下来。

目录
AFL状态窗口代表意义
Fuzz网络程序
 构建Modbus TCP Server
 利用 preeny库
 编译 modbus server
 获取样本数据
 使用获取的样本再次fuzz
 总结
AFL Persistent Mode
总结

使用 afl 的常规步骤

  • 如果有源码,用 afl-gcc 或者 afl-clang-fast 编译源码,afl 会利用这些工具在编译期间对代码进行插桩,为后面的测试提供代码覆盖率,测试样本的变异则会基于代码覆盖率进行。无源码的话可以使用 qemu 进行插桩
  • 搜集好 初始样本集,如果必要的话使用 afl-cmin 把样本集进行精简。
  • 然后用 afl-fuzz 开始 fuzz
afl-cmin -i in/ -o out/ /path/to/program

in/ 是初始样本集目录

out/ 是 精简后的样本集存放的目录

afl-fuzz -i in/ -o out/ /path/to/program

in/ 是初始样本集目录

out/ 用于保存 fuzz 过程中的一些文件

afl-fuzz 默认是往 stdin 中写测试数据,它同时支持从文件喂 测试数据给目标程序,只要把设置文件的参数修改为 @@fuzz 过程中 afl-fuzz 会把它替换成 文件名。

比如 ./a 这个程序的 第二个参数是要处理的文件的名称, 那么相应的 afl-fuzz 的命令就是

afl-fuzz -i in/ -o out/ ./a arg1 @@

AFL状态窗口代表意义

android cpp获取当前应用包名 c获取当前程序的路径_ubuntu_02

① Process timing:Fuzzer运行时长、以及距离最近发现的路径、崩溃和挂起经过了多长时间。

② Overall results:Fuzzer当前状态的概述。

③ Cycle progress:我们输入队列的距离。

④ Map coverage:目标二进制文件中的插桩代码所观察到覆盖范围的细节。

⑤ Stage progress:Fuzzer现在正在执行的文件变异策略、执行次数和执行速度。

⑥ Findings in depth:有关我们找到的执行路径,异常和挂起数量的信息。

⑦ Fuzzing strategy yields:关于突变策略产生的最新行为和结果的详细信息。

⑧ Path geometry:有关Fuzzer找到的执行路径的信息。

⑨ CPU load:CPU利用率

因为afl-fuzz永远不会停止,所以何时停止测试很多时候就是依靠afl-fuzz提供的状态来决定的。

Fuzz 网络程序

这里以 libmodbus 这个库为目标进行 fuzz 。

构建 Modbus TCP Server

库的官网地址如下

http://libmodbus.org/documentation/

这是一个用于 modbus 通讯的库, 通过这个库可以很方便的实现 modbus 服务器 和 客户端。这里以 modbus tcp 的服务端作为 fuzz 的对象。

首先在官网下载好源码

http://libmodbus.org/releases/libmodbus-3.1.4.tar.gz

源码目录下的 tests 目录里面有一些示例程序, 其中 tests/bandwidth-server-one.c 就实现了一个 modbus tcp server

android cpp获取当前应用包名 c获取当前程序的路径_ubuntu_03

精简得到

#include 
#include 
#include 
#include 
#include 

int main(int argc, char *argv[]){
  int s = -1;
  modbus_t *ctx = NULL;
  modbus_mapping_t *mb_mapping = NULL;
  int rc;
  int use_backend;
  ctx = modbus_new_tcp("127.0.0.1", 1502);
  s = modbus_tcp_listen(ctx, 1);
  modbus_tcp_accept(ctx, &s);
  mb_mapping = modbus_mapping_new(MODBUS_MAX_READ_BITS, 0,
                                  MODBUS_MAX_READ_REGISTERS, 0);
  if (mb_mapping == NULL) {
      modbus_free(ctx);
      return -1;
  }
  uint8_t query[MODBUS_TCP_MAX_ADU_LENGTH];
  memset(query, 0, MODBUS_TCP_MAX_ADU_LENGTH);
  rc = modbus_receive(ctx, query); // 获取客户端的请求数据
  if (rc > 0) {
      modbus_reply(ctx, query, rc, mb_mapping); // 处理并响应之
  }
  modbus_mapping_free(mb_mapping);
  if (s != -1) {
      close(s);
  }
  /* For RTU, skipped by TCP (no TCP connect) */
  modbus_close(ctx);
  modbus_free(ctx);
  return 0;
}

代码逻辑简单理一下

  • modbus_new_tcp 初始化 modbus_t 结构体
  • modbus_tcp_acceptmodbus_tcp_listen 就是调用 socket 监听端口
  • modbus_mapping_new 初始化一个缓冲区,用于模拟寄存器信息
  • 然后 modbus_receive 接收客户端的请求和输入
  • 获取输入后就 通过 modbus_reply 处理 请求,以及构造响应数据包, 同时返回响应
  • 然后就是释放掉分配的一些内存

利用 preeny 库辅助

afl 默认只能 fuzz 通过 stdin 和 文件 获取输入的程序, 要 fuzz 网络相关的程序,需要使用一个库

https://github.com/zardus/preeny

这个库利用 LD_PRELOAD 机制,重写了 很多库函数, 其中 desock.c 这个文件负责重写 socket 相关的函数,其实现的功能就是当应用从 socket 获取输入时,其实是从 stdin 获取输入。

首先下载编译下

git clone https://github.com/zardus/preeny.git
cd preeny/
sudo apt-get install libseccomp-dev
make

然后会在 x86_64-linux-gnu 目录下生成编译好的 lib

android cpp获取当前应用包名 c获取当前程序的路径_android cpp获取当前应用包名_04

写个测试脚本,测试一下 (根据 tests 目录里面的 sock.c 改造)

#include 
#include 
#include 
#include 

int main(){
  int s = socket(AF_INET, SOCK_STREAM, 0);
  char buf[1024]={0};
  char send_msg[] = "hello, send by send() :\n";
  send(s, send_msg, strlen(send_msg), 0);
  recv(s, buf, 1024, 0);
  printf("recv from recv() : %s\n", buf);
}
编译运行

编译运行

gcc sock_test.c -o sock_test
LD_PRELOAD="/home/giantbranch/afl-2.52b/preeny/x86_64-linux-gnu/desock.so" ./sock_test

╭─birdpwn@ubuntu ~/vuln
╰─$ LD_PRELOAD="/home/giantbranch/afl-2.52b/preeny/x86_64-linux-gnu/desock.so" ./sock_test
hello, send by send() :
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
recv from recv() : AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

socket 调用 send , 成功往 stdout 输出了 字符串。

stdin 输入 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA ,可以看到成功写入 buf 里面

所以我们就可以利用 preenyfuzz modbus tcp server

编译 modbus server

首先使用 afl-gcc 编译 libmodbus ,对 libmodbus 插桩。

cd libmodbus-master/
CC=afl-gcc CXX=afl-g++ ./configure --enable-static
make -j4

--enable-static:用于生成静态库

android cpp获取当前应用包名 c获取当前程序的路径_ubuntu_05

然后在 src/.libs 下就可以看到编译好的库

─birdpwn@ubuntu ~/vuln/libmodbus-3.1.4
╰─$ ls src/.libs/
libmodbus.a libmodbus.la libmodbus.lai libmodbus.so libmodbus.so.5 libmodbus.so.5.1.0 modbus-data.o modbus.o modbus-rtu.o modbus-tcp.o

libmodbus.a 就是编译好的静态库

然后使用我们修改过的 bandwidth-server-one.c 编译 和 fuzz

cd tests/
vim bandwidth-server-one.c
afl-gcc bandwidth-server-one.c -I../src ../src/.libs/libmodbus.a -o server
mkdir in
echo 11111 > in/1
LD_PRELOAD="/home/giantbranch/afl-2.52b/preeny/x86_64-linux-gnu/desock.so" afl-fuzz -i in -o out ./server

这里 直接用 echo 生成了一个 测试文件,如果直接用这个去测的话会发现速度非常的慢。

─birdpwn@ubuntu ~/vuln/libmodbus-3.1.4/tests
╰─$ afl-gcc bandwidth-server-one.c -I../src ../src/.libs/libmodbus.a -o server
afl-cc 2.52b by 
afl-as 2.52b by 
[+] Instrumented 24 locations (64-bit, non-hardened mode, ratio 100%).
╭─birdpwn@ubuntu ~/vuln/libmodbus-3.1.4/tests
╰─$ mkdir in
╭─birdpwn@ubuntu ~/vuln/libmodbus-3.1.4/tests
╰─$ echo 11111 > in/1
╭─birdpwn@ubuntu ~/vuln/libmodbus-3.1.4/tests
╰─$ LD_PRELOAD="/home/giantbranch/afl-2.52b/preeny/x86_64-linux-gnu/desock.so" afl-fuzz -i in -o out ./server
afl-fuzz 2.52b by 
[+] You have 1 CPU core and 7 runnable tasks (utilization: 700%).
[*] Checking core_pattern...
[*] Setting up output directories...
[*] Scanning 'in'...
[+] No auto-generated dictionary tokens to reuse.
[*] Creating hard links for all input files...
[*] Validating target binary...
[*] Attempting dry run with 'id:000000,orig:1'...
[*] Spinning up the fork server...
[+] All right - fork server is up.
  len = 6, map size = 108, exec speed = 501074 us
[+] All test cases processed.
[!] WARNING: The target binary is pretty slow! See /usr/local/share/doc/afl/perf_tips.txt.
[+] Here are some useful stats:
  Test case count : 1 favored, 0 variable, 1 total
      Bitmap range : 108 to 108 bits (average: 108.00 bits)
      Exec timing : 501k to 501k us (average: 501k us)
[*] No -t option specified, so I'll use exec timeout of 1000 ms.
[+] All set and ready to roll!

这里 直接用 echo 生成了一个 测试文件,如果直接用这个去测的话会发现速度非常的慢。

android cpp获取当前应用包名 c获取当前程序的路径_ubuntu_06

获取样本数据

一组好的样本数据对 fuzzer 的影响还是非常大的,一般我们可以去网上搜索样本,比如图片,视频文件等。对于我们这次的目标 libmodbus , 它自带了很多的测试程序,我们可以利用这些测试程序测试,然后用 tcpdump 抓包, 最后在把其中的请求数据保存下来,作为测试样本集。

首先使用 random-test-server 在 127.0.0.1:1502 起一个 modbus tcp 服务

╭─birdpwn@ubuntu ~/vuln/libmodbus-3.1.4/tests
╰─$ ./random-test-server

然后开启 tcpdump , 保存数据包到 ~/modbus.pcap

─birdpwn@ubuntu ~
╰─$sudo tcpdump -i lo -w ~/modbus.pcap
[sudo] password for birdpwn:
tcpdump: listening on lo, link-type EN10MB (Ethernet), capture size 262144 bytes

最后使用 random-test-client 随机发送各种 modbus 请求到 127.0.0.1:1502

╭─birdpwn@ubuntu ~/vuln/libmodbus-3.1.4/tests
╰─$ ./random-test-client
Connecting to 127.0.0.1:1502
[00][01][00][00][00][06][FF][05][00][00][FF][00]
Waiting for a confirmation...
<00><01><00><00><00><06><FF><05><00><00><FF><00>
[00][02][00][00][00][06][FF][01][00][00][00][01]
Waiting for a confirmation...

然后写一个脚本把 ~/modbus.pcap 中 由客户端发送的数据包 (也就是目的地为 127.0.0.1:1502的数据包) 的内容提取出来,每个数据包内容保存为一个单独的文件。

sudo apt-get install python-scapy

from scapy.all import *
save_path = "/tmp/seeds/"
uuid = 0

if not os.path.exists(save_path):
  os.system("mkdir %s" %(save_path))

def save_to_file(data):
  global uuid
  with open("{}{}".format(save_path, uuid), "w") as fp:
      fp.write(str(data))
  uuid += 1
  print "write test file: {}".format(uuid)

modbus_session = ''
pg = rdpcap("modbus.pcap")
session = pg.sessions()
for k in session.keys():
  if k.endswith("127.0.0.1:1502"):
      modbus_session = session[k]

for s in modbus_session:
  payload = s[TCP].payload
  if len(payload) > 4:
      save_to_file(payload)

print "Total: %d tests" %(uuid)

生成测试用例:

android cpp获取当前应用包名 c获取当前程序的路径_c获取当前程序的路径_07

─birdpwn@ubuntu /tmp/seeds
╰─$ ls
0   120 143 166 189 210 233 256 279 300 323 346 369 391 413 436 459 481 503 526 549 571 594 616 639 661 684 706 729 751 774 797 819 841 864 887 909 931 954 977
1   121 144 167 19   211 234 257 28   301 324 347 37   392 414 437 46   482 504 527 55   572 595 617 64   662 685 707 73   752 775 798 82   842 865 888 91   932 955 978
10   122 145 168 190 212 235 258 280 302 325 348 370 393 415 438  460 483 505 528 550 573 596 618 640 663 686 708 730 753 776 799 820 843 866 889 910 933 956 979
100 123 146 169 191 213 236 259 281 303 326 349 371 394 416 439 461 484 506 529 551 574 597 619 641 664 687 709 731 754 777 8   821 844 867 89   911 934 957 98
101 124 147 17   192 214 237 26   282 304 327 35   372 395 417 44   462 485 507 53   552 575 598 62   642 665 688 71   732 755 778 80   822 845 868 890 912 935 958 980
102 125 148 170 193 215 238 260 283 305 328 350 373 396 418 440 463 486 508 530 553 576 599 620 643 666 689 710 733 756 779 800 823 846 869 891 913 936 959 981
103 126 149 171 194 216 239 261 284 306 329 351 374 397 419 441 464 487 509 531 554 577 6   621 644 667 69   711 734 757 78   801 824 847 87   892 914 937 96   982
104 127 15   172 195 217 24   262 285 307 33   352 375 398 42   442 465 488 51   532 555 578 60   622 645 668 690 712 735 758 780 802 825 848 870 893 915 938 960 983
105 128 150 173 196 218 240 263 286 308 330 353 376 399 420 443 466 489 510 533 556 579 600 623 646 669 691 713 736 759 781 803 826 849 871 894 916 939 961 984
106 129 151 174 197 219 241 264 287 309 331 354 377 4   421 444 467 49   511 534 557 58   601 624 647 67   692 714 737 76   782 804 827 85   872 895 917 94   962 985
107 13   152 175 198 22   242 265 288 31   332 355 378 40   422 445 468 490 512 535 558 580 602 625 648 670 693 715 738 760 783 805 828 850 873 896 918 940 963 986
108 130 153 176 199 220 243 266 289 310 333 356 379 400 423 446 469 491 513 536 559 581 603 626 649 671 694 716 739 761 784 806 829 851 874 897 919 941 964 987
109 131 154 177 2   221 244 267 29   311 334 357 38   401 424 447 47   492 514 537 56   582 604 627 65   672 695 717 74   762 785 807 83   852 875 898 92   942 965 988
11   132 155 178 20   222 245 268 290 312 335 358 380 402 425 448 470 493 515 538 560 583 605 628 650 673 696 718 740 763 786 808 830 853 876 899 920 943 966 989
110 133 156 179 200 223 246 269 291 313 336 359 381 403 426 449 471 494 516 539 561 584 606 629 651 674 697 719 741 764 787 809 831 854 877 9   921 944 967 99
111 134 157 18   201 224 247 27   292 314 337 36   382 404 427 45   472 495 517 54   562 585 607 63   652 675 698 72   742 765 788 81   832 855 878 90   922 945 968
112 135 158 180 202 225 248 270 293 315 338 360 383 405 428 450 473 496 518 540 563 586 608 630 653 676 699 720 743 766 789 810 833 856 879 900 923 946 969
113 136 159 181 203 226 249 271 294 316 339 361 384 406 429 451 474 497 519 541 564 587 609 631 654 677 7   721 744 767 79   811  834 857 88   901 924 947 97
114 137 16   182 204 227 25   272 295 317 34   362 385 407 43   452 475 498 52   542 565 588 61   632 655 678 70   722 745 768 790 812 835 858 880 902 925 948 970
115 138 160 183 205 228 250 273 296 318 340 363 386 408 430 453 476 499 520 543 566 589 610 633 656 679 700 723 746 769 791 813 836 859 881 903 926 949 971
116 139 161 184 206 229 251 274 297 319 341 364 387 409 431 454 477 5   521 544 567 59   611 634 657 68   701 724 747 77   792 814 837 86   882 904 927 95   972
117 14   162 185 207 23   252 275 298 32   342 365 388 41   432 455 478 50   522 545 568 590 612 635 658 680 702 725 748 770 793  815 838 860 883 905 928 950 973
118 140 163 186 208 230 253 276 299 320 343 366 389 410 433 456 479 500 523 546 569 591 613 636 659 681 703 726 749 771 794 816 839 861 884 906 929 951 974
119 141 164 187 209 231 254 277 3   321 344 367 39   411 434 457  48   501 524 547 57   592 614 637 66   682 704 727 75   772 795 817 84   862 885 907 93   952 975
12   142 165 188 21   232 255 278 30   322 345 368 390 412 435 458 480 502 525 548 570 593 615 638 660 683 705 728 750 773 796 818 840 863 886 908 930 953 976

使用获取的样本再次 fuzz

然后以生成的样本集作为初始样本集进行 fuzz

LD_PRELOAD="/home/giantbranch/afl-2.52b/preeny/x86_64-linux-gnu/desock.so" afl-fuzz -i /tmp/seeds -o out ./server

刚开始一直报错

android cpp获取当前应用包名 c获取当前程序的路径_ubuntu_08

在一顿查找原因后,是配置有问题

╭─birdpwn@ubuntu ~/vuln/libmodbus-3.1.4/tests
╰─$ LD_PRELOAD="/home/giantbranch/afl-2.52b/preeny/x86_64-linux-gnu/desock.so" afl-fuzz -t 100+ -i seeds -o out ./server export AFL_NO_FORKSRV=1                                                     1 ↵
afl-fuzz 2.52b by 
[+] You have 1 CPU core and 7 runnable tasks (utilization: 700%).
[*] Checking core_pattern...

android cpp获取当前应用包名 c获取当前程序的路径_c获取当前程序的路径_09

总结

afl + preenyfuzz 网络应用 速度还行, 关键的还是要找到好的样本,从程序自带的测试用例中抓取也是一个不错的思路。

AFL Persistent Mode

在介绍一个 在 fuzz 一些网络程序时可能用到的特性, AFLpersistent 模式。

persistent 模式就是在程序的某个代码位置不断喂生成的变异数据进行 fuzz , 而不用每次喂数据都得重新 fork 一个程序。

要使用这个特性,首先得编译 llvm_mode

cd afl-2.52b/
cd llvm_mode/
make
cd ..
sudo make install

此时就会有 afl-clang-fastafl-clang-fast++ 两个命令, 要使用这个模式,就要用这两个命令来编译目标应用。

面还是用 afl 自带的 测试文件 experimental/persistent_demo/persistent_demo.c 来看看。

#include 
#include 
#include 
#include 
#include 
int main(int argc, char** argv) {
char buf[100];
while (__AFL_LOOP(1000)) {
  memset(buf, 0, 100);
  read(0, buf, 100);
  if (buf[0] == 'f') {
    printf("one\n");
    if (buf[1] == 'o') {
      printf("two\n");
      if (buf[2] == 'o') {
        printf("three\n");
        if (buf[3] == '!') {
          printf("four\n");
          abort();
        }
      }
    }
  }
} // end of while (__AFL_LOOP(1000))
return 0;
}

最关键的 就是 AFL_LOOP(1000) 这个宏, 其中的参数指定循环的次数。

每一次循环 afl 都会生成 测试数据,然后喂到 stdin , 这样 fuzzer 就可以在 AFL_LOOP 宏 包围的内部,通过 read(0,buf, size) 来获取测试数据,然后喂给目标程序的数据处理的代码,这样可以减少 fork 等操作的开销。

对应到上面的程序,就是 afl 会在

while (__AFL_LOOP(1000)) {
........
........
}

里面 fuzz 1000 次,即生成 1000 次测试数据, 然后会 return 0 . 程序结束,然后 afl 会重新起一个程序。继续这样的 fuzz .

while (__AFL_LOOP(1000)) 包围的代码,就是不断的 从 stdin 获取测试数据,然后进入下面的 if 判断逻辑。

编译 然后用 afl-fuzz

afl-clang-fast persistent_demo.c -o persistent_demo
afl-fuzz -i in/ -o out/ ./persistent_demo

总结

如果使用 aflfuzz 网络应用,有两种方式

  • 利用 preeny 把从 socket 获取数据,转变为 从 stdin 获取数据
  • 利用 aflpersistent 模式