-
-
[原创]EMBA安装、使用与源代码分析_0
-
发表于: 2023-5-1 15:56 25282
-
项目地址:https://github.com/e-m-b-a/emba
本次分析对象的最后一次提交:https://github.com/e-m-b-a/emba/commit/de9dc53980962c8a62ea1239c9039e87962b32e5
克隆项目
EMBA 被设计为渗透测试人员的中央固件分析工具。它支持完整的安全分析过程,从固件提取过程开始,通过仿真进行静态分析和动态分析,最后生成 Web 报告。EMBA 自动发现固件中可能存在的弱点和漏洞。例如不安全的二进制文件、旧的和过时的软件组件、可能易受攻击的脚本或硬编码密码。EMBA是一个命令行工具,可以选择生成易于使用的 Web 报告以供进一步分析。
EMBA 结合了多种成熟的分析工具,可以通过一个简单的命令启动。之后,它会测试固件是否存在可能的安全风险和感兴趣的区域以进行进一步调查。无需手动安装所有帮助程序,执行集成安装脚本后,您就可以测试固件了。
EMBA 旨在协助渗透测试人员,而不是作为一个没有人工交互的独立工具。EMBA 应该提供尽可能多的关于固件的信息,测试人员可以决定重点领域,并负责验证和解释结果。
官方视频:
https://youtu.be/_dvdy3klFFY
项目采用纯Shell编写,非常适合这种需要结合许多外部工具并执行大量命令的工具。
项目统计:
Summary
Date : 2023-04-19 10:38:56
Total : 225 files, 28187 codes, 3873 comments, 4716 blanks, all 36776 lines
Languages
Directories
由代码量可知其主要功能集中在modules文件夹内。通过后面的分析可以知道,EMBA将根据运行参数分别调用各个模块对固件进行静态或动态的分析。
项目结构
描述:
建议:
注意!
国内用户记得配置代理,不然git啥的会报错。另外,sudo运行的命令不会继承当前用户的环境变量。
cve-search 的安装需要配置代理,需要修改安装流程(不然特别特别慢,还容易失败)
这将安装所需要的依赖工具,例如cve-search
、下载大约6GB
的docker镜像等等。
手动构建:docker-compose build emba
安装完后测试 cve-search:./external/cve-search/bin/search.py -p busybox
默认方式安装和运行操作都将使用 docker-compose 运行 emba
首先加载helpers
或installer
文件夹下的helpers_emba_load_strict_settings.sh
,并执行其中的load_strict_mode_settings
函数用于加载严格模式的设置
安装docker
加载所有installer
文件夹下的*.sh
(但是一般都是以函数的形式存在,加载时并不会安装)
检查参数个数,必须为1
检查参数cCdDFghlr
,设置对应的安装标记,然后根据安装标记进行针对性安装。在此过程还会检查wsl
等环境进行针对性安装。
cve-search is always installed on the host,使用IF20_cve_search
函数。
cve-search使用mongodb存储,并会使用pip安装redis等组件。
必须指定日志和固件文件:
使用 checksec.sh 的kernel checker
仅测试内核配置:
如果添加-f ./firmware
,它将忽略-k
并在固件中搜索内核配置checksec
相信打过 pwn 的人应该都很熟悉。关于 checksec 的 kernel checker:
checksec 是一种用于检查Linux系统安全性的工具,其中包括一个kernel checker。checksec kernel checker通过检查当前正在运行的内核的各种安全配置选项来帮助用户评估其安全性。
checksec kernel checker可以检查以下配置选项:
通过检查这些配置选项,checksec kernel checker可以提供有关系统安全性的重要信息,并帮助用户确定是否需要采取额外的安全措施。
运行主文件。首先定义了一些函数,然后在最后调用主函数,并传递所有参数:
然后解析参数、检查参数、文件、路径、依赖工具等。设置相关环境变量。
监控docker日志和通知:
helpers\helpers_emba_print.sh:
如果指定了-t
参数,则会设置THREADED
和MAX_MOD_THREADS
参数(MAX_MOD_THREADS
为核心数乘2):
预处理HTML输出
带-k
参数运行:
会创建一个子进程,用来监控剩余空间容量:
运行容器,并执行分析:
初始化状态栏:
预检查模块(所有以 P 开头的模块)
关键在run_modules "P" "${THREADED}" "0"
这一行,我们看看这个函数的定义:emba line 111
:
函数比较长。接收三个参数的作用在声明前写的很清楚。大概功能:根据传入的参数和一些其他条件,动态地加载和运行符合要求的模块脚本,有时候可以进行多线程并发执行。另外,还会检查某个模块是否已经运行过,并在必要时跳过不需要重新运行的模块,提高运行效率。如果开启了 HTML 选项,则会生成报告文件。
固件检查模块(S模块)
同理,会运行所有S模块,并等待子进程结束。必要时会使用多线程。
实时模拟模块(L模块)
会使用单线程运行。并运行所有L开头的模块。
报告模块(F模块)
单线程运行"F"模块的程序,用于处理测试结果并生成报告。如果指定了-B
参数则删除状态栏。
在测试结束后,如果指定了-r
参数则将产生的临时文件夹和文件删除(只有运行了S模块才会产生)。
总结:主运行文件将检查参数等,并调用各个模块:
因此各个模块源代码的审计将是理解固件分析实现的重点。
给出有关所提供的固件二进制文件的一些非常基本的信息。
主函数:
fw_bin_detector函数:
用patools工具提取zip、tar、tgz
binwalk_deep_extract_helper函数:
提取vmdk镜像
vmdk_extractor函数:
提取D-link加密固件镜像
dlink_SHRS_enc_extractor函数:
dlink_enc_img_extractor函数:
使用Freetz-NG提取AVM固件映像
avm_extractor函数:
显示Uboot映像的内部
P13_uboot_mkimage函数:
挂载和提取extX映像
ext_extractor函数:
提取ubi文件系统
ubi_extractor函数:
用EnGenius提取固件镜像
engenius_enc_extractor函数:
提取没有加密的gpg压缩的固件镜像
gpg_decompress_extractor函数:
从QNAP中提取加密固件映像
首先调用 qnap_enc_extractor 函数:
qnap_extractor函数:
挂载和提取BSD UFS映像
ufs_extractor函数
提取Foscam公司的加密固件映像
首先调用foscam_enc_extractor函数:
foscam_ubi_extractor函数:
提取Buffalo公司的加密固件映像
buffalo_enc_extractor函数:
提取被密码保护的Zyxel固件镜像
zyxel_zip_extractor函数:
binwalk_deep_extract_helper函数(在P60_firmware_bin_extractor.sh
文件内定义):
挂载和提取Qemu QCOW2镜像
qcow_extractor函数:
copy_qemu_nbd函数:
提取Android OTA更新文件
android_ota_extractor函数:
提取UEFI镜像与BIOSUtilities
uefi_extractor函数:
分析固件与binwalk,检查熵和提取固件到日志目录
P59_binwalk_extractor函数:
binwalking函数:
对固件进行简单地分析并给出熵图。
detect_root_dir_helper函数:
通过特殊二进制路径来推测文件系统根目录在哪
linux_basic_identification_helper函数:
用于统计linux文件系统中基本的特征文件或文件名
分析固件与binwalk,检查熵和提取固件到日志目录
P60_firmware_bin_extractor函数:
check_disk_space函数:
用于检查磁盘空间
deep_extractor函数:
深度提取模式
deeper_extractor_helper函数:
进行深度提取
识别和提取典型的软件包档案,如deb, apk, ipk
逻辑比较简单,识别文件名然后针对性解包
将带有unblob的固件提取到模块日志目录(仅用于评估)
逻辑比较简单,直接使用unblob进行提取,然后识别文件系统根目录、统计信息。
一些准备工作(检查固件、架构检查等)
检查固件、准备二进制文件列表、架构检查、文件系统根目录识别、设置配置文件路径、准备文件列表。
git clone https:
/
/
github.com
/
e
-
m
-
b
-
a
/
emba.git
git clone https:
/
/
github.com
/
e
-
m
-
b
-
a
/
emba.git
language | files | code | comment | blank | total |
---|---|---|---|---|---|
Shell Script | 173 | 24,559 | 3,657 | 4,361 | 32,577 |
Properties | 22 | 1,269 | 70 | 20 | 1,359 |
XML | 2 | 1,034 | 1 | 3 | 1,038 |
YAML | 17 | 555 | 92 | 86 | 733 |
CSS | 1 | 343 | 14 | 77 | 434 |
Markdown | 8 | 309 | 14 | 146 | 469 |
HTML | 1 | 106 | 22 | 15 | 143 |
Docker | 1 | 12 | 3 | 8 | 23 |
path | files | code | comment | blank | total |
---|---|---|---|---|---|
. | 225 | 28,187 | 3,873 | 4,716 | 36,776 |
. (Files) | 9 | 812 | 87 | 220 | 1,119 |
.github | 19 | 549 | 81 | 116 | 746 |
.github (Files) | 2 | 6 | 1 | 15 | 22 |
.github\ISSUE_TEMPLATE | 2 | 47 | 0 | 19 | 66 |
.github\workflows | 15 | 496 | 80 | 82 | 658 |
config | 62 | 1,395 | 110 | 101 | 1,606 |
config (Files) | 22 | 1,269 | 70 | 20 | 1,359 |
config\report_templates | 40 | 126 | 40 | 81 | 247 |
helpers | 26 | 5,523 | 729 | 672 | 6,924 |
installer | 26 | 1,734 | 519 | 361 | 2,614 |
modules | 83 | 18,174 | 2,347 | 3,246 | 23,767 |
modules (Files) | 77 | 17,704 | 2,269 | 3,162 | 23,135 |
modules\L10_system_emulation | 6 | 470 | 78 | 84 | 632 |
> tree .
.
├── check_project.sh
├── CODE_OF_CONDUCT.md
├── config
│ ├── banner
│ │ ├── ...
│ │ └── Vegas_Edt
-
v1.
1.0
.txt
│ ├── report_templates
│ │ ├── ...
│ │ └── S99_grepit
-
pre.sh
│ ├── ...
│ └── trickest_cve
-
db.txt
├── CONTRIBUTING.md
├── CONTRIBUTORS.md
├── docker
-
compose.yml
├── Dockerfile
├── emba
├── helpers
│ ├── ...
│ └── trickest_db_update.sh
├── installer
│ ├── ...
│ └── wickStrictModeFail.sh
├── installer.sh
├── LICENSE
├── licenses
│ └── LICENSE
-
MIT
-
firmae
-
firmadyne.txt
├── modules
│ ├── L10_system_emulation
│ │ ├── ...
│ │ └── run_service.sh
│ ├── ...
│ └── template_module.sh
├── README.md
├── scan
-
profiles
│ ├── ...
│ └── full
-
scan.emba
└── SECURITY.md
9
directories,
250
files
> tree .
.
├── check_project.sh
├── CODE_OF_CONDUCT.md
├── config
│ ├── banner
│ │ ├── ...
│ │ └── Vegas_Edt
-
v1.
1.0
.txt
│ ├── report_templates
│ │ ├── ...
│ │ └── S99_grepit
-
pre.sh
│ ├── ...
│ └── trickest_cve
-
db.txt
├── CONTRIBUTING.md
├── CONTRIBUTORS.md
├── docker
-
compose.yml
├── Dockerfile
├── emba
├── helpers
│ ├── ...
│ └── trickest_db_update.sh
├── installer
│ ├── ...
│ └── wickStrictModeFail.sh
├── installer.sh
├── LICENSE
├── licenses
│ └── LICENSE
-
MIT
-
firmae
-
firmadyne.txt
├── modules
│ ├── L10_system_emulation
│ │ ├── ...
│ │ └── run_service.sh
│ ├── ...
│ └── template_module.sh
├── README.md
├── scan
-
profiles
│ ├── ...
│ └── full
-
scan.emba
└── SECURITY.md
9
directories,
250
files
sudo .
/
installer.sh
-
d
sudo .
/
installer.sh
-
d
# installer\IF20_cve_search.sh line 38
# we always need the cve-search stuff:
if
! [[
-
d external
/
cve
-
search ]]; then
git clone https:
/
/
github.com
/
EMBA
-
support
-
repos
/
cve
-
search.git external
/
cve
-
search
# external\cve-search\lib\Config.py line 37
default
=
{
"redisHost"
:
"localhost"
,
"redisPort"
:
6379
,
"redisQ"
:
9
,
...
# installer\IF20_cve_search.sh line 38
# we always need the cve-search stuff:
if
! [[
-
d external
/
cve
-
search ]]; then
git clone https:
/
/
github.com
/
EMBA
-
support
-
repos
/
cve
-
search.git external
/
cve
-
search
# external\cve-search\lib\Config.py line 37
default
=
{
"redisHost"
:
"localhost"
,
"redisPort"
:
6379
,
"redisQ"
:
9
,
...
sudo .
/
emba.sh
-
l .
/
log
-
f .
/
firmware
sudo .
/
emba.sh
-
l .
/
log
-
f .
/
firmware
sudo .
/
emba.sh
-
l .
/
logs
/
kernel_conf
-
k .
/
kernel.config
sudo .
/
emba.sh
-
l .
/
logs
/
kernel_conf
-
k .
/
kernel.config
# calculate the maximum threads per module
if
[[ ${THREADED}
-
eq
1
]] && [[
"${MAX_MOD_THREADS}"
-
eq
0
]]; then
# the maximum threads per modules - if this value does not match adjust it via
# local MAX_MOD_THREADS=123 in module area
export MAX_MOD_THREADS
=
"$(( 2* "
$(grep
-
c ^processor
/
proc
/
cpuinfo)
" ))"
fi
# calculate the maximum threads per module
if
[[ ${THREADED}
-
eq
1
]] && [[
"${MAX_MOD_THREADS}"
-
eq
0
]]; then
# the maximum threads per modules - if this value does not match adjust it via
# local MAX_MOD_THREADS=123 in module area
export MAX_MOD_THREADS
=
"$(( 2* "
$(grep
-
c ^processor
/
proc
/
cpuinfo)
" ))"
fi
# Change log output to color for web report and prepare report
if
[[ ${HTML}
-
eq
1
]] ; then
if
[[ ${FORMAT_LOG}
-
eq
0
]] ; then
FORMAT_LOG
=
1
print_output
"[*] Activate colored log for webreport"
"no_log"
fi
print_output
"[*] Prepare webreport"
"no_log"
prepare_report
fi
# Change log output to color for web report and prepare report
if
[[ ${HTML}
-
eq
1
]] ; then
if
[[ ${FORMAT_LOG}
-
eq
0
]] ; then
FORMAT_LOG
=
1
print_output
"[*] Activate colored log for webreport"
"no_log"
fi
print_output
"[*] Prepare webreport"
"no_log"
prepare_report
fi
#######################################################################################
# Kernel configuration check
#######################################################################################
if
[[
"${KERNEL}"
-
eq
1
]]; then
if
[[ ${IN_DOCKER}
-
eq
1
]] && [[
-
f
"${LOG_DIR}"
/
kernel_config ]]; then
export KERNEL_CONFIG
=
"${LOG_DIR}"
/
kernel_config
fi
if
! [[
-
f
"${KERNEL_CONFIG}"
]] ; then
print_output
"[-] Invalid kernel configuration file: ${ORANGE}${KERNEL_CONFIG}${NC}"
"no_log"
exit
1
else
if
[[ ${IN_DOCKER}
-
eq
0
]] ; then
# we copy the kernel config file from outside the container into our log directory
# further modules are using LOG_DIR/kernel_config for accessing the kernel config
if
[[
-
d
"${LOG_DIR}"
]] ; then
cp
"${KERNEL_CONFIG}"
"${LOG_DIR}"
/
kernel_config
else
print_output
"[!] Missing log directory"
"no_log"
exit
1
fi
fi
fi
fi
#######################################################################################
# Kernel configuration check
#######################################################################################
if
[[
"${KERNEL}"
-
eq
1
]]; then
if
[[ ${IN_DOCKER}
-
eq
1
]] && [[
-
f
"${LOG_DIR}"
/
kernel_config ]]; then
export KERNEL_CONFIG
=
"${LOG_DIR}"
/
kernel_config
fi
if
! [[
-
f
"${KERNEL_CONFIG}"
]] ; then
print_output
"[-] Invalid kernel configuration file: ${ORANGE}${KERNEL_CONFIG}${NC}"
"no_log"
exit
1
else
if
[[ ${IN_DOCKER}
-
eq
0
]] ; then
# we copy the kernel config file from outside the container into our log directory
# further modules are using LOG_DIR/kernel_config for accessing the kernel config
if
[[
-
d
"${LOG_DIR}"
]] ; then
cp
"${KERNEL_CONFIG}"
"${LOG_DIR}"
/
kernel_config
else
print_output
"[!] Missing log directory"
"no_log"
exit
1
fi
fi
fi
fi
disk_space_monitor() {
local DDISK
=
"$LOG_DIR"
while
! [[
-
f
"$MAIN_LOG"
]]; do
sleep
1
done
while
true; do
# print_output "[*] Disk space monitoring active" "no_log"
FREE_SPACE
=
$(df
-
-
output
=
avail
"$DDISK"
| awk
'NR==2'
)
if
[[
"$FREE_SPACE"
-
lt
10000000
]]; then
print_ln
"no_log"
print_output
"[!] WARNING: EMBA is running out of disk space!"
"main"
print_output
"[!] WARNING: EMBA is stopping now"
"main"
df
-
h || true
print_ln
"no_log"
# give the container some more seconds for the cleanup process
[[
"$IN_DOCKER"
-
eq
0
]] && sleep
5
cleaner
1
fi
if
[[
-
f
"$MAIN_LOG"
]]; then
if
grep
-
q
"Test ended\|EMBA failed"
"$MAIN_LOG"
2
>
/
dev
/
null; then
break
fi
fi
sleep
5
done
}
disk_space_monitor() {
local DDISK
=
"$LOG_DIR"
while
! [[
-
f
"$MAIN_LOG"
]]; do
sleep
1
done
while
true; do
# print_output "[*] Disk space monitoring active" "no_log"
FREE_SPACE
=
$(df
-
-
output
=
avail
"$DDISK"
| awk
'NR==2'
)
if
[[
"$FREE_SPACE"
-
lt
10000000
]]; then
print_ln
"no_log"
print_output
"[!] WARNING: EMBA is running out of disk space!"
"main"
print_output
"[!] WARNING: EMBA is stopping now"
"main"
df
-
h || true
print_ln
"no_log"
# give the container some more seconds for the cleanup process
[[
"$IN_DOCKER"
-
eq
0
]] && sleep
5
cleaner
1
fi
if
[[
-
f
"$MAIN_LOG"
]]; then
if
grep
-
q
"Test ended\|EMBA failed"
"$MAIN_LOG"
2
>
/
dev
/
null; then
break
fi
fi
sleep
5
done
}
initial_status_bar() {
# PID for box updater threads
export PID_SYSTEM_LOAD
=
""
export PID_STATUS
=
""
export PID_MODULES
=
""
export PID_STATUS_2
=
""
# Path to status tmp file
# each line is dedicated to a specific function
# 1: Count of boxes visible
# 2: CPU load string (needs to be cached, because it takes about a second to get the information)
# 3: Start time of status bar - not exactly the same as the EMBA timer, but near enough to get an idea
# 4: Count modules
export STATUS_TMP_PATH
=
""
# overwrites $LINES and "$COLUMNS" with the actual values of the window
shopt
-
s checkwinsize; (:;:)
local LINE_POS
=
"$(( LINES - 6 ))"
printf
"\e[%s;1f\e[0J\e[%s;1f"
"$LINE_POS"
"$LINE_POS"
reset
# create new tmp file with empty lines
STATUS_TMP_PATH
=
"$TMP_DIR/status"
if
[[ !
-
f
"$STATUS_TMP_PATH"
&&
-
d
"$TMP_DIR"
]] ; then
echo
-
e
"\\n\\n\\n\\n"
>
"$STATUS_TMP_PATH"
fi
# calculate boxes fitting and draw them
local INITIAL_STR
=
""
INITIAL_STR
=
"\e[${LINE_POS};1f\e[0J\e[0;${LINE_POS}r\e[${LINE_POS};1f"
if
[[ $LINES
-
gt
10
]] ; then
# column has to be increased with 2 characters because of possible arrow column
local ARROW_POS
=
0
STATUS_BAR_BOX_COUNT
=
0
if
[[ $COLUMNS
-
ge
27
]] ; then
INITIAL_STR
+
=
"$(draw_box 26 "
SYSTEM LOAD
" 0)"
STATUS_BAR_BOX_COUNT
=
1
ARROW_POS
=
27
fi
if
[[ $COLUMNS
-
ge
54
]] ; then
INITIAL_STR
+
=
"$(draw_box 26 "
STATUS
" 27)"
STATUS_BAR_BOX_COUNT
=
2
ARROW_POS
=
53
fi
if
[[ $COLUMNS
-
ge
80
]] ; then
INITIAL_STR
+
=
"$(draw_box 26 "
MODULES
" 53)"
STATUS_BAR_BOX_COUNT
=
3
ARROW_POS
=
79
fi
if
[[ $COLUMNS
-
ge
104
]] ; then
INITIAL_STR
+
=
"$(draw_box 26 "
STATUS
2
" 79)"
STATUS_BAR_BOX_COUNT
=
4
fi
if
[[ $STATUS_BAR_BOX_COUNT
-
lt
4
]] ; then
INITIAL_STR
+
=
"$(draw_arrows "
$ARROW_POS
")"
fi
fi
if
[[
-
f
"$STATUS_TMP_PATH"
]] ; then
sed
-
i
"1s/.*/$STATUS_BAR_BOX_COUNT/"
"$STATUS_TMP_PATH"
2
>
/
dev
/
null || true
fi
INITIAL_STR
+
=
"\e[H"
# set cursor and boxes
printf
"%b"
"$INITIAL_STR"
box_updaters
}
initial_status_bar() {
# PID for box updater threads
export PID_SYSTEM_LOAD
=
""
export PID_STATUS
=
""
export PID_MODULES
=
""
export PID_STATUS_2
=
""
# Path to status tmp file
# each line is dedicated to a specific function
# 1: Count of boxes visible
# 2: CPU load string (needs to be cached, because it takes about a second to get the information)
# 3: Start time of status bar - not exactly the same as the EMBA timer, but near enough to get an idea
# 4: Count modules
export STATUS_TMP_PATH
=
""
# overwrites $LINES and "$COLUMNS" with the actual values of the window
shopt
-
s checkwinsize; (:;:)
local LINE_POS
=
"$(( LINES - 6 ))"
printf
"\e[%s;1f\e[0J\e[%s;1f"
"$LINE_POS"
"$LINE_POS"
reset
# create new tmp file with empty lines
STATUS_TMP_PATH
=
"$TMP_DIR/status"
if
[[ !
-
f
"$STATUS_TMP_PATH"
&&
-
d
"$TMP_DIR"
]] ; then
echo
-
e
"\\n\\n\\n\\n"
>
"$STATUS_TMP_PATH"
fi
# calculate boxes fitting and draw them
local INITIAL_STR
=
""
INITIAL_STR
=
"\e[${LINE_POS};1f\e[0J\e[0;${LINE_POS}r\e[${LINE_POS};1f"
if
[[ $LINES
-
gt
10
]] ; then
# column has to be increased with 2 characters because of possible arrow column
local ARROW_POS
=
0
STATUS_BAR_BOX_COUNT
=
0
if
[[ $COLUMNS
-
ge
27
]] ; then
INITIAL_STR
+
=
"$(draw_box 26 "
SYSTEM LOAD
" 0)"
STATUS_BAR_BOX_COUNT
=
1
ARROW_POS
=
27
fi
if
[[ $COLUMNS
-
ge
54
]] ; then
INITIAL_STR
+
=
"$(draw_box 26 "
STATUS
" 27)"
STATUS_BAR_BOX_COUNT
=
2
ARROW_POS
=
53
fi
if
[[ $COLUMNS
-
ge
80
]] ; then
INITIAL_STR
+
=
"$(draw_box 26 "
MODULES
" 53)"
STATUS_BAR_BOX_COUNT
=
3
ARROW_POS
=
79
fi
if
[[ $COLUMNS
-
ge
104
]] ; then
INITIAL_STR
+
=
"$(draw_box 26 "
STATUS
2
" 79)"
STATUS_BAR_BOX_COUNT
=
4
fi
if
[[ $STATUS_BAR_BOX_COUNT
-
lt
4
]] ; then
INITIAL_STR
+
=
"$(draw_arrows "
$ARROW_POS
")"
fi
fi
if
[[
-
f
"$STATUS_TMP_PATH"
]] ; then
sed
-
i
"1s/.*/$STATUS_BAR_BOX_COUNT/"
"$STATUS_TMP_PATH"
2
>
/
dev
/
null || true
fi
INITIAL_STR
+
=
"\e[H"
# set cursor and boxes
printf
"%b"
"$INITIAL_STR"
box_updaters
}
#######################################################################################
# Pre-Check (P-modules)
#######################################################################################
if
[[
"${PRE_CHECK}"
-
eq
1
]] ; then
print_ln
"no_log"
if
[[
-
d
"${LOG_DIR}"
]]; then
print_output
"[!] Pre-checking phase started on "
"$(date)"
"\\n"
"$(indent "
${NC}"
"Firmware binary path: "
"${FIRMWARE_PATH}"
)
" "
main"
else
print_output
"[!] Pre-checking phase started on "
"$(date)"
"\\n"
"$(indent "
${NC}"
"Firmware binary path: "
"${FIRMWARE_PATH}"
)
" "
no_log"
fi
write_notification
"Pre-checking phase started"
# 'main' functions of imported modules
# in the pre-check phase we execute all modules with P[Number]_Name.sh
run_modules
"P"
"${THREADED}"
"0"
# if we running threaded we ware going to wait for the slow guys here
[[ ${THREADED}
-
eq
1
]] && wait_for_pid
"${WAIT_PIDS[@]}"
print_ln
"no_log"
if
[[
-
d
"${LOG_DIR}"
]]; then
print_output
"[!] Pre-checking phase ended on "
"$(date)"
" and took about "
"$(date -d@"
${SECONDS}
" -u +%H:%M:%S)"
" \\n"
"main"
else
print_output
"[!] Pre-checking phase ended on "
"$(date)"
" and took about "
"$(date -d@"
${SECONDS}
" -u +%H:%M:%S)"
" \\n"
"no_log"
fi
write_notification
"Pre-checking phase finished"
# useful prints for debugging:
# print_output "[!] Firmware value: ${FIRMWARE}"
# print_output "[!] Firmware path: ${FIRMWARE}_PATH"
# print_output "[!] Output dir: $OUTPUT_DIR"
# print_output "[!] LINUX_PATH_COUNTER: $LINUX_PATH_COUNTER"
# print_output "[!] LINUX_PATH_ARRAY: ${#ROOT_PATH[@]}"
fi
#######################################################################################
# Pre-Check (P-modules)
#######################################################################################
if
[[
"${PRE_CHECK}"
-
eq
1
]] ; then
print_ln
"no_log"
if
[[
-
d
"${LOG_DIR}"
]]; then
print_output
"[!] Pre-checking phase started on "
"$(date)"
"\\n"
"$(indent "
${NC}"
"Firmware binary path: "
"${FIRMWARE_PATH}"
)
" "
main"
else
print_output
"[!] Pre-checking phase started on "
"$(date)"
"\\n"
"$(indent "
${NC}"
"Firmware binary path: "
"${FIRMWARE_PATH}"
)
" "
no_log"
fi
write_notification
"Pre-checking phase started"
# 'main' functions of imported modules
# in the pre-check phase we execute all modules with P[Number]_Name.sh
run_modules
"P"
"${THREADED}"
"0"
# if we running threaded we ware going to wait for the slow guys here
[[ ${THREADED}
-
eq
1
]] && wait_for_pid
"${WAIT_PIDS[@]}"
print_ln
"no_log"
if
[[
-
d
"${LOG_DIR}"
]]; then
print_output
"[!] Pre-checking phase ended on "
"$(date)"
" and took about "
"$(date -d@"
${SECONDS}
" -u +%H:%M:%S)"
" \\n"
"main"
else
print_output
"[!] Pre-checking phase ended on "
"$(date)"
" and took about "
"$(date -d@"
${SECONDS}
" -u +%H:%M:%S)"
" \\n"
"no_log"
fi
write_notification
"Pre-checking phase finished"
# useful prints for debugging:
# print_output "[!] Firmware value: ${FIRMWARE}"
# print_output "[!] Firmware path: ${FIRMWARE}_PATH"
# print_output "[!] Output dir: $OUTPUT_DIR"
# print_output "[!] LINUX_PATH_COUNTER: $LINUX_PATH_COUNTER"
# print_output "[!] LINUX_PATH_ARRAY: ${#ROOT_PATH[@]}"
fi
# $1: module group letter [P, S, L, F]
# $2: 0=single thread 1=multithread
# $3: HTML=1 - generate html file
run_modules()
{
MODULE_GROUP
=
"${1:-}"
printf
-
v THREADING_SET
'%d\n'
"${2}"
2
>
/
dev
/
null
THREADING_MOD_GROUP
=
"${THREADING_SET}"
local SELECT_PRE_MODULES_COUNT
=
0
for
SELECT_NUM
in
"${SELECT_MODULES[@]}"
; do
if
[[
"${SELECT_NUM}"
=
~ ^[
"${MODULE_GROUP,,}"
,
"${MODULE_GROUP^^}"
]{
1
} ]]; then
...
# $1: module group letter [P, S, L, F]
# $2: 0=single thread 1=multithread
# $3: HTML=1 - generate html file
run_modules()
{
MODULE_GROUP
=
"${1:-}"
printf
-
v THREADING_SET
'%d\n'
"${2}"
2
>
/
dev
/
null
THREADING_MOD_GROUP
=
"${THREADING_SET}"
local SELECT_PRE_MODULES_COUNT
=
0
for
SELECT_NUM
in
"${SELECT_MODULES[@]}"
; do
if
[[
"${SELECT_NUM}"
=
~ ^[
"${MODULE_GROUP,,}"
,
"${MODULE_GROUP^^}"
]{
1
} ]]; then
...
#######################################################################################
# Firmware-Check (S modules)
#######################################################################################
WAIT_PIDS
=
()
if
[[ ${FIRMWARE}
-
eq
1
]] ; then
print_output
"\n=================================================================\n"
"no_log"
if
[[
-
d
"${LOG_DIR}"
]]; then
print_output
"[!] Testing phase started on "
"$(date)"
"\\n"
"$(indent "
${NC}"
"Firmware path: "
"${FIRMWARE_PATH}"
)
" "
main"
else
print_output
"[!] Testing phase started on "
"$(date)"
"\\n"
"$(indent "
${NC}"
"Firmware path: "
"${FIRMWARE_PATH}"
)
" "
no_log"
fi
write_notification
"Testing phase finished"
write_grep_log
"$(date)"
"TIMESTAMP"
run_modules
"S"
"${THREADED}"
"${HTML}"
[[ ${THREADED}
-
eq
1
]] && wait_for_pid
"${WAIT_PIDS[@]}"
print_ln
"no_log"
if
[[
-
d
"${LOG_DIR}"
]]; then
print_output
"[!] Testing phase ended on "
"$(date)"
" and took about "
"$(date -d@"
${SECONDS}
" -u +%H:%M:%S)"
" \\n"
"main"
else
print_output
"[!] Testing phase ended on "
"$(date)"
" and took about "
"$(date -d@"
${SECONDS}
" -u +%H:%M:%S)"
" \\n"
"no_log"
fi
write_notification
"Testing phase ended"
TESTING_DONE
=
1
fi
#######################################################################################
# Firmware-Check (S modules)
#######################################################################################
WAIT_PIDS
=
()
if
[[ ${FIRMWARE}
-
eq
1
]] ; then
print_output
"\n=================================================================\n"
"no_log"
if
[[
-
d
"${LOG_DIR}"
]]; then
print_output
"[!] Testing phase started on "
"$(date)"
"\\n"
"$(indent "
${NC}"
"Firmware path: "
"${FIRMWARE_PATH}"
)
" "
main"
else
print_output
"[!] Testing phase started on "
"$(date)"
"\\n"
"$(indent "
${NC}"
"Firmware path: "
"${FIRMWARE_PATH}"
)
" "
no_log"
fi
write_notification
"Testing phase finished"
write_grep_log
"$(date)"
"TIMESTAMP"
run_modules
"S"
"${THREADED}"
"${HTML}"
[[ ${THREADED}
-
eq
1
]] && wait_for_pid
"${WAIT_PIDS[@]}"
print_ln
"no_log"
if
[[
-
d
"${LOG_DIR}"
]]; then
print_output
"[!] Testing phase ended on "
"$(date)"
" and took about "
"$(date -d@"
${SECONDS}
" -u +%H:%M:%S)"
" \\n"
"main"
else
print_output
"[!] Testing phase ended on "
"$(date)"
" and took about "
"$(date -d@"
${SECONDS}
" -u +%H:%M:%S)"
" \\n"
"no_log"
fi
write_notification
"Testing phase ended"
TESTING_DONE
=
1
fi
#######################################################################################
# Live Emulation - Check (L-modules)
#######################################################################################
if
[[
"${FULL_EMULATION}"
-
eq
1
]] ; then
print_output
"\n=================================================================\n"
"no_log"
if
[[
-
d
"${LOG_DIR}"
]]; then
print_output
"[!] System emulation phase started on "
"$(date)"
"\\n"
"$(indent "
${NC}"
"Firmware path: "
"${FIRMWARE_PATH}"
)
" "
main"
else
print_output
"[!] System emulation phase started on "
"$(date)"
"\\n"
"$(indent "
${NC}"
"Firmware path: "
"${FIRMWARE_PATH}"
)
" "
no_log"
fi
write_notification
"System emulation phase started"
write_grep_log
"$(date)"
"TIMESTAMP"
# these modules are not threaded!
run_modules
"L"
"0"
"${HTML}"
print_ln
"no_log"
if
[[
-
d
"${LOG_DIR}"
]]; then
print_output
"[!] System emulation phase ended on "
"$(date)"
" and took about "
"$(date -d@"
${SECONDS}
" -u +%H:%M:%S)"
" \\n"
"main"
else
print_output
"[!] System emulation ended on "
"$(date)"
" and took about "
"$(date -d@"
${SECONDS}
" -u +%H:%M:%S)"
" \\n"
"no_log"
fi
write_notification
"System emulation phase ended"
fi
#######################################################################################
# Live Emulation - Check (L-modules)
#######################################################################################
if
[[
"${FULL_EMULATION}"
-
eq
1
]] ; then
print_output
"\n=================================================================\n"
"no_log"
if
[[
-
d
"${LOG_DIR}"
]]; then
print_output
"[!] System emulation phase started on "
"$(date)"
"\\n"
"$(indent "
${NC}"
"Firmware path: "
"${FIRMWARE_PATH}"
)
" "
main"
else
print_output
"[!] System emulation phase started on "
"$(date)"
"\\n"
"$(indent "
${NC}"
"Firmware path: "
"${FIRMWARE_PATH}"
)
" "
no_log"
fi
write_notification
"System emulation phase started"
write_grep_log
"$(date)"
"TIMESTAMP"
# these modules are not threaded!
run_modules
"L"
"0"
"${HTML}"
print_ln
"no_log"
if
[[
-
d
"${LOG_DIR}"
]]; then
print_output
"[!] System emulation phase ended on "
"$(date)"
" and took about "
"$(date -d@"
${SECONDS}
" -u +%H:%M:%S)"
" \\n"
"main"
else
print_output
"[!] System emulation ended on "
"$(date)"
" and took about "
"$(date -d@"
${SECONDS}
" -u +%H:%M:%S)"
" \\n"
"no_log"
fi
write_notification
"System emulation phase ended"
fi
#######################################################################################
# Reporting (F-modules)
#######################################################################################
if
[[
-
d
"${LOG_DIR}"
]]; then
print_output
"[!] Reporting phase started on "
"$(date)"
"\\n"
"main"
else
print_output
"[!] Reporting phase started on "
"$(date)"
"\\n"
"no_log"
fi
write_notification
"Reporting phase started"
run_modules
"F"
"0"
"${HTML}"
[[ ${DISABLE_STATUS_BAR}
-
eq
0
]] && remove_status_bar
write_notification
"Reporting phase ended"
if
[[
"${TESTING_DONE}"
-
eq
1
]]; then
if
[[
"${FINAL_FW_RM}"
-
eq
1
&&
-
d
"${LOG_DIR}"
/
firmware ]]; then
print_output
"[*] Removing temp firmware directory\\n"
"no_log"
rm
-
r
"${LOG_DIR}"
/
firmware
2
>
/
dev
/
null
fi
if
[[
"${FINAL_FW_RM}"
-
eq
1
&&
-
d
"${LOG_DIR}"
/
p61_unblob_eval
/
unblob_extracted ]]; then
print_output
"[*] Removing unblob firmware directory\\n"
"no_log"
rm
-
r
"${LOG_DIR}"
/
p61_unblob_eval
/
unblob_extracted
2
>
/
dev
/
null
fi
print_ln
"no_log"
if
[[
-
d
"${LOG_DIR}"
]]; then
print_output
"[!] Test ended on "
"$(date)"
" and took about "
"$(date -d@"
${SECONDS}
" -u +%H:%M:%S)"
" \\n"
"main"
write_notification
"EMBA finished analysis"
rm
-
r
"${TMP_DIR}"
2
>
/
dev
/
null || true
else
print_output
"[!] Test ended on "
"$(date)"
" and took about "
"$(date -d@"
${SECONDS}
" -u +%H:%M:%S)"
" \\n"
"no_log"
fi
write_grep_log
"$(date)"
"TIMESTAMP"
write_grep_log
"$(date -d@"
${SECONDS}
" -u +%H:%M:%S)"
"DURATION"
else
print_output
"[!] No extracted firmware found"
"no_log"
print_output
"$(indent "
Try using binwalk
or
something
else
to extract the firmware
")"
exit
1
fi
[[
"${HTML}"
-
eq
1
]] && update_index
if
[[
-
f
"${HTML_PATH}"
/
index.html ]] && [[
"${IN_DOCKER}"
-
eq
0
]]; then
print_output
"[*] Web report created HTML report in ${ORANGE}${LOG_DIR}/html-report${NC}\\n"
"main"
print_output
"[*] Open the web-report with${ORANGE} firefox $(abs_path "
${HTML_PATH}
/
index.html
")${NC}\\n"
"main"
fi
# we need to change the permissions of the LOG_DIR to the orig. user from the host
[[
"${IN_DOCKER}"
-
eq
1
]] && restore_permissions
cleaner
0
#######################################################################################
# Reporting (F-modules)
#######################################################################################
if
[[
-
d
"${LOG_DIR}"
]]; then
print_output
"[!] Reporting phase started on "
"$(date)"
"\\n"
"main"
else
print_output
"[!] Reporting phase started on "
"$(date)"
"\\n"
"no_log"
fi
write_notification
"Reporting phase started"
run_modules
"F"
"0"
"${HTML}"
[[ ${DISABLE_STATUS_BAR}
-
eq
0
]] && remove_status_bar
write_notification
"Reporting phase ended"
if
[[
"${TESTING_DONE}"
-
eq
1
]]; then
if
[[
"${FINAL_FW_RM}"
-
eq
1
&&
-
d
"${LOG_DIR}"
/
firmware ]]; then
print_output
"[*] Removing temp firmware directory\\n"
"no_log"
rm
-
r
"${LOG_DIR}"
/
firmware
2
>
/
dev
/
null
fi
if
[[
"${FINAL_FW_RM}"
-
eq
1
&&
-
d
"${LOG_DIR}"
/
p61_unblob_eval
/
unblob_extracted ]]; then
print_output
"[*] Removing unblob firmware directory\\n"
"no_log"
rm
-
r
"${LOG_DIR}"
/
p61_unblob_eval
/
unblob_extracted
2
>
/
dev
/
null
fi
print_ln
"no_log"
if
[[
-
d
"${LOG_DIR}"
]]; then
print_output
"[!] Test ended on "
"$(date)"
" and took about "
"$(date -d@"
${SECONDS}
" -u +%H:%M:%S)"
" \\n"
"main"
write_notification
"EMBA finished analysis"
rm
-
r
"${TMP_DIR}"
2
>
/
dev
/
null || true
else
print_output
"[!] Test ended on "
"$(date)"
" and took about "
"$(date -d@"
${SECONDS}
" -u +%H:%M:%S)"
" \\n"
"no_log"
fi
write_grep_log
"$(date)"
"TIMESTAMP"
write_grep_log
"$(date -d@"
${SECONDS}
" -u +%H:%M:%S)"
"DURATION"
else
print_output
"[!] No extracted firmware found"
"no_log"
print_output
"$(indent "
Try using binwalk
or
something
else
to extract the firmware
")"
exit
1
fi
[[
"${HTML}"
-
eq
1
]] && update_index
if
[[
-
f
"${HTML_PATH}"
/
index.html ]] && [[
"${IN_DOCKER}"
-
eq
0
]]; then
print_output
"[*] Web report created HTML report in ${ORANGE}${LOG_DIR}/html-report${NC}\\n"
"main"
print_output
"[*] Open the web-report with${ORANGE} firefox $(abs_path "
${HTML_PATH}
/
index.html
")${NC}\\n"
"main"
fi
# we need to change the permissions of the LOG_DIR to the orig. user from the host
[[
"${IN_DOCKER}"
-
eq
1
]] && restore_permissions
cleaner
0
P02_firmware_bin_file_check.sh 给出有关所提供的固件二进制文件的一些非常基本的信息。
P05_patools_init.sh 用patools工具提取
zip
、tar、tgz
P10_vmdk_extractor.sh 提取vmdk镜像
P11_dlink_SHRS_enc_extract.sh 提取D
-
link加密固件镜像
P12_avm_freetz_ng_extract.sh 使用Freetz
-
NG提取AVM固件映像
P13_uboot_mkimage.sh 显示Uboot映像的内部
P14_ext_mounter.sh 挂载和提取extX映像
P15_ubi_extractor.sh 提取ubi文件系统
P16_EnGenius_decryptor.sh 用EnGenius提取固件镜像
P17_gpg_decompress.sh 提取没有加密的gpg压缩的固件镜像
P18_qnap_decryptor.sh 从QNAP中提取加密固件映像
P19_bsd_ufs_mounter.sh 挂载和提取BSD UFS映像
P20_foscam_decryptor.sh 提取Foscam公司的加密固件映像
P21_buffalo_decryptor.sh 提取Buffalo公司的加密固件映像
P22_Zyxel_zip_decrypt.sh 提取被密码保护的Zyxel固件镜像
P23_qemu_qcow_mounter.sh 挂载和提取Qemu QCOW2镜像
P25_android_ota.sh 提取Android OTA更新文件
P35_UEFI_extractor.sh 提取UEFI镜像与BIOSUtilities
P59_binwalk_extractor.sh 分析固件与binwalk,检查熵和提取固件到日志目录
P60_firmware_bin_extractor.sh 和上面一样
P65_package_extractor.sh 识别和提取典型的软件包档案,如deb, apk, ipk
P70_unblob.sh 将带有unblob的固件提取到模块日志目录(仅用于评估)
P99_prepare_analyzer.sh 一些准备工作(检查固件、架构检查等)
P02_firmware_bin_file_check.sh 给出有关所提供的固件二进制文件的一些非常基本的信息。
P05_patools_init.sh 用patools工具提取
zip
、tar、tgz
P10_vmdk_extractor.sh 提取vmdk镜像
P11_dlink_SHRS_enc_extract.sh 提取D
-
link加密固件镜像
P12_avm_freetz_ng_extract.sh 使用Freetz
-
NG提取AVM固件映像
P13_uboot_mkimage.sh 显示Uboot映像的内部
P14_ext_mounter.sh 挂载和提取extX映像
P15_ubi_extractor.sh 提取ubi文件系统
P16_EnGenius_decryptor.sh 用EnGenius提取固件镜像
P17_gpg_decompress.sh 提取没有加密的gpg压缩的固件镜像
P18_qnap_decryptor.sh 从QNAP中提取加密固件映像
P19_bsd_ufs_mounter.sh 挂载和提取BSD UFS映像
P20_foscam_decryptor.sh 提取Foscam公司的加密固件映像
P21_buffalo_decryptor.sh 提取Buffalo公司的加密固件映像
P22_Zyxel_zip_decrypt.sh 提取被密码保护的Zyxel固件镜像
P23_qemu_qcow_mounter.sh 挂载和提取Qemu QCOW2镜像
P25_android_ota.sh 提取Android OTA更新文件
P35_UEFI_extractor.sh 提取UEFI镜像与BIOSUtilities
P59_binwalk_extractor.sh 分析固件与binwalk,检查熵和提取固件到日志目录
P60_firmware_bin_extractor.sh 和上面一样
P65_package_extractor.sh 识别和提取典型的软件包档案,如deb, apk, ipk
P70_unblob.sh 将带有unblob的固件提取到模块日志目录(仅用于评估)
P99_prepare_analyzer.sh 一些准备工作(检查固件、架构检查等)
S02_UEFI_FwHunt.sh 使用FwHunt来识别可能的UEFI固件中的漏洞
S03_firmware_bin_base_analyzer.sh 对操作系统或架构进行识别
S05_firmware_details.sh 统计可执行文件
S06_distribution_identification.sh 识别发行版
S08_package_mgmt_extractor.sh 搜索已知位置的包管理信息
S09_firmware_base_version_check.sh 搜索二进制文件版本
S100_command_inj_check.sh 搜索web文件并搜索可以代码执行的东西
S106_deep_key_search.sh 搜素文件里的特殊字符串
S107_deep_password_search.sh 搜索文件里的特殊密码
S108_stacs_password_search.sh 使用stacs搜索密码
S109_jtr_local_pw_cracking.sh 破解文件哈希
S10_binaries_basic_check.sh 搜索二进制的风险
S110_yara_check.sh 用yara搜索
S115_usermode_emulator.sh 模拟执行固件获取版本信息(实验功能,需要
-
E单独开启)
S116_qemu_version_detection.sh 该模块从S115的结果中提取版本信息
S120_cwe_checker.sh 用Ghidra扫描二进制文件中的常见风险
S12_binary_protection.sh 搜索二进制文件的保护机制
S13_weak_func_check.sh 和S10类似
S14_weak_func_radare_check.sh 和S10类似,使用radare
S15_bootloader_check.sh 扫描设备树等
S17_apk_check.sh 识别apk包并用APKHunt扫漏洞
S20_shell_check.sh 扫描shell脚本的漏洞
S21_python_check.sh 扫描python脚本的漏洞
S22_php_check.sh 扫描php脚本的漏洞和php配置文件
S24_kernel_bin_identifier.sh 识别内核文件
S25_kernel_check.sh 扫漏洞,包括版本、描述、内核配置等
S26_kernel_vuln_verifier.sh 内核漏洞识别
S35_http_file_check.sh 搜索http相关文件
S36_lighttpd.sh 识别lighttpd配置文件等
S40_weak_perm_check.sh 检查系统用户相关配置、密码文件的风险
S45_pass_file_check.sh 检查密码相关文件
S50_authentication_check.sh 检查身份验证等
S55_history_file_check.sh 检查历史文件
S60_cert_file_check.sh 检查证书文件
S65_config_file_check.sh 扫描典型的配置文件
S70_hidden_file_check.sh 隐藏文件搜索
S75_network_check.sh 检查网络相关的配置文件
S80_cronjob_check.sh 检查所有定时配置文件
S85_ssh_check.sh 检查ssh相关配置文件
S90_mail_check.sh 搜素邮箱文件
S95_interesting_binaries_check.sh 搜索一些二进制文件
S99_grepit.sh 用grepit扫风险
S02_UEFI_FwHunt.sh 使用FwHunt来识别可能的UEFI固件中的漏洞
S03_firmware_bin_base_analyzer.sh 对操作系统或架构进行识别
S05_firmware_details.sh 统计可执行文件
S06_distribution_identification.sh 识别发行版
S08_package_mgmt_extractor.sh 搜索已知位置的包管理信息
S09_firmware_base_version_check.sh 搜索二进制文件版本
S100_command_inj_check.sh 搜索web文件并搜索可以代码执行的东西
S106_deep_key_search.sh 搜素文件里的特殊字符串
S107_deep_password_search.sh 搜索文件里的特殊密码
S108_stacs_password_search.sh 使用stacs搜索密码
S109_jtr_local_pw_cracking.sh 破解文件哈希
S10_binaries_basic_check.sh 搜索二进制的风险
S110_yara_check.sh 用yara搜索
S115_usermode_emulator.sh 模拟执行固件获取版本信息(实验功能,需要
-
E单独开启)
S116_qemu_version_detection.sh 该模块从S115的结果中提取版本信息
S120_cwe_checker.sh 用Ghidra扫描二进制文件中的常见风险
S12_binary_protection.sh 搜索二进制文件的保护机制
S13_weak_func_check.sh 和S10类似
S14_weak_func_radare_check.sh 和S10类似,使用radare
S15_bootloader_check.sh 扫描设备树等
S17_apk_check.sh 识别apk包并用APKHunt扫漏洞
S20_shell_check.sh 扫描shell脚本的漏洞
S21_python_check.sh 扫描python脚本的漏洞
S22_php_check.sh 扫描php脚本的漏洞和php配置文件
S24_kernel_bin_identifier.sh 识别内核文件
S25_kernel_check.sh 扫漏洞,包括版本、描述、内核配置等
S26_kernel_vuln_verifier.sh 内核漏洞识别
S35_http_file_check.sh 搜索http相关文件
S36_lighttpd.sh 识别lighttpd配置文件等
S40_weak_perm_check.sh 检查系统用户相关配置、密码文件的风险
S45_pass_file_check.sh 检查密码相关文件
S50_authentication_check.sh 检查身份验证等
S55_history_file_check.sh 检查历史文件
S60_cert_file_check.sh 检查证书文件
S65_config_file_check.sh 扫描典型的配置文件
S70_hidden_file_check.sh 隐藏文件搜索
S75_network_check.sh 检查网络相关的配置文件
S80_cronjob_check.sh 检查所有定时配置文件
S85_ssh_check.sh 检查ssh相关配置文件
S90_mail_check.sh 搜素邮箱文件
S95_interesting_binaries_check.sh 搜索一些二进制文件
S99_grepit.sh 用grepit扫风险
L10_system_emulation 文件夹
L10_system_emulation.sh 基于firmadyne和firmAE进行固件模拟(实验模块,需要
-
Q单独激活。)
L15_emulated_checks_nmap.sh 测试是否成功模拟
L20_snmp_checks.sh 同上
L25_web_checks.sh 测试模拟的web服务
L30_routersploit.sh 测试
L35_metasploit_check.sh 用metasploit测试
L99_cleanup.sh 停止并清理模拟环境
L10_system_emulation 文件夹
L10_system_emulation.sh 基于firmadyne和firmAE进行固件模拟(实验模块,需要
-
Q单独激活。)
L15_emulated_checks_nmap.sh 测试是否成功模拟
L20_snmp_checks.sh 同上
L25_web_checks.sh 测试模拟的web服务
L30_routersploit.sh 测试
L35_metasploit_check.sh 用metasploit测试
L99_cleanup.sh 停止并清理模拟环境
F10_license_summary.sh 收集许可证信息
F20_vul_aggregator.sh 收集漏洞
F21_cyclonedx_sbom.sh 生成json
F50_base_aggregator.sh 生成一个所有模块的概览
F10_license_summary.sh 收集许可证信息
F20_vul_aggregator.sh 收集漏洞
F21_cyclonedx_sbom.sh 生成json
F50_base_aggregator.sh 生成一个所有模块的概览
P02_firmware_bin_file_check() {
module_log_init
"${FUNCNAME[0]}"
module_title
"Binary firmware file analyzer"
set_p02_default_exports
local FILE_BIN_OUT
# we set this var global to 1 if we find something UEFI related
export UEFI_DETECTED
=
0
write_csv_log
"Entity"
"data"
"Notes"
write_csv_log
"Firmware path"
"$FIRMWARE_PATH"
"NA"
if
[[
-
f
"$FIRMWARE_PATH"
]]; then
# 计算固件文件哈希
SHA512_CHECKSUM
=
"$(sha512sum "
$FIRMWARE_PATH
" | awk '{print $1}')"
write_csv_log
"SHA512"
"${SHA512_CHECKSUM:-}"
"NA"
SHA1_CHECKSUM
=
"$(sha1sum "
$FIRMWARE_PATH
" | awk '{print $1}')"
write_csv_log
"SHA1"
"${SHA1_CHECKSUM:-}"
"NA"
MD5_CHECKSUM
=
"$(md5sum "
$FIRMWARE_PATH
" | awk '{print $1}')"
write_csv_log
"MD5"
"${MD5_CHECKSUM:-}"
"NA"
# 使用 ent 计算文件的熵信息
ENTROPY
=
"$(ent "
$FIRMWARE_PATH
" | grep Entropy | sed -e 's/^Entropy\ \=\ //')"
write_csv_log
"Entropy"
"${ENTROPY:-}"
"NA"
print_output
"[*] Entropy testing with binwalk ... "
# we have to change the working directory for binwalk, because everything except the log directory is read-only in
# Docker container and binwalk fails to save the entropy picture there
if
[[ $IN_DOCKER
-
eq
1
]] ; then
cd
"$LOG_DIR"
||
return
# 使用 binwalk 提取固件,并输出 json 的结果
print_output
"$(binwalk -E -F -J "
$FIRMWARE_PATH
")"
mv
"$(basename "
$FIRMWARE_PATH
".png)"
"$LOG_DIR"
/
firmware_entropy.png
2
>
/
dev
/
null || true
cd
/
emba ||
return
else
print_output
"$(binwalk -E -F -J "
$FIRMWARE_PATH
")"
mv
"$(basename "
$FIRMWARE_PATH
".png)"
"$LOG_DIR"
/
firmware_entropy.png
2
>
/
dev
/
null || true
fi
fi
local FILE_LS_OUT
FILE_LS_OUT
=
$(ls
-
lh
"$FIRMWARE_PATH"
)
print_ln
print_output
"[*] Details of the firmware file:"
print_ln
print_output
"$(indent "
$FILE_LS_OUT
")"
print_ln
if
[[
-
f
"$FIRMWARE_PATH"
]]; then
print_ln
# 使用 file 命令提取基本信息
print_output
"$(indent "
$(
file
"$FIRMWARE_PATH"
)
")"
print_ln
# 使用 hexdump 输出文件前面的十六进制和ASCII信息
hexdump
-
C
"$FIRMWARE_PATH"
| head | tee
-
a
"$LOG_FILE"
|| true
print_ln
print_output
"[*] SHA512 checksum: $ORANGE$SHA512_CHECKSUM$NC"
print_ln
print_output
"$(indent "
$ENTROPY
")"
print_ln
if
[[
-
x
"$EXT_DIR"
/
pixde ]]; then
# 可视化二进制文件
print_output
"[*] Visualized firmware file (first 2000 bytes):\n"
"$EXT_DIR"
/
pixde
-
r
-
0x2000
"$FIRMWARE_PATH"
| tee
-
a
"$LOG_DIR"
/
p02_pixd.txt
print_ln
python3
"$EXT_DIR"
/
pixd_png.py
-
i
"$LOG_DIR"
/
p02_pixd.txt
-
o
"$LOG_DIR"
/
pixd.png
-
p
10
>
/
dev
/
null
write_link
"$LOG_DIR"
/
pixd.png
fi
# 对二进制文件进行检测(将在下方进行分析)
fw_bin_detector
"$FIRMWARE_PATH"
# 备份所有的变量
backup_p02_vars
fi
module_end_log
"${FUNCNAME[0]}"
1
}
P02_firmware_bin_file_check() {
module_log_init
"${FUNCNAME[0]}"
module_title
"Binary firmware file analyzer"
set_p02_default_exports
local FILE_BIN_OUT
# we set this var global to 1 if we find something UEFI related
export UEFI_DETECTED
=
0
write_csv_log
"Entity"
"data"
"Notes"
write_csv_log
"Firmware path"
"$FIRMWARE_PATH"
"NA"
if
[[
-
f
"$FIRMWARE_PATH"
]]; then
# 计算固件文件哈希
SHA512_CHECKSUM
=
"$(sha512sum "
$FIRMWARE_PATH
" | awk '{print $1}')"
write_csv_log
"SHA512"
"${SHA512_CHECKSUM:-}"
"NA"
SHA1_CHECKSUM
=
"$(sha1sum "
$FIRMWARE_PATH
" | awk '{print $1}')"
write_csv_log
"SHA1"
"${SHA1_CHECKSUM:-}"
"NA"
MD5_CHECKSUM
=
"$(md5sum "
$FIRMWARE_PATH
" | awk '{print $1}')"
write_csv_log
"MD5"
"${MD5_CHECKSUM:-}"
"NA"
# 使用 ent 计算文件的熵信息
ENTROPY
=
"$(ent "
$FIRMWARE_PATH
" | grep Entropy | sed -e 's/^Entropy\ \=\ //')"
write_csv_log
"Entropy"
"${ENTROPY:-}"
"NA"
print_output
"[*] Entropy testing with binwalk ... "
# we have to change the working directory for binwalk, because everything except the log directory is read-only in
# Docker container and binwalk fails to save the entropy picture there
if
[[ $IN_DOCKER
-
eq
1
]] ; then
cd
"$LOG_DIR"
||
return
# 使用 binwalk 提取固件,并输出 json 的结果
print_output
"$(binwalk -E -F -J "
$FIRMWARE_PATH
")"
mv
"$(basename "
$FIRMWARE_PATH
".png)"
"$LOG_DIR"
/
firmware_entropy.png
2
>
/
dev
/
null || true
cd
/
emba ||
return
else
print_output
"$(binwalk -E -F -J "
$FIRMWARE_PATH
")"
mv
"$(basename "
$FIRMWARE_PATH
".png)"
"$LOG_DIR"
/
firmware_entropy.png
2
>
/
dev
/
null || true
fi
fi
local FILE_LS_OUT
FILE_LS_OUT
=
$(ls
-
lh
"$FIRMWARE_PATH"
)
print_ln
print_output
"[*] Details of the firmware file:"
print_ln
print_output
"$(indent "
$FILE_LS_OUT
")"
print_ln
if
[[
-
f
"$FIRMWARE_PATH"
]]; then
print_ln
# 使用 file 命令提取基本信息
print_output
"$(indent "
$(
file
"$FIRMWARE_PATH"
)
")"
print_ln
# 使用 hexdump 输出文件前面的十六进制和ASCII信息
hexdump
-
C
"$FIRMWARE_PATH"
| head | tee
-
a
"$LOG_FILE"
|| true
print_ln
print_output
"[*] SHA512 checksum: $ORANGE$SHA512_CHECKSUM$NC"
print_ln
print_output
"$(indent "
$ENTROPY
")"
print_ln
if
[[
-
x
"$EXT_DIR"
/
pixde ]]; then
# 可视化二进制文件
print_output
"[*] Visualized firmware file (first 2000 bytes):\n"
"$EXT_DIR"
/
pixde
-
r
-
0x2000
"$FIRMWARE_PATH"
| tee
-
a
"$LOG_DIR"
/
p02_pixd.txt
print_ln
python3
"$EXT_DIR"
/
pixd_png.py
-
i
"$LOG_DIR"
/
p02_pixd.txt
-
o
"$LOG_DIR"
/
pixd.png
-
p
10
>
/
dev
/
null
write_link
"$LOG_DIR"
/
pixd.png
fi
# 对二进制文件进行检测(将在下方进行分析)
fw_bin_detector
"$FIRMWARE_PATH"
# 备份所有的变量
backup_p02_vars
fi
module_end_log
"${FUNCNAME[0]}"
1
}
fw_bin_detector() {
# 固件路径
local CHECK_FILE
=
"${1:-}"
local FILE_BIN_OUT
=
""
local DLINK_ENC_CHECK
=
""
local QNAP_ENC_CHECK
=
""
local AVM_CHECK
=
0
local UEFI_CHECK
=
0
set_p02_default_exports
FILE_BIN_OUT
=
$(
file
"$CHECK_FILE"
)
# 输出第一行用于检查是否为DLINK公司产品
DLINK_ENC_CHECK
=
$(hexdump
-
C
"$CHECK_FILE"
| head
-
1
|| true)
# 从固件中所有的字符串中检查AVM正则出现的行数。用于判断固件是否为AVM公司产品。
AVM_CHECK
=
$(strings
"$CHECK_FILE"
| grep
-
c
"AVM GmbH .*. All rights reserved.\|(C) Copyright .* AVM"
|| true)
# 搜索字符串并只显示包含指定字符串的结果,用于判断是否为QNAP加密文件系统
QNAP_ENC_CHECK
=
$(binwalk
-
y
"qnap encrypted"
"$CHECK_FILE"
)
# we are running binwalk on the file to analyze the output afterwards:
binwalk
"$CHECK_FILE"
>
"$TMP_DIR"
/
s02_binwalk_output.txt
UEFI_CHECK
=
$(grep
-
c
"UEFI"
"$TMP_DIR"
/
s02_binwalk_output.txt || true)
UEFI_CHECK
=
$((
"$UEFI_CHECK"
+
"$(grep -c "
UEFI
" "
$CHECK_FILE
" || true)"
))
if
[[
-
f
"$KERNEL_CONFIG"
]] && [[
"$KERNEL"
-
eq
1
]]; then
# we set the FIRMWARE_PATH to the kernel config path if we have only -k parameter
if
[[
"$(md5sum "
$KERNEL_CONFIG
" | awk '{print $1}')"
=
=
"$(md5sum "
$FIRMWARE_PATH
" | awk '{print $1}')"
]]; then
print_output
"[+] Identified Linux kernel configuration file"
write_csv_log
"kernel config"
"yes"
"NA"
export SKIP_PRE_CHECKERS
=
1
return
fi
fi
if
[[
"$UEFI_CHECK"
-
gt
0
]]; then
print_output
"[+] Identified possible UEFI firmware - using fwhunt-scan vulnerability scanning module"
export UEFI_DETECTED
=
1
UEFI_AMI_CAPSULE
=
$(grep
-
c
"AMI.*EFI.*capsule"
"$TMP_DIR"
/
s02_binwalk_output.txt || true)
if
[[
"$UEFI_AMI_CAPSULE"
-
gt
0
]]; then
print_output
"[+] Identified possible UEFI-AMI capsule firmware - using capsule extractors"
fi
write_csv_log
"UEFI firmware detected"
"yes"
"NA"
fi
if
[[
"$AVM_CHECK"
-
gt
0
]] || [[
"$FW_VENDOR"
=
=
*
"AVM"
*
]]; then
print_output
"[+] Identified AVM firmware - using AVM extraction module"
export AVM_DETECTED
=
1
write_csv_log
"AVM firmware detected"
"yes"
"NA"
fi
# if we have a zip, tgz, tar archive we are going to use the patools extractor
if
[[
"$FILE_BIN_OUT"
=
=
*
"gzip compressed data"
*
||
"$FILE_BIN_OUT"
=
=
*
"Zip archive data"
*
|| \
"$FILE_BIN_OUT"
=
=
*
"POSIX tar archive"
*
||
"$FILE_BIN_OUT"
=
=
*
"ISO 9660 CD-ROM filesystem data"
*
|| \
"$FILE_BIN_OUT"
=
=
*
"7-zip archive data"
*
||
"$FILE_BIN_OUT"
=
=
*
"XZ compressed data"
*
|| \
"$FILE_BIN_OUT"
=
=
*
"bzip2 compressed data"
*
]]; then
# as the AVM images are also zip files we need to bypass it here:
if
[[
"$AVM_DETECTED"
-
ne
1
]]; then
print_output
"[+] Identified gzip/zip/tar/iso/xz/bzip2 archive file - using patools extraction module"
export PATOOLS_INIT
=
1
write_csv_log
"basic compressed (patool)"
"yes"
"NA"
fi
fi
if
[[
"$FILE_BIN_OUT"
=
=
*
"QEMU QCOW2 Image"
*
]]; then
print_output
"[+] Identified Qemu QCOW image - using QCOW extraction module"
export QCOW_DETECTED
=
1
write_csv_log
"Qemu QCOW firmware detected"
"yes"
"NA"
fi
if
[[
"$FILE_BIN_OUT"
=
=
*
"VMware4 disk image"
*
]]; then
print_output
"[+] Identified VMWware VMDK archive file - using VMDK extraction module"
export VMDK_DETECTED
=
1
write_csv_log
"VMDK"
"yes"
"NA"
fi
if
[[
"$FILE_BIN_OUT"
=
=
*
"UBI image"
*
]]; then
print_output
"[+] Identified UBI filesystem image - using UBI extraction module"
export UBI_IMAGE
=
1
write_csv_log
"UBI filesystem"
"yes"
"NA"
fi
# 识别DLINK固件
if
[[
"$DLINK_ENC_CHECK"
=
=
*
"SHRS"
*
]]; then
print_output
"[+] Identified D-Link SHRS encrpyted firmware - using D-Link extraction module"
export DLINK_ENC_DETECTED
=
1
write_csv_log
"D-Link SHRS"
"yes"
"NA"
fi
if
[[
"$DLINK_ENC_CHECK"
=
~
00000000
\ \
00
\
00
\
00
\
00
\
00
\
00
\
0.
\ ..\ \
00
\
00
\
0.
\ ..\
31
\
32
\
33
\
00
]]; then
print_output
"[+] Identified EnGenius encrpyted firmware - using EnGenius extraction module"
export ENGENIUS_ENC_DETECTED
=
1
write_csv_log
"EnGenius encrypted"
"yes"
"NA"
fi
if
[[
"$DLINK_ENC_CHECK"
=
~
00000000
\ \
00
\
00
\
00
\
00
\
00
\
00
\
01
\
01
\ \
00
\
00
\
0.
\ ..\
33
\
2e
\
3
[
89
]\
2e
]]; then
print_output
"[+] Identified EnGenius encrpyted firmware - using EnGenius extraction module"
export ENGENIUS_ENC_DETECTED
=
1
write_csv_log
"EnGenius encrypted"
"yes"
"NA"
fi
if
[[
"$DLINK_ENC_CHECK"
=
=
*
"encrpted_img"
*
]]; then
print_output
"[+] Identified D-Link encrpted_img encrpyted firmware - using D-Link extraction module"
export DLINK_ENC_DETECTED
=
2
write_csv_log
"D-Link encrpted_img encrypted"
"yes"
"NA"
fi
# 识别u-boot固件
if
[[
"$FILE_BIN_OUT"
=
=
*
"u-boot legacy uImage"
*
]]; then
print_output
"[+] Identified u-boot firmware - using u-boot module"
export UBOOT_IMAGE
=
1
write_csv_log
"Uboot image"
"yes"
"NA"
fi
if
[[
"$FILE_BIN_OUT"
=
=
*
"Unix Fast File system [v2]"
*
]]; then
print_output
"[+] Identified UFS filesytem - using UFS filesytem extraction module"
export BSD_UFS
=
1
write_csv_log
"BSD UFS filesystem"
"yes"
"NA"
fi
if
[[
"$FILE_BIN_OUT"
=
=
*
"Linux rev 1.0 ext2 filesystem data"
*
]]; then
print_output
"[+] Identified Linux ext2 filesytem - using EXT filesytem extraction module"
export EXT_IMAGE
=
1
write_csv_log
"EXT2 filesystem"
"yes"
"NA"
fi
if
[[
"$FILE_BIN_OUT"
=
=
*
"Linux rev 1.0 ext3 filesystem data"
*
]]; then
print_output
"[+] Identified Linux ext3 filesytem - using EXT filesytem extraction module"
export EXT_IMAGE
=
1
write_csv_log
"EXT3 filesystem"
"yes"
"NA"
fi
if
[[
"$FILE_BIN_OUT"
=
=
*
"Linux rev 1.0 ext4 filesystem data"
*
]]; then
print_output
"[+] Identified Linux ext4 filesytem - using EXT filesytem extraction module"
export EXT_IMAGE
=
1
write_csv_log
"EXT4 filesystem"
"yes"
"NA"
fi
if
[[
"$QNAP_ENC_CHECK"
=
=
*
"QNAP encrypted firmware footer , model"
*
]]; then
print_output
"[+] Identified QNAP encrpyted firmware - using QNAP extraction module"
export QNAP_ENC_DETECTED
=
1
write_csv_log
"QNAP encrypted filesystem"
"yes"
"NA"
fi
# probably we need to take a deeper look to identify the gpg compressed firmware files better.
# Currently this detection mechanism works quite good on the known firmware images
if
[[
"$DLINK_ENC_CHECK"
=
~
00000000
\ \ a3\
01
\ ]]; then
GPG_CHECK
=
"$(gpg --list-packets "
$FIRMWARE_PATH
" | grep "
compressed packet:
")"
if
[[
"$GPG_CHECK"
=
=
*
"compressed packet: algo="
*
]]; then
print_output
"[+] Identified GPG compressed firmware - using GPG extraction module"
export GPG_COMPRESS
=
1
write_csv_log
"GPG compressed firmware"
"yes"
"NA"
fi
fi
if
[[
"$DLINK_ENC_CHECK"
=
=
*
"CrAU"
*
]]; then
print_output
"[+] Identified Android OTA payload.bin update file - using Android extraction module"
export ANDROID_OTA
=
1
write_csv_log
"Android OTA update"
"yes"
"NA"
fi
if
[[
"$FILE_BIN_OUT"
=
=
*
"openssl enc'd data with salted password"
*
]]; then
print_output
"[+] Identified OpenSSL encrypted file - trying OpenSSL module for Foscam firmware"
export OPENSSL_ENC_DETECTED
=
1
write_csv_log
"OpenSSL encrypted"
"yes"
"NA"
fi
# This check is currently only tested on one firmware - further tests needed:
if
[[
"$DLINK_ENC_CHECK"
=
~
00000000
\ \
62
\
67
\
6e
\
00
\
00
\
00
\
00
\
00
\ \
00
\
00
\
00
\ b9\
01
\ ]]; then
print_output
"[+] Identified Buffalo encrpyted firmware - using Buffalo extraction module"
export BUFFALO_ENC_DETECTED
=
1
write_csv_log
"Buffalo encrypted"
"yes"
"NA"
fi
if
[[
"$(basename "
$CHECK_FILE
")"
=
~ .
*
\.ri ]] && [[
"$FILE_BIN_OUT"
=
=
*
"data"
*
]]; then
# ri files are usually used by zyxel
if
[[ $(find
"$LOG_DIR"
/
firmware
-
name
"$(basename -s .ri "
$CHECK_FILE
")"
.
bin
| wc
-
l)
-
gt
0
]]; then
# if we find a bin file with the same name then it is a Zyxel firmware image
print_output
"[+] Identified ZyXel encrpyted ZIP firmware - using ZyXel extraction module"
export ZYXEL_ZIP
=
1
write_csv_log
"ZyXel encrypted ZIP"
"yes"
""
fi
fi
print_ln
}
fw_bin_detector() {
# 固件路径
local CHECK_FILE
=
"${1:-}"
local FILE_BIN_OUT
=
""
local DLINK_ENC_CHECK
=
""
local QNAP_ENC_CHECK
=
""
local AVM_CHECK
=
0
local UEFI_CHECK
=
0
set_p02_default_exports
FILE_BIN_OUT
=
$(
file
"$CHECK_FILE"
)
# 输出第一行用于检查是否为DLINK公司产品
DLINK_ENC_CHECK
=
$(hexdump
-
C
"$CHECK_FILE"
| head
-
1
|| true)
# 从固件中所有的字符串中检查AVM正则出现的行数。用于判断固件是否为AVM公司产品。
AVM_CHECK
=
$(strings
"$CHECK_FILE"
| grep
-
c
"AVM GmbH .*. All rights reserved.\|(C) Copyright .* AVM"
|| true)
# 搜索字符串并只显示包含指定字符串的结果,用于判断是否为QNAP加密文件系统
QNAP_ENC_CHECK
=
$(binwalk
-
y
"qnap encrypted"
"$CHECK_FILE"
)
# we are running binwalk on the file to analyze the output afterwards:
binwalk
"$CHECK_FILE"
>
"$TMP_DIR"
/
s02_binwalk_output.txt
UEFI_CHECK
=
$(grep
-
c
"UEFI"
"$TMP_DIR"
/
s02_binwalk_output.txt || true)
UEFI_CHECK
=
$((
"$UEFI_CHECK"
+
"$(grep -c "
UEFI
" "
$CHECK_FILE
" || true)"
))
if
[[
-
f
"$KERNEL_CONFIG"
]] && [[
"$KERNEL"
-
eq
1
]]; then
# we set the FIRMWARE_PATH to the kernel config path if we have only -k parameter
if
[[
"$(md5sum "
$KERNEL_CONFIG
" | awk '{print $1}')"
=
=
"$(md5sum "
$FIRMWARE_PATH
" | awk '{print $1}')"
]]; then
print_output
"[+] Identified Linux kernel configuration file"
write_csv_log
"kernel config"
"yes"
"NA"
export SKIP_PRE_CHECKERS
=
1
return
fi
fi
if
[[
"$UEFI_CHECK"
-
gt
0
]]; then
print_output
"[+] Identified possible UEFI firmware - using fwhunt-scan vulnerability scanning module"
export UEFI_DETECTED
=
1
UEFI_AMI_CAPSULE
=
$(grep
-
c
"AMI.*EFI.*capsule"
"$TMP_DIR"
/
s02_binwalk_output.txt || true)
if
[[
"$UEFI_AMI_CAPSULE"
-
gt
0
]]; then
print_output
"[+] Identified possible UEFI-AMI capsule firmware - using capsule extractors"
fi
write_csv_log
"UEFI firmware detected"
"yes"
"NA"
fi
if
[[
"$AVM_CHECK"
-
gt
0
]] || [[
"$FW_VENDOR"
=
=
*
"AVM"
*
]]; then
print_output
"[+] Identified AVM firmware - using AVM extraction module"
export AVM_DETECTED
=
1
write_csv_log
"AVM firmware detected"
"yes"
"NA"
fi
# if we have a zip, tgz, tar archive we are going to use the patools extractor
if
[[
"$FILE_BIN_OUT"
=
=
*
"gzip compressed data"
*
||
"$FILE_BIN_OUT"
=
=
*
"Zip archive data"
*
|| \
"$FILE_BIN_OUT"
=
=
*
"POSIX tar archive"
*
||
"$FILE_BIN_OUT"
=
=
*
"ISO 9660 CD-ROM filesystem data"
*
|| \
"$FILE_BIN_OUT"
=
=
*
"7-zip archive data"
*
||
"$FILE_BIN_OUT"
=
=
*
"XZ compressed data"
*
|| \
"$FILE_BIN_OUT"
=
=
*
"bzip2 compressed data"
*
]]; then
# as the AVM images are also zip files we need to bypass it here:
if
[[
"$AVM_DETECTED"
-
ne
1
]]; then
print_output
"[+] Identified gzip/zip/tar/iso/xz/bzip2 archive file - using patools extraction module"
export PATOOLS_INIT
=
1
write_csv_log
"basic compressed (patool)"
"yes"
"NA"
fi
fi
if
[[
"$FILE_BIN_OUT"
=
=
*
"QEMU QCOW2 Image"
*
]]; then
print_output
"[+] Identified Qemu QCOW image - using QCOW extraction module"
export QCOW_DETECTED
=
1
write_csv_log
"Qemu QCOW firmware detected"
"yes"
"NA"
fi
if
[[
"$FILE_BIN_OUT"
=
=
*
"VMware4 disk image"
*
]]; then
print_output
"[+] Identified VMWware VMDK archive file - using VMDK extraction module"
export VMDK_DETECTED
=
1
write_csv_log
"VMDK"
"yes"
"NA"
fi
if
[[
"$FILE_BIN_OUT"
=
=
*
"UBI image"
*
]]; then
print_output
"[+] Identified UBI filesystem image - using UBI extraction module"
export UBI_IMAGE
=
1
write_csv_log
"UBI filesystem"
"yes"
"NA"
fi
# 识别DLINK固件
if
[[
"$DLINK_ENC_CHECK"
=
=
*
"SHRS"
*
]]; then
print_output
"[+] Identified D-Link SHRS encrpyted firmware - using D-Link extraction module"
export DLINK_ENC_DETECTED
=
1
write_csv_log
"D-Link SHRS"
"yes"
"NA"
fi
if
[[
"$DLINK_ENC_CHECK"
=
~
00000000
\ \
00
\
00
\
00
\
00
\
00
\
00
\
0.
\ ..\ \
00
\
00
\
0.
\ ..\
31
\
32
\
33
\
00
]]; then
print_output
"[+] Identified EnGenius encrpyted firmware - using EnGenius extraction module"
export ENGENIUS_ENC_DETECTED
=
1
write_csv_log
"EnGenius encrypted"
"yes"
"NA"
fi
if
[[
"$DLINK_ENC_CHECK"
=
~
00000000
\ \
00
\
00
\
00
\
00
\
00
\
00
\
01
\
01
\ \
00
\
00
\
0.
\ ..\
33
\
2e
\
3
[
89
]\
2e
]]; then
print_output
"[+] Identified EnGenius encrpyted firmware - using EnGenius extraction module"
export ENGENIUS_ENC_DETECTED
=
1
write_csv_log
"EnGenius encrypted"
"yes"
"NA"
fi
if
[[
"$DLINK_ENC_CHECK"
=
=
*
"encrpted_img"
*
]]; then
print_output
"[+] Identified D-Link encrpted_img encrpyted firmware - using D-Link extraction module"
export DLINK_ENC_DETECTED
=
2
write_csv_log
"D-Link encrpted_img encrypted"
"yes"
"NA"
fi
# 识别u-boot固件
if
[[
"$FILE_BIN_OUT"
=
=
*
"u-boot legacy uImage"
*
]]; then
print_output
"[+] Identified u-boot firmware - using u-boot module"
export UBOOT_IMAGE
=
1
write_csv_log
"Uboot image"
"yes"
"NA"
fi
if
[[
"$FILE_BIN_OUT"
=
=
*
"Unix Fast File system [v2]"
*
]]; then
print_output
"[+] Identified UFS filesytem - using UFS filesytem extraction module"
export BSD_UFS
=
1
write_csv_log
"BSD UFS filesystem"
"yes"
"NA"
fi
if
[[
"$FILE_BIN_OUT"
=
=
*
"Linux rev 1.0 ext2 filesystem data"
*
]]; then
print_output
"[+] Identified Linux ext2 filesytem - using EXT filesytem extraction module"
export EXT_IMAGE
=
1
write_csv_log
"EXT2 filesystem"
"yes"
"NA"
fi
if
[[
"$FILE_BIN_OUT"
=
=
*
"Linux rev 1.0 ext3 filesystem data"
*
]]; then
print_output
"[+] Identified Linux ext3 filesytem - using EXT filesytem extraction module"
export EXT_IMAGE
=
1
write_csv_log
"EXT3 filesystem"
"yes"
"NA"
fi
if
[[
"$FILE_BIN_OUT"
=
=
*
"Linux rev 1.0 ext4 filesystem data"
*
]]; then
print_output
"[+] Identified Linux ext4 filesytem - using EXT filesytem extraction module"
export EXT_IMAGE
=
1
write_csv_log
"EXT4 filesystem"
"yes"
"NA"
fi
if
[[
"$QNAP_ENC_CHECK"
=
=
*
"QNAP encrypted firmware footer , model"
*
]]; then
print_output
"[+] Identified QNAP encrpyted firmware - using QNAP extraction module"
export QNAP_ENC_DETECTED
=
1
write_csv_log
"QNAP encrypted filesystem"
"yes"
"NA"
fi
# probably we need to take a deeper look to identify the gpg compressed firmware files better.
# Currently this detection mechanism works quite good on the known firmware images
if
[[
"$DLINK_ENC_CHECK"
=
~
00000000
\ \ a3\
01
\ ]]; then
GPG_CHECK
=
"$(gpg --list-packets "
$FIRMWARE_PATH
" | grep "
compressed packet:
")"
if
[[
"$GPG_CHECK"
=
=
*
"compressed packet: algo="
*
]]; then
print_output
"[+] Identified GPG compressed firmware - using GPG extraction module"
export GPG_COMPRESS
=
1
write_csv_log
"GPG compressed firmware"
"yes"
"NA"
fi
fi
if
[[
"$DLINK_ENC_CHECK"
=
=
*
"CrAU"
*
]]; then
print_output
"[+] Identified Android OTA payload.bin update file - using Android extraction module"
export ANDROID_OTA
=
1
write_csv_log
"Android OTA update"
"yes"
"NA"
fi
if
[[
"$FILE_BIN_OUT"
=
=
*
"openssl enc'd data with salted password"
*
]]; then
print_output
"[+] Identified OpenSSL encrypted file - trying OpenSSL module for Foscam firmware"
export OPENSSL_ENC_DETECTED
=
1
write_csv_log
"OpenSSL encrypted"
"yes"
"NA"
fi
# This check is currently only tested on one firmware - further tests needed:
if
[[
"$DLINK_ENC_CHECK"
=
~
00000000
\ \
62
\
67
\
6e
\
00
\
00
\
00
\
00
\
00
\ \
00
\
00
\
00
\ b9\
01
\ ]]; then
print_output
"[+] Identified Buffalo encrpyted firmware - using Buffalo extraction module"
export BUFFALO_ENC_DETECTED
=
1
write_csv_log
"Buffalo encrypted"
"yes"
"NA"
fi
if
[[
"$(basename "
$CHECK_FILE
")"
=
~ .
*
\.ri ]] && [[
"$FILE_BIN_OUT"
=
=
*
"data"
*
]]; then
# ri files are usually used by zyxel
if
[[ $(find
"$LOG_DIR"
/
firmware
-
name
"$(basename -s .ri "
$CHECK_FILE
")"
.
bin
| wc
-
l)
-
gt
0
]]; then
# if we find a bin file with the same name then it is a Zyxel firmware image
print_output
"[+] Identified ZyXel encrpyted ZIP firmware - using ZyXel extraction module"
export ZYXEL_ZIP
=
1
write_csv_log
"ZyXel encrypted ZIP"
"yes"
""
fi
fi
print_ln
}
export PRE_THREAD_ENA
=
0
P05_patools_init() {
local NEG_LOG
=
0
if
[[
"$PATOOLS_INIT"
-
eq
1
]]; then
module_log_init
"${FUNCNAME[0]}"
module_title
"Initial extractor of different archive types via patools"
pre_module_reporter
"${FUNCNAME[0]}"
EXTRACTION_DIR
=
"$LOG_DIR"
/
firmware
/
patool_extraction
/
patools_extractor
"$FIRMWARE_PATH"
"$EXTRACTION_DIR"
if
[[
"$FILES_PATOOLS"
-
gt
0
]]; then
MD5_DONE_DEEP
+
=
(
"$(md5sum "
$FIRMWARE_PATH
" | awk '{print $1}')"
)
export FIRMWARE_PATH
=
"$LOG_DIR"
/
firmware
/
backup_var
"FIRMWARE_PATH"
"$FIRMWARE_PATH"
fi
NEG_LOG
=
1
module_end_log
"${FUNCNAME[0]}"
"$NEG_LOG"
fi
}
patools_extractor() {
sub_module_title
"Patool filesystem extractor"
local FIRMWARE_PATH_
=
"${1:-}"
local EXTRACTION_DIR_
=
"${2:-}"
FILES_PATOOLS
=
0
local DIRS_PATOOLS
=
0
local FIRMWARE_NAME_
=
""
if
! [[
-
f
"$FIRMWARE_PATH_"
]]; then
print_output
"[-] No file for extraction provided"
return
fi
FIRMWARE_NAME_
=
"$(basename "
$FIRMWARE_PATH_
")"
[[
"$STRICT_MODE"
-
eq
1
]] &&
set
+
e
# 使用patool测试
patool
-
v test
"$FIRMWARE_PATH_"
| tee
-
a
"$LOG_PATH_MODULE"
/
paextract_test_
"$FIRMWARE_NAME_"
.log
[[
"$STRICT_MODE"
-
eq
1
]] &&
set
-
e
cat
"$LOG_PATH_MODULE"
/
paextract_test_
"$FIRMWARE_NAME_"
.log >>
"$LOG_FILE"
if
! [[
-
d
"$EXTRACTION_DIR_"
]]; then
mkdir
"$EXTRACTION_DIR_"
fi
if
grep
-
q
"patool: ... tested ok."
"$LOG_PATH_MODULE"
/
paextract_test_
"$FIRMWARE_NAME_"
.log ; then
print_ln
print_output
"[*] Valid compressed file detected - extraction process via patool started"
# 提取
patool
-
v extract
"$FIRMWARE_PATH_"
-
-
outdir
"$EXTRACTION_DIR_"
| tee
-
a
"$LOG_PATH_MODULE"
/
paextract_extract_
"$FIRMWARE_NAME_"
.log
cat
"$LOG_PATH_MODULE"
/
paextract_extract_
"$FIRMWARE_NAME_"
.log >>
"$LOG_FILE"
else
# Fallback if unzip does not work:
print_ln
print_output
"[*] No valid compressed file detected - extraction process via binwalk started"
# P60里的函数,下方给出分析
binwalk_deep_extract_helper
0
"$FIRMWARE_PATH_"
"$EXTRACTION_DIR_"
fi
print_ln
print_output
"[*] Using the following firmware directory ($ORANGE$EXTRACTION_DIR_$NC) as base directory:"
find
"$EXTRACTION_DIR_"
-
xdev
-
maxdepth
1
-
ls | tee
-
a
"$LOG_FILE"
print_ln
FILES_PATOOLS
=
$(find
"$EXTRACTION_DIR_"
-
type
f | wc
-
l)
DIRS_PATOOLS
=
$(find
"$EXTRACTION_DIR_"
-
type
d | wc
-
l)
print_output
"[*] Extracted $ORANGE$FILES_PATOOLS$NC files and $ORANGE$DIRS_PATOOLS$NC directories from the firmware image."
write_csv_log
"Extractor module"
"Original file"
"extracted file/dir"
"file counter"
"directory counter"
"further details"
write_csv_log
"Patool extractor"
"$FIRMWARE_PATH_"
"$EXTRACTION_DIR_"
"$FILES_PATOOLS"
"$DIRS_PATOOLS"
"NA"
print_ln
}
export PRE_THREAD_ENA
=
0
P05_patools_init() {
local NEG_LOG
=
0
if
[[
"$PATOOLS_INIT"
-
eq
1
]]; then
module_log_init
"${FUNCNAME[0]}"
module_title
"Initial extractor of different archive types via patools"
pre_module_reporter
"${FUNCNAME[0]}"
EXTRACTION_DIR
=
"$LOG_DIR"
/
firmware
/
patool_extraction
/
patools_extractor
"$FIRMWARE_PATH"
"$EXTRACTION_DIR"
if
[[
"$FILES_PATOOLS"
-
gt
0
]]; then
MD5_DONE_DEEP
+
=
(
"$(md5sum "
$FIRMWARE_PATH
" | awk '{print $1}')"
)
export FIRMWARE_PATH
=
"$LOG_DIR"
/
firmware
/
backup_var
"FIRMWARE_PATH"
"$FIRMWARE_PATH"
fi
NEG_LOG
=
1
module_end_log
"${FUNCNAME[0]}"
"$NEG_LOG"
fi
}
patools_extractor() {
sub_module_title
"Patool filesystem extractor"
local FIRMWARE_PATH_
=
"${1:-}"
local EXTRACTION_DIR_
=
"${2:-}"
FILES_PATOOLS
=
0
local DIRS_PATOOLS
=
0
local FIRMWARE_NAME_
=
""
if
! [[
-
f
"$FIRMWARE_PATH_"
]]; then
print_output
"[-] No file for extraction provided"
return
fi
FIRMWARE_NAME_
=
"$(basename "
$FIRMWARE_PATH_
")"
[[
"$STRICT_MODE"
-
eq
1
]] &&
set
+
e
# 使用patool测试
patool
-
v test
"$FIRMWARE_PATH_"
| tee
-
a
"$LOG_PATH_MODULE"
/
paextract_test_
"$FIRMWARE_NAME_"
.log
[[
"$STRICT_MODE"
-
eq
1
]] &&
set
-
e
cat
"$LOG_PATH_MODULE"
/
paextract_test_
"$FIRMWARE_NAME_"
.log >>
"$LOG_FILE"
if
! [[
-
d
"$EXTRACTION_DIR_"
]]; then
mkdir
"$EXTRACTION_DIR_"
fi
if
grep
-
q
"patool: ... tested ok."
"$LOG_PATH_MODULE"
/
paextract_test_
"$FIRMWARE_NAME_"
.log ; then
print_ln
print_output
"[*] Valid compressed file detected - extraction process via patool started"
# 提取
patool
-
v extract
"$FIRMWARE_PATH_"
-
-
outdir
"$EXTRACTION_DIR_"
| tee
-
a
"$LOG_PATH_MODULE"
/
paextract_extract_
"$FIRMWARE_NAME_"
.log
cat
"$LOG_PATH_MODULE"
/
paextract_extract_
"$FIRMWARE_NAME_"
.log >>
"$LOG_FILE"
else
# Fallback if unzip does not work:
print_ln
print_output
"[*] No valid compressed file detected - extraction process via binwalk started"
# P60里的函数,下方给出分析
binwalk_deep_extract_helper
0
"$FIRMWARE_PATH_"
"$EXTRACTION_DIR_"
fi
print_ln
print_output
"[*] Using the following firmware directory ($ORANGE$EXTRACTION_DIR_$NC) as base directory:"
find
"$EXTRACTION_DIR_"
-
xdev
-
maxdepth
1
-
ls | tee
-
a
"$LOG_FILE"
print_ln
FILES_PATOOLS
=
$(find
"$EXTRACTION_DIR_"
-
type
f | wc
-
l)
DIRS_PATOOLS
=
$(find
"$EXTRACTION_DIR_"
-
type
d | wc
-
l)
print_output
"[*] Extracted $ORANGE$FILES_PATOOLS$NC files and $ORANGE$DIRS_PATOOLS$NC directories from the firmware image."
write_csv_log
"Extractor module"
"Original file"
"extracted file/dir"
"file counter"
"directory counter"
"further details"
write_csv_log
"Patool extractor"
"$FIRMWARE_PATH_"
"$EXTRACTION_DIR_"
"$FILES_PATOOLS"
"$DIRS_PATOOLS"
"NA"
print_ln
}
binwalk_deep_extract_helper() {
# Matryoshka mode is first parameter: 1 - enable, 0 - disable
local MATRYOSHKA_
=
"${1:-0}"
local FILE_TO_EXTRACT_
=
"${2:-}"
local DEST_FILE_
=
"${3:-}"
if
! [[
-
f
"$FILE_TO_EXTRACT_"
]]; then
print_output
"[-] No file for extraction provided"
return
fi
# 前面通过检查binwalk的版本,使用不同方法提取
if
[[
"$BINWALK_VER_CHECK"
=
=
1
]]; then
if
[[
"$MATRYOSHKA_"
-
eq
1
]]; then
# 使用binwalk提取
binwalk
-
-
run
-
as
=
root
-
-
preserve
-
symlinks
-
-
dd
=
'.*'
-
e
-
M
-
C
"$DEST_FILE_"
"$FILE_TO_EXTRACT_"
| tee
-
a
"$LOG_FILE"
|| true
else
# no more Matryoshka mode ... we are doing it manually and check the files every round via MD5
binwalk
-
-
run
-
as
=
root
-
-
preserve
-
symlinks
-
-
dd
=
'.*'
-
e
-
C
"$DEST_FILE_"
"$FILE_TO_EXTRACT_"
| tee
-
a
"$LOG_FILE"
|| true
fi
else
if
[[
"$MATRYOSHKA_"
-
eq
1
]]; then
binwalk
-
-
dd
=
'.*'
-
e
-
M
-
C
"$DEST_FILE_"
"$FILE_TO_EXTRACT_"
| tee
-
a
"$LOG_FILE"
|| true
else
binwalk
-
-
dd
=
'.*'
-
e
-
C
"$DEST_FILE_"
"$FILE_TO_EXTRACT_"
| tee
-
a
"$LOG_FILE"
|| true
fi
fi
}
binwalk_deep_extract_helper() {
# Matryoshka mode is first parameter: 1 - enable, 0 - disable
local MATRYOSHKA_
=
"${1:-0}"
local FILE_TO_EXTRACT_
=
"${2:-}"
local DEST_FILE_
=
"${3:-}"
if
! [[
-
f
"$FILE_TO_EXTRACT_"
]]; then
print_output
"[-] No file for extraction provided"
return
fi
# 前面通过检查binwalk的版本,使用不同方法提取
if
[[
"$BINWALK_VER_CHECK"
=
=
1
]]; then
if
[[
"$MATRYOSHKA_"
-
eq
1
]]; then
# 使用binwalk提取
binwalk
-
-
run
-
as
=
root
-
-
preserve
-
symlinks
-
-
dd
=
'.*'
-
e
-
M
-
C
"$DEST_FILE_"
"$FILE_TO_EXTRACT_"
| tee
-
a
"$LOG_FILE"
|| true
else
# no more Matryoshka mode ... we are doing it manually and check the files every round via MD5
binwalk
-
-
run
-
as
=
root
-
-
preserve
-
symlinks
-
-
dd
=
'.*'
-
e
-
C
"$DEST_FILE_"
"$FILE_TO_EXTRACT_"
| tee
-
a
"$LOG_FILE"
|| true
fi
else
if
[[
"$MATRYOSHKA_"
-
eq
1
]]; then
binwalk
-
-
dd
=
'.*'
-
e
-
M
-
C
"$DEST_FILE_"
"$FILE_TO_EXTRACT_"
| tee
-
a
"$LOG_FILE"
|| true
else
binwalk
-
-
dd
=
'.*'
-
e
-
C
"$DEST_FILE_"
"$FILE_TO_EXTRACT_"
| tee
-
a
"$LOG_FILE"
|| true
fi
fi
}
P10_vmdk_extractor() {
local NEG_LOG
=
0
if
[[
"${VMDK_DETECTED-0}"
-
eq
1
]]; then
module_log_init
"${FUNCNAME[0]}"
module_title
"VMDK (Virtual Machine Disk) extractor"
EXTRACTION_DIR
=
"$LOG_DIR"
/
firmware
/
vmdk_extractor
/
# 提取vmdk
vmdk_extractor
"$FIRMWARE_PATH"
"$EXTRACTION_DIR"
if
[[
"$VMDK_FILES"
-
gt
0
]]; then
MD5_DONE_DEEP
+
=
(
"$(md5sum "
$FIRMWARE_PATH
" | awk '{print $1}')"
)
export FIRMWARE_PATH
=
"$LOG_DIR"
/
firmware
/
backup_var
"FIRMWARE_PATH"
"$FIRMWARE_PATH"
fi
NEG_LOG
=
1
module_end_log
"${FUNCNAME[0]}"
"$NEG_LOG"
fi
}
P10_vmdk_extractor() {
local NEG_LOG
=
0
if
[[
"${VMDK_DETECTED-0}"
-
eq
1
]]; then
module_log_init
"${FUNCNAME[0]}"
module_title
"VMDK (Virtual Machine Disk) extractor"
EXTRACTION_DIR
=
"$LOG_DIR"
/
firmware
/
vmdk_extractor
/
# 提取vmdk
vmdk_extractor
"$FIRMWARE_PATH"
"$EXTRACTION_DIR"
if
[[
"$VMDK_FILES"
-
gt
0
]]; then
MD5_DONE_DEEP
+
=
(
"$(md5sum "
$FIRMWARE_PATH
" | awk '{print $1}')"
)
export FIRMWARE_PATH
=
"$LOG_DIR"
/
firmware
/
backup_var
"FIRMWARE_PATH"
"$FIRMWARE_PATH"
fi
NEG_LOG
=
1
module_end_log
"${FUNCNAME[0]}"
"$NEG_LOG"
fi
}
vmdk_extractor() {
local VMDK_PATH_
=
"${1:-}"
local EXTRACTION_DIR_
=
"${2:-}"
local MOUNT_DEV
=
""
local DEV_NAME
=
""
local TMP_VMDK_MNT
=
"$TMP_DIR/vmdk_mount_$RANDOM"
local VMDK_DIRS
=
0
local RET
=
0
VMDK_FILES
=
0
if
! [[
-
f
"$VMDK_PATH_"
]]; then
print_output
"[-] No file for extraction provided"
return
fi
# 设置子模块title
sub_module_title
"VMDK (Virtual Machine Disk) extractor"
print_output
"[*] Enumeration of devices in VMDK images $ORANGE$VMDK_PATH_$NC"
disable_strict_mode
"$STRICT_MODE"
0
# 使用virt工具输出文件系统信息
virt
-
filesystems
-
a
"$VMDK_PATH_"
>
"$TMP_DIR"
/
vmdk.log
RET
=
"$?"
if
[[
"$RET"
-
ne
0
]]; then
# 用7z解压vmdk(7z挺强大)
# backup with 7z
7z
x
-
o
"$EXTRACTION_DIR_"
"$VMDK_PATH_"
# 获取7z结果返回的状态码,并进行错误处理
RET
=
"$?"
if
[[
"$RET"
-
ne
0
]]; then
print_output
"[-] WARNING: VMDK filesystem not enumerated"
enable_strict_mode
"$STRICT_MODE"
0
return
fi
else
mapfile
-
t VMDK_VIRT_FS <
"$TMP_DIR"
/
vmdk.log
for
MOUNT_DEV
in
"${VMDK_VIRT_FS[@]}"
; do
print_output
"[*] Found device $ORANGE$MOUNT_DEV$NC"
done
fi
enable_strict_mode
"$STRICT_MODE"
0
mkdir
-
p
"$TMP_VMDK_MNT"
|| true
for
MOUNT_DEV
in
"${VMDK_VIRT_FS[@]}"
; do
DEV_NAME
=
$(basename
"$MOUNT_DEV"
)
# 尝试挂载vmdk
print_output
"[*] Trying to mount $ORANGE$MOUNT_DEV$NC to $ORANGE$TMP_VMDK_MNT$NC directory"
# if troubles ahead with vmdk mount, remove the error redirection
guestmount
-
a
"$VMDK_PATH_"
-
m
"$MOUNT_DEV"
-
-
ro
"$TMP_VMDK_MNT"
2
>
/
dev
/
null || true
if
mount | grep
-
q vmdk_mount; then
print_output
"[*] Copying $ORANGE$MOUNT_DEV$NC to firmware directory $ORANGE$EXTRACTION_DIR_/$DEV_NAME$NC"
mkdir
-
p
"$EXTRACTION_DIR_"
/
"$DEV_NAME"
/
|| true
cp
-
pri
"$TMP_VMDK_MNT"
/
*
"$EXTRACTION_DIR_"
/
"$DEV_NAME"
/
|| true
umount
"$TMP_VMDK_MNT"
fi
done
# 统计提取出的文件和文件夹数量
if
[[
-
d
"$EXTRACTION_DIR_"
]]; then
VMDK_FILES
=
$(find
"$EXTRACTION_DIR_"
-
type
f | wc
-
l)
VMDK_DIRS
=
$(find
"$EXTRACTION_DIR_"
-
type
d | wc
-
l)
fi
# 输出结果
if
[[
"$VMDK_FILES"
-
gt
0
]]; then
print_ln
print_output
"[*] Extracted $ORANGE$VMDK_FILES$NC files and $ORANGE$VMDK_DIRS$NC directories from the firmware image."
write_csv_log
"Extractor module"
"Original file"
"extracted file/dir"
"file counter"
"directory counter"
"further details"
write_csv_log
"VMDK extractor"
"$VMDK_PATH_"
"$EXTRACTION_DIR_"
"$VMDK_FILES"
"$VMDK_DIRS"
"NA"
# currently unblob has issues with VMDKs. We need to disable it for this extraction process
safe_echo
0
>
"$TMP_DIR"
/
unblob_disable.cfg
fi
# 删除临时用于挂载的文件夹
rm
-
r
"$TMP_VMDK_MNT"
|| true
}
vmdk_extractor() {
local VMDK_PATH_
=
"${1:-}"
local EXTRACTION_DIR_
=
"${2:-}"
local MOUNT_DEV
=
""
local DEV_NAME
=
""
local TMP_VMDK_MNT
=
"$TMP_DIR/vmdk_mount_$RANDOM"
local VMDK_DIRS
=
0
local RET
=
0
VMDK_FILES
=
0
if
! [[
-
f
"$VMDK_PATH_"
]]; then
print_output
"[-] No file for extraction provided"
return
fi
# 设置子模块title
sub_module_title
"VMDK (Virtual Machine Disk) extractor"
print_output
"[*] Enumeration of devices in VMDK images $ORANGE$VMDK_PATH_$NC"
disable_strict_mode
"$STRICT_MODE"
0
# 使用virt工具输出文件系统信息
virt
-
filesystems
-
a
"$VMDK_PATH_"
>
"$TMP_DIR"
/
vmdk.log
RET
=
"$?"
if
[[
"$RET"
-
ne
0
]]; then
# 用7z解压vmdk(7z挺强大)
# backup with 7z
7z
x
-
o
"$EXTRACTION_DIR_"
"$VMDK_PATH_"
# 获取7z结果返回的状态码,并进行错误处理
RET
=
"$?"
if
[[
"$RET"
-
ne
0
]]; then
print_output
"[-] WARNING: VMDK filesystem not enumerated"
enable_strict_mode
"$STRICT_MODE"
0
return
fi
else
mapfile
-
t VMDK_VIRT_FS <
"$TMP_DIR"
/
vmdk.log
for
MOUNT_DEV
in
"${VMDK_VIRT_FS[@]}"
; do
print_output
"[*] Found device $ORANGE$MOUNT_DEV$NC"
done
fi
enable_strict_mode
"$STRICT_MODE"
0
mkdir
-
p
"$TMP_VMDK_MNT"
|| true
for
MOUNT_DEV
in
"${VMDK_VIRT_FS[@]}"
; do
DEV_NAME
=
$(basename
"$MOUNT_DEV"
)
# 尝试挂载vmdk
print_output
"[*] Trying to mount $ORANGE$MOUNT_DEV$NC to $ORANGE$TMP_VMDK_MNT$NC directory"
# if troubles ahead with vmdk mount, remove the error redirection
guestmount
-
a
"$VMDK_PATH_"
-
m
"$MOUNT_DEV"
-
-
ro
"$TMP_VMDK_MNT"
2
>
/
dev
/
null || true
if
mount | grep
-
q vmdk_mount; then
print_output
"[*] Copying $ORANGE$MOUNT_DEV$NC to firmware directory $ORANGE$EXTRACTION_DIR_/$DEV_NAME$NC"
mkdir
-
p
"$EXTRACTION_DIR_"
/
"$DEV_NAME"
/
|| true
cp
-
pri
"$TMP_VMDK_MNT"
/
*
"$EXTRACTION_DIR_"
/
"$DEV_NAME"
/
|| true
umount
"$TMP_VMDK_MNT"
fi
done
# 统计提取出的文件和文件夹数量
if
[[
-
d
"$EXTRACTION_DIR_"
]]; then
VMDK_FILES
=
$(find
"$EXTRACTION_DIR_"
-
type
f | wc
-
l)
VMDK_DIRS
=
$(find
"$EXTRACTION_DIR_"
-
type
d | wc
-
l)
fi
# 输出结果
if
[[
"$VMDK_FILES"
-
gt
0
]]; then
print_ln
print_output
"[*] Extracted $ORANGE$VMDK_FILES$NC files and $ORANGE$VMDK_DIRS$NC directories from the firmware image."
write_csv_log
"Extractor module"
"Original file"
"extracted file/dir"
"file counter"
"directory counter"
"further details"
write_csv_log
"VMDK extractor"
"$VMDK_PATH_"
"$EXTRACTION_DIR_"
"$VMDK_FILES"
"$VMDK_DIRS"
"NA"
# currently unblob has issues with VMDKs. We need to disable it for this extraction process
safe_echo
0
>
"$TMP_DIR"
/
unblob_disable.cfg
fi
# 删除临时用于挂载的文件夹
rm
-
r
"$TMP_VMDK_MNT"
|| true
}
P11_dlink_SHRS_enc_extract() {
local NEG_LOG
=
0
if
[[
"$DLINK_ENC_DETECTED"
-
ne
0
]] && [[
"$MODULE_DISABLED"
-
ne
1
]]; then
module_log_init
"${FUNCNAME[0]}"
module_title
"DLink encrypted firmware extractor"
pre_module_reporter
"${FUNCNAME[0]}"
EXTRACTION_FILE
=
"$LOG_DIR"
/
firmware
/
firmware_dlink_dec.
bin
# 有不同的加密方式,使用对应的方式解密
if
[[
"$DLINK_ENC_DETECTED"
-
eq
1
]]; then
dlink_SHRS_enc_extractor
"$FIRMWARE_PATH"
"$EXTRACTION_FILE"
n
=
elif
[[
"$DLINK_ENC_DETECTED"
-
eq
2
]]; then
dlink_enc_img_extractor
"$FIRMWARE_PATH"
"$EXTRACTION_FILE"
fi
NEG_LOG
=
1
module_end_log
"${FUNCNAME[0]}"
"$NEG_LOG"
fi
}
P11_dlink_SHRS_enc_extract() {
local NEG_LOG
=
0
if
[[
"$DLINK_ENC_DETECTED"
-
ne
0
]] && [[
"$MODULE_DISABLED"
-
ne
1
]]; then
module_log_init
"${FUNCNAME[0]}"
module_title
"DLink encrypted firmware extractor"
pre_module_reporter
"${FUNCNAME[0]}"
EXTRACTION_FILE
=
"$LOG_DIR"
/
firmware
/
firmware_dlink_dec.
bin
# 有不同的加密方式,使用对应的方式解密
if
[[
"$DLINK_ENC_DETECTED"
-
eq
1
]]; then
dlink_SHRS_enc_extractor
"$FIRMWARE_PATH"
"$EXTRACTION_FILE"
n
=
elif
[[
"$DLINK_ENC_DETECTED"
-
eq
2
]]; then
dlink_enc_img_extractor
"$FIRMWARE_PATH"
"$EXTRACTION_FILE"
fi
NEG_LOG
=
1
module_end_log
"${FUNCNAME[0]}"
"$NEG_LOG"
fi
}
dlink_SHRS_enc_extractor() {
local DLINK_ENC_PATH_
=
"${1:-}"
local EXTRACTION_FILE_
=
"${2:-}"
if
! [[
-
f
"$DLINK_ENC_PATH_"
]]; then
print_output
"[-] No file for decryption provided"
return
fi
local MODULE_DISABLED
=
1
if
[[
"$MODULE_DISABLED"
-
eq
1
]]; then
print_output
"[*] Module ${FUNCNAME[0]} is deprecated and will be removed in the future"
return
fi
sub_module_title
"DLink encrypted firmware extractor"
hexdump
-
C
"$DLINK_ENC_PATH_"
| head | tee
-
a
"$LOG_FILE"
|| true
print_ln
# 使用DLINK密钥对固件进行AES解密
# 参考:https://www.bleepingcomputer.com/news/security/d-link-blunder-firmware-encryption-key-exposed-in-unencrypted-image/
dd
if
=
"$DLINK_ENC_PATH_"
skip
=
1756
iflag
=
skip_bytes|openssl aes
-
128
-
cbc
-
d
-
p
-
nopad
-
nosalt
-
K
"c05fbf1936c99429ce2a0781f08d6ad8"
-
iv
"67c6697351ff4aec29cdbaabf2fbe346"
-
-
nosalt
-
in
/
dev
/
stdin
-
out
"$EXTRACTION_FILE_"
2
>&
1
|| true | tee
-
a
"$LOG_FILE"
print_ln
if
[[
-
f
"$EXTRACTION_FILE_"
]]; then
print_output
"[+] Decrypted D-Link firmware file to $ORANGE$EXTRACTION_FILE_$NC"
print_ln
print_output
"[*] Firmware file details: $ORANGE$(file "
$EXTRACTION_FILE_
")$NC"
write_csv_log
"Extractor module"
"Original file"
"extracted file/dir"
"file counter"
"directory counter"
"further details"
write_csv_log
"DLink SHRS decryptor"
"$DLINK_ENC_PATH_"
"$EXTRACTION_FILE_"
"1"
"NA"
"NA"
export FIRMWARE_PATH
=
"$EXTRACTION_FILE_"
backup_var
"FIRMWARE_PATH"
"$FIRMWARE_PATH"
if
[[
-
z
"${FW_VENDOR:-}"
]]; then
FW_VENDOR
=
"D-Link"
backup_var
"FW_VENDOR"
"$FW_VENDOR"
fi
else
print_output
"[-] Decryption of D-Link firmware file failed"
fi
}
dlink_SHRS_enc_extractor() {
local DLINK_ENC_PATH_
=
"${1:-}"
local EXTRACTION_FILE_
=
"${2:-}"
if
! [[
-
f
"$DLINK_ENC_PATH_"
]]; then
print_output
"[-] No file for decryption provided"
return
fi
local MODULE_DISABLED
=
1
if
[[
"$MODULE_DISABLED"
-
eq
1
]]; then
print_output
"[*] Module ${FUNCNAME[0]} is deprecated and will be removed in the future"
return
fi
sub_module_title
"DLink encrypted firmware extractor"
hexdump
-
C
"$DLINK_ENC_PATH_"
| head | tee
-
a
"$LOG_FILE"
|| true
print_ln
# 使用DLINK密钥对固件进行AES解密
# 参考:https://www.bleepingcomputer.com/news/security/d-link-blunder-firmware-encryption-key-exposed-in-unencrypted-image/
dd
if
=
"$DLINK_ENC_PATH_"
skip
=
1756
iflag
=
skip_bytes|openssl aes
-
128
-
cbc
-
d
-
p
-
nopad
-
nosalt
-
K
"c05fbf1936c99429ce2a0781f08d6ad8"
-
iv
"67c6697351ff4aec29cdbaabf2fbe346"
-
-
nosalt
-
in
/
dev
/
stdin
-
out
"$EXTRACTION_FILE_"
2
>&
1
|| true | tee
-
a
"$LOG_FILE"
print_ln
if
[[
-
f
"$EXTRACTION_FILE_"
]]; then
print_output
"[+] Decrypted D-Link firmware file to $ORANGE$EXTRACTION_FILE_$NC"
print_ln
print_output
"[*] Firmware file details: $ORANGE$(file "
$EXTRACTION_FILE_
")$NC"
write_csv_log
"Extractor module"
"Original file"
"extracted file/dir"
"file counter"
"directory counter"
"further details"
write_csv_log
"DLink SHRS decryptor"
"$DLINK_ENC_PATH_"
"$EXTRACTION_FILE_"
"1"
"NA"
"NA"
export FIRMWARE_PATH
=
"$EXTRACTION_FILE_"
backup_var
"FIRMWARE_PATH"
"$FIRMWARE_PATH"
if
[[
-
z
"${FW_VENDOR:-}"
]]; then
FW_VENDOR
=
"D-Link"
backup_var
"FW_VENDOR"
"$FW_VENDOR"
fi
else
print_output
"[-] Decryption of D-Link firmware file failed"
fi
}
dlink_enc_img_extractor(){
local TMP_DIR
=
"$LOG_DIR"
"/tmp"
local DLINK_ENC_PATH_
=
"${1:-}"
local EXTRACTION_FILE_
=
"${2:-}"
local TMP_IMAGE_FILE
=
"$TMP_DIR/image.bin"
if
! [[
-
f
"$DLINK_ENC_PATH_"
]]; then
print_output
"[-] No file for decryption provided"
return
fi
local IMAGE_SIZE
=
0
local OFFSET
=
0
local ITERATION
=
0
local MODULE_DISABLED
=
1
if
[[
"$MODULE_DISABLED"
-
eq
1
]]; then
print_output
"[*] Module ${FUNCNAME[0]} is deprecated and will be removed in the future"
return
fi
sub_module_title
"DLink encrpted_image extractor"
hexdump
-
C
"$DLINK_ENC_PATH_"
| head | tee
-
a
"$LOG_FILE"
|| true
# 从偏移量为 16 的位置开始复制到另外一个文件 $TMP_IMAGE_FILE 中
dd
if
=
"$DLINK_ENC_PATH_"
skip
=
16
iflag
=
skip_bytes of
=
"$TMP_IMAGE_FILE"
2
>&
1
| tee
-
a
"$LOG_FILE"
IMAGE_SIZE
=
$(stat
-
c
%
s
"$TMP_IMAGE_FILE"
)
(( ROOF
=
IMAGE_SIZE
/
131072
))
# 每 131072(128KB) 为一块进行处理
for
((ITERATION
=
0
; ITERATION<ROOF; ITERATION
+
+
)); do
if
[[
"$ITERATION"
-
eq
0
]]; then
OFFSET
=
0
else
(( OFFSET
=
131072
*
ITERATION ))
fi
# aes解密
dd
if
=
"$TMP_IMAGE_FILE"
skip
=
"$OFFSET"
iflag
=
skip_bytes count
=
256
| openssl aes
-
256
-
cbc
-
d
-
in
/
dev
/
stdin
-
out
/
dev
/
stdout \
-
K
"6865392d342b4d212964363d6d7e7765312c7132613364316e26322a5a5e2538"
-
iv
"4a253169516c38243d6c6d2d3b384145"
-
-
nopad \
-
-
nosalt | dd
if
=
/
dev
/
stdin of
=
"$EXTRACTION_FILE_"
oflag
=
append conv
=
notrunc
2
>&
1
| tee
-
a
"$LOG_FILE"
done
# Now it should be a .ubi file thats somewhat readable and extractable via ubireader
print_ln
if
[[
-
f
"$EXTRACTION_FILE_"
]]; then
UBI_OUT
=
$(
file
"$EXTRACTION_FILE_"
)
if
[[
"$UBI_OUT"
=
=
*
"UBI image, version"
*
]]; then
print_output
"[+] Decrypted D-Link firmware file to $ORANGE$EXTRACTION_FILE_$NC"
print_ln
print_output
"[*] Firmware file details: $ORANGE$(file "
$EXTRACTION_FILE_
")$NC"
write_csv_log
"Extractor module"
"Original file"
"extracted file/dir"
"file counter"
"directory counter"
"further details"
write_csv_log
"DLink enc_img decryptor"
"$DLINK_ENC_PATH_"
"$EXTRACTION_FILE_"
"1"
"NA"
"NA"
export FIRMWARE_PATH
=
"$EXTRACTION_FILE_"
backup_var
"FIRMWARE_PATH"
"$FIRMWARE_PATH"
if
[[
-
z
"${FW_VENDOR:-}"
]]; then
FW_VENDOR
=
"D-Link"
backup_var
"FW_VENDOR"
"$FW_VENDOR"
fi
EXTRACTION_DIR
=
"$LOG_DIR/firmware/dlink_ubi_extracted"
mkdir
-
p
"$EXTRACTION_DIR"
|| true
# ubi提取
ubi_extractor
"$FIRMWARE_PATH"
"$EXTRACTION_DIR"
else
print_output
"[-] Further extraction of D-Link firmware file via deep extraction"
fi
else
print_output
"[-] Decryption of D-Link firmware file failed"
fi
}
dlink_enc_img_extractor(){
local TMP_DIR
=
"$LOG_DIR"
"/tmp"
local DLINK_ENC_PATH_
=
"${1:-}"
local EXTRACTION_FILE_
=
"${2:-}"
local TMP_IMAGE_FILE
=
"$TMP_DIR/image.bin"
if
! [[
-
f
"$DLINK_ENC_PATH_"
]]; then
print_output
"[-] No file for decryption provided"
return
fi
local IMAGE_SIZE
=
0
local OFFSET
=
0
local ITERATION
=
0
local MODULE_DISABLED
=
1
if
[[
"$MODULE_DISABLED"
-
eq
1
]]; then
print_output
"[*] Module ${FUNCNAME[0]} is deprecated and will be removed in the future"
return
fi
sub_module_title
"DLink encrpted_image extractor"
hexdump
-
C
"$DLINK_ENC_PATH_"
| head | tee
-
a
"$LOG_FILE"
|| true
# 从偏移量为 16 的位置开始复制到另外一个文件 $TMP_IMAGE_FILE 中
dd
if
=
"$DLINK_ENC_PATH_"
skip
=
16
iflag
=
skip_bytes of
=
"$TMP_IMAGE_FILE"
2
>&
1
| tee
-
a
"$LOG_FILE"
IMAGE_SIZE
=
$(stat
-
c
%
s
"$TMP_IMAGE_FILE"
)
(( ROOF
=
IMAGE_SIZE
/
131072
))
# 每 131072(128KB) 为一块进行处理
for
((ITERATION
=
0
; ITERATION<ROOF; ITERATION
+
+
)); do
if
[[
"$ITERATION"
-
eq
0
]]; then
OFFSET
=
0
else
(( OFFSET
=
131072
*
ITERATION ))
fi
# aes解密
dd
if
=
"$TMP_IMAGE_FILE"
skip
=
"$OFFSET"
iflag
=
skip_bytes count
=
256
| openssl aes
-
256
-
cbc
-
d
-
in
/
dev
/
stdin
-
out
/
dev
/
stdout \
-
K
"6865392d342b4d212964363d6d7e7765312c7132613364316e26322a5a5e2538"
-
iv
"4a253169516c38243d6c6d2d3b384145"
-
-
nopad \
-
-
nosalt | dd
if
=
/
dev
/
stdin of
=
"$EXTRACTION_FILE_"
oflag
=
append conv
=
notrunc
2
>&
1
| tee
-
a
"$LOG_FILE"
done
# Now it should be a .ubi file thats somewhat readable and extractable via ubireader
print_ln
if
[[
-
f
"$EXTRACTION_FILE_"
]]; then
UBI_OUT
=
$(
file
"$EXTRACTION_FILE_"
)
if
[[
"$UBI_OUT"
=
=
*
"UBI image, version"
*
]]; then
print_output
"[+] Decrypted D-Link firmware file to $ORANGE$EXTRACTION_FILE_$NC"
print_ln
print_output
"[*] Firmware file details: $ORANGE$(file "
$EXTRACTION_FILE_
")$NC"
write_csv_log
"Extractor module"
"Original file"
"extracted file/dir"
"file counter"
"directory counter"
"further details"
write_csv_log
"DLink enc_img decryptor"
"$DLINK_ENC_PATH_"
"$EXTRACTION_FILE_"
"1"
"NA"
"NA"
export FIRMWARE_PATH
=
"$EXTRACTION_FILE_"
backup_var
"FIRMWARE_PATH"
"$FIRMWARE_PATH"
if
[[
-
z
"${FW_VENDOR:-}"
]]; then
FW_VENDOR
=
"D-Link"
backup_var
"FW_VENDOR"
"$FW_VENDOR"
fi
EXTRACTION_DIR
=
"$LOG_DIR/firmware/dlink_ubi_extracted"
mkdir
-
p
"$EXTRACTION_DIR"
|| true
# ubi提取
ubi_extractor
"$FIRMWARE_PATH"
"$EXTRACTION_DIR"
else
print_output
"[-] Further extraction of D-Link firmware file via deep extraction"
fi
else
print_output
"[-] Decryption of D-Link firmware file failed"
fi
}
avm_extractor() {
local AVM_FW_PATH_
=
"${1:-}"
local EXTRACTION_DIR_
=
"${2:-}"
if
! [[
-
f
"$AVM_FW_PATH_"
]]; then
return
fi
local FRITZ_DIRS
=
0
local FIT_IMAGES
=
()
local FIT_IMAGE
=
""
local RAM_DISKS
=
()
local RAM_DISK
=
""
local RAM_DISK_NAME
=
""
export FRITZ_FILE
=
0
export FRITZ_VERSION
=
""
local MODULE_DISABLED
=
1
if
[[
"$MODULE_DISABLED"
-
eq
1
]]; then
print_output
"[*] Module ${FUNCNAME[0]} is deprecated and will be removed in the future"
return
fi
sub_module_title
"AVM freetz-ng firmware extractor"
# read only filesystem bypass:
# 将 freetz-ng 工具链的 .config 文件复制到临时目录中
cp
"$EXT_DIR"
/
freetz
-
ng
/
.config
"$TMP_DIR"
/
.config
# 使用 freetz-ng/fwmod 工具从 AVM 固件中提取文件
"$EXT_DIR"
/
freetz
-
ng
/
fwmod
-
u
-
i
"$TMP_DIR"
/
.config
-
d
"$EXTRACTION_DIR_"
"$AVM_FW_PATH_"
| tee
-
a
"$LOG_FILE"
|| true
if
[[
-
d
"$EXTRACTION_DIR_"
]]; then
# FRITZ 是来自德国 AVM 公司生产的一系列家用网络设备,包括路由器、网关、电话和其他相关产品。
# 统计提取出的文件和文件夹数量
FRITZ_FILES
=
$(find
"$EXTRACTION_DIR_"
-
type
f | wc
-
l)
FRITZ_DIRS
=
$(find
"$EXTRACTION_DIR_"
-
type
d | wc
-
l)
# 提取版本信息
FRITZ_VERSION
=
$(grep
"detected firmware version:"
"$LOG_FILE"
| cut
-
d
":"
-
f2
-
|| true)
if
[[
-
z
"$FRITZ_VERSION"
]]; then
FRITZ_VERSION
=
"NA"
else
print_output
"[+] Detected Fritz version: $ORANGE$FRITZ_VERSION$NC"
fi
# fitimages are handled here with fitimg - binwalk and unblob are also able to handle these images
# but it is currently more beautiful doing the AVM extraction in one place here
mapfile
-
t FIT_IMAGES < <(find
"$EXTRACTION_DIR_"
-
type
f
-
name
"fit-image"
)
# 在提取的文件中,该函数会检测是否存在名为 "fit-image" 的文件
# 如果存在则调用 fitimg 工具对其解压缩
# 解压缩结果输出到 EXTRACTION_DIR/fit-image-extraction 目录中
# 并从中提取 RAM_DISK
if
[[
"${#FIT_IMAGES[@]}"
-
gt
0
]]; then
if
[[
-
f
"$EXT_DIR"
/
fitimg
-
0.8
/
fitimg ]]; then
for
FIT_IMAGE
in
"${FIT_IMAGES[@]}"
; do
print_output
"[*] Detected fit-image: $ORANGE$FIT_IMAGE$NC"
print_output
"[*] Extracting fit-image with fitimg to $ORANGE$EXTRACTION_DIR/fit-image-extraction$NC"
mkdir
-
p
"$EXTRACTION_DIR/fit-image-extraction"
"$EXT_DIR"
/
fitimg
-
0.8
/
fitimg
-
x
"$FIT_IMAGE"
-
d
"$EXTRACTION_DIR"
/
fit
-
image
-
extraction || true
mapfile
-
t RAM_DISKS < <(find
"$EXTRACTION_DIR_"
/
fit
-
image
-
extraction
-
type
f
-
name
"*ramdisk"
)
print_ln
done
else
print_output
"[-] Fitimg installation not available - check your installation"
fi
fi
if
[[
"${#RAM_DISKS[@]}"
-
gt
0
]]; then
for
RAM_DISK
in
"${RAM_DISKS[@]}"
; do
print_output
"[*] Detected AVM ramdisk: $ORANGE$RAM_DISK$NC"
RAM_DISK_NAME
=
"$(basename "
$RAM_DISK
")"
# 对RAM_DISK进行深度提取
binwalk_deep_extract_helper
1
"$RAM_DISK"
"$EXTRACTION_DIR_"
/
fit
-
image
-
extraction
/
"$RAM_DISK_NAME"
_binwalk
print_ln
done
fi
if
[[
"$FRITZ_FILES"
-
gt
0
]]; then
print_ln
print_output
"[*] Extracted $ORANGE$FRITZ_FILES$NC files and $ORANGE$FRITZ_DIRS$NC directories from the firmware image."
write_csv_log
"Extractor module"
"Original file"
"extracted file/dir"
"file counter"
"directory counter"
"further details"
write_csv_log
"AVM extractor"
"$AVM_FW_PATH_"
"$EXTRACTION_DIR_"
"$FRITZ_FILES"
"$FRITZ_DIRS"
"$FRITZ_VERSION"
export DEEP_EXTRACTOR
=
1
MD5_DONE_DEEP
+
=
(
"$(md5sum "
$AVM_FW_PATH_
" | awk '{print $1}')"
)
if
[[
-
z
"${FW_VENDOR:-}"
]]; then
FW_VENDOR
=
"AVM"
backup_var
"FW_VENDOR"
"$FW_VENDOR"
fi
if
[[
-
z
"${FW_VERSION:-}"
&&
"$FRITZ_VERSION"
!
=
"NA"
]]; then
FW_VERSION
=
"$FRITZ_VERSION"
fi
fi
fi
}
avm_extractor() {
local AVM_FW_PATH_
=
"${1:-}"
local EXTRACTION_DIR_
=
"${2:-}"
if
! [[
-
f
"$AVM_FW_PATH_"
]]; then
return
fi
local FRITZ_DIRS
=
0
local FIT_IMAGES
=
()
local FIT_IMAGE
=
""
local RAM_DISKS
=
()
local RAM_DISK
=
""
local RAM_DISK_NAME
=
""
export FRITZ_FILE
=
0
export FRITZ_VERSION
=
""
local MODULE_DISABLED
=
1
if
[[
"$MODULE_DISABLED"
-
eq
1
]]; then
print_output
"[*] Module ${FUNCNAME[0]} is deprecated and will be removed in the future"
return
fi
sub_module_title
"AVM freetz-ng firmware extractor"
# read only filesystem bypass:
# 将 freetz-ng 工具链的 .config 文件复制到临时目录中
cp
"$EXT_DIR"
/
freetz
-
ng
/
.config
"$TMP_DIR"
/
.config
# 使用 freetz-ng/fwmod 工具从 AVM 固件中提取文件
"$EXT_DIR"
/
freetz
-
ng
/
fwmod
-
u
-
i
"$TMP_DIR"
/
.config
-
d
"$EXTRACTION_DIR_"
"$AVM_FW_PATH_"
| tee
-
a
"$LOG_FILE"
|| true
if
[[
-
d
"$EXTRACTION_DIR_"
]]; then
# FRITZ 是来自德国 AVM 公司生产的一系列家用网络设备,包括路由器、网关、电话和其他相关产品。
# 统计提取出的文件和文件夹数量
FRITZ_FILES
=
$(find
"$EXTRACTION_DIR_"
-
type
f | wc
-
l)
FRITZ_DIRS
=
$(find
"$EXTRACTION_DIR_"
-
type
d | wc
-
l)
# 提取版本信息
FRITZ_VERSION
=
$(grep
"detected firmware version:"
"$LOG_FILE"
| cut
-
d
":"
-
f2
-
|| true)
if
[[
-
z
"$FRITZ_VERSION"
]]; then
FRITZ_VERSION
=
"NA"
else
print_output
"[+] Detected Fritz version: $ORANGE$FRITZ_VERSION$NC"
fi
# fitimages are handled here with fitimg - binwalk and unblob are also able to handle these images
# but it is currently more beautiful doing the AVM extraction in one place here
mapfile
-
t FIT_IMAGES < <(find
"$EXTRACTION_DIR_"
-
type
f
-
name
"fit-image"
)
# 在提取的文件中,该函数会检测是否存在名为 "fit-image" 的文件
# 如果存在则调用 fitimg 工具对其解压缩
# 解压缩结果输出到 EXTRACTION_DIR/fit-image-extraction 目录中
# 并从中提取 RAM_DISK
if
[[
"${#FIT_IMAGES[@]}"
-
gt
0
]]; then
if
[[
-
f
"$EXT_DIR"
/
fitimg
-
0.8
/
fitimg ]]; then
for
FIT_IMAGE
in
"${FIT_IMAGES[@]}"
; do
print_output
"[*] Detected fit-image: $ORANGE$FIT_IMAGE$NC"
print_output
"[*] Extracting fit-image with fitimg to $ORANGE$EXTRACTION_DIR/fit-image-extraction$NC"
mkdir
-
p
"$EXTRACTION_DIR/fit-image-extraction"
"$EXT_DIR"
/
fitimg
-
0.8
/
fitimg
-
x
"$FIT_IMAGE"
-
d
"$EXTRACTION_DIR"
/
fit
-
image
-
extraction || true
mapfile
-
t RAM_DISKS < <(find
"$EXTRACTION_DIR_"
/
fit
-
image
-
extraction
-
type
f
-
name
"*ramdisk"
)
print_ln
done
else
print_output
"[-] Fitimg installation not available - check your installation"
fi
fi
if
[[
"${#RAM_DISKS[@]}"
-
gt
0
]]; then
for
RAM_DISK
in
"${RAM_DISKS[@]}"
; do
print_output
"[*] Detected AVM ramdisk: $ORANGE$RAM_DISK$NC"
RAM_DISK_NAME
=
"$(basename "
$RAM_DISK
")"
# 对RAM_DISK进行深度提取
binwalk_deep_extract_helper
1
"$RAM_DISK"
"$EXTRACTION_DIR_"
/
fit
-
image
-
extraction
/
"$RAM_DISK_NAME"
_binwalk
print_ln
done
fi
if
[[
"$FRITZ_FILES"
-
gt
0
]]; then
print_ln
print_output
"[*] Extracted $ORANGE$FRITZ_FILES$NC files and $ORANGE$FRITZ_DIRS$NC directories from the firmware image."
write_csv_log
"Extractor module"
"Original file"
"extracted file/dir"
"file counter"
"directory counter"
"further details"
write_csv_log
"AVM extractor"
"$AVM_FW_PATH_"
"$EXTRACTION_DIR_"
"$FRITZ_FILES"
"$FRITZ_DIRS"
"$FRITZ_VERSION"
export DEEP_EXTRACTOR
=
1
MD5_DONE_DEEP
+
=
(
"$(md5sum "
$AVM_FW_PATH_
" | awk '{print $1}')"
)
if
[[
-
z
"${FW_VENDOR:-}"
]]; then
FW_VENDOR
=
"AVM"
backup_var
"FW_VENDOR"
"$FW_VENDOR"
fi
if
[[
-
z
"${FW_VERSION:-}"
&&
"$FRITZ_VERSION"
!
=
"NA"
]]; then
FW_VERSION
=
"$FRITZ_VERSION"
fi
fi
fi
}
P13_uboot_mkimage() {
local NEG_LOG
=
0
if
[[
"$UBOOT_IMAGE"
-
eq
1
]]; then
module_log_init
"${FUNCNAME[0]}"
local IMAGE_NAME
=
""
local IMAGE_TYPE
=
""
module_title
"Uboot image details"
pre_module_reporter
"${FUNCNAME[0]}"
# 使用mkimage工具读取固件
mkimage
-
l
"$FIRMWARE_PATH"
| tee
-
a
"$LOG_FILE"
IMAGE_NAME
=
$(grep
"Image Name"
"$LOG_FILE"
2
>
/
dev
/
null | awk
'{print $3,$4,$5,$6,$7,$8,$9,$10}'
|| true)
IMAGE_TYPE
=
$(grep
"Image Type"
"$LOG_FILE"
2
>
/
dev
/
null | awk
'{print $3,$4,$5,$6,$7,$8,$9,$10}'
|| true)
write_csv_log
"Identifier"
"Value"
write_csv_log
"ImageName"
"$IMAGE_NAME"
write_csv_log
"ImageType"
"$IMAGE_TYPE"
NEG_LOG
=
1
module_end_log
"${FUNCNAME[0]}"
"$NEG_LOG"
fi
}
P13_uboot_mkimage() {
local NEG_LOG
=
0
if
[[
"$UBOOT_IMAGE"
-
eq
1
]]; then
module_log_init
"${FUNCNAME[0]}"
local IMAGE_NAME
=
""
local IMAGE_TYPE
=
""
module_title
"Uboot image details"
pre_module_reporter
"${FUNCNAME[0]}"
# 使用mkimage工具读取固件
mkimage
-
l
"$FIRMWARE_PATH"
| tee
-
a
"$LOG_FILE"
IMAGE_NAME
=
$(grep
"Image Name"
"$LOG_FILE"
2
>
/
dev
/
null | awk
'{print $3,$4,$5,$6,$7,$8,$9,$10}'
|| true)
IMAGE_TYPE
=
$(grep
"Image Type"
"$LOG_FILE"
2
>
/
dev
/
null | awk
'{print $3,$4,$5,$6,$7,$8,$9,$10}'
|| true)
write_csv_log
"Identifier"
"Value"
write_csv_log
"ImageName"
"$IMAGE_NAME"
write_csv_log
"ImageType"
"$IMAGE_TYPE"
NEG_LOG
=
1
module_end_log
"${FUNCNAME[0]}"
"$NEG_LOG"
fi
}
ext_extractor() {
local EXT_PATH_
=
"${1:-}"
local EXTRACTION_DIR_
=
"${2:-}"
local TMP_EXT_MOUNT
=
"$TMP_DIR"
"/ext_mount_$RANDOM"
local DIRS_EXT_MOUNT
=
0
FILES_EXT_MOUNT
=
0
if
! [[
-
f
"$EXT_PATH_"
]]; then
print_output
"[-] No file for decryption provided"
return
fi
sub_module_title
"EXT filesystem extractor"
mkdir
-
p
"$TMP_EXT_MOUNT"
|| true
print_output
"[*] Trying to mount $ORANGE$EXT_PATH_$NC to $ORANGE$TMP_EXT_MOUNT$NC directory"
mount
-
o ro
"$EXT_PATH_"
"$TMP_EXT_MOUNT"
if
mount | grep
-
q ext_mount; then
print_output
"[*] Copying $ORANGE$TMP_EXT_MOUNT$NC to firmware tmp directory ($EXTRACTION_DIR_)"
mkdir
-
p
"$EXTRACTION_DIR_"
cp
-
pri
"$TMP_EXT_MOUNT"
/
*
"$EXTRACTION_DIR_"
print_ln
print_output
"[*] Using the following firmware directory ($ORANGE$EXTRACTION_DIR_$NC) as base directory:"
find
"$EXTRACTION_DIR_"
-
xdev
-
maxdepth
1
-
ls | tee
-
a
"$LOG_FILE"
print_ln
print_output
"[*] Unmounting $ORANGE$TMP_EXT_MOUNT$NC directory"
FILES_EXT_MOUNT
=
$(find
"$EXTRACTION_DIR_"
-
type
f | wc
-
l)
DIRS_EXT_MOUNT
=
$(find
"$EXTRACTION_DIR_"
-
type
d | wc
-
l)
print_output
"[*] Extracted $ORANGE$FILES_EXT_MOUNT$NC files and $ORANGE$DIRS_EXT_MOUNT$NC directories from the firmware image."
write_csv_log
"Extractor module"
"Original file"
"extracted file/dir"
"file counter"
"directory counter"
"further details"
write_csv_log
"EXT filesystem extractor"
"$EXT_PATH_"
"$EXTRACTION_DIR_"
"$FILES_EXT_MOUNT"
"$DIRS_EXT_MOUNT"
"NA"
umount
"$TMP_EXT_MOUNT"
|| true
fi
rm
-
r
"$TMP_EXT_MOUNT"
}
ext_extractor() {
local EXT_PATH_
=
"${1:-}"
local EXTRACTION_DIR_
=
"${2:-}"
local TMP_EXT_MOUNT
=
"$TMP_DIR"
"/ext_mount_$RANDOM"
local DIRS_EXT_MOUNT
=
0
FILES_EXT_MOUNT
=
0
if
! [[
-
f
"$EXT_PATH_"
]]; then
print_output
"[-] No file for decryption provided"
return
fi
sub_module_title
"EXT filesystem extractor"
mkdir
-
p
"$TMP_EXT_MOUNT"
|| true
print_output
"[*] Trying to mount $ORANGE$EXT_PATH_$NC to $ORANGE$TMP_EXT_MOUNT$NC directory"
mount
-
o ro
"$EXT_PATH_"
"$TMP_EXT_MOUNT"
if
mount | grep
-
q ext_mount; then
print_output
"[*] Copying $ORANGE$TMP_EXT_MOUNT$NC to firmware tmp directory ($EXTRACTION_DIR_)"
mkdir
-
p
"$EXTRACTION_DIR_"
cp
-
pri
"$TMP_EXT_MOUNT"
/
*
"$EXTRACTION_DIR_"
print_ln
print_output
"[*] Using the following firmware directory ($ORANGE$EXTRACTION_DIR_$NC) as base directory:"
find
"$EXTRACTION_DIR_"
-
xdev
-
maxdepth
1
-
ls | tee
-
a
"$LOG_FILE"
print_ln
print_output
"[*] Unmounting $ORANGE$TMP_EXT_MOUNT$NC directory"
FILES_EXT_MOUNT
=
$(find
"$EXTRACTION_DIR_"
-
type
f | wc
-
l)
DIRS_EXT_MOUNT
=
$(find
"$EXTRACTION_DIR_"
-
type
d | wc
-
l)
print_output
"[*] Extracted $ORANGE$FILES_EXT_MOUNT$NC files and $ORANGE$DIRS_EXT_MOUNT$NC directories from the firmware image."
write_csv_log
"Extractor module"
"Original file"
"extracted file/dir"
"file counter"
"directory counter"
"further details"
write_csv_log
"EXT filesystem extractor"
"$EXT_PATH_"
"$EXTRACTION_DIR_"
"$FILES_EXT_MOUNT"
"$DIRS_EXT_MOUNT"
"NA"
umount
"$TMP_EXT_MOUNT"
|| true
fi
rm
-
r
"$TMP_EXT_MOUNT"
}
ubi_extractor() {
local UBI_PATH_
=
"${1:-}"
local EXTRACTION_DIR_
=
"${2:-}"
local UBI_FILE
=
""
local UBI_INFO
=
""
local UBI_1st_ROUND
=
""
local UBI_DATA
=
""
local DIRS_UBI_EXT
=
0
FILES_UBI_EXT
=
0
if
! [[
-
f
"$UBI_PATH_"
]]; then
print_output
"[-] No file for extraction provided"
return
fi
sub_module_title
"UBI filesystem extractor"
print_output
"[*] Extracts UBI firmware image $ORANGE$UBI_PATH_$NC with ${ORANGE}ubireader_extract_images$NC."
print_output
"[*] File details: $ORANGE$(file "
$UBI_PATH_
" | cut -d ':' -f2-)$NC"
# 提取ubi镜像
# 工具仓库:https://github.com/jrspruitt/ubi_reader
ubireader_extract_images
-
i
-
v
-
w
-
o
"$EXTRACTION_DIR_"
/
ubi_images
"$UBI_PATH_"
| tee
-
a
"$LOG_FILE"
|| true
FILES_UBI_EXT
=
$(find
"$EXTRACTION_DIR_"
/
ubi_images
-
type
f | wc
-
l)
DIRS_UBI_EXT
=
$(find
"$EXTRACTION_DIR_"
/
ubi_images
-
type
d | wc
-
l)
print_output
"[*] Extracted $ORANGE$FILES_UBI_EXT$NC files and $ORANGE$DIRS_UBI_EXT$NC directories from the firmware image via UBI extraction round 1."
print_output
"[*] Extracts UBI firmware image $ORANGE$UBI_PATH_$NC with ${ORANGE}ubireader_extract_files$NC."
ubireader_extract_files
-
i
-
v
-
w
-
o
"$EXTRACTION_DIR_"
/
ubi_files
"$UBI_PATH_"
| tee
-
a
"$LOG_FILE"
|| true
FILES_UBI_EXT
=
$(find
"$EXTRACTION_DIR_"
/
ubi_files
-
type
f | wc
-
l)
DIRS_UBI_EXT
=
$(find
"$EXTRACTION_DIR_"
/
ubi_files
-
type
d | wc
-
l)
print_output
"[*] Extracted $ORANGE$FILES_UBI_EXT$NC files and $ORANGE$DIRS_UBI_EXT$NC directories from the firmware image via UBI extraction round 2."
# 深度提取,继续查找UBI文件镜像,然后提取
if
[[
-
d
"$EXTRACTION_DIR_"
]]; then
mapfile
-
t UBI_1st_ROUND < <(find
"$EXTRACTION_DIR_"
-
type
f
-
exec
file
{} \; | grep
"UBI image"
|| true)
for
UBI_DATA
in
"${UBI_1st_ROUND[@]}"
; do
UBI_FILE
=
$(safe_echo
"$UBI_DATA"
| cut
-
d:
-
f1)
UBI_INFO
=
$(safe_echo
"$UBI_DATA"
| cut
-
d:
-
f2)
if
[[
"$UBI_INFO"
=
=
*
"UBIfs image"
*
]]; then
sub_module_title
"UBIfs deep extraction"
print_output
"[*] Extracts UBIfs firmware image $ORANGE$UBI_PATH_$NC with ${ORANGE}ubireader_extract_files$NC."
print_output
"[*] File details: $ORANGE$(file "
$UBI_FILE
" | cut -d ':' -f2-)$NC"
ubireader_extract_files
-
l
-
i
-
w
-
v
-
o
"$EXTRACTION_DIR_"
/
UBIfs_extracted
"$UBI_FILE"
| tee
-
a
"$LOG_FILE"
|| true
FILES_UBI_EXT
=
$(find
"$EXTRACTION_DIR_"
/
UBIfs_extracted
-
type
f | wc
-
l)
DIRS_UBI_EXT
=
$(find
"$EXTRACTION_DIR_"
/
UBIfs_extracted
-
type
d | wc
-
l)
print_output
"[*] Extracted $ORANGE$FILES_UBI_EXT$NC files and $ORANGE$DIRS_UBI_EXT$NC directories from the firmware image via UBI deep extraction."
fi
done
print_ln
FILES_UBI_EXT
=
$(find
"$EXTRACTION_DIR_"
-
type
f | wc
-
l)
DIRS_UBI_EXT
=
$(find
"$EXTRACTION_DIR_"
-
type
d | wc
-
l)
print_output
"[*] Extracted $ORANGE$FILES_UBI_EXT$NC files and $ORANGE$DIRS_UBI_EXT$NC directories from the firmware image."
write_csv_log
"Extractor module"
"Original file"
"extracted file/dir"
"file counter"
"directory counter"
"further details"
write_csv_log
"UBI filesystem extractor"
"$UBI_PATH_"
"$EXTRACTION_DIR_"
"$FILES_UBI_EXT"
"$DIRS_UBI_EXT"
"NA"
else
print_output
"[-] First round UBI extractor failed!"
fi
}
ubi_extractor() {
local UBI_PATH_
=
"${1:-}"
local EXTRACTION_DIR_
=
"${2:-}"
local UBI_FILE
=
""
local UBI_INFO
=
""
local UBI_1st_ROUND
=
""
local UBI_DATA
=
""
local DIRS_UBI_EXT
=
0
FILES_UBI_EXT
=
0
if
! [[
-
f
"$UBI_PATH_"
]]; then
print_output
"[-] No file for extraction provided"
return
fi
sub_module_title
"UBI filesystem extractor"
print_output
"[*] Extracts UBI firmware image $ORANGE$UBI_PATH_$NC with ${ORANGE}ubireader_extract_images$NC."
print_output
"[*] File details: $ORANGE$(file "
$UBI_PATH_
" | cut -d ':' -f2-)$NC"
# 提取ubi镜像
# 工具仓库:https://github.com/jrspruitt/ubi_reader
ubireader_extract_images
-
i
-
v
-
w
-
o
"$EXTRACTION_DIR_"
/
ubi_images
"$UBI_PATH_"
| tee
-
a
"$LOG_FILE"
|| true
FILES_UBI_EXT
=
$(find
"$EXTRACTION_DIR_"
/
ubi_images
-
type
f | wc
-
l)
DIRS_UBI_EXT
=
$(find
"$EXTRACTION_DIR_"
/
ubi_images
-
type
d | wc
-
l)
print_output
"[*] Extracted $ORANGE$FILES_UBI_EXT$NC files and $ORANGE$DIRS_UBI_EXT$NC directories from the firmware image via UBI extraction round 1."
print_output
"[*] Extracts UBI firmware image $ORANGE$UBI_PATH_$NC with ${ORANGE}ubireader_extract_files$NC."
ubireader_extract_files
-
i
-
v
-
w
-
o
"$EXTRACTION_DIR_"
/
ubi_files
"$UBI_PATH_"
| tee
-
a
"$LOG_FILE"
|| true
FILES_UBI_EXT
=
$(find
"$EXTRACTION_DIR_"
/
ubi_files
-
type
f | wc
-
l)
DIRS_UBI_EXT
=
$(find
"$EXTRACTION_DIR_"
/
ubi_files
-
type
d | wc
-
l)
print_output
"[*] Extracted $ORANGE$FILES_UBI_EXT$NC files and $ORANGE$DIRS_UBI_EXT$NC directories from the firmware image via UBI extraction round 2."
# 深度提取,继续查找UBI文件镜像,然后提取
if
[[
-
d
"$EXTRACTION_DIR_"
]]; then
mapfile
-
t UBI_1st_ROUND < <(find
"$EXTRACTION_DIR_"
-
type
f
-
exec
file
{} \; | grep
"UBI image"
|| true)
for
UBI_DATA
in
"${UBI_1st_ROUND[@]}"
; do
UBI_FILE
=
$(safe_echo
"$UBI_DATA"
| cut
-
d:
-
f1)
UBI_INFO
=
$(safe_echo
"$UBI_DATA"
| cut
-
d:
-
f2)
if
[[
"$UBI_INFO"
=
=
*
"UBIfs image"
*
]]; then
sub_module_title
"UBIfs deep extraction"
print_output
"[*] Extracts UBIfs firmware image $ORANGE$UBI_PATH_$NC with ${ORANGE}ubireader_extract_files$NC."
print_output
"[*] File details: $ORANGE$(file "
$UBI_FILE
" | cut -d ':' -f2-)$NC"
ubireader_extract_files
-
l
-
i
-
w
-
v
-
o
"$EXTRACTION_DIR_"
/
UBIfs_extracted
"$UBI_FILE"
| tee
-
a
"$LOG_FILE"
|| true
FILES_UBI_EXT
=
$(find
"$EXTRACTION_DIR_"
/
UBIfs_extracted
-
type
f | wc
-
l)
DIRS_UBI_EXT
=
$(find
"$EXTRACTION_DIR_"
/
UBIfs_extracted
-
type
d | wc
-
l)
print_output
"[*] Extracted $ORANGE$FILES_UBI_EXT$NC files and $ORANGE$DIRS_UBI_EXT$NC directories from the firmware image via UBI deep extraction."
fi
done
print_ln
FILES_UBI_EXT
=
$(find
"$EXTRACTION_DIR_"
-
type
f | wc
-
l)
DIRS_UBI_EXT
=
$(find
"$EXTRACTION_DIR_"
-
type
d | wc
-
l)
print_output
"[*] Extracted $ORANGE$FILES_UBI_EXT$NC files and $ORANGE$DIRS_UBI_EXT$NC directories from the firmware image."
write_csv_log
"Extractor module"
"Original file"
"extracted file/dir"
"file counter"
"directory counter"
"further details"
write_csv_log
"UBI filesystem extractor"
"$UBI_PATH_"
"$EXTRACTION_DIR_"
"$FILES_UBI_EXT"
"$DIRS_UBI_EXT"
"NA"
else
print_output
"[-] First round UBI extractor failed!"
fi
}
engenius_enc_extractor() {
local ENGENIUS_ENC_PATH_
=
"${1:-}"
local EXTRACTION_FILE_
=
"${2:-}"
if
! [[
-
f
"$ENGENIUS_ENC_PATH_"
]]; then
print_output
"[-] No file for decryption provided"
return
fi
sub_module_title
"EnGenius encrypted firmware extractor"
hexdump
-
C
"$ENGENIUS_ENC_PATH_"
| head | tee
-
a
"$LOG_FILE"
|| true
if
[[
-
f
"$EXT_DIR"
/
engenius
-
decrypt.py ]]; then
# 运行解密脚本
python3
"$EXT_DIR"
/
engenius
-
decrypt.py
"$ENGENIUS_ENC_PATH_"
>
"$EXTRACTION_FILE_"
else
print_output
"[-] Decryptor not found - check your installation"
fi
print_ln
if
[[
-
f
"$EXTRACTION_FILE_"
]]; then
print_output
"[+] Decrypted EnGenius firmware file to $ORANGE$EXTRACTION_FILE_$NC"
export FIRMWARE_PATH
=
"$EXTRACTION_FILE_"
MD5_DONE_DEEP
+
=
(
"$(md5sum "
$ENGENIUS_ENC_PATH_
" | awk '{print $1}')"
)
print_ln
print_output
"[*] Firmware file details: $ORANGE$(file "
$EXTRACTION_FILE_
")$NC"
write_csv_log
"Extractor module"
"Original file"
"extracted file/dir"
"file counter"
"directory counter"
"further details"
write_csv_log
"EnGenius decryptor"
"$ENGENIUS_ENC_PATH_"
"$EXTRACTION_FILE_"
"1"
"NA"
"NA"
if
[[
-
z
"${FW_VENDOR:-}"
]]; then
FW_VENDOR
=
"EnGenius"
backup_var
"FW_VENDOR"
"$FW_VENDOR"
fi
else
print_output
"[-] Decryption of EnGenius firmware file failed"
fi
}
engenius_enc_extractor() {
local ENGENIUS_ENC_PATH_
=
"${1:-}"
local EXTRACTION_FILE_
=
"${2:-}"
if
! [[
-
f
"$ENGENIUS_ENC_PATH_"
]]; then
print_output
"[-] No file for decryption provided"
return
fi
sub_module_title
"EnGenius encrypted firmware extractor"
hexdump
-
C
"$ENGENIUS_ENC_PATH_"
| head | tee
-
a
"$LOG_FILE"
|| true
if
[[
-
f
"$EXT_DIR"
/
engenius
-
decrypt.py ]]; then
# 运行解密脚本
python3
"$EXT_DIR"
/
engenius
-
decrypt.py
"$ENGENIUS_ENC_PATH_"
>
"$EXTRACTION_FILE_"
else
print_output
"[-] Decryptor not found - check your installation"
fi
print_ln
if
[[
-
f
"$EXTRACTION_FILE_"
]]; then
print_output
"[+] Decrypted EnGenius firmware file to $ORANGE$EXTRACTION_FILE_$NC"
export FIRMWARE_PATH
=
"$EXTRACTION_FILE_"
MD5_DONE_DEEP
+
=
(
"$(md5sum "
$ENGENIUS_ENC_PATH_
" | awk '{print $1}')"
)
print_ln
print_output
"[*] Firmware file details: $ORANGE$(file "
$EXTRACTION_FILE_
")$NC"
write_csv_log
"Extractor module"
"Original file"
"extracted file/dir"
"file counter"
"directory counter"
"further details"
write_csv_log
"EnGenius decryptor"
"$ENGENIUS_ENC_PATH_"
"$EXTRACTION_FILE_"
"1"
"NA"
"NA"
if
[[
-
z
"${FW_VENDOR:-}"
]]; then
FW_VENDOR
=
"EnGenius"
backup_var
"FW_VENDOR"
"$FW_VENDOR"
fi
else
print_output
"[-] Decryption of EnGenius firmware file failed"
fi
}
gpg_decompress_extractor() {
local GPG_FILE_PATH_
=
"${1:-}"
local EXTRACTION_FILE_
=
"${2:-}"
if
! [[
-
f
"$GPG_FILE_PATH_"
]]; then
print_output
"[-] No file for extraction provided"
return
fi
sub_module_title
"GPG compressed firmware extractor"
# 列出包列表并解密
gpg
-
-
list
-
packets
"$GPG_FILE_PATH_"
2
>
/
dev
/
null | tee
-
a
"$LOG_FILE"
gpg
-
-
decrypt
"$GPG_FILE_PATH_"
>
"$EXTRACTION_FILE_"
|| true
print_ln
if
[[
-
f
"$EXTRACTION_FILE_"
]]; then
print_output
"[+] Extracted GPG compressed firmware file to $ORANGE$EXTRACTION_FILE_$NC"
export FIRMWARE_PATH
=
"$EXTRACTION_FILE_"
backup_var
"FIRMWARE_PATH"
"$FIRMWARE_PATH"
print_ln
print_output
"[*] Firmware file details: $ORANGE$(file "
$EXTRACTION_FILE_
")$NC"
write_csv_log
"Extractor module"
"Original file"
"extracted file/dir"
"file counter"
"directory counter"
"further details"
write_csv_log
"GPG decompression"
"$GPG_FILE_PATH_"
"$EXTRACTION_FILE_"
"1"
"NA"
"NA"
else
print_output
"[-] Extraction of GPG compressed firmware file failed"
fi
}
gpg_decompress_extractor() {
local GPG_FILE_PATH_
=
"${1:-}"
local EXTRACTION_FILE_
=
"${2:-}"
if
! [[
-
f
"$GPG_FILE_PATH_"
]]; then
print_output
"[-] No file for extraction provided"
return
fi
sub_module_title
"GPG compressed firmware extractor"
# 列出包列表并解密
gpg
-
-
list
-
packets
"$GPG_FILE_PATH_"
2
>
/
dev
/
null | tee
-
a
"$LOG_FILE"
gpg
-
-
decrypt
"$GPG_FILE_PATH_"
>
"$EXTRACTION_FILE_"
|| true
print_ln
if
[[
-
f
"$EXTRACTION_FILE_"
]]; then
print_output
"[+] Extracted GPG compressed firmware file to $ORANGE$EXTRACTION_FILE_$NC"
export FIRMWARE_PATH
=
"$EXTRACTION_FILE_"
backup_var
"FIRMWARE_PATH"
"$FIRMWARE_PATH"
print_ln
print_output
"[*] Firmware file details: $ORANGE$(file "
$EXTRACTION_FILE_
")$NC"
write_csv_log
"Extractor module"
"Original file"
"extracted file/dir"
"file counter"
"directory counter"
"further details"
write_csv_log
"GPG decompression"
"$GPG_FILE_PATH_"
"$EXTRACTION_FILE_"
"1"
"NA"
"NA"
else
print_output
"[-] Extraction of GPG compressed firmware file failed"
fi
}
qnap_enc_extractor() {
local QNAP_ENC_PATH_
=
"${1:-}"
local EXTRACTION_FILE_
=
"${2:-}"
export QNAP
=
0
if
! [[
-
f
"$QNAP_ENC_PATH_"
]]; then
print_output
"[-] No file for decryption provided"
return
fi
sub_module_title
"QNAP encrypted firmware extractor"
hexdump
-
C
"$QNAP_ENC_PATH_"
| head | tee
-
a
"$LOG_FILE"
|| true
if
[[
-
f
"$EXT_DIR"
/
PC1 ]]; then
print_ln
print_output
"[*] Decrypting QNAP firmware with leaked key material ..."
print_ln
# 如果有PC1工具,则用PC1工具提取
"$EXT_DIR"
/
PC1 d QNAPNASVERSION4
"$QNAP_ENC_PATH_"
"$EXTRACTION_FILE_"
| tee
-
a
"$LOG_FILE"
else
print_output
"[-] QNAP decryptor not found - check your installation"
fi
print_ln
if
[[
-
f
"$EXTRACTION_FILE_"
&&
"$(file "
$EXTRACTION_FILE_
")"
=
=
*
"gzip compressed data"
*
]]; then
print_output
"[+] Decrypted QNAP firmware file to $ORANGE$EXTRACTION_FILE_$NC"
MD5_DONE_DEEP
+
=
(
"$(md5sum "
$QNAP_ENC_PATH_
" | awk '{print $1}')"
)
export FIRMWARE_PATH
=
"$EXTRACTION_FILE_"
backup_var
"FIRMWARE_PATH"
"$FIRMWARE_PATH"
# 如果提取出来是gzip文件,那再提取一次,使用下面的函数
export QNAP
=
1
print_ln
print_output
"[*] Firmware file details: $ORANGE$(file "
$EXTRACTION_FILE_
")$NC"
print_ln
write_csv_log
"Extractor module"
"Original file"
"extracted file/dir"
"file counter"
"directory counter"
"further details"
write_csv_log
"QNAP decryptor"
"$QNAP_ENC_PATH_"
"$EXTRACTION_FILE_"
"1"
"NA"
"gzip compressed data"
if
[[
-
z
"${FW_VENDOR:-}"
]]; then
FW_VENDOR
=
"QNAP"
backup_var
"FW_VENDOR"
"$FW_VENDOR"
fi
else
print_output
"[-] Decryption of QNAP firmware file failed"
fi
}
qnap_enc_extractor() {
local QNAP_ENC_PATH_
=
"${1:-}"
local EXTRACTION_FILE_
=
"${2:-}"
export QNAP
=
0
if
! [[
-
f
"$QNAP_ENC_PATH_"
]]; then
print_output
"[-] No file for decryption provided"
return
fi
sub_module_title
"QNAP encrypted firmware extractor"
hexdump
-
C
"$QNAP_ENC_PATH_"
| head | tee
-
a
"$LOG_FILE"
|| true
if
[[
-
f
"$EXT_DIR"
/
PC1 ]]; then
print_ln
print_output
"[*] Decrypting QNAP firmware with leaked key material ..."
print_ln
# 如果有PC1工具,则用PC1工具提取
"$EXT_DIR"
/
PC1 d QNAPNASVERSION4
"$QNAP_ENC_PATH_"
"$EXTRACTION_FILE_"
| tee
-
a
"$LOG_FILE"
else
print_output
"[-] QNAP decryptor not found - check your installation"
fi
print_ln
if
[[
-
f
"$EXTRACTION_FILE_"
&&
"$(file "
$EXTRACTION_FILE_
")"
=
=
*
"gzip compressed data"
*
]]; then
print_output
"[+] Decrypted QNAP firmware file to $ORANGE$EXTRACTION_FILE_$NC"
MD5_DONE_DEEP
+
=
(
"$(md5sum "
$QNAP_ENC_PATH_
" | awk '{print $1}')"
)
export FIRMWARE_PATH
=
"$EXTRACTION_FILE_"
backup_var
"FIRMWARE_PATH"
"$FIRMWARE_PATH"
# 如果提取出来是gzip文件,那再提取一次,使用下面的函数
export QNAP
=
1
print_ln
print_output
"[*] Firmware file details: $ORANGE$(file "
$EXTRACTION_FILE_
")$NC"
print_ln
write_csv_log
"Extractor module"
"Original file"
"extracted file/dir"
"file counter"
"directory counter"
"further details"
write_csv_log
"QNAP decryptor"
"$QNAP_ENC_PATH_"
"$EXTRACTION_FILE_"
"1"
"NA"
"gzip compressed data"
if
[[
-
z
"${FW_VENDOR:-}"
]]; then
FW_VENDOR
=
"QNAP"
backup_var
"FW_VENDOR"
"$FW_VENDOR"
fi
else
print_output
"[-] Decryption of QNAP firmware file failed"
fi
}
qnap_extractor() {
local DECRYPTED_FW_
=
"${1:-}"
if
! [[
-
f
"$DECRYPTED_FW_"
]]; then
return
fi
sub_module_title
"QNAP firmware extraction"
print_output
"[!] WARNING: This module is in an very early alpha state."
print_output
"[!] WARNING: Some areas of this module are not tested."
# This module is a full copy of https://github.com/max-boehm/qnap-utils/blob/master/extract_qnap_fw.sh
# some areas of this code are completely untested. Please report bugs via https://github.com/e-m-b-a/emba/issues
QNAP_EXTRACTION_ROOT
=
"$LOG_DIR"
/
firmware
/
qnap_extraction
QNAP_EXTRACTION_ROOT_DST
=
"$QNAP_EXTRACTION_ROOT"
/
root_filesystem
mkdir
-
p
"$QNAP_EXTRACTION_ROOT_DST"
|| true
if
file
"$DECRYPTED_FW_"
| grep
-
q
": gzip"
; then
print_output
"[*] Extracting $ORANGE$DECRYPTED_FW_$NC into $ORANGE$QNAP_EXTRACTION_ROOT$NC."
mkdir
-
p
"$QNAP_EXTRACTION_ROOT"
|| true
# 解压gzip文件
tar xvf
"$DECRYPTED_FW_"
-
C
"$QNAP_EXTRACTION_ROOT"
2
>
/
dev
/
null || true | tee
-
a
"$LOG_FILE"
print_ln
print_output
"[*] Extracted firmware structure ($ORANGE$QNAP_EXTRACTION_ROOT$NC):"
# 统计输出
find
"$QNAP_EXTRACTION_ROOT"
-
xdev
-
ls | tee
-
a
"$LOG_FILE"
print_files_dirs
print_bar ""
else
print_output
"[-] No QNAP firmware file found"
return
1
fi
UIMAGE
=
"$QNAP_EXTRACTION_ROOT/uImage"
# x31,x31+
UBI
=
"$QNAP_EXTRACTION_ROOT/rootfs2.ubi"
# x31,x31+
IMAGE
=
"$QNAP_EXTRACTION_ROOT_DST/image"
# initial ramdisk root filesystem
INITRAMFS
=
"$QNAP_EXTRACTION_ROOT_DST/initramfs"
# x31,x31+
INITRD
=
"$QNAP_EXTRACTION_ROOT/initrd.boot"
# x10,x12,x19,x20,x21
if
[ !
-
e
"$INITRD"
]; then
INITRD
=
"$QNAP_EXTRACTION_ROOT/initrd"
# x51,x53
fi
ROOTFS2
=
"$QNAP_EXTRACTION_ROOT/rootfs2.tgz"
ROOTFS2_BZ
=
"$QNAP_EXTRACTION_ROOT/rootfs2.bz"
ROOTFS2_IMG
=
"$QNAP_EXTRACTION_ROOT/rootfs2.img"
ROOTFS_EXT
=
"$QNAP_EXTRACTION_ROOT/rootfs_ext.tgz"
QPKG
=
"$QNAP_EXTRACTION_ROOT/qpkg.tar"
if
[
-
e
"$UBI"
]; then
ROOTFS2
=
"$QNAP_EXTRACTION_ROOT_DST/rootfs2.tgz"
ROOTFS_EXT
=
"$QNAP_EXTRACTION_ROOT_DST/rootfs_ext.tgz"
QPKG
=
"$QNAP_EXTRACTION_ROOT_DST/qpkg.tar"
fi
SYSROOT
=
"$QNAP_EXTRACTION_ROOT_DST/sysroot"
mkdir
"$SYSROOT"
if
[
-
e
"$UIMAGE"
]; then
print_ln
print_output
"[*] Scanning $ORANGE$UIMAGE$NC for (gzipped) parts..."
# 识别是否为gzip文件,并定位到首次出现gzip文件头的偏移,用于后面的dd命令
a
=
$(od
-
t x1
-
w4
-
Ad
-
v
"$UIMAGE"
| grep
'1f 8b 08 00'
| awk
'{print $1}'
)
if
[
-
n
"$a"
]; then
# 按照块大小(block size) $a 跳过第一个块,然后将其余的内容复制到输出文件(output file) $IMAGE.gz 中
dd
if
=
"$UIMAGE"
bs
=
"$a"
skip
=
1
of
=
"$IMAGE.gz"
status
=
none
# 解压
gunzip
-
-
quiet
"$IMAGE.gz"
|| [ $?
-
eq
2
]
print_output
"[+] Extracted and uncompressed $ORANGE$IMAGE$NC at offset $ORANGE$a$NC"
i
=
0
for
a
in
$(od
-
t x1
-
w4
-
Ad
-
v
"$IMAGE"
| grep
'1f 8b 08 00'
| awk
'{print $1}'
); do
i
=
$((i
+
1
))
# 再识别IMAGE文件里的所有gzip文件,分别提取所有部分
dd
if
=
"$IMAGE"
bs
=
"$a"
skip
=
1
of
=
"$IMAGE.part$i.gz"
status
=
none
gunzip
-
-
quiet
"$IMAGE.part$i.gz"
|| [ $?
-
eq
2
]
print_output
"[+] Extracted and uncompressed '$IMAGE.part$i' at offset $a"
done
if
[ $i
-
gt
0
]; then
mv
"$IMAGE.part$i"
"$INITRAMFS"
|| true
print_output
"[*] Renamed $ORANGE$IMAGE.part$i$NC to $ORANGE$INITRAMFS$NC"
rm
"$IMAGE"
|| true
fi
fi
print_files_dirs
print_bar ""
fi
if
[
-
e
"$UBI"
]; then
# rootfs2.ubi
print_ln
print_output
"[*] Unpacking $ORANGE$UBI$NC."
# TODO: we should evaluate moving to the EMBA UBI extractor in the future
# see http://trac.gateworks.com/wiki/linux/ubi
#
# apt-get install mtd-utils
# 256MB flash
modprobe
-
r nandsim || true
if
[
-
e
/
dev
/
mtdblock0 ]; then
print_output
"[-] /dev/mtdblock0 does already exist! Exiting to not overwrite it."
; exit
fi
modprobe nandsim first_id_byte
=
0x2c
second_id_byte
=
0xda
third_id_byte
=
0x90
fourth_id_byte
=
0x95
print_output
"[*] Copy UBI image into simulated flash device"
# populate NAND with an existing ubi:
modprobe mtdblock
dd
if
=
"$UBI"
of
=
/
dev
/
mtdblock0 bs
=
2048
status
=
none
print_output
"[*] Attach simulated flash device"
# attach ubi
modprobe ubi
ubiattach
/
dev
/
ubi_ctrl
-
m0
-
O2048
# ubinfo -a
print_output
"[*] Mounting ubifs file system"
# mount the ubifs to host
modprobe ubifs
local TMP_EXT_MOUNT
=
"$TMP_DIR"
"/ext_mount_$RANDOM"
mkdir
-
p
"$TMP_EXT_MOUNT"
|| true
mount
-
t ubifs ubi0
"$TMP_EXT_MOUNT"
if
mount | grep
-
q ext_mount; then
print_output
"[*] Copying contents from UBI mount"
cp
-
a
"$TMP_EXT_MOUNT"
/
boot
/
*
"$QNAP_EXTRACTION_ROOT_DST"
|| true
print_ln
print_output
"[*] Extracted firmware structure ($ORANGE$QNAP_EXTRACTION_ROOT_DST$NC):"
find
"$QNAP_EXTRACTION_ROOT_DST"
-
xdev
-
ls | tee
-
a
"$LOG_FILE"
print_output
"[*] UBI cleanup"
umount
"$TMP_EXT_MOUNT"
else
print_output
"[-] Something went wrong!"
fi
rm
-
r
"$TMP_EXT_MOUNT"
|| true
ubidetach
/
dev
/
ubi_ctrl
-
m0
modprobe
-
r nandsim
print_files_dirs
print_bar ""
fi
# 提取初始内存文件系统
if
[
-
e
"$INITRAMFS"
]; then
print_ln
print_output
"[*] Extracting $ORANGE$INITRAMFS$NC."
(cd
"$SYSROOT"
&& (cpio
-
i
-
-
make
-
directories||true) ) <
"$INITRAMFS"
print_ln
print_output
"[*] Extracted firmware structure ($ORANGE$SYSROOT$NC):"
find
"$SYSROOT"
-
xdev
-
ls | tee
-
a
"$LOG_FILE"
print_files_dirs
print_bar ""
fi
if
[
-
e
"$INITRD"
]; then
print_ln
# 如果是lzma压缩文件,则解压
if
file
"$INITRD"
| grep
-
q LZMA ; then
print_output
"[*] Extracting $ORANGE$INITRD$NC (LZMA)."
lzma
-
d <
"$INITRD"
| (cd
"$SYSROOT"
&& (cpio
-
i
-
-
make
-
directories||true) )
print_ln
print_output
"[*] Extracted firmware structure ($ORANGE$SYSROOT$NC):"
find
"$SYSROOT"
-
xdev
-
ls | tee
-
a
"$LOG_FILE"
print_files_dirs
print_bar ""
fi
# 如果是gzip,则解压
if
file
"$INITRD"
| grep
-
q gzip ; then
print_ln
print_output
"[*] Extracting $ORANGE$INITRD$NC (gzip)."
gzip
-
d <
"$INITRD"
>
"$QNAP_EXTRACTION_ROOT_DST/initrd.$$"
print_output
"[*] Mounting $ORANGE$INITRD$NC."
local TMP_EXT_MOUNT
=
"$TMP_DIR"
"/ext_mount_$RANDOM"
mkdir
-
p
"$TMP_EXT_MOUNT"
|| true
mount
-
t ext2
"$QNAP_EXTRACTION_ROOT_DST/initrd.$$"
"$TMP_EXT_MOUNT"
-
oro,loop
if
mount | grep
-
q ext_mount; then
cp
-
a
"$TMP_EXT_MOUNT"
/
*
"$SYSROOT"
|| true
umount
"$TMP_EXT_MOUNT"
print_ln
print_output
"[*] Extracted firmware structure ($ORANGE$SYSROOT$NC):"
find
"$SYSROOT"
-
xdev
-
ls | tee
-
a
"$LOG_FILE"
rm
"$QNAP_EXTRACTION_ROOT_DST/initrd.$$"
|| true
else
print_output
"[-] Something went wrong!"
fi
rm
-
r
"$TMP_EXT_MOUNT"
|| true
print_files_dirs
print_bar ""
fi
fi
# 用tar解压
if
[
-
e
"$ROOTFS2"
]; then
print_ln
print_output
"[*] Extracting $ORANGE$ROOTFS2$NC (gzip, tar)."
tar
-
xvzf
"$ROOTFS2"
-
C
"$SYSROOT"
print_ln
print_output
"[*] Extracted firmware structure ($ORANGE$SYSROOT$NC):"
find
"$SYSROOT"
-
xdev
-
ls | tee
-
a
"$LOG_FILE"
print_files_dirs
print_bar ""
fi
# 用lzma解压
if
[
-
e
"$ROOTFS2_BZ"
]; then
print_ln
if
file
"$ROOTFS2_BZ"
| grep
-
q
"LZMA"
; then
print_output
"[*] Extracting $ORANGE$ROOTFS2_BZ$NC (LZMA)."
lzma
-
d <
"$ROOTFS2_BZ"
| (cd
"$SYSROOT"
&& (cpio
-
i
-
-
make
-
directories||true) )
else
print_output
"[*] Extracting $ORANGE$ROOTFS2_BZ$NC (bzip2, tar)."
tar
-
xvjf
"$ROOTFS2_BZ"
-
C
"$SYSROOT"
fi
print_ln
print_output
"[*] Extracted firmware structure ($ORANGE$SYSROOT$NC):"
find
"$SYSROOT"
-
xdev
-
ls | tee
-
a
"$LOG_FILE"
print_files_dirs
print_bar ""
fi
if
[
-
f
"$ROOTFS2_IMG"
]; then
print_ln
print_output
"[*] Extracting $ORANGE$ROOTFS2_IMG$NC (ext2)..."
local TMP_EXT_MOUNT
=
"$TMP_DIR"
"/ext_mount_$RANDOM"
mkdir
-
p
"$TMP_EXT_MOUNT"
|| true
mount
-
t ext2
"$ROOTFS2_IMG"
"$TMP_EXT_MOUNT"
-
oro,loop
if
mount | grep
-
q ext_mount; then
# 挂载ROOTFS2_IMG,然后解压里面的rootfs2.bz
tar
-
xvjf
"$TMP_EXT_MOUNT"
/
rootfs2.bz
-
C
"$SYSROOT"
print_ln
print_output
"[*] Extracted firmware structure ($ORANGE$SYSROOT$NC):"
find
"$SYSROOT"
-
xdev
-
ls | tee
-
a
"$LOG_FILE"
umount
"$TMP_EXT_MOUNT"
else
print_output
"[-] Something went wrong!"
fi
rm
-
r
"$TMP_EXT_MOUNT"
|| true
print_files_dirs
print_bar ""
fi
if
[
-
e
"$ROOTFS_EXT"
]; then
print_ln
print_output
"[*] Extracting EXT filesystem $ORANGE$ROOTFS_EXT$NC."
# tar解压ext根文件系统
tar xzvf
"$ROOTFS_EXT"
-
C
"$QNAP_EXTRACTION_ROOT_DST"
print_output
"[*] Mounting EXT filesystem $ORANGE$ROOTFS_EXT$NC."
local TMP_EXT_MOUNT
=
"$TMP_DIR"
"/ext_mount_$RANDOM"
mkdir
-
p
"$TMP_EXT_MOUNT"
|| true
# 挂载ext根文件系统,然后复制出根文件系统下的所有文件
mount
"$QNAP_EXTRACTION_ROOT_DST"
/
rootfs_ext.img
"$TMP_EXT_MOUNT"
-
oro,loop
if
mount | grep
-
q ext_mount; then
cp
-
a
"$TMP_EXT_MOUNT"
/
*
"$SYSROOT"
|| true
umount
"$TMP_EXT_MOUNT"
fi
print_output
"[*] Removing EXT filesystem ${ORANGE}rootfs_ext.img$NC."
rm
"$QNAP_EXTRACTION_ROOT_DST"
/
rootfs_ext.img || true
rm
-
r
"$TMP_EXT_MOUNT"
|| true
print_ln
print_output
"[*] Extracted firmware structure ($ORANGE$SYSROOT$NC):"
find
"$SYSROOT"
-
xdev
-
ls | tee
-
a
"$LOG_FILE"
print_files_dirs
print_bar ""
fi
# 查找根文件系统/opt/source下的所有tgz文件并解压到/usr/local下
USR_LOCAL
=
$(find
"$SYSROOT/opt/source"
-
name
"*.tgz"
2
>
/
dev
/
null)
# if [[ "${#USR_LOCAL[@]}" -gt 0 ]]; then
if
[[
-
v USR_LOCAL[@] ]]; then
print_ln
for
f
in
"${USR_LOCAL[@]}"
; do
print_output
"[*] Extracting $ORANGE$f$NC -> ${ORANGE}sysroot/usr/local$NC ..."
mkdir
-
p
"$SYSROOT/usr/local"
|| true
tar xvzf
"$f"
-
C
"$SYSROOT/usr/local"
done
print_files_dirs
print_bar ""
fi
# "$QNAP_EXTRACTION_ROOT/qpkg.tar"
if
[
-
e
"$QPKG"
]; then
print_ln
print_output
"[*] Extracting $ORANGE$QPKG$NC."
mkdir
-
p
"$QNAP_EXTRACTION_ROOT_DST/qpkg"
|| true
# 解压
tar xvf
"$QPKG"
-
C
"$QNAP_EXTRACTION_ROOT_DST/qpkg"
# 从解压出来的文件夹里继续搜tgz解压
for
f
in
"$QNAP_EXTRACTION_ROOT_DST"
/
qpkg
/
*
.tgz; do
if
file
"$f"
| grep
-
q gzip; then
print_output
"[*] Extracting QPKG $ORANGE$f$NC."
tar tvzf
"$f"
>
"$f"
.txt
fi
done
print_files_dirs
print_bar ""
fi
# 解压出一些服务的tgz
for
name
in
apache_php5 mysql5 mariadb5; do
if
[
-
e
"$QNAP_EXTRACTION_ROOT_DST/qpkg/$name.tgz"
]; then
print_output
"[*] Extracting ${ORANGE}qpkg/$name.tgz$NC -> ${ORANGE}sysroot/usr/local$NC ..."
tar xvzf
"$QNAP_EXTRACTION_ROOT_DST/qpkg/$name.tgz"
-
C
"$SYSROOT/usr/local"
fi
done
# Boost C++库解压到$SYSROOT/usr/lib下
if
[
-
e
"$QNAP_EXTRACTION_ROOT_DST"
/
qpkg
/
libboost.tgz ]; then
print_ln
print_output
"[*] Extracting ${ORANGE}qpkg/libboost.tgz$NC -> ${ORANGE}sysroot/usr/lib$NC."
mkdir
-
p
"$SYSROOT/usr/lib"
|| true
tar xvzf
"$QNAP_EXTRACTION_ROOT_DST"
/
qpkg
/
libboost.tgz
-
C
"$SYSROOT/usr/lib"
elif
[
-
e
"$QNAP_EXTRACTION_ROOT_DST"
/
qpkg
/
DSv3.tgz ]; then
print_output
"[*] Extracting ${ORANGE}libboost$NC from ${ORANGE}qpkg/DSv3.tgz$NC -> ${ORANGE}sysroot/usr/lib$NC."
tar tzf
"$QNAP_EXTRACTION_ROOT_DST"
/
qpkg
/
DSv3.tgz |grep libboost | tar xzf
"$QNAP_EXTRACTION_ROOT_DST"
/
qpkg
/
DSv3.tgz
-
C
"$SYSROOT"
-
T
-
fi
if
[[
-
d
"$SYSROOT"
/
usr
/
lib ]]; then
HOME_DIR
=
"$(pwd)"
# 创建软链接
(cd
"$SYSROOT/usr/lib"
|| exit;
for
f
in
libboost
*
.so.
1.42
.
0
; do ln
-
s
"$f"
"${f%.1.42.0}"
; done)
cd
"$HOME_DIR"
|| exit
fi
print_files_dirs
print_bar ""
}
qnap_extractor() {
local DECRYPTED_FW_
=
"${1:-}"
if
! [[
-
f
"$DECRYPTED_FW_"
]]; then
return
fi
sub_module_title
"QNAP firmware extraction"
print_output
"[!] WARNING: This module is in an very early alpha state."
print_output
"[!] WARNING: Some areas of this module are not tested."
# This module is a full copy of https://github.com/max-boehm/qnap-utils/blob/master/extract_qnap_fw.sh
# some areas of this code are completely untested. Please report bugs via https://github.com/e-m-b-a/emba/issues
QNAP_EXTRACTION_ROOT
=
"$LOG_DIR"
/
firmware
/
qnap_extraction
QNAP_EXTRACTION_ROOT_DST
=
"$QNAP_EXTRACTION_ROOT"
/
root_filesystem
mkdir
-
p
"$QNAP_EXTRACTION_ROOT_DST"
|| true
if
file
"$DECRYPTED_FW_"
| grep
-
q
": gzip"
; then
print_output
"[*] Extracting $ORANGE$DECRYPTED_FW_$NC into $ORANGE$QNAP_EXTRACTION_ROOT$NC."
mkdir
-
p
"$QNAP_EXTRACTION_ROOT"
|| true
# 解压gzip文件
tar xvf
"$DECRYPTED_FW_"
-
C
"$QNAP_EXTRACTION_ROOT"
2
>
/
dev
/
null || true | tee
-
a
"$LOG_FILE"
print_ln
print_output
"[*] Extracted firmware structure ($ORANGE$QNAP_EXTRACTION_ROOT$NC):"
# 统计输出
find
"$QNAP_EXTRACTION_ROOT"
-
xdev
-
ls | tee
-
a
"$LOG_FILE"
print_files_dirs
print_bar ""
else
print_output
"[-] No QNAP firmware file found"
return
1
fi
UIMAGE
=
"$QNAP_EXTRACTION_ROOT/uImage"
# x31,x31+
UBI
=
"$QNAP_EXTRACTION_ROOT/rootfs2.ubi"
# x31,x31+
IMAGE
=
"$QNAP_EXTRACTION_ROOT_DST/image"
# initial ramdisk root filesystem
INITRAMFS
=
"$QNAP_EXTRACTION_ROOT_DST/initramfs"
# x31,x31+
INITRD
=
"$QNAP_EXTRACTION_ROOT/initrd.boot"
# x10,x12,x19,x20,x21
if
[ !
-
e
"$INITRD"
]; then
INITRD
=
"$QNAP_EXTRACTION_ROOT/initrd"
# x51,x53
fi
ROOTFS2
=
"$QNAP_EXTRACTION_ROOT/rootfs2.tgz"
ROOTFS2_BZ
=
"$QNAP_EXTRACTION_ROOT/rootfs2.bz"
ROOTFS2_IMG
=
"$QNAP_EXTRACTION_ROOT/rootfs2.img"
ROOTFS_EXT
=
"$QNAP_EXTRACTION_ROOT/rootfs_ext.tgz"
QPKG
=
"$QNAP_EXTRACTION_ROOT/qpkg.tar"
if
[
-
e
"$UBI"
]; then
ROOTFS2
=
"$QNAP_EXTRACTION_ROOT_DST/rootfs2.tgz"
ROOTFS_EXT
=
"$QNAP_EXTRACTION_ROOT_DST/rootfs_ext.tgz"
QPKG
=
"$QNAP_EXTRACTION_ROOT_DST/qpkg.tar"
fi
SYSROOT
=
"$QNAP_EXTRACTION_ROOT_DST/sysroot"
mkdir
"$SYSROOT"
if
[
-
e
"$UIMAGE"
]; then
print_ln
print_output
"[*] Scanning $ORANGE$UIMAGE$NC for (gzipped) parts..."
# 识别是否为gzip文件,并定位到首次出现gzip文件头的偏移,用于后面的dd命令
a
=
$(od
-
t x1
-
w4
-
Ad
-
v
"$UIMAGE"
| grep
'1f 8b 08 00'
| awk
'{print $1}'
)
if
[
-
n
"$a"
]; then
# 按照块大小(block size) $a 跳过第一个块,然后将其余的内容复制到输出文件(output file) $IMAGE.gz 中
dd
if
=
"$UIMAGE"
bs
=
"$a"
skip
=
1
of
=
"$IMAGE.gz"
status
=
none
# 解压
gunzip
-
-
quiet
"$IMAGE.gz"
|| [ $?
-
eq
2
]
print_output
"[+] Extracted and uncompressed $ORANGE$IMAGE$NC at offset $ORANGE$a$NC"
i
=
0
for
a
in
$(od
-
t x1
-
w4
-
Ad
-
v
"$IMAGE"
| grep
'1f 8b 08 00'
| awk
'{print $1}'
); do
i
=
$((i
+
1
))
# 再识别IMAGE文件里的所有gzip文件,分别提取所有部分
dd
if
=
"$IMAGE"
bs
=
"$a"
skip
=
1
of
=
"$IMAGE.part$i.gz"
status
=
none
gunzip
-
-
quiet
"$IMAGE.part$i.gz"
|| [ $?
-
eq
2
]
print_output
"[+] Extracted and uncompressed '$IMAGE.part$i' at offset $a"
赞赏
- [原创]某相安全平台jar加密逆向 10623
- [原创]MC禁止多人游戏引发的破解 17971
- [分享]arm汇编初探 6943
- [原创]AWD竞赛从0到1 8747
- [原创]EMBA安装、使用与源代码分析_0 25283