[1-day] 자동화 취약점 탐지 도구 활용

goldenGlow_21·2025년 3월 19일
post-thumbnail

도구 조사 및 계획 수립

탐색

  • Firmwalker
    - 하드코딩된 비밀번호 및 민감한 데이터 확인
  • Nuclei
    - 웹 및 API 취약점 스캔
  • Qemu-Emulation + AFL++ (Fuzzing)
    - 펌웨어 바이너리를 가상 환경에서 실행하여 동적 취약점 탐색
  • Radare2 (r2) + Cutter
    - 바이너리에서 취약한 함수 및 시스템 호출(system, execve) 자동 검색
  • Ghidra Auto-Scripts
    - Ghidra에서 특정 패턴(예: 버퍼 오버플로우, 취약 함수)을 자동 탐색
  • Firmware Analysis Toolkit (FAT) + Firmadyne (Full-System Emulation)
    - 펌웨어 전체를 가상 머신(QEMU)에서 실행하여 동적 분석 가능

수행 계획 수립

  1. 펌웨어 추출 (Binwalk 활용)
  2. 하드코딩된 비밀번호 및 민감한 데이터 확인 (Firmwalker)
  3. 웹 및 API 취약점 스캔 (Nuclei)
  4. QEMU 또는 Firmadyne으로 펌웨어 실행 후 동적 스캔
  5. 정적 분석으로 실행 파일 탐색 (Ghidra 또는 Radare2)

Nuclei

1단계: nuclei -t http -target /path/to/extracted/firmware/ (정적 분석)
2단계: 펌웨어를 QEMU로 실행 후 nuclei -t http -u http://192.168.1.1 (동적 분석)


단계별 작업 수행

Binwalk

  • 지금까지의 작업으로 마무리됨

Firmwalker

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

cd firmwalker

./firmwalker.sh ~/Desktop/Firmware/inspection_result/_DIR882A1_FW104B02_Middle_FW_Unencrypt.bin.extracted/_A0.extracted/_8AB758.extracted/cpio_root

┌──(lee㉿kali)-[~/Desktop/firmwalker]
└─$ ./firmwalker.sh /home/lee/Desktop/Firmware/inspection_result/_DIR882A1_FW104B02_Middle_FW_Unencrypt.bin.extracted/_A0.extracted/_8AB758.extracted/cpio-root
***Firmware Directory***
/home/lee/Desktop/Firmware/inspection_result/_DIR882A1_FW104B02_Middle_FW_Unencrypt.bin.extracted/_A0.extracted/_8AB758.extracted/cpio-root
***Search for password files***
##################################### passwd

##################################### shadow

##################################### *.psk

***Search for Unix-MD5 hashes***


***Search for SSL related files***
##################################### *.crt

##################################### *.pem
t/etc_ro/public.pem
Could not find certificate from /home/lee/Desktop/Firmware/inspection_result/_DIR882A1_FW104B02_Middle_FW_Unencrypt.bin.extracted/_A0.extracted/_8AB758.extracted/cpio-root/etc_ro/public.pem
40F70198207F0000:error:1608010C:STORE routines:ossl_store_handle_load_result:unsupported:../crypto/store/store_result.c:151:
Incorrect File Content:Continuing
Error: Please run "shodan init <api key>" before using this command

결과 분석

  • 비밀번호 관련 정보(passwd, shadow, .psk) 탐지 실패

    • /etc/passwd, /etc/shadow 같은 파일에서 사용자 계정 정보가 발견되지 않음
    • 펌웨어 내부에서 기본적인 계정이 존재하지 않거나, 별도의 인증 메커니즘을 사용할 가능성이 있음
  • SSL 관련 파일 탐지 (public.pem)

    • etc_ro/public.pem 파일이 탐지되었지만, 오류가 발생
    • OpenSSL 관련 라이브러리에서 파일을 제대로 해석하지 못하는 듯함
  • Shodan API 키 관련 경고

    • Firmwalker는 추가적인 네트워크 분석을 위해 Shodan API를 사용할 수 있음
    • 하지만 이 기능이 활성화되지 않아서 경고 메시지가 출력된 것으로 보임

SSL 인증서 분석 결과

┌──(lee㉿kali)-[~/Desktop/Firmware/inspection_result/_DIR882A1_FW104B02_Middle_FW_Unencrypt.bin.extracted/_A0.extracted/_8AB758.extracted/cpio-root/etc_ro]
└─$ cat public.pem 
-----BEGIN RSA PUBLIC KEY-----
MIICCgKCAgEApZLuH2XFDWuazEMpx4v6QY0ePRJm344JgkLKfeofovxvbjfX6RHU
7yUz6b2wJnW4lomEzjrJEQFnPGNFV/oWO/NaTb3k0rPUewDzlzy/pn7ZMehqnMK1
tHVnyQ6RZ+9qkdYEu08f79UgZcGQzSy2TLNMquAB9ffGbTHAjRfoK7cDjQX+RKWh
OOs5tbnzhR0B4Jdd6UL9Sqoq5UisTdlnFhy67RdsItz3OOrHIiDYmfkEOqAZySKZ
MhY7h7kkC8t1IzZOncBx3LYU4PMo9ulycAx7xDUric8xswnKoYAJbbKtp9xnGKRJ
HPuZOZyXFdWNlTVhzG3sGdDzcpHxrFOJZ5RK/n19DArbq6w9MEInTmU3bcwDYFvX
JCQ5Al05lgqP8vk7U4xx3AcwZUQHNVzduBuibB26jhpPXSk1Cl6NpFdXlKvcynfV
H8XaCHy8LXhZBMiuR62Ft6YkcIpBdsQ2uBGL5GOmVFA/cOEtPZjWxzN/miXaZ7In
iRhXEHFus6zYIPOTa9DNyAA87UCqxkem7Xgu59fgq49YwGPk+Q7HJXKgts9QTn9y
26OtlUAq1i23EJK6GJvTmszslXbAWEi5Mlb/o7QdpEQt/gyz9udnVmfXOy4UmNXN
ZxuVyXNomTBFRObZ5Zmn6n+xat5eBDpvct+OO1IUMC154div9i2szF0CAwEAAQ==
-----END RSA PUBLIC KEY-----
  • RSA 공개 키가 포함된 PEM 파일
  • SSL 인증서 또는 암호화된 데이터의 검증을 위한 키로 사용될 가능성
