[1-day] 담당 CVE쪽 취약점 분석

goldenGlow_21·2025년 3월 19일
post-thumbnail

사전 준비

  • 선정된 CVE는 CVE-2022-28895
  • 해당 CVE는 DIR882A1_FW130B06 펌웨어에서 발견됨

1.30B06 펌웨어 준비 및 복호화

┌──(kali㉿kali)-[~/Desktop/Firmware/source] └─$ binwalk -E ~/Desktop/Firmware/source/DIR882A1_FW130B06.bin DECIMAL HEXADECIMAL ENTROPY -------------------------------------------------------------------------------- 0 0x0 Rising entropy edge (0.969675)
  • 해당 펌웨어의 .bin 파일은 암호화된 것으로 보임
  • dlink-decrypt라는 오픈소스 툴을 이용해 복호화를 수행

환경 준비

┌──(kali㉿kali)-[~/Desktop/dlink-decrypt]
└─$ python3 -m venv venv
                                                
┌──(kali㉿kali)-[~/Desktop/dlink-decrypt]
└─$ source venv/bin/activate
                                               
┌──(venv)─(kali㉿kali)-[~/Desktop/dlink-decrypt]
└─$ pip3 install -r requirements.txt
Collecting pycryptodome (from -r requirements.txt (line 1))
  Downloading pycryptodome-3.21.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (3.4 kB)
