Upgrade to Pro — share decks privately, control downloads, hide ads and more …

從零開始的_IoT___Router_之旅.pdf

Sponsored · Your Podcast. Everywhere. Effortlessly. Share. Educate. Inspire. Entertain. You do you. We'll handle the rest. →
Avatar for 許貽昇 許貽昇
March 14, 2025

 從零開始的_IoT___Router_之旅.pdf

Avatar for 許貽昇

許貽昇

March 14, 2025

Other Decks in Education

Transcript

  1. $Whoami Eason / Easoncoolboy • 台北科技大學 is1ab • 奧義智慧科技 資安實習研究員

    • Red team LLM / Vulnerability Discovery • CTF Pwn 我是誰 ??? ★ Gmail: [email protected] ★ Discord: eason8912004
  2. $ LINK • My Pwn notes Share Projects • Firmware

    and patched httpd https://drive.google.com/drive/folders/1Yd9M0l_j4HOlEkCoGQE QLOVSKYqltOYs?usp=drive_link
  3. $ Table of Content • Basic Pwn • IoT Security

    • Firmware Simulation • Analyze Firmware • Attack
  4. $ IoT Not Security? • 掃地機器人 • 寵物攝影機 • Router

    • NAS • Printer LINK LINK LINK LINK We will reproduce!!!!!
  5. $ Why IoT Not Security? • 效率 > 安全 •

    用 C 寫,但開發不好 • 架構不支援保護機制 (MIPS NO NX) • 開發者 backdoor • 串接第三方庫時寫爛 • 沒再更新 Firmware
  6. $ Why Router Is My Target ? • 因為好打 (

    ? • 基本上每間企業一定都會有 • 拿來當肉雞或跳板 • 通常都是同一型號,打下一台等於很多台 • 挖礦 • 勒索
  7. gdb-multiarch $ Reverse & debugger • IDA pro 9.0 beta

    自己手搓 ( Linux 版) • Pwndbg • Pwngdb
  8. $ Reverse & debugger • IDA pro 9.0 beta 自己手搓

    ( Linux 版) • Pwndbg • Pwngdb gdb-multiarch
  9. $ Extract Firmware ➔ binwalk -e US_AC15V1.0BR_V15.03.05.19_multi_TD01.bin OR ➔ binwalk

    -Me US_AC15V1.0BR_V15.03.05.19_multi_TD01.bin Binwalk 會掃描韌體映像檔,辨別不同的類型和結構。 例如 : SquashFS、uImage、zImage、TRX header。
  10. $ Extract Firmware ➔ binwalk -e US_AC15V1.0BR_V15.03.05.19_multi_TD01.bin OR ➔ binwalk

    -Me US_AC15V1.0BR_V15.03.05.19_multi_TD01.bin 解包失敗可以先裝這個 : https://github.com/devttys0/sasquatch
  11. $ Extract Firmware ➔ binwalk -e US_AC15V1.0BR_V15.03.05.19_multi_TD01.bin OR ➔ binwalk

    -Me US_AC15V1.0BR_V15.03.05.19_multi_TD01.bin 解包失敗可以先裝這個 : https://github.com/devttys0/sasquatch fix.txt : https://gist.github.com/0rphon/8e7ae101ab2a2d08eaab2a226aa8e90c
  12. $ Emulate Firmware ➔ sudo cp $(which qemu-arm-static) ./ ➔

    mv qemu-arm-static qemu ➔ sudo chroot ./ ./qemu ./bin/httpd
  13. $ Emulate Firmware ➔ sudo cp $(which qemu-arm-static) ./ ➔

    mv qemu-arm-static qemu ➔ sudo chroot ./ ./qemu ./bin/httpd 好像卡住了...
  14. $ Patched httpd - Part 1 • “ Ctrl +

    F ” search “ WeLoveLinux ”
  15. x64 (64-bit) Calling Convention : Windows : (整數) RCX RDX

    R8 R9 Linux、macOS : (整數) RDI RSI RDX RCX R8 R9 返回值 : 整數或指標通常儲存在 RAX。
  16. x64 (64-bit) Calling Convention : Windows : (整數) RCX RDX

    R8 R9 Linux、macOS : (整數) RDI RSI RDX RCX R8 R9 返回值 : 整數或指標通常儲存在 RAX。 AArch32 (ARM 32-bit) Calling Convention :
  17. x64 (64-bit) Calling Convention : Windows : (整數) RCX RDX

    R8 R9 Linux、macOS : (整數) RDI RSI RDX RCX R8 R9 返回值 : 整數或指標通常儲存在 RAX。 AArch32 (ARM 32-bit) Calling Convention : 傳遞順序 : (整數) R0 R1 R2 R3 返回值 : 儲存在 R0。
  18. x64 (64-bit) Calling Convention : Windows : (整數) RCX RDX

    R8 R9 Linux、macOS : (整數) RDI RSI RDX RCX R8 R9 返回值 : 整數或指標通常儲存在 RAX。 AArch32 (ARM 32-bit) Calling Convention : 傳遞順序 : (整數) R0 R1 R2 R3 返回值 : 儲存在 R0。 AArch64 (ARM 64-bit) Calling Convention :
  19. x64 (64-bit) Calling Convention : Windows : (整數) RCX RDX

    R8 R9 Linux、macOS : (整數) RDI RSI RDX RCX R8 R9 返回值 : 整數或指標通常儲存在 RAX。 AArch32 (ARM 32-bit) Calling Convention : 傳遞順序 : (整數) R0 R1 R2 R3 返回值 : 儲存在 R0。 AArch64 (ARM 64-bit) Calling Convention : 傳遞順序 : (整數) X0 X1 X2 X3 X4 X5 X6 X7 返回值 : 整數或指標儲存在 X0。
  20. x64 (64-bit) Calling Convention : Windows : (整數) RCX Linux、macOS

    : (整數) 返回值 : 整數或指標通常儲存在 RAX。 AArch32 (ARM 32-bit) Calling Convention : 傳遞順序 : (整數) R0 R1 R2 R3 返回值 : 儲存在 R0。 AArch64 (ARM 64-bit) Calling Convention : 傳遞順序 : (整數) X0 X7 返回值 : 整數或指標儲存在 X0。
  21. $ Patched httpd - Part 1 • check_network() return value

    is R0 • MOV R3, R0 and then CMP R3, #0 • BGT ( Branch if Greater Than )
  22. $ Patched httpd - Part 1 MOV R3,R0 MOV R3,#1

    • check_network() return value is R0 • MOV R3, R0 and then CMP R3, #0 • BGT ( Branch if Greater Than )
  23. $ Patched httpd - Part 1 • check_network() return value

    is R0 • MOV R3, R0 and then CMP R3, #0 • BGT ( Branch if Greater Than ) MOV R3,R0 ( 0030a0e1 ) MOV R3,#1 ( 0130A0E3 )
  24. • ConnectCfm() return value is R0 • MOV R3, R0

    and then CMP R3, #0 • BNE ( Branch if Not Equal ) 如果不是 0 就走右邊。 $ Patched httpd - Part 2
  25. • ConnectCfm() return value is R0 • MOV R3, R0

    and then CMP R3, #0 • BNE ( Branch if Not Equal ) 如果不是 0 就走右邊。 $ Patched httpd - Part 2 MOV R3,R0 ( 0030a0e1 ) MOV R3,#1 ( ? )
  26. • ConnectCfm() return value is R0 • MOV R3, R0

    and then CMP R3, #0 • BNE ( Branch if Not Equal ) 如果不是 0 就走右邊。 $ Patched httpd - Part 2 MOV R3,R0 ( 0030a0e1 ) MOV R3,#1 (0130A0E3 )
  27. $ Network Problem • “ Ctrl + F ” Search

    “ httpd listen ip = ” • In sub_1B84C
  28. $ Network Problem • “ Ctrl + F ” Search

    “ httpd listen ip = ” • In sub_1B84C
  29. $ Network Problem • “ Ctrl + F ” Search

    “ httpd listen ip = ” • In sub_1B84C • v8 is s.sa_data[2]
  30. $ Network Problem 跟 g_lan_ip 有關 : • s •

    v19 • v16 • getIfIp() • LanIfName = getLanIfName()
  31. $ Network Problem 跟 g_lan_ip 有關 : • s (

    array ) • v19 ( array ) • v16 ( array ) • getIfIp() • LanIfName = getLanIfName()
  32. $ Network Problem 跟 g_lan_ip 有關 : • s (

    array ) • v19 ( array ) • v16 ( array ) • getIfIp() • LanIfName = getLanIfName()
  33. • Search getLanIfName() • libtpi.so and libcommon.so ➔ grep -rn

    getLanIfName $ Network Problem ( search getLanIfName() in lib )
  34. • libtpi.so and libcommon.so ➔ grep -rn getLanIfName • Search

    getLanIfName() $ Network Problem ( search getLanIfName() in lib )
  35. • Search getLanIfName() in libcommon.so $ Network Problem ( search

    getLanIfName() in libcommon.so ) Important !!!
  36. $ Network Problem ( search getLanIfName() in libcommon.so ) Important

    !!! • Search getLanIfName() in libcommon.so
  37. • Search get_eth_name() $ Network Problem ( search get_eth_name() in

    lib ) ➔ grep –rn get_eth_name • libtpi.so and libChipApi.so and libcommon.so
  38. • Search get_eth_name() $ Network Problem ( search get_eth_name() in

    lib ) ➔ grep –rn get_eth_name • libtpi.so and libChipApi.so and libcommon.so
  39. • Search get_eth_name() $ Network Problem ( search get_eth_name() in

    lib ) ➔ grep –rn get_eth_name • libtpi.so and libChipApi.so and libcommon.so
  40. $ Network Problem 跟 g_lan_ip 有關 : • s (

    array ) • v19 ( array ) • v16 ( array ) • getIfIp() • LanIfName = getLanIfName() = br0
  41. $ Network Problem ( getIfIp() in libcommon.so ) • getIfIp()

    Ioctl ( fd , 0x8915u , dest ) I/O 控制系統調用 作用是向設備驅動程式發送控制命令 ioctl() 會返回一個整數,表示操作的結果
  42. $ Network Problem ( getIfIp() in libcommon.so ) • getIfIp()

    Ioctl ( fd , 0x8915u , dest ) I/O 控制系統調用 作用是向設備驅動程式發送控制命令 ioctl() 會返回一個整數,表示操作的結果 ( SIOCGIFADDR ) 請求碼
  43. $ Network Problem Ioctl ( int fd, int request, (char*)

    argstruct ) socket (AF_INET, SOCK_DGRAM, 0) 創建一個 IPv4 的 UDP socket
  44. $ Network Problem Ioctl ( int fd, int request, (char*)

    argstruct ) 0x8915 socket (AF_INET, SOCK_DGRAM, 0) 創建一個 IPv4 的 UDP socket
  45. $ Network Problem Ioctl ( int fd, int request, (char*)

    argstruct ) 0x8915 Search <linux/sockios.h> socket (AF_INET, SOCK_DGRAM, 0) 創建一個 IPv4 的 UDP socket
  46. $ Network Problem Ioctl ( int fd, int request, (char*)

    argstruct ) 0x8915 ➔ Subl /usr/include/linux/sockios.h Search <linux/sockios.h> socket (AF_INET, SOCK_DGRAM, 0) 創建一個 IPv4 的 UDP socket
  47. $ Network Problem Ioctl ( int fd, int request, (char*)

    argstruct ) 0x8915 dest Search <linux/sockios.h> ➔ Subl /usr/include/linux/sockios.h socket (AF_INET, SOCK_DGRAM, 0) 創建一個 IPv4 的 UDP socket
  48. $ Network Problem Ioctl ( int fd, int request, (char*)

    argstruct ) 0x8915 dest (br0) Search <linux/sockios.h> ➔ Subl /usr/include/linux/sockios.h socket (AF_INET, SOCK_DGRAM, 0) 創建一個 IPv4 的 UDP socket
  49. 跟 g_lan_ip 有關 : • s ( array ) •

    v19 ( array ) • v16 ( array ) • getIfIp() -> get IP address • LanifName = getLanIfName() = br0 $ Network Problem
  50. ➔ sudo apt install net-tools ➔ sudo apt install uml-utilities

    bridge-utils ➔ sudo brctl addbr br0 ➔ sudo brctl addif br0 ens33 ➔ sudo ifconfig br0 up ➔ sudo dhclient br0 $ Network Problem 結論 : • 來自 br0 網卡 • 建一張 br0 網卡
  51. $ Symbolic link Problem ➔ rm -rf webroot ➔ sudo

    ln -s webroot_ro/ webroot • Code 是透過 symbolic link 找到 html resource • symbolic link 爛了
  52. $ Debug environment • 用 gdb-multiarch 可以去 debug 不同架構的 binary

    ➔ sudo apt install gdb-multiarch • 用 qemu 模擬時,開一個 port 作為 gdb server,連上去 ➔ sudo chroot ./ ./qemu -g 30000 ./bin/httpd
  53. $ Debug environment • 用 gdb-multiarch 可以去 debug 不同架構的 binary

    ➔ sudo apt install gdb-multiarch • 用 qemu 模擬時,開一個 port 作為 gdb server,連上去 ➔ gdb-multiarch ./bin/httpd ➔ target remote :30000 ➔ c • 之後開一個debug,remote上去 ➔ sudo chroot ./ ./qemu -g 30000 ./bin/httpd
  54. $ Debug environment • 用 gdb-multiarch 可以去 debug不同架構的binary ➔ sudo

    apt install gdb-multiarch ➔ sudo chroot ./ ./qemu -g 30000 ./bin/httpd_patch • 用qemu模擬時,開一個port作為gdb server,連上去 ➔ gdb-multiarch ./bin/httpd_patch ➔ target remote :30000 ➔ c • 之後開一個debug,remote上去 • 按下 c 會開始執行
  55. • First, you can find which service does it have?

    • Webs 開頭 $ Analyze Httpd ( find http server)
  56. • First, you can find which service does it have?

    • Webs 開頭 • Form $ Analyze Httpd ( find http server)
  57. $ Analyze Httpd ( find http server) • First, you

    can find which service does it have? • Webs 開頭 • Form • goform
  58. $ Analyze Httpd ( find http server) • First, you

    can find which service does it have? • Webs 開頭 • Form • goform • Http server : GoAhead
  59. • Second, you can find Http server version • Version

    : 2.1.8 $ Analyze Httpd ( find http server version )
  60. • sub_ 179A8 = websUrlHandlerDefine() • &unk_DC618 = DCB 0

    = “” $ Analyze Httpd ( initWebs() )
  61. $ Analyze Httpd • sub_42378() have some many many route

    https://fengfan349.github.io/2017/05/27/2017-05-27/
  62. $ Analyze Httpd • You can think which route we

    need to analyze • You can touch is important !!!
  63. $ Analyze Httpd ( formSetQosBand() ) • 透過 sub_2BA8C() 取得

    “list” 的值,然後放到 v8 • 然後將 v8 傳遞到 sub_7DD20() 裡面
  64. $ Analyze Httpd ( formSetQosBand() ) • 透過 sub_2BA8C() 取得

    “list” 的值,然後放到 v8 • 然後將 v8 傳遞到 sub_7DD20() 裡面 • 主要功能是接收並處理用戶通過網頁介面提交的 QoS(Quality of Service)頻寬控制規則列表。
  65. $ Analyze Httpd ( sub_7DD20() in formSetQosBand() ) • a1

    is your data • src is a1 • strcpy a1 to dest
  66. • a1 is list • src is a1 • strcpy

    a1 to dest $ Analyze Httpd ( sub_7DD20() in formSetQosBand() )
  67. $ Analyze Httpd aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa ....... browser formsetQosBand

    表單 用戶 sub_7dd20 解析和應用 QoS 規則 處理表單資料 list data
  68. $ Analyze Httpd aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa ....... browser formsetQosBand

    表單 用戶 sub_7dd20 解析和應用 QoS 規則 處理表單資料 list data
  69. IDA pro error : • dest [580] • memset (dest

    , 0 , 576) $ Analyze Httpd ( sub_7DD20() in formSetQosBand() )
  70. IDA pro error : • dest [580] • memset (dest

    , 0 , 576) memset (dest, 0 , sizeof(dest)) $ Analyze Httpd ( sub_7DD20() in formSetQosBand() )
  71. IDA pro error : • dest [580] -> dest [256]

    $ Analyze Httpd 解決方式 : Ghidra
  72. IDA pro error : • dest [580] 位置在 bp -

    0x260 $ Analyze Httpd ( sub_7DD20() in formSetQosBand() )
  73. $ Analyze Httpd (gdb) • Locat sub_7dd20() • 0x7dd78 :

    r2 = fp – 0x260 • 0x7dd7c : r3 = 0x100 • 0x7dd80 : r0 = r2 • 0x7dd84 : r1 = 0 • 0x7dd88 : r2 = r3 = 0x100 • 0x7dd8c : memset() memset (dest, 0 , sizeof(dest))
  74. $ Analyze Httpd (gdb) • Locat sub_7dd20() • 0x7dd78 :

    r2 = fp – 0x260 • 0x7dd7c : r3 = 0x100 • 0x7dd80 : r0 = r2 • 0x7dd84 : r1 = 0 • 0x7dd88 : r2 = r3 = 0x100 • 0x7dd8c : memset() memset (dest, 0 , sizeof(dest)) memset ( fp – 0x260 , 0 , 0x100 )
  75. $ Analyze Httpd (gdb) • Locat sub_7dd20() • 0x7dd78 :

    r2 = fp – 0x260 • 0x7dd7c : r3 = 0x100 • 0x7dd80 : r0 = r2 • 0x7dd84 : r1 = 0 • 0x7dd88 : r2 = r3 = 0x100 • 0x7dd8c : memset() memset (dest, 0 , sizeof(dest)) memset ( fp – 0x260 , 0 , 0x100 )
  76. IDA pro set lvar type : • dest [256] 位置在

    bp - 0x260 • memset (dest, 0 , sizeof(dest)) $ Analyze Httpd
  77. $ Analyze Httpd • dest is 256 bytes, if you

    send > 256 bytes, you have a buffer overflow.
  78. $ Attack ( find libc_base ) • call “system(‘/bin/sh’)” •

    前面有用 puts ,利用這個 puts 來 leak libc_base。
  79. $ Attack ( find libc_base ) • gdb trace,設斷點,然後 ni,找到

    puts 的 address。 • puts_address : 0x3fdd1cd4
  80. $ Attack ( find libc_base ) • gdb trace,設斷點 0x2E4FC,然後

    ni,找到 puts 的 address。 • puts_address : 0x3fdd1cd4
  81. $ Attack ( find libc_base ) • gdb trace,設斷點 0x2E4FC,然後

    ni,找到 puts 的 address。 • puts_address : 0x3fdd1cd4 • 找到 puts 在 libc 裡的 offset
  82. trace,設斷點,然後 ,找到 puts 的 address。 • puts_address : 0x3fdd1cd4 找到

    puts 裡的 offset • puts_libc_offset : 0x35cd4 ➔ readelf -a /lib/libc.so.0 | grep puts $ Attack ( find libc_base )
  83. trace,設斷點,然後 ,找到 puts 的 address。 • puts_address : 0x3fdd1cd4 找到

    puts 裡的 offset • puts_libc_offset : 0x35cd4 • puts_address - puts_libc_offset = libc_base 0x3fdd1cd4 - 0x35cd4 = 0x3fd9c000 $ Attack ( find libc_base )
  84. $ Attack ( find gadgets) GADGET ADDRESS pop {r3, pc}

    0x00018298 libc@system 0x0005a270 mov r0, sp ; blx r3 0x00040cb8 ➔ ROPgadget --binary ./lib/libc.so.0 ➔ readelf -a libc.so.0 | grep system
  85. 記憶體空間 aaaaaaaaaaaa aaaaaaaaaaaa aaaaaaaaaaaa aaaaaaaaaaaa r0 r3 sp pc 高位址

    stack frame 低位址 Pop {r3,pc} libc@system Mov r0, sp; blx r3 /bin/sh\x00
  86. • return address 跳上 pop r3 ,pc r0 r3 sp

    - pop r3 gadget address pc - pop r3 gadget address 記憶體空間 aaaaaaaaaaaa aaaaaaaaaaaa aaaaaaaaaaaa aaaaaaaaaaaa 高位址 stack frame 低位址 Pop {r3,pc} libc@system Mov r0, sp; blx r3 /bin/sh\x00 sp pc
  87. r0 r3 - libc@system sp - libc@system pc - pop

    r3 gadget address 記憶體空間 aaaaaaaaaaaa aaaaaaaaaaaa aaaaaaaaaaaa aaaaaaaaaaaa 高位址 stack frame 低位址 Pop {r3,pc} libc@system Mov r0, sp; blx r3 /bin/sh\x00 sp pc • 執行 pop r3。把 sp 指到的 8 bytes 的 address 放入 r3。
  88. r0 r3 - libc@system sp - mov r0 gadget pc

    - Mov r0, sp; blx r3 aaaaaaaaaaaa aaaaaaaaaaaa aaaaaaaaaaaa aaaaaaaaaaaa 高位址 低位址 Pop {r3,pc} libc@system Mov r0, sp; blx r3 /bin/sh\x00 sp Mov r0, sp; blx r3 pc • 執行 pop pc。把 sp 指到的 address 放入 pc。
  89. aaaaaaaaaaaa aaaaaaaaaaaa aaaaaaaaaaaa aaaaaaaaaaaa 高位址 低位址 Pop {r3,pc} libc@system Mov

    r0, sp; blx r3 /bin/sh\x00 sp Mov r0, sp; blx r3 r0 - /bin/sh\x00 address r3 - libc@system sp - /bin/sh\x00 address pc - mov r0 gadget pc • 執行 mov r0, sp,把 sp 指到的 address 放入 r0。
  90. aaaaaaaaaaaa aaaaaaaaaaaa aaaaaaaaaaaa aaaaaaaaaaaa 高位址 低位址 Pop {r3,pc} libc@system Mov

    r0, sp; blx r3 /bin/sh\x00 sp • 執行 blx r3 。 r0 is /bin/sh\x00 Mov r0, sp; blx r3 pc r0 - /bin/sh\x00 address r3 - libc@system sp - /bin/sh\x00 address pc - mov r0 gadget