┌──(lee㉿kali)-[~/Desktop]
└─$ grep -R "public.pem" ~/Desktop/Firmware/inspection_result/_DIR882A1_FW104B02_Middle_FW_Unencrypt.bin.extracted/_A0.extracted/_8AB758.extracted/cpio-root/
grep: /home/lee/Desktop/Firmware/inspection_result/_DIR882A1_FW104B02_Middle_FW_Unencrypt.bin.extracted/_A0.extracted/_8AB758.extracted/cpio-root/bin/imgdecrypt: binary file matches
  • public.pemimgdecrypt 바이너리에서 참조됨
  • imgdecrypt가 RSA 공개 키를 사용해 파일(펌웨어 이미지 등)을 복호화하는 기능을 포함하고 있을 가능성
┌──(lee㉿kali)-[~/Desktop]
└─$ file ~/Desktop/Firmware/inspection_result/_DIR882A1_FW104B02_Middle_FW_Unencrypt.bin.extracted/_A0.extracted/_8AB758.extracted/cpio-root/bin/imgdecrypt
/home/lee/Desktop/Firmware/inspection_result/_DIR882A1_FW104B02_Middle_FW_Unencrypt.bin.extracted/_A0.extracted/_8AB758.extracted/cpio-root/bin/imgdecrypt: ELF 32-bit LSB executable, MIPS, MIPS32 rel2 version 1 (SYSV), dynamically linked, interpreter /lib/ld-uClibc.so.0, stripped

┌──(lee㉿kali)-[~/Desktop]
└─$ strings ~/Desktop/Firmware/inspection_result/_DIR882A1_FW104B02_Middle_FW_Unencrypt.bin.extracted/_A0.extracted/_8AB758.extracted/cpio-root/bin/imgdecrypt | grep -i "public.pem"
/etc_ro/public.pem

┌──(lee㉿kali)-[~/Desktop]
└─$ ldd ~/Desktop/Firmware/inspection_result/_DIR882A1_FW104B02_Middle_FW_Unencrypt.bin.extracted/_A0.extracted/_8AB758.extracted/cpio-root/bin/imgdecrypt
	not a dynamic executable
  • 파일 타입 (file 명령어 결과)
    - MIPS 32-bit Little Endian ELF 실행 파일
    - 동적으로 링크됨 (dynamically linked)
    - Stripped (디버깅 심볼 제거됨)
    - uClibc 사용 (/lib/ld-uClibc.so.0)

  • 파일 내부 문자열 (strings 분석 결과)
    - /etc_ro/public.pem을 직접 참조하고 있음 → RSA 공개 키를 이용한 암호화/복호화 기능 포함 가능성

  • 라이브러리 의존성 (ldd 결과)
    - "not a dynamic executable" 오류 발생
    - 보통 statically linked (정적으로 링크됨) 실행 파일일 경우 나타남
    - 즉, 라이브러리가 바이너리에 직접 포함되어 있으며, ldd로 의존성을 확인할 수 없음

Nuclei

apt 패키지 관리자 이용, Nuclei 설치

sudo apt install nuclei -y

┌──(lee㉿kali)-[~/Desktop]
└─$ nuclei -version
[INF] Nuclei Engine Version: v3.3.8
[INF] Nuclei Config Directory: /home/lee/.config/nuclei
[INF] Nuclei Cache Directory: /home/lee/.cache/nuclei
[INF] PDCP Directory: /home/lee/.pdcp

취약점 템플릿 업데이트

┌──(lee㉿kali)-[~/Desktop]
└─$ nuclei -ut

                     __     _
   ____  __  _______/ /__  (_)
  / __ \/ / / / ___/ / _ \/ /
 / / / / /_/ / /__/ /  __/ /
/_/ /_/\__,_/\___/_/\___/_/   v3.3.8

		projectdiscovery.io

[INF] nuclei-templates are not installed, installing...
[INF] Successfully installed nuclei-templates at /home/lee/.local/nuclei-templates
[INF] No new updates found for nuclei templates

웹 서버 관련 파일 대상 취약점 검사