Downloading pycryptodome-3.21.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (2.3 MB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 2.3/2.3 MB 26.9 MB/s eta 0:00:00
Installing collected packages: pycryptodome
Successfully installed pycryptodome-3.21.0

복호화 수행

┌──(venv)─(kali㉿kali)-[~/Desktop/dlink-decrypt]
└─$ python3 dlink-dec.py -i ~/Desktop/Firmware/source/DIR882A1_FW130B06.bin -o decrypted.bin

[*] Calculating key...
        [+] OK!
[*] Checking magic bytes...
        [+] OK!
[*] Verifying SHA512 message digest of encrypted payload...
        [+] OK!
[*] Verifying SHA512 message digests of decrypted payload...
        [+] OK!
        [+] OK!
[+] Successfully decrypted "DIR882A1_FW130B06.bin"!
  • 결과로 decrypted.bin을 얻음
  • 이름은 원본과 같도록 DIR882A1_FW130B06_decrpyted.bin 으로 변경

파일 시스템 재조사

┌──(kali㉿kali)-[~/…/_DIR882A1_FW130B06_decrypted.bin.extracted/_A0.extracted/_8897DC.extracted/cpio-root]
└─$ ls -R
.:
bin  etc     home  lib    mnt      proc  share  tmp  var
dev  etc_ro  init  media  private  sbin  sys    usr  www

./bin:
ac        dnsmasq      i2scmd             iwconfig      mtd_write     ps           tc
acl       dumpleases   igmpproxy          iwpriv        mtr           pwd          time_client
addgroup  echo         igmpproxy.sh       kill          mv            qos_run      touch
adduser   egrep        imgdecrypt         lighttpd      netstat       ralink_init  umount
ash       eth_mac      init_system        lld2d         ntpclient     rc           uname
ated      fgrep        ip                 ln            nvram_daemon  reg          vi
bndstrg2  flash        ip6tables          login         nvram_get     rm           web
busybox   fota         ip6tables-restore  ls            nvram_set     routel       webdav.sh
cat       fota_config  ip6tables-save     lsusb         openssl       rt2860apd    wsc_monitor.sh
chmod     fota_output  ipaddr             mii_mgr       pcmcmd        rtinicapd    xtables-multi
cp        gpio         iplink             mii_mgr_cl45  ping          seama        zcat
curl      grep         iproute            miniupnpd     ping6         sed
date      gunzip       iprule             mkconfig      proftpd       sh
dd        gzip         iptables           mkdir         proftpd.sh    sleep
delgroup  hostname     iptables-restore   mknod         prog-cgi      spdifcmd
deluser   hw_nat       iptables-save      mount         prog.cgi      switch
dmesg     i2ccmd       iptunnel           mpstat        protest       tar

./dev:
pts

./dev/pts:

./etc:
fstab  jcpd.conf

./etc_ro:
apcli_connect_trial.sh  icon.large.ico  lld2d.conf  rcS                          web
bndstrg.conf            inittab         motd        rept_dbdc_test.sh            wifi
cacert.pem              l7-protocols    onetouch    rept_test.sh                 Wireless
fp_db                   lighttpd        ppp         tr069_voip_default_settings  wlan
icon.ico                linuxigd        public.pem  usb                          xml

...

./www/rssui:
base64.js             finish.asp      isp.js          main.asp       wireless.js
check_survey.asp      fwupgrade2.asp  language_en.js  public
config.asp            fwupgrade.asp   language_ko.js  public.js
config.js             fwupgrade.js    language_tw.js  scan.js
default_redirect.asp  img             language_zh.js  _sys_info.asp

./www/rssui/img:
ic_fw_controller.png    ios_guan.png  wireless_icon_100.png  wireless_icon_50.png
ic_network_starter.png  ios_kai.png   wireless_icon_25.png   wireless_icon_75.png

./www/rssui/public:
dbros.css  login.asp  login_error.asp  login_keyissue.asp  login_lock.asp  __md5.js

우선 분석 스크립트 선정

┌──(kali㉿kali)-[~/Desktop]
└─$ find ~/Desktop/Firmware/inspect_result/emba_log/ -type f \( -name "*.sh" -o -name "*.cgi" -o -name "*.php" -o -name "*.conf" -o -name "*.cfg" \) | grep -iE "network|ip|set|config|dhcp|apply|firewall"    

/home/kali/Desktop/Firmware/inspect_result/emba_log/firmware/unblob_extracted/firmware_extract/160-13265262.lzma_extract/lzma.uncompressed_extract/9090904-18668237.lzma_extract/lzma.uncompressed_extract/etc_ro/onetouch/scripts/rss_xml.sh
/home/kali/Desktop/Firmware/inspect_result/emba_log/firmware/unblob_extracted/firmware_extract/160-13265262.lzma_extract/lzma.uncompressed_extract/9090904-18668237.lzma_extract/lzma.uncompressed_extract/etc_ro/onetouch/scripts/rss_xml.php
/home/kali/Desktop/Firmware/inspect_result/emba_log/firmware/unblob_extracted/firmware_extract/160-13265262.lzma_extract/lzma.uncompressed_extract/9090904-18668237.lzma_extract/lzma.uncompressed_extract/etc_ro/onetouch/scripts/rss_checker.sh
/home/kali/Desktop/Firmware/inspect_result/emba_log/firmware/unblob_extracted/firmware_extract/160-13265262.lzma_extract/lzma.uncompressed_extract/9090904-18668237.lzma_extract/lzma.uncompressed_extract/etc_ro/lighttpd/www/web/HNAP1/dlquickvpnsettings.cgi
/home/kali/Desktop/Firmware/inspect_result/emba_log/firmware/unblob_extracted/firmware_extract/160-13265262.lzma_extract/lzma.uncompressed_extract/9090904-18668237.lzma_extract/lzma.uncompressed_extract/sbin/config-igmpproxy.sh
/home/kali/Desktop/Firmware/inspect_result/emba_log/firmware/unblob_extracted/firmware_extract/160-13265262.lzma_extract/lzma.uncompressed_extract/9090904-18668237.lzma_extract/lzma.uncompressed_extract/sbin/config-pptp.sh
/home/kali/Desktop/Firmware/inspect_result/emba_log/firmware/unblob_extracted/firmware_extract/160-13265262.lzma_extract/lzma.uncompressed_extract/9090904-18668237.lzma_extract/lzma.uncompressed_extract/sbin/ipv6_logo.sh
/home/kali/Desktop/Firmware/inspect_result/emba_log/firmware/unblob_extracted/firmware_extract/160-13265262.lzma_extract/lzma.uncompressed_extract/9090904-18668237.lzma_extract/lzma.uncompressed_extract/sbin/config-eee.sh
/home/kali/Desktop/Firmware/inspect_result/emba_log/firmware/unblob_extracted/firmware_extract/160-13265262.lzma_extract/lzma.uncompressed_extract/9090904-18668237.lzma_extract/lzma.uncompressed_extract/sbin/config-vlan.sh
/home/kali/Desktop/Firmware/inspect_result/emba_log/firmware/unblob_extracted/firmware_extract/160-13265262.lzma_extract/lzma.uncompressed_extract/9090904-18668237.lzma_extract/lzma.uncompressed_extract/sbin/config-dslite.sh
/home/kali/Desktop/Firmware/inspect_result/emba_log/firmware/unblob_extracted/firmware_extract/160-13265262.lzma_extract/lzma.uncompressed_extract/9090904-18668237.lzma_extract/lzma.uncompressed_extract/sbin/udhcpc.sh
/home/kali/Desktop/Firmware/inspect_result/emba_log/firmware/unblob_extracted/firmware_extract/160-13265262.lzma_extract/lzma.uncompressed_extract/9090904-18668237.lzma_extract/lzma.uncompressed_extract/sbin/config.sh
/home/kali/Desktop/Firmware/inspect_result/emba_log/firmware/unblob_extracted/firmware_extract/160-13265262.lzma_extract/lzma.uncompressed_extract/9090904-18668237.lzma_extract/lzma.uncompressed_extract/sbin/config-dns.sh
/home/kali/Desktop/Firmware/inspect_result/emba_log/firmware/unblob_extracted/firmware_extract/160-13265262.lzma_extract/lzma.uncompressed_extract/9090904-18668237.lzma_extract/lzma.uncompressed_extract/sbin/config-longloop.sh
/home/kali/Desktop/Firmware/inspect_result/emba_log/firmware/unblob_extracted/firmware_extract/160-13265262.lzma_extract/lzma.uncompressed_extract/9090904-18668237.lzma_extract/lzma.uncompressed_extract/sbin/config-pppoe.sh
/home/kali/Desktop/Firmware/inspect_result/emba_log/firmware/unblob_extracted/firmware_extract/160-13265262.lzma_extract/lzma.uncompressed_extract/9090904-18668237.lzma_extract/lzma.uncompressed_extract/sbin/config-powersave.sh
/home/kali/Desktop/Firmware/inspect_result/emba_log/firmware/unblob_extracted/firmware_extract/160-13265262.lzma_extract/lzma.uncompressed_extract/9090904-18668237.lzma_extract/lzma.uncompressed_extract/sbin/config-l2tp.sh
/home/kali/Desktop/Firmware/inspect_result/emba_log/firmware/unblob_extracted/firmware_extract/160-13265262.lzma_extract/lzma.uncompressed_extract/9090904-18668237.lzma_extract/lzma.uncompressed_extract/sbin/config-iTunes.sh
/home/kali/Desktop/Firmware/inspect_result/emba_log/firmware/unblob_extracted/firmware_extract/160-13265262.lzma_extract/lzma.uncompressed_extract/9090904-18668237.lzma_extract/lzma.uncompressed_extract/sbin/firewall.sh
/home/kali/Desktop/Firmware/inspect_result/emba_log/firmware/unblob_extracted/firmware_extract/160-13265262.lzma_extract/lzma.uncompressed_extract/9090904-18668237.lzma_extract/lzma.uncompressed_extract/sbin/config-udhcpd.sh
  • 네트워크 설정을 다루는 스크립트config, network, dhcp, firewall 관련 스크립트
  • 라우터 설정을 직접 변경할 가능성이 있는 파일config-, set-, apply- 접두사가 포함된 파일
  • 웹 인터페이스와 관련된 CGI 스크립트cgi 또는 www 관련 파일

1️. /sbin/config.sh

  • 라우터의 전반적인 설정을 담당할 가능성이 높음
  • 네트워크 설정과 관련된 서브 스크립트를 호출할 수도?
  • 내부적으로 system() 또는 eval 같은 명령 실행 함수가 포함될 가능성이 있음

2️. /sbin/config-dns.sh

  • IP 주소 설정과 관련이 있을 가능성이 큼
  • /setnetworksettings/IPAddress에서 DNS와 함께 설정될 가능성이 있음

3️. /etc_ro/lighttpd/www/web/HNAP1/dlquickvpnsettings.cgi

  • CGI 스크립트이므로 웹 인터페이스에서 호출될 가능성이 있음
  • 직접적인 사용자 입력 → 명령어 실행 흐름을 포함할 수도 있음
  • 취약점이 존재하는 /setnetworksettings/IPAddress와 같은 구조의 엔드포인트일 가능성...(희망사항)

스크립트 분석

/sbin/config.sh

CONFIG_MIPS=y

CONFIG_ZONE_DMA=y
CONFIG_RALINK_MT7621=y
CONFIG_MT7621_ASIC=y
CONFIG_KERNEL_START_ADDR=0x81001000
CONFIG_RT2880_DRAM_128M=y
CONFIG_MTD_ANY_RALINK=y
CONFIG_KERNEL_NVRAM=y
CONFIG_RALINK_RAM_SIZE=128
CONFIG_MTD_PHYSMAP_START=0x1C000000
CONFIG_MTD_PHYSMAP_LEN=0x1000000
CONFIG_MTD_PHYSMAP_BUSWIDTH=2
...
  • 단순한 펌웨어 설정을 다루는 부분...

/sbin/config-dns.sh

#!/bin/sh

# $Id: //WIFI_SOC/MP/SDK_5_0_0_0/RT288x_SDK/source/user/rt2880_app/scripts/config-dns.sh#1 $
# usage: config-dns.sh [<dns1>] [<dns2>]

fname="/etc/resolv.conf"
fbak="/etc/resolv_conf.bak"

# in case no previous file
touch $fname

# backup file without nameserver part
sed -e '/nameserver/d' $fname > $fbak

# set primary and seconday DNS
if [ "$1" != "" ]; then
  echo "nameserver $1" > $fname
else # empty dns
  rm -f $fname
fi
if [ "$2" != "" ]; then
  echo "nameserver $2" >> $fname
fi

cat $fbak >> $fname
rm -f $fbak
  • DNS 설정을 변경하는 역할
  • 사용자로부터 DNS 서버를 입력받아 /etc/resolv.conf에 저장하는 방식
  • 명령어 실행 (system(), popen(), eval)을 포함하지 않음

분석 내용

  • 스크립트 기능

    • DNS 서버를 설정하는 역할
    • 기존 /etc/resolv.conf를 백업한 후, 새로운 DNS 정보를 덮어씀
    • $1$2에 각각 Primary DNS와 Secondary DNS를 받아 nameserver 항목을 추가
  • 보안 취약점 여부

    • 취약한 명령 실행 없음. system(), eval, popen() 같은 명령 실행 함수 사용 안 함
    • 단순한 파일 조작, echosed를 활용하여 파일을 수정하는 수준
    • 입력 검증 없음. $1, $2 값을 그대로 echo로 추가하지만, 이는 단순한 텍스트 추가로 명령 실행과는 무관
  • CVE-2022-28895와의 연관성

    • 이 스크립트는 /setnetworksettings/IPAddress와 관련 없음
    • IP 주소 설정이 아니라 DNS 서버 설정을 담당

/sbin/config-udhcpd.sh

#!/bin/sh
#
# $Id: //WIFI_SOC/MP/SDK_5_0_0_0/RT288x_SDK/source/user/rt2880_app/scripts/config-udhcpd.sh#1 $
#
# usage: see function usage()
#
. /sbin/config.sh
. /sbin/global.sh
  
fname="/etc/udhcpd.conf"
fbak="/etc/udhcpd.conf_bak"
pidfile="/var/run/udhcpd.pid"
leases="/var/udhcpd.leases"

usage () {
  echo "usage: config-udhcpd.sh [option]..."
  echo "options:"
  echo "  -h              : print this help"
  echo "  -s ipaddr       : set ipaddr as start of the IP lease block"
  echo "  -e ipaddr       : set ipaddr as end of the IP lease block"
  echo "  -i ifc          : set ifc as the interface that udhcpd will use"
  echo "  -d dns1 [dns2]  : set dns1 and dns2 as DNS"
  echo "  -m mask         : set mask as subnet netmask"
  echo "  -g gateway      : set gateway as router's IP address"
  echo "  -t time         : set time seconds as the IP life time"
  echo "  -r [sleep_time] : run dhcp server"
  echo "  -k              : kill the running dhcp server"
  echo "  -S [mac ipaddr] : statically assign IP to given MAC address"
# echo "  -x static_netmask : Ra propritary cmd"
# echo "  -y static_router  : Ra propritary cmd"
  exit
}

config () {
  case "$1" in
    "-s")
      sed -e '/start/d' $fname > $fbak
      echo "start $2" >> $fbak ;;
    "-e")
      sed -e '/end/d' $fname > $fbak
      echo "end $2" >> $fbak ;;
    "-i")
      sed -e '/interface/d' $fname > $fbak
      echo "interface $2" >> $fbak ;;
    "-d")
      sed -e '/option *dns/d' $fname > $fbak
      echo "option dns $2 $3" >> $fbak ;;
    "-m")
      sed -e '/option *subnet/d' $fname > $fbak
      echo "option subnet $2" >> $fbak ;;
    "-g")
      sed -e '/option *router/d' $fname > $fbak
      echo "option router $2" >> $fbak ;;
    "-t")
      sed -e '/option *lease/d' $fname > $fbak
      echo "option lease $2" >> $fbak ;;
    "-S")
      if [ "$2" = "" ]; then
        sed -e '/static_lease/d' $fname > $fbak
      elif [ "$3" = "" ]; then
  echo "insufficient arguments.."
  usage
      else
        echo "static_lease $2 $3" >> $fname
  return
      fi
      ;;
    "-x")
      sed -e '/static_netmask/d' $fname > $fbak
      echo "static_netmask $2" >> $fbak ;;
    "-y")
      sed -e '/static_router/d' $fname > $fbak
      echo "static_router $2" >> $fbak ;;
    *) return;;
  esac
  cat $fbak > $fname
  rm -f $fbak
  return
}
  