┌──(lee㉿kali)-[~/Desktop]
└─$ nuclei -t http -target ~/Desktop/Firmware/inspection_result/_DIR882A1_FW104B02_Middle_FW_Unencrypt.bin.extracted/_A0.extracted/_8AB758.extracted/cpio-root/etc_ro/lighttpd/www/web/

                     __     _
   ____  __  _______/ /__  (_)
  / __ \/ / / / ___/ / _ \/ /
 / / / / /_/ / /__/ /  __/ /
/_/ /_/\__,_/\___/_/\___/_/   v3.3.8

		projectdiscovery.io

[WRN] Found 2 templates with runtime error (use -validate flag for further examination)
[INF] Current nuclei version: v3.3.8 (latest)
[INF] Current nuclei-templates version: v10.1.2 (latest)
[WRN] Scan results upload to cloud is disabled.
[INF] New templates added in latest release: 52
[INF] Templates loaded for current scan: 7397
[INF] Executing 7020 signed templates from projectdiscovery/nuclei-templates
[WRN] Loading 377 unsigned templates for scan. Use with caution.
[INF] Targets loaded for current scan: 1
[INF] Running httpx on input host
[INF] Found 0 URL from httpx
[INF] Templates clustered: 1647 (Reduced 1550 Requests)
[INF] Using Interactsh Server: oast.live
[INF] No results found. Better luck next time!
  • 템플릿 관련 에러에 대응하기 위해 -validate 태그 붙여줌
┌──(lee㉿kali)-[~/Desktop]
└─$ nuclei -t http -target ~/Desktop/Firmware/inspection_result/_DIR882A1_FW104B02_Middle_FW_Unencrypt.bin.extracted/_A0.extracted/_8AB758.extracted/cpio-root/etc_ro/lighttpd/www/web/ -validate

                     __     _
   ____  __  _______/ /__  (_)
  / __ \/ / / / ___/ / _ \/ /
 / / / / /_/ / /__/ /  __/ /
/_/ /_/\__,_/\___/_/\___/_/   v3.3.8

		projectdiscovery.io

[url] got empty hostname for /home/lee/Desktop/Firmware/inspection_result/_DIR882A1_FW104B02_Middle_FW_Unencrypt.bin.extracted/_A0.extracted/_8AB758.extracted/cpio-root/etc_ro/lighttpd/www/web/ skipping ip selection
[VER] Started metrics server at localhost:9092
[ERR] Error occurred parsing template /home/lee/.local/nuclei-templates/http/technologies/wordpress/plugins/userfeedback-lite.yaml: could not compile request: could not parse payloads: the helpers/wordpress/plugins/userfeedback-lite.txt file for payload last_version does not exist or does not contain enough elements
[WRN] Found duplicate template ID during validation '/home/lee/.local/nuclei-templates/http/exposures/configs/javascript-env.yaml' => '/home/lee/.local/nuclei-templates/http/exposures/files/javascript-env.yaml': javascript-env
[ERR] Error occurred parsing template /home/lee/.local/nuclei-templates/http/technologies/wordpress/plugins/jeg-elementor-kit.yaml: could not compile request: could not parse payloads: the helpers/wordpress/plugins/jeg-elementor-kit.txt file for payload last_version does not exist or does not contain enough elements
[FTL] Could not validate templates: errors occurred during template validation
  • 현재 /www/web/ 디렉토리는 로컬 파일 시스템이므로, Nuclei가 이를 대상으로 제대로 작동할 수 없음
  • 웹 서버가 실행된 상태에서 http://TARGET_IP/을 대상으로 스캔해야 함
  • 지금은 정적 분석만 수행 중이므로, 이 단계는 보류하고 동적 분석 시 진행하는 것으로 결정

HNAP API 관련 파일 대상 취약점 검사

┌──(lee㉿kali)-[~/Desktop]
└─$ nuclei -t http/hnap -target ~/Desktop/Firmware/inspection_result/_DIR882A1_FW104B02_Middle_FW_Unencrypt.bin.extracted/_A0.extracted/_8AB758.extracted/cpio-root/etc_ro/lighttpd/www/web/hnap/

                     __     _
   ____  __  _______/ /__  (_)
  / __ \/ / / / ___/ / _ \/ /
 / / / / /_/ / /__/ /  __/ /
/_/ /_/\__,_/\___/_/\___/_/   v3.3.8

		projectdiscovery.io

[ERR] Could not find template 'http/hnap': could not find file: open /home/lee/.local/nuclei-templates/http/hnap: no such file or directory
[INF] Current nuclei version: v3.3.8 (latest)
[INF] Current nuclei-templates version: v10.1.2 (latest)
[WRN] Scan results upload to cloud is disabled.
[INF] Targets loaded for current scan: 1
[INF] No results found. Better luck next time!
[FTL] Could not run nuclei: no templates provided for scan
  • 마찬가지로 템플릿 에러 발생. 다만 여러 조치(중복 템플릿 제거, 재설치 등)에도 불구하고 해결 불가

Radare2

기본 파일 정보 확인