#  arg1:  phy address.
link_down()
{
  # get original register value
  get_mii=`mii_mgr -g -p $1 -r 0`
  orig=`echo $get_mii | sed 's/^.....................//'`
  
  # stupid hex value calculation.
  pre=`echo $orig | sed 's/...$//'`
  post=`echo $orig | sed 's/^..//'`
  num_hex=`echo $orig | sed 's/^.//' | sed 's/..$//'`
  case $num_hex in
    "0")  rep="8" ;;
    "1")  rep="9" ;;
    "2")  rep="a" ;;
    "3")  rep="b" ;;
    "4")  rep="c" ;;
    "5")  rep="d" ;;
    "6")  rep="e" ;;
    "7")  rep="f" ;;
    # The power is already down
    *)    echo "Port$1 is down. Skip.";return;;
  esac
  new=$pre$rep$post
  # power down
  mii_mgr -s -p $1 -r 0 -v $new
}

link_up()
{
  # get original register value
  get_mii=`mii_mgr -g -p $1 -r 0`
  orig=`echo $get_mii | sed 's/^.....................//'`

  # stupid hex value calculation.
  pre=`echo $orig | sed 's/...$//'`
  post=`echo $orig | sed 's/^..//'`
  num_hex=`echo $orig | sed 's/^.//' | sed 's/..$//'`
  case $num_hex in
    "8")  rep="2" ;;
    "9")  rep="3" ;;
    "a")  rep="2" ;;
    "b")  rep="3" ;;
    "c")  rep="6" ;;
    "d")  rep="7" ;;
    "e")  rep="6" ;;
    "f")  rep="7" ;;
    # The power is already up
    *)    echo "Port$1 is up. Skip.";return;;
  esac
  new=$pre$rep$post
  # power up
  mii_mgr -s -p $1 -r 0 -v $new
}