┌──(lee㉿kali)-[~/Desktop]
└─$ file ~/Desktop/Firmware/inspection_result/_DIR882A1_FW104B02_Middle_FW_Unencrypt.bin.extracted/_A0.extracted/_8AB758.extracted/cpio-root/sbin/fwupload.cgi
/home/lee/Desktop/Firmware/inspection_result/_DIR882A1_FW104B02_Middle_FW_Unencrypt.bin.extracted/_A0.extracted/_8AB758.extracted/cpio-root/sbin/fwupload.cgi: ELF 32-bit LSB executable, MIPS, MIPS32 rel2 version 1 (SYSV), dynamically linked, interpreter /lib/ld-uClibc.so.0, stripped
  • MIPS 32-bit Little Endian ELF 실행 파일
  • Dynamically linked (동적 라이브러리 참조)
  • Stripped (디버깅 심볼 제거됨)
  • uClibc 사용 (/lib/ld-uClibc.so.0)

문자열 분석

┌──(lee㉿kali)-[~/Desktop]
└─$ strings ~/Desktop/Firmware/inspection_result/_DIR882A1_FW104B02_Middle_FW_Unencrypt.bin.extracted/_A0.extracted/_8AB758.extracted/cpio-root/sbin/fwupload.cgi | less
/lib/ld-uClibc.so.0
_init
_fini
__uClibc_main
__deregister_frame_info
__register_frame_info
_Jv_RegisterClasses
memchr
memcmp
memset
FCGI_fopen
malloc
FCGI_fseek
FCGI_ftell
FCGI_fread
ntohl
nvram_safe_get
strcmp
crc32
FCGI_fclose
free
FCGI_printf
FCGI_perror
lseek
snprintf
__errno_location
ftruncate
strlen
FCGI_fwrite
system
getenv
strstr
exit
libnvram.so.0
_DYNAMIC_LINKING
__RLD_MAP
_GLOBAL_OFFSET_TABLE_
libc.so.0
memmem
libfcgi.so.0
libjson-c.so.2
libm.so.0
libcrypto.so.1.0.0
libnotifyrc.so
librcm.so
libssl.so.1.0.0
_ftext
_fdata
_edata
__bss_start
_fbss
_end
#9'g
's&#
$! `
%E$x
B$! 
%D$0
$! `
%D$t
%B$$
'! `
$!0@
'! @
$! `
$! `
&D$@
<(&E$x
<,&D$
$!0@
&D$@
<(&E$x
<,&D$
$!0@
&D$@
<(&E$x
<,&D$
<0&B$0
$!0@
&D$@
<(&E$x
'! @
'! `
$!0@
$! `
$! `
%D$t
<H&D$t
<X&B$H
'! `
$!0@
'! @
<d&B$H
'! `
$!0@
'! @
$! `
<x&D$t
&B$H
'! `
$!0@
'! @
'! `
&D$t
&P$8
'! @
&P$8
'! @
&P$8
'! @
&B$H
$!0@
'! @
$! `
'B$$
'! `
$!0@
'! @
'P$@
<('D$
'! `
'! @
<8'D$
<H'E$P
<T'D$!(
<t'C$A
$!0`
'! @
'D$!(
'D$!(
SHRS
model_name
Usage %s file_name offset : %d,length : %d
open
ftruncate_file,filename:%s
/dev/console
fail :%s , status :%d
read head tail
offset:%d
endoffset end:%d
remove read head tail
n :%d
error end boundary
len:%d,%p,%s
endoffset:%d - offset:%d = %d,strlen(p)=%d
error:%d,%s
UPLOAD_FILENAME
filename:%s
SERVER_SOFTWARE:%s
SERVER_SOFTWARE
CONTENT_TYPE
boundary=
failed, can't find boundary=.
boundary:%s
failed, can't remove head tail.
check fw header FAILED
.shstrtab
.interp
.reginfo
.dynamic
.hash
.dynsym
.dynstr
.init
.text
.MIPS.stubs
.fini
.rodata
.eh_frame
.ctors
.dtors
.jcr
.data
.rld_map
.got
.sdata
.bss
.pdr
.gnu.attributes
.mdebug.abi32

1. 실행 파일이 system() 함수를 호출

  • system() 함수가 포함되어 있음 → 명령어 실행 취약점(RCE, Command Injection) 가능성 있음
  • 외부 입력을 검증 없이 system()을 호출하는 경우, 임의 명령 실행 가능

2. FCGI_* 관련 함수 발견 → FastCGI 기반 웹 서비스

  • FCGI_fopen, FCGI_fseek, FCGI_ftell, FCGI_fread, FCGI_printf, FCGI_fwrite 등 FastCGI 관련 함수 다수 발견
  • 이는 웹 인터페이스에서 FastCGI 프로토콜을 통해 실행됨을 의미
  • CGI에서 FastCGI를 통해 업로드된 파일을 처리하는 방식이 포함될 가능성 높음

3. nvram_safe_get() 함수 발견 → NVRAM 설정 접근 가능성

  • NVRAM을 읽어오는 함수(nvram_safe_get)가 포함
  • 업로드된 데이터를 NVRAM에서 검증하거나, 업로드된 파일이 NVRAM 설정을 변경할 가능성 있음

4. "UPLOAD_FILENAME" / "filename=%s" 문자열 발견 → 파일 업로드 기능 포함

  • 업로드된 파일을 처리하는 기능이 존재
  • "check fw header FAILED" 메시지 → 업로드된 펌웨어 파일의 헤더 검증을 수행하는 것으로 보임

5. "boundary=" 관련 문자열 발견 → Multipart Form Data 처리

  • "failed, can't find boundary=.", "boundary:%s" 등의 문자열이 포함됨
  • HTTP Multipart 업로드를 처리하는 코드 포함 가능성
  • 특정 웹 요청(multipart/form-data)을 통해 파일 업로드를 수행할 수 있음

6. "fail :%s , status :%d", "error end boundary" → 오류 메시지 포함

  • 에러 핸들링 메시지 존재 → 파일 업로드 과정에서 발생할 수 있는 오류들을 디버깅할 수 있음

Radare2에서 실행 파일 로드 (r2 사용)

┌──(lee㉿kali)-[~/Desktop]
└─$ r2 -AA ~/Desktop/Firmware/inspection_result/_DIR882A1_FW104B02_Middle_FW_Unencrypt.bin.extracted/_A0.extracted/_8AB758.extracted/cpio-root/sbin/fwupload.cgi
WARN: Relocs has not been applied. Please use `-e bin.relocs.apply=true` or `-e bin.cache=true` next time
INFO: Analyze all flags starting with sym. and entry0 (aa)
INFO: Analyze imports (af@@@i)
INFO: Analyze entrypoint (af@ entry0)
INFO: Analyze symbols (af@@@s)
INFO: Recovering variables
INFO: Analyze all functions arguments/locals (afva@@@F)
INFO: Analyze function calls (aac)
INFO: Analyze len bytes of instructions for references (aar)
INFO: Finding and parsing C++ vtables (avrr)
INFO: Analyzing methods
INFO: Finding xrefs in noncode section (e anal.in=io.maps.x)
INFO: Emulate functions to find computed references (aaef)
INFO: Recovering local variables (afva)
INFO: Type matching analysis for all functions (aaft)
INFO: Propagate noreturn information (aanr)
INFO: Scanning for strings constructed in code (/azs)
INFO: Finding function preludes (aap)
INFO: Enable anal.types.constraint for experimental type propagation
[0x00400980]>

함수 목록 확인

[0x00400980]> afl
0x00402530    1     32 sym.imp.ntohl
0x004009e0    8    204 fcn.004009e0
0x00402520    1     16 sym.imp.FCGI_fwrite
0x00402510    1     16 sym.imp.free
0x00402500    1     16 sym.imp.FCGI_fclose
0x004024f0    1     16 sym.imp.FCGI_printf
0x004024e0    1     16 sym.imp.FCGI_ftell
0x004024d0    1     16 sym.imp.strcmp
0x004024c0    1     16 sym.imp.strstr
0x004024b0    1     16 sym.imp.exit
0x004024a0    1     16 sym.imp.memchr
0x00402490    1     16 sym.imp.FCGI_fseek
0x00402480    1     16 sym.imp.memcmp
0x00402470    1     16 sym.imp.ftruncate
0x00402460    1     16 sym.imp.memset
0x00402450    1     16 sym.imp.close
0x00402440    1     16 sym.imp.write
0x00402430    1     16 sym.imp.FCGI_perror
0x00402420    1     16 sym.imp.FCGI_fopen
0x00402410    1     16 sym.imp.crc32
0x00402400    1     16 sym.imp.nvram_safe_get
0x004023f0    1     16 sym.imp.read
0x004023e0    1     16 sym.imp.snprintf
0x004023d0    1     16 sym.imp.lseek
0x004023c0    1     16 sym.imp.strlen
0x004023b0    1     16 sym.imp.FCGI_fread
0x004023a0    1     16 sym.imp.__uClibc_main
0x00402390    1     16 sym.imp.malloc
0x00402380    1     16 sym.imp.system
0x00402370    1     16 sym.imp.getenv
0x00402360    1     16 sym.imp.open
0x00402350    1     16 sym.imp.__errno_location
0x00400980    2     88 entry0
0x00402550    1     84 sym._fini
0x00400b30   10    348 sym.memmem
0x00402030    9    720 main
0x004008fc    1    120 sym._init
0x00400aac    6    120 fcn.00400aac
0x00402300    4     76 fcn.00402300
0x00401528    9    780 fcn.00401528
0x00401434    9    244 fcn.00401434
0x004010b8   18    892 fcn.004010b8
0x00401834   28   2044 fcn.00401834
0x00400c8c   20   1068 fcn.00400c8c

중간 결산

  • fwupload.cgi 실행 파일이 파일 업로드를 처리하고 system() 함수를 호출하는 것이 확인
  • Radare2를 이용해 system() 호출이 어디서 이루어지는지 확인, 이후 심층 분석 진행

system() 함수를 호출하는 코드 확인

[0x00400980]> afl | grep system
0x00402380    1     16 sym.imp.system

main 함수 분석

[0x00400980]> pdf @ main
            ; NULL XREF from section..dynsym @ +0xd4(r)
            ; ICOD XREF from entry0 @ 0x400998(r)
┌ 720: int main (int argc, char **argv, int32_t envp, int32_t arg_134h);
│           ; arg int argc @ a0
│           ; arg char **argv @ a1
│           ; arg int32_t envp @ sp+0x158
│           ; arg int32_t arg_134h @ sp+0x15c
│           ; var int32_t var_10h @ sp+0x38
│           ; var int32_t var_18h @ sp+0x40
│           ; var int32_t var_1ch @ sp+0x44
│           ; var int32_t var_20h @ sp+0x48
│           ; var int32_t var_24h @ sp+0x4c
│           ; var int32_t var_128h @ sp+0x150
│           ; var int32_t var_12ch @ sp+0x154
│           0x00402030      d0febd27       addiu sp, sp, -0x130
│           0x00402034      2c01bfaf       sw ra, (var_12ch)
│           0x00402038      2801b0af       sw s0, (var_128h)
│           0x0040203c      42001c3c       lui gp, 0x42                ; 'B'
│           0x00402040      f0a79c27       addiu gp, gp, -0x5810
│           0x00402044      1000bcaf       sw gp, (var_10h)
│           0x00402048      3001a4af       sw a0, (envp)
│           0x0040204c      3401a5af       sw a1, (arg_134h)
│           0x00402050      2400a327       addiu v1, sp, 0x24
│           0x00402054      00010224       addiu v0, zero, 0x100
│           0x00402058      21206000       move a0, v1
│           0x0040205c      21280000       move a1, zero
│           0x00402060      21304000       move a2, v0
│           0x00402064      6880828f       lw v0, -sym.imp.memset(gp)  ; [0x412858:4]=0x402460 sym.imp.memset ; "`$@"
│           0x00402068      00000000       nop
│           0x0040206c      21c84000       move t9, v0
│           0x00402070      09f82003       jalr t9
│           0x00402074      00000000       nop
│           0x00402078      1000bc8f       lw gp, (var_10h)
│           0x0040207c      4000023c       lui v0, 0x40                ; '@'
│           0x00402080      f4264424       addiu a0, v0, 0x26f4        ; 0x4026f4 ; "UPLOAD_FILENAME" ; argc ; str.UPLOAD_FILENAME
│           0x00402084      a880828f       lw v0, -sym.imp.getenv(gp)  ; [0x412898:4]=0x402370 sym.imp.getenv ; "p#@"
│           0x00402088      00000000       nop
│           0x0040208c      21c84000       move t9, v0
│           0x00402090      09f82003       jalr t9
│           0x00402094      00000000       nop
│           0x00402098      1000bc8f       lw gp, (var_10h)
│           0x0040209c      1800a2af       sw v0, (var_18h)
│           0x004020a0      4000023c       lui v0, 0x40                ; '@'
│           0x004020a4      04274224       addiu v0, v0, 0x2704        ; 0x402704 ; "filename:%s\n" ; str.filename:_s_n
│           0x004020a8      2400a327       addiu v1, sp, 0x24
│           0x004020ac      21206000       move a0, v1
│           0x004020b0      00010524       addiu a1, zero, 0x100       ; argv
│           0x004020b4      21304000       move a2, v0                 ; int32_t arg3
│           0x004020b8      1800a78f       lw a3, (var_18h)            ; int32_t arg_138h
│           0x004020bc      8880828f       lw v0, -sym.imp.snprintf(gp) ; [0x412878:4]=0x4023e0 sym.imp.snprintf
│           0x004020c0      00000000       nop
│           0x004020c4      21c84000       move t9, v0
│           0x004020c8      09f82003       jalr t9
│           0x004020cc      00000000       nop
│           0x004020d0      1000bc8f       lw gp, (var_10h)
│           0x004020d4      2400a227       addiu v0, sp, 0x24
│           0x004020d8      21204000       move a0, v0                 ; int32_t arg1
│           0x004020dc      21280000       move a1, zero               ; int32_t arg2
│           0x004020e0      4a05100c       jal fcn.00401528
│           0x004020e4      00000000       nop
│           0x004020e8      1000bc8f       lw gp, (var_10h)
│           0x004020ec      4000023c       lui v0, 0x40                ; '@'
│           0x004020f0      14275024       addiu s0, v0, 0x2714        ; 0x402714 ; "SERVER_SOFTWARE:%s\n" ; str.SERVER_SOFTWARE:_s_n
│           0x004020f4      4000023c       lui v0, 0x40                ; '@'
│           0x004020f8      28274424       addiu a0, v0, 0x2728        ; 0x402728 ; "SERVER_SOFTWARE" ; str.SERVER_SOFTWARE
│           0x004020fc      a880828f       lw v0, -sym.imp.getenv(gp)  ; [0x412898:4]=0x402370 sym.imp.getenv ; "p#@"
│           0x00402100      00000000       nop
│           0x00402104      21c84000       move t9, v0
│           0x00402108      09f82003       jalr t9
│           0x0040210c      00000000       nop
│           0x00402110      1000bc8f       lw gp, (var_10h)
│           0x00402114      2400a327       addiu v1, sp, 0x24
│           0x00402118      21206000       move a0, v1
│           0x0040211c      00010524       addiu a1, zero, 0x100
│           0x00402120      21300002       move a2, s0                 ; int32_t arg3
│           0x00402124      21384000       move a3, v0                 ; int32_t arg_138h
│           0x00402128      8880828f       lw v0, -sym.imp.snprintf(gp) ; [0x412878:4]=0x4023e0 sym.imp.snprintf
│           0x0040212c      00000000       nop
│           0x00402130      21c84000       move t9, v0
│           0x00402134      09f82003       jalr t9
│           0x00402138      00000000       nop
│           0x0040213c      1000bc8f       lw gp, (var_10h)
│           0x00402140      2400a227       addiu v0, sp, 0x24
│           0x00402144      21204000       move a0, v0                 ; int32_t arg1
│           0x00402148      21280000       move a1, zero               ; int32_t arg2
│           0x0040214c      4a05100c       jal fcn.00401528
│           0x00402150      00000000       nop
│           0x00402154      1000bc8f       lw gp, (var_10h)
│           0x00402158      4000023c       lui v0, 0x40                ; '@'
│           0x0040215c      38274424       addiu a0, v0, 0x2738        ; 0x402738 ; "CONTENT_TYPE" ; str.CONTENT_TYPE
│           0x00402160      a880828f       lw v0, -sym.imp.getenv(gp)  ; [0x412898:4]=0x402370 sym.imp.getenv ; "p#@"
│           0x00402164      00000000       nop
│           0x00402168      21c84000       move t9, v0
│           0x0040216c      09f82003       jalr t9
│           0x00402170      00000000       nop
│           0x00402174      1000bc8f       lw gp, (var_10h)
│           0x00402178      1c00a2af       sw v0, (var_1ch)
│           0x0040217c      2000a0af       sw zero, (var_20h)
│           0x00402180      1c00a28f       lw v0, (var_1ch)
│           0x00402184      00000000       nop
│       ┌─< 0x00402188      0f004010       beqz v0, 0x4021c8
│       │   0x0040218c      00000000       nop
│       │   0x00402190      1c00a48f       lw a0, (var_1ch)
│       │   0x00402194      4000023c       lui v0, 0x40                ; '@'
│       │   0x00402198      48274524       addiu a1, v0, 0x2748        ; 0x402748 ; "boundary=" ; str.boundary
│       │   0x0040219c      5080828f       lw v0, -sym.imp.strstr(gp)  ; [0x412840:4]=0x4024c0 sym.imp.strstr
│       │   0x004021a0      00000000       nop
│       │   0x004021a4      21c84000       move t9, v0
│       │   0x004021a8      09f82003       jalr t9
│       │   0x004021ac      00000000       nop
│       │   0x004021b0      1000bc8f       lw gp, (var_10h)
│       │   0x004021b4      2000a2af       sw v0, (var_20h)
│       │   0x004021b8      2000a28f       lw v0, (var_20h)
│       │   0x004021bc      00000000       nop
│      ┌──< 0x004021c0      09004014       bnez v0, 0x4021e8
│      ││   0x004021c4      00000000       nop
│      ││   ; CODE XREF from main @ 0x402188(x)
│      │└─> 0x004021c8      4000023c       lui v0, 0x40                ; '@'
│      │    0x004021cc      54274424       addiu a0, v0, 0x2754        ; 0x402754 ; "failed, can't find boundary=.\n" ; int32_t arg1 ; str.failed__cant_find_boundary._n
│      │    0x004021d0      21280000       move a1, zero               ; int32_t arg2
│      │    0x004021d4      4a05100c       jal fcn.00401528
│      │    0x004021d8      00000000       nop
│      │    0x004021dc      1000bc8f       lw gp, (var_10h)
│      │┌─< 0x004021e0      b8081008       j 0x4022e0
│      ││   0x004021e4      00000000       nop
│      ││   ; CODE XREF from main @ 0x4021c0(x)
│      └──> 0x004021e8      2000a28f       lw v0, (var_20h)
│       │   0x004021ec      00000000       nop
│       │   0x004021f0      09004224       addiu v0, v0, 9
│       │   0x004021f4      2000a2af       sw v0, (var_20h)
│       │   0x004021f8      4100023c       lui v0, 0x41                ; 'A'
│       │   0x004021fc      2000a38f       lw v1, (var_20h)
│       │   0x00402200      00000000       nop
│       │   0x00402204      d42843ac       sw v1, 0x28d4(v0)
│       │   0x00402208      4000023c       lui v0, 0x40                ; '@'
│       │   0x0040220c      74274324       addiu v1, v0, 0x2774        ; 0x402774 ; "boundary:%s" ; str.boundary:_s
│       │   0x00402210      4100023c       lui v0, 0x41                ; 'A'
│       │   0x00402214      d428428c       lw v0, 0x28d4(v0)
│       │   0x00402218      2400a427       addiu a0, sp, 0x24
│       │   0x0040221c      00010524       addiu a1, zero, 0x100
│       │   0x00402220      21306000       move a2, v1                 ; int32_t arg3
│       │   0x00402224      21384000       move a3, v0                 ; int32_t arg_138h
│       │   0x00402228      8880828f       lw v0, -sym.imp.snprintf(gp) ; [0x412878:4]=0x4023e0 sym.imp.snprintf
│       │   0x0040222c      00000000       nop
│       │   0x00402230      21c84000       move t9, v0
│       │   0x00402234      09f82003       jalr t9
│       │   0x00402238      00000000       nop
│       │   0x0040223c      1000bc8f       lw gp, (var_10h)
│       │   0x00402240      2400a227       addiu v0, sp, 0x24
│       │   0x00402244      21204000       move a0, v0                 ; int32_t arg1
│       │   0x00402248      21280000       move a1, zero               ; int32_t arg2
│       │   0x0040224c      4a05100c       jal fcn.00401528
│       │   0x00402250      00000000       nop
│       │   0x00402254      1000bc8f       lw gp, (var_10h)
│       │   0x00402258      1800a48f       lw a0, (var_18h)            ; int32_t arg1
│       │   0x0040225c      0d06100c       jal fcn.00401834
│       │   0x00402260      00000000       nop
│       │   0x00402264      1000bc8f       lw gp, (var_10h)
│      ┌──< 0x00402268      09004010       beqz v0, 0x402290
│      ││   0x0040226c      00000000       nop
│      ││   0x00402270      4000023c       lui v0, 0x40                ; '@'
│      ││   0x00402274      80274424       addiu a0, v0, 0x2780        ; 0x402780 ; "failed, can't remove head tail.\n" ; int32_t arg1 ; str.failed__cant_remove_head_tail._n
│      ││   0x00402278      21280000       move a1, zero               ; int32_t arg2
│      ││   0x0040227c      4a05100c       jal fcn.00401528
│      ││   0x00402280      00000000       nop
│      ││   0x00402284      1000bc8f       lw gp, (var_10h)
│     ┌───< 0x00402288      b8081008       j 0x4022e0
│     │││   0x0040228c      00000000       nop
│     │││   ; CODE XREF from main @ 0x402268(x)
│     │└──> 0x00402290      1800a48f       lw a0, (var_18h)            ; int32_t arg1
│     │ │   0x00402294      2303100c       jal fcn.00400c8c
│     │ │   0x00402298      00000000       nop
│     │ │   0x0040229c      1000bc8f       lw gp, (var_10h)
│     │┌──< 0x004022a0      09004014       bnez v0, 0x4022c8
│     │││   0x004022a4      00000000       nop
│     │││   0x004022a8      4000023c       lui v0, 0x40                ; '@'
│     │││   0x004022ac      a4274424       addiu a0, v0, 0x27a4        ; 0x4027a4 ; "check fw header FAILED\r\n" ; int32_t arg1 ; str.check_fw_header_FAILED_r_n
│     │││   0x004022b0      21280000       move a1, zero               ; int32_t arg2
│     │││   0x004022b4      4a05100c       jal fcn.00401528
│     │││   0x004022b8      00000000       nop
│     │││   0x004022bc      1000bc8f       lw gp, (var_10h)
│    ┌────< 0x004022c0      b8081008       j 0x4022e0
│    ││││   0x004022c4      00000000       nop
│    ││││   ; CODE XREF from main @ 0x4022a0(x)
│    ││└──> 0x004022c8      21200000       move a0, zero
│    ││ │   0x004022cc      5480828f       lw v0, -sym.imp.exit(gp)    ; [0x412844:4]=0x4024b0 sym.imp.exit
│    ││ │   0x004022d0      00000000       nop
│    ││ │   0x004022d4      21c84000       move t9, v0
│    ││ │   0x004022d8      09f82003       jalr t9
│    ││ │   0x004022dc      00000000       nop
│    ││ │   ; CODE XREFS from main @ 0x4021e0(x), 0x402288(x), 0x4022c0(x)
│    └└─└─> 0x004022e0      ffff0424       addiu a0, zero, -1
│           0x004022e4      5480828f       lw v0, -sym.imp.exit(gp)    ; [0x412844:4]=0x4024b0 sym.imp.exit
│           0x004022e8      00000000       nop
│           0x004022ec      21c84000       move t9, v0
│           0x004022f0      09f82003       jalr t9
│           0x004022f4      00000000       nop
│           0x004022f8      00000000       nop
└           0x004022fc      00000000       nop

fwupload.cgi 정적 분석 결과 요약

  • system() 함수가 존재 → 임의 명령 실행(RCE) 가능성
  • "UPLOAD_FILENAME" 환경 변수를 사용 → 파일 업로드 취약점 가능성
  • "boundary=" 문자열 확인 → HTTP Multipart Form 데이터 처리
  • "check fw header FAILED"펌웨어 파일 검증 과정 존재

system() 함수의 사용 방식?

  • system() 호출이 0x00402380 주소에서 확인됨 (afl | grep system 결과)
  • 어떤 값이 system()에 전달되는지 확인 필요!!
  • 현재 main 함수에서 환경 변수 "UPLOAD_FILENAME"을 가져오고 있음
0x00402080      f4264424       addiu a0, v0, 0x26f4        ; "UPLOAD_FILENAME"
0x00402084      a880828f       lw v0, -sym.imp.getenv(gp)
  • 이는 getenv("UPLOAD_FILENAME")를 호출하여 값을 가져옴
  • 만약 "UPLOAD_FILENAME" 값을 검증 없이 system()에 전달한다면 명령어 주입(Command Injection) 취약점 발생 가능

취약점 가능성 생각해보기

  • system()UPLOAD_FILENAME을 통해 실행될 경우, 외부 입력을 통해 임의 명령어 실행 가능
  • 업로드된 파일의 이름이 "&& malicious_command" 형태로 구성되면 쉘 명령어 실행이 가능할 수 있음
  • "boundary="가 포함되어 있어 HTTP Multipart 업로드 처리를 수행 → 파일 업로드 취약점 가능성도 존재

그럼... 추가 분석은

1. system() 호출부 추적

  • pdg 명령으로 system()이 어디에서 호출되는지 확인

2. 입력값 검증 확인

  • UPLOAD_FILENAME 값이 system()에 직접 전달되는지 확인
  • "check fw header FAILED"가 있는 부분이 system() 실행 전 수행되는지 확인
profile
안드로이드는 리눅스의 꿈을 꾸는가

0개의 댓글