reset_all_phys()
{
  sleep_time=$1

  if [ "$CONFIG_RAETH_ROUTER" != "y" -a "$CONFIG_RT_3052_ESW" != "y" ]; then
    return
  fi

  opmode=`nvram_get 2860 OperationMode`

  #skip WAN port
  if [ "$opmode" != "1" ]; then #no wan port
    link_down 0
    link_down 4
  elif [ "$CONFIG_WAN_AT_P4" = "y" ]; then #wan port at port4
    link_down 0
  elif [ "$CONFIG_WAN_AT_P0" = "y" ]; then #wan port at port0
    link_down 4
  fi
  link_down 1
  link_down 2
  link_down 3

  #force Windows clients to renew IP and update DNS server
  sleep $sleep_time

  #skip WAN port
  if [ "$opmode" != "1" ]; then #no wan port
    link_up 0
    link_up 4
  elif  [ "$CONFIG_WAN_AT_P4" = "y" ]; then #wan port at port4
    link_up 0
  elif [ "$CONFIG_WAN_AT_P0" = "y" ]; then #wan port at port0
    link_up 4
  fi
  link_up 1
  link_up 2
  link_up 3
}

# argv 1 is empty
if [ "$1" = "" ]; then
  usage
fi

# argv 2 is empty
if [ "$2" = "" ]; then
  if [ "$1" != "-r" -a "$1" != "-k" -a "$1" != "-S" ]; then
      usage
  fi
fi

touch $fname

case "$1" in
  "-h") usage;;
  "-s") config "$1" "$2";;
  "-e") config "$1" "$2";;
  "-i") config "$1" "$2";;
  "-d") config "$1" "$2" "$3";;
  "-m") config "$1" "$2";;
  "-g") config "$1" "$2";;
  "-t") config "$1" "$2";;
  "-S") config "$1" "$2" "$3";;
  "-r")
    if [ -e ${pidfile} ]; then
      kill `cat $pidfile`
    else
      killall udhcpd
    fi
    rm -f $pidfile
    touch $leases
  sed '/^lease_file /d' $fname > $fbak
  cat $fbak > $fname
    echo "lease_file $leases" >> $fname
    udhcpd $fname
    reset_all_phys $2;;
  "-k")
    if [ -e ${pidfile} ]; then
      kill `cat $pidfile`
    else
      killall udhcpd
    fi
    rm -f $pidfile ;;
  "-x") config "$1" "$2";;
  "-y") config "$1" "$2";;
  *) usage;;
esac
  • DHCP 서버(udhcpd) 설정을 변경하고 제어하는 역할
  • 명령어 실행(kill, udhcpd, mii_mgr)이 포함되어 있어 보안 취약점 가능성이 존재
  • setnetworksettings/IPAddress를 직접 다루지는 않음
  • CVE-2022-28895(명령어 주입 취약점)와 연관될 가능성이 있지만, 추가 확인 필요

분석 내용

스크립트 기능 개요
  • DHCP 서버 설정 파일(/etc/udhcpd.conf)을 수정하고, udhcpd 데몬을 실행 또는 종료
스크립트 주요 기능
  • -s ipaddr → DHCP IP 범위 시작 주소 설정
  • -e ipaddr → DHCP IP 범위 끝 주소 설정
  • -i ifc → 사용할 인터페이스 지정
  • -d dns1 [dns2] → DNS 서버 설정
  • -m mask → 서브넷 마스크 설정
  • -g gateway → 게이트웨이 설정
  • -t time → 리스 타임 설정
  • -r [sleep_time] → DHCP 서버 실행
  • -k → DHCP 서버 종료
  • -S [mac ipaddr] → MAC 주소에 특정 IP를 할당
보안 취약점 가능성 분석

(1) 사용자 입력 처리 방식 분석

  • config() 함수에서 사용자 입력($1, $2, $3)을 직접 sedecho를 사용하여 /etc/udhcpd.conf에 기록
  • system(), eval, popen() 같은 직접적인 명령 실행 함수는 없지만, 입력값이 sed를 통해 처리
  • 만약 사용자 입력이 쉘 메타문자(;, &, |, `, $() 등)를 포함할 경우, 의도하지 않은 동작이 발생할 가능성이 있음
  • 하지만 현재 sed 명령 자체는 명령어 실행을 포함하지 않으므로 바로 명령어 주입 취약점으로 이어지지는 않을 것

(2) -r 옵션에서 udhcpd 실행 방식

  "-r")
    if [ -e ${pidfile} ]; then
      kill `cat $pidfile`
    else
      killall udhcpd
    fi
    rm -f $pidfile
    touch $leases
	sed '/^lease_file /d' $fname > $fbak
	cat $fbak > $fname
    echo "lease_file $leases" >> $fname
    udhcpd $fname
    reset_all_phys $2;;
  • udhcpd 실행 시, 설정 파일($fname = /etc/udhcpd.conf)을 인자로 전달
  • 만약 /etc/udhcpd.conf가 조작되었거나, 특정 환경 변수(lease_file 등)가 조작되었다면, 악성 설정이 적용될 가능성이 있음
  • 그러나 이 스크립트 자체가 명령어를 주입하는 구조는 아님

(3) reset_all_phys() 함수에서 mii_mgr 명령 실행

	get_mii=`mii_mgr -g -p $1 -r 0`
	orig=`echo $get_mii | sed 's/^.....................//'`
  • mii_mgr는 네트워크 인터페이스의 PHY(Link) 상태를 제어하는 명령어
  • $1이 직접 명령 실행에 사용되지는 않지만, 입력값이 mii_mgr -g -p 뒤에 그대로 전달되므로 입력값 조작이 가능하면 오작동까지는 가능해 보임

/etc_ro/lighttpd/www/web/HNAP1/dlquickvpnsettings.cgi

  • IDA에서 disassemble한 main 함수
int __fastcall main(int argc, const char **argv, const char **envp)
{
  int v3; // $a2
  int v4; // $a2
  int v5; // $a2
  int v6; // $a2
  int v7; // $v0
  int v8; // $a2
  int v10; // [sp+20h] [-28h]
  int v11; // [sp+28h] [-20h]
  int v12; // [sp+2Ch] [-1Ch]
  int v13; // [sp+30h] [-18h]
  int v14; // [sp+34h] [-14h]
  int v15; // [sp+38h] [-10h]
  int v16; // [sp+3Ch] [-Ch]
  int v17; // [sp+40h] [-8h]
  int v18; // [sp+44h] [-4h]

  v10 = 0;
  v12 = fopen("/tmp/vpnprofile.mobileconfig", "r", envp);
  if ( v12 )
  {
    fseek(v12, 0, 2);
    v13 = ftell(v12);
    if ( v13 )
    {
      fseek(v12, 0, 0);
      v10 = malloc(v13 + 1);
      if ( v10 )
      {
        v11 = fread(v10, 1, v13, v12);
        if ( v11 == v13 )
        {
          *(_BYTE *)(v10 + v13) = 0;
          printf("HTTP/1.1 %d %s\n", 200, "OK");
          puts("Pragma: no-cache");
          puts("Cache-Control: no-cache");
          puts("Content-Type: application/force-download");
          puts("Content-Transfer-Encoding: binary");
          puts("Content-Disposition: attachment; filename=\"vpnprofile.mobileconfig\"");
          putchar(10);
          v7 = strlen(v10);
          fwrite(v10, 1, v7, stdout);
          v18 = fopen("/dev/console", "w", v8);
          fprintf(
            v18,
            "%s:%s:%d:download quick vpn profile finish.\n\n",
            "cgi-bin/dlquickvpnsettings.cgi.c",
            "main",
            67);
          fclose(v18);
        }
        else
        {
          v17 = fopen("/dev/console", "w", v6);
          fprintf(v17, "%s:%s:%d:fread len %d not correct!\n\n", "cgi-bin/dlquickvpnsettings.cgi.c", "main", 51, v11);
          fclose(v17);
        }
      }
      else
      {
        v16 = fopen("/dev/console", "w", v5);
        fprintf(v16, "%s:%s:%d:malloc fail\n\n", "cgi-bin/dlquickvpnsettings.cgi.c", "main", 45);
        fclose(v16);
      }
    }
    else
    {
      v15 = fopen("/dev/console", "w", v4);
      fprintf(v15, "%s:%s:%d:profile len %d not correct!\n\n", "cgi-bin/dlquickvpnsettings.cgi.c", "main", 38, 0);
      fclose(v15);
    }
  }
  else
  {
    v14 = fopen("/dev/console", "w", v3);
    fprintf(
      v14,
      "%s:%s:%d:profile %s not exist!\n\n",
      "cgi-bin/dlquickvpnsettings.cgi.c",
      "main",
      31,
      "/tmp/vpnprofile.mobileconfig");
    fclose(v14);
  }
  if ( v12 )
    fclose(v12);
  if ( v10 )
    free(v10);
  return 0;
}
  • /tmp/vpnprofile.mobileconfig 파일을 읽어와 클라이언트에 다운로드하는 기능을 수행
  • 입력값을 직접적으로 처리하는 부분이 없음
  • system(), popen(), execve() 같은 명령 실행 함수가 없음

분석 내용

주요한 동작 흐름
  1. VPN 프로파일 파일 열기

    • /tmp/vpnprofile.mobileconfig 파일을 읽기 모드(r)로 오픈
    • 파일이 존재하지 않으면 "profile not exist!" 로그를 /dev/console에 출력
  2. 파일 크기 확인

    • fseek()을 이용해 파일의 끝으로 이동한 후, ftell()로 파일 크기를 확인
    • 파일 크기가 0이면 "profile len 0 not correct!" 로그를 출력하고 종료
  3. 파일 내용 읽기

    • 파일 크기만큼 malloc()을 사용하여 메모리 할당
    • 파일 내용을 fread()로 읽고, 널(\0) 문자를 추가해 문자열 종료
  4. HTTP 응답 출력

    • HTTP 응답 헤더를 출력하여 브라우저가 파일을 다운로드하도록 설정
    • fwrite(v10, 1, v7, stdout);을 사용하여 클라이언트에게 파일 전송
  5. 로그 기록

    • /dev/console에 다운로드 완료 로그를 기록
보안 취약점 분석

(1) 사용자 입력 처리 방식

  • getenv(), fgets(), recv(), scanf() 같은 사용자 입력을 직접 받는 부분이 없음
  • 사용자가 제공하는 입력값이 직접 코드 실행에 영향을 미치지 않음

(2) 명령 실행 함수 없음

  • system(), popen(), execve() 같은 함수가 없음
  • CVE-2022-28895와 같은 명령어 주입 공격이 불가능함

(3) 주요 보안 이슈 없음

  • /tmp/vpnprofile.mobileconfig 파일이 조작되었을 경우, 클라이언트에게 악성 파일이 다운로드될 가능성
  • 하지만 이는 명령 주입과는 관계없음
profile
안드로이드는 리눅스의 꿈을 꾸는가

0개의 댓글