[KOR] Breaking the Charge: An EV Charger Takeover Scenario — Pwn2Own Tokyo Journey, Part 1

[KOR] Breaking the Charge: An EV Charger Takeover Scenario — Pwn2Own Tokyo Journey, Part 1

Introduction

PetoWorks 연구진은 이번 Tokyo에서 개최한 Pwn2Own 2026에 참가해 총 3개의 타겟에 대해 성공적으로 취약점을 발견하고 제어권 장악 시나리오를 시연하여 최종 4위를 기록했습니다. Pwn2Own Tokyo는 자동차와 관련 인프라를 주요 대상으로 하는 보안 대회로, 전기차 충전기, 차량용 OS, 인포테인먼트 시스템, Tesla 등이 주요 타겟으로 선정되었습니다. PetoWorks는 이 중 두 개의 전기차 충전기와 한 개의 인포테인먼트 시스템을 대상으로 제어권 장악 시나리오를 성공적으로 시연했습니다.

이번 글에서는 여러 충전기 타겟 중 하나인 Phoenix사의 CHARX SEC-3150에서 어떠한 분석 과정을 통해 취약점을 발견했고, 세 가지 취약점을 어떻게 연계하여 장치의 제어권을 장악했는지 설명하고자 합니다.


Phoenix CHARX SEC-3150

Phoenix 사의 차량용 충전기는 매년 Pwn2Own 대회에 타겟으로 선정되었습니다. 그 중 CHARX SEC-3150은 AC Charging Controller로 차량 충전을 제어할 수 있는 시스템입니다.

CHARX SEC-3150 차량용 충전기는 다양한 공격 표면(attack surface)이 존재합니다. 기본적으로 외부에서 관리하기 위해 WAN Port가 존재하며 접근할 수 있는 서비스로는 Modbus, MQTT, Web Management 등이 존재합니다. 또한, 물리적으로 접근할 수 있는 포트로 USB와 MicroSD, 그리고 SIM 포트가 존재합니다. Pwn2Own 규정상 제출 가능한 공격 시나리오는 일반적인 운용 환경에서 WAN 포트를 통해 접근하거나, 대회 규정에서 허용하는 물리적 인터페이스를 이용하는 방식으로 제한됩니다. 저희는 내부 서비스를 분석하기 전에 Pwn2Own에서 허용되는 공격 시나리오에 알맞은 공격 벡터를 우선 식별하여 분석을 수행하였습니다.

파일시스템 접근 및 디버깅은 다소 간단했습니다. 먼저 CHARX SEC-3150의 펌웨어는 공식 사이트에서 다운로드받을 수 있으며, 암호화되어 있지 않아 카빙하여 파일시스템을 추출할 수 있습니다.

또한, CHARX SEC-3150은 root 가 아닌 사용자 권한의 ssh가 주어져 있습니다. CHARX SEC-3150 장치는 내부적으로 권한 분리가 적절하게 되어있어 Root 권한이 없다면 대부분의 프로세스에 디버깅을 수행하거나 운용 시 유의미한 파일에 접근할 수 없습니다. 따라서 이번 분석에서는 최대한 정적으로 분석하여 취약점을 발견하고자 했습니다.

Vulnerabilities

장치에 대해 분석하며 다양한 취약점을 발견하였으며, 총 3개의 취약점을 연계하여 제어권 탈취 시나리오를 개발하였습니다. 각 단일 취약점만으로는 장치의 제어권을 탈취하는 시나리오를 세울 수 없습니다. 하지만 발견한 취약점을 적절히 연계하여 제어권 장악을 위한 선행 조건을 해소하여 시나리오 시연에 성공할 수 있었습니다. 이번 Pwn2Own 시연 시 사용한 취약점들은 다음과 같습니다.

Vulnerability #1 : ModBus Server Exposed Dangerous Function Denial-of-Service Vulnerability

CWE : CWE-749 - Exposed dangerous method or function

CVSS : 6.5 AV:A/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H

Description:

CHARX SEC-3150은 Modbus를 통해 제어 및 상태 확인을 할 수 있습니다. 기본적으로 502 포트가 개방되어 있습니다. 502 포트는 CharxModbusServer 서비스가 관리하는 포트로, Modbus에 대한 전반적인 기능을 수행하기 위해 운용됩니다. Modbus 서비스는 장치의 재부팅 등을 수행할 수 있는 기능을 제공합니다. 그러나 적절한 접근 제어가 이루어지지 않아 장치와 동일망에 있는 어떤 Client든 502 포트에 접근할 수 있습니다.

따라서 공격자는 장치 재부팅 기능을 담당하는 레지스터의 값을 변경하여 임의로 장치의 재부팅을 유발할 수 있습니다.

이 취약점만으로는 장치의 가용성을 침해하는 수준에 그칩니다. 그러나 이후 설명할 취약점과 연계하면 장치의 제어권 장악으로까지 공격 영향도를 확대할 수 있습니다.


Vulnerability #2 : Race Condition Firewall Bypass Vulnerability

CWE : CWE-696 - Incorrect Behavior Order

CVSS : 6.4 AV:A/AC:H/PR:N/UI:N/S:U/C:L/I:H/A:L

Description:

CHARX SEC-3150은 방화벽을 통해 중요 기능을 수행하는 포트의 접근 제어를 수행하여 0.0.0.0에 바인딩된 여러 중요 기능 서비스에 접근할 수 없도록 구현되어 있습니다. 다음과 같이 허용된 서비스의 Port만 허용하고 나머지는 차단하는 것을 알 수 있습니다.




특히, 2024년 Pwn2Own Tokyo에서는 장치의 주요 설정을 변경할 수 있는 서비스인 CharxSystemConfigManager의 접근 제어가 존재하지 않아 해당 취약점을 응용한 사례가 다수 존재했습니다. 최신 버전의 펌웨어에서는 해당 서비스의 포트인 5001의 바인딩은 0.0.0.0으로 되어있으나 localhost으로만 접근하는 것이 허용되어 있습니다.




정상적인 운용 상태에서는 외부에서 주요 서비스에 직접 접근할 수 없도록 구성되어 있습니다.

저희는 방화벽 우회를 고민하던 중 방화벽이 활성화되고 종료되는 루틴에 대해 분석하였습니다. 방화벽은 Linux의 /etc/rc[n].d 경로에 초기화/셧다운 스크립트를 통해 시작과 종료가 이루어지는데 그 중 셧다운 스크립트에서 잘못된 로직을 발견하였습니다. 셧다운 스크립트 디렉토리의 구조는 다음과 같습니다.

ev3000:/etc/rc6.d$ ls -al
total 7
drwxr-xr-x  2 root root 3072 Aug 29 07:50 .
drwxr-xr-x 63 root root 4096 Aug 29 07:47 ..
lrwxrwxrwx  1 root root   37 Aug 28 12:50 K01update-check-ev2000-service -> ../init.d/update-check-ev2000-service
lrwxrwxrwx  1 root root   23 Aug 28 12:50 K04charx-hw-init -> ../init.d/charx-hw-init
lrwxrwxrwx  1 root root   31 Aug 28 12:50 K05charx-network-restore -> ../init.d/charx-network-restore
lrwxrwxrwx  1 root root   16 Aug 28 12:50 K05pxc-ip -> ../init.d/pxc-ip
lrwxrwxrwx  1 root root   22 Aug 28 12:50 K05reset-button -> ../init.d/reset-button
lrwxrwxrwx  1 root root   14 Aug 28 12:50 K09sshd -> ../init.d/sshd
lrwxrwxrwx  1 root root   19 Aug 28 12:50 K10charx-qca -> ../init.d/charx-qca
lrwxrwxrwx  1 root root   32 Aug 28 12:50 K12charx-system-configure -> ../init.d/charx-system-configure
lrwxrwxrwx  1 root root   24 Aug 28 12:50 K20charx-modem-on -> ../init.d/charx-modem-on
lrwxrwxrwx  1 root root   16 Aug 28 12:50 K20dbus-1 -> ../init.d/dbus-1
lrwxrwxrwx  1 root root   15 Aug 28 12:50 K20nginx -> ../init.d/nginx
lrwxrwxrwx  1 root root   24 Aug 28 12:50 K20rauc-mark-good -> ../init.d/rauc-mark-good
lrwxrwxrwx  1 root root   32 Aug 29 07:50 K20wpa_supplicant_service -> ../init.d/wpa_supplicant_service
lrwxrwxrwx  1 root root   25 Aug 28 12:50 K25fail2ban-server -> ../init.d/fail2ban-server
lrwxrwxrwx  1 root root   34 Aug 28 12:50 K30charx-firewall-configure -> ../init.d/charx-firewall-configure
lrwxrwxrwx  1 root root   19 Aug 28 12:50 K30rng-tools -> ../init.d/rng-tools
lrwxrwxrwx  1 root root   22 Aug 28 12:50 K31umountnfs.sh -> ../init.d/umountnfs.sh
lrwxrwxrwx  1 root root   18 Aug 28 12:50 K35firewall -> ../init.d/firewall <strong>// – Disable Firewall</strong>
lrwxrwxrwx  1 root root   21 Aug 28 12:50 K45dhcp-server -> ../init.d/dhcp-server
lrwxrwxrwx  1 root root   37 Aug 28 12:50 K50charx-system-config-manager -> ../init.d/charx-system-config-manager <strong>// – Service not yet disabled</strong>

ev3000:/etc/rc6.d$ ls -al
total 7
drwxr-xr-x  2 root root 3072 Aug 29 07:50 .
drwxr-xr-x 63 root root 4096 Aug 29 07:47 ..
lrwxrwxrwx  1 root root   37 Aug 28 12:50 K01update-check-ev2000-service -> ../init.d/update-check-ev2000-service
lrwxrwxrwx  1 root root   23 Aug 28 12:50 K04charx-hw-init -> ../init.d/charx-hw-init
lrwxrwxrwx  1 root root   31 Aug 28 12:50 K05charx-network-restore -> ../init.d/charx-network-restore
lrwxrwxrwx  1 root root   16 Aug 28 12:50 K05pxc-ip -> ../init.d/pxc-ip
lrwxrwxrwx  1 root root   22 Aug 28 12:50 K05reset-button -> ../init.d/reset-button
lrwxrwxrwx  1 root root   14 Aug 28 12:50 K09sshd -> ../init.d/sshd
lrwxrwxrwx  1 root root   19 Aug 28 12:50 K10charx-qca -> ../init.d/charx-qca
lrwxrwxrwx  1 root root   32 Aug 28 12:50 K12charx-system-configure -> ../init.d/charx-system-configure
lrwxrwxrwx  1 root root   24 Aug 28 12:50 K20charx-modem-on -> ../init.d/charx-modem-on
lrwxrwxrwx  1 root root   16 Aug 28 12:50 K20dbus-1 -> ../init.d/dbus-1
lrwxrwxrwx  1 root root   15 Aug 28 12:50 K20nginx -> ../init.d/nginx
lrwxrwxrwx  1 root root   24 Aug 28 12:50 K20rauc-mark-good -> ../init.d/rauc-mark-good
lrwxrwxrwx  1 root root   32 Aug 29 07:50 K20wpa_supplicant_service -> ../init.d/wpa_supplicant_service
lrwxrwxrwx  1 root root   25 Aug 28 12:50 K25fail2ban-server -> ../init.d/fail2ban-server
lrwxrwxrwx  1 root root   34 Aug 28 12:50 K30charx-firewall-configure -> ../init.d/charx-firewall-configure
lrwxrwxrwx  1 root root   19 Aug 28 12:50 K30rng-tools -> ../init.d/rng-tools
lrwxrwxrwx  1 root root   22 Aug 28 12:50 K31umountnfs.sh -> ../init.d/umountnfs.sh
lrwxrwxrwx  1 root root   18 Aug 28 12:50 K35firewall -> ../init.d/firewall <strong>// – Disable Firewall</strong>
lrwxrwxrwx  1 root root   21 Aug 28 12:50 K45dhcp-server -> ../init.d/dhcp-server
lrwxrwxrwx  1 root root   37 Aug 28 12:50 K50charx-system-config-manager -> ../init.d/charx-system-config-manager <strong>// – Service not yet disabled</strong>

ev3000:/etc/rc6.d$ ls -al
total 7
drwxr-xr-x  2 root root 3072 Aug 29 07:50 .
drwxr-xr-x 63 root root 4096 Aug 29 07:47 ..
lrwxrwxrwx  1 root root   37 Aug 28 12:50 K01update-check-ev2000-service -> ../init.d/update-check-ev2000-service
lrwxrwxrwx  1 root root   23 Aug 28 12:50 K04charx-hw-init -> ../init.d/charx-hw-init
lrwxrwxrwx  1 root root   31 Aug 28 12:50 K05charx-network-restore -> ../init.d/charx-network-restore
lrwxrwxrwx  1 root root   16 Aug 28 12:50 K05pxc-ip -> ../init.d/pxc-ip
lrwxrwxrwx  1 root root   22 Aug 28 12:50 K05reset-button -> ../init.d/reset-button
lrwxrwxrwx  1 root root   14 Aug 28 12:50 K09sshd -> ../init.d/sshd
lrwxrwxrwx  1 root root   19 Aug 28 12:50 K10charx-qca -> ../init.d/charx-qca
lrwxrwxrwx  1 root root   32 Aug 28 12:50 K12charx-system-configure -> ../init.d/charx-system-configure
lrwxrwxrwx  1 root root   24 Aug 28 12:50 K20charx-modem-on -> ../init.d/charx-modem-on
lrwxrwxrwx  1 root root   16 Aug 28 12:50 K20dbus-1 -> ../init.d/dbus-1
lrwxrwxrwx  1 root root   15 Aug 28 12:50 K20nginx -> ../init.d/nginx
lrwxrwxrwx  1 root root   24 Aug 28 12:50 K20rauc-mark-good -> ../init.d/rauc-mark-good
lrwxrwxrwx  1 root root   32 Aug 29 07:50 K20wpa_supplicant_service -> ../init.d/wpa_supplicant_service
lrwxrwxrwx  1 root root   25 Aug 28 12:50 K25fail2ban-server -> ../init.d/fail2ban-server
lrwxrwxrwx  1 root root   34 Aug 28 12:50 K30charx-firewall-configure -> ../init.d/charx-firewall-configure
lrwxrwxrwx  1 root root   19 Aug 28 12:50 K30rng-tools -> ../init.d/rng-tools
lrwxrwxrwx  1 root root   22 Aug 28 12:50 K31umountnfs.sh -> ../init.d/umountnfs.sh
lrwxrwxrwx  1 root root   18 Aug 28 12:50 K35firewall -> ../init.d/firewall <strong>// – Disable Firewall</strong>
lrwxrwxrwx  1 root root   21 Aug 28 12:50 K45dhcp-server -> ../init.d/dhcp-server
lrwxrwxrwx  1 root root   37 Aug 28 12:50 K50charx-system-config-manager -> ../init.d/charx-system-config-manager <strong>// – Service not yet disabled</strong>

내부에는 여러 서비스 및 데몬을 정리하는 스크립트가 포함되어 있습니다. 여기서 중요한 점은 서비스를 종료하는 순서에서 문제가 발생한다는 점입니다. 자세히 보면 중요 서비스나 네트워크 서비스를 정리하기도 전에 방화벽을 비활성화하는 것을 볼 수 있습니다. 따라서 장치가 종료되는 시점에는 방화벽이 비활성화되고 중요 서비스가 비활성화되는 그 틈에 저희가 요청을 보낼 수 있다면 아주 짧은 시간동안 중요 서비스에 접근할 수 있는 Race Condition 취약점이 발현하게 됩니다. 이 아이디어를 테스트해봤을 때 높은 확률로 해당 Race Condition을 재현할 수 있었습니다.

이를 통해 저희는 장치 내부에 주요 설정을 변경할 수 있었고(Ex. 기본 서비스 포트, 네트워크 설정, 서비스 옵션 등) 기타 다른 민감 서비스에 접근할 수 있게 되었습니다. 하지만 이것만으로 저희가 장치의 제어권을 장악했다고 보기 다소 어렵죠.

그래서 마지막 취약점을 통해 장치의 모든 제어권을 장악할 수 있었습니다.


Vulnerability #3 : Configuration Injection Remote Code Execution Vulnerability

CWE : CWE-77 - Improper Neutralization of Special Elements used in a Command (’Command Injection’)

CVSS : 7.5 AV:A/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H

Description:

저희는 모든 장비에 대해 선행 취약점을 조사하고 각 취약점의 변종들을 탐색합니다. 하지만 이 취약점은 동일 벤더의 다른 모델 CHARX SEC-3100에서 NCC Group에 의해 발견된 취약점입니다. 이 케이스는 발견되어 제보된 취약점이더라도 벤더에서 적절한 관리가 이루어져야 한다는 것을 보여주는 사례입니다.

CHARX SEC-3150 장치는 모뎀 기능을 구현하기 위해 오픈 소스인 pppd (Point-to-Point Protocol Daemon)를 사용합니다. 해당 데몬은 /etc/ppp 경로에 있는 설정 파일의 설정값(Ex. APN, 폰 번호, Default route 등)을 인자로 동작합니다. 이 설정값은 모두 앞서 언급한 설정 관리 데몬인 CharxSystemConfigManager 서비스에서 값을 변경할 수 있습니다. 설정값 예시는 다음과 같습니다.

이 여러 설정 중 idledisconnect 옵션에 대한 적절한 검증이 없는 것을 확인했습니다. CharxSystemConfigManager 서비스를 통해 pppd의 설정 변경 시 idledisconnect는 정수형 값이 요구되는 설정이지만, CharxSystemConfigManager에서 이에 대한 적절한 입력 검증을 수행하지 않아 임의 문자열과 개행 문자를 입력할 수 있었습니다.

또한, pppd는 옵션을 개행 문자를 기준으로 인식하기 때문에 이를 악용하여 원하는 옵션을 생성하고 부여할 수 있습니다.

pppd의 여러 옵션 중 등록된 인자 경로의 Script를 서비스 시작 시 실행할 수 있는 init 옵션이 존재합니다. 분석 결과 init 옵션은 실행할 스크립트 경로뿐 아니라 추가 인자도 함께 전달할 수 있음을 확인했습니다. |, ;와 같은 셸 메타문자(shell metacharacter) 역시 별도의 제한 없이 사용할 수 있었습니다.

Manual 설명은 다음과 같습니다.

그럼 공격자가 idledisconnect 옵션의 값을 CharxSystemConfigManeger 서비스를 활용하여 변조할 수 있다면, init 설정을 새롭게 등록하여 임의 바이너리 및 스크립트를 임의 인자와 함께 호출할 수 있게 됩니다.


이 3개의 취약점을 조합하여 다음의 공격 시나리오를 개발하였습니다.

  1. Vulnerability #1 Modbus 재부팅 취약점을 통해 장치를 재부팅합니다.

  2. Vulnerability #2 Race condition을 활용한 방화벽 우회 취약점을 통해 장치의 주요 설정을 변경할 수 있는 CharxSystemConfigManager를 Wan으로 접근할 수 있도록 허용합니다.

  3. Vulnerability #3 pppd 설정값 변조를 통해 Reverse Shell 명령어를 init 옵션에 등록합니다.

  4. Vulnerability #1 Modbus 재부팅 취약점을 다시 사용하여 장치를 재부팅합니다.

  5. 장치 재부팅으로 인해 pppd가 재시작됐을 때 init 옵션에 등록한 Reverse Shell 명령어가 실행되어 제어권을 장악하게 됩니다.

pppd는 Root 권한으로 동작하는 Service여서 모든 시스템 접근 권한을 획득할 수 있습니다.

테스트 환경에서는 95% 이상의 높은 재현율을 보였습니다. 다만 실제 대회에서는 첫 번째 시도가 실패했고, 두 번째 시도에서 공격 시연에 성공했습니다.

이 공격 시나리오를 Pwn2Own Tokyo에서 성공적으로 시연할 수 있었습니다. 흥미롭고 재밌는 대회를 운영해준 ZDI Team, 그리고 적절한 Disclosure Process를 갖고 알맞은 패치를 수행해준 Phoenix 팀에게 감사드립니다.


Conclusion

대회는 2026년 1월에 이루어졌으며 성공적인 공격 시연 후 Phoenix 보안팀 담당자와의 Private Disclosure를 수행하여 취약점에 대한 세부 내용과 패치 방향에 대해 논의하였습니다. 해당 취약점은 2026년 7월 30일 공개되었으며, 펌웨어 버전 1.9.0에서 패치되었습니다.

본 연구는 파급도가 낮은 취약점이더라도 연계될 경우 큰 위험도를 보이는 시나리오로 발전할 수 있음을 시사합니다. 또한, 발견된 취약점에 대한 적절한 관리가 이루어지지 않는다면 이 사례와 같은 이슈가 발생할 수 있습니다. 이번 연구는 단독으로는 영향도가 제한적인 취약점도 여러 시스템 구성 요소와 결합될 경우 장치 전체의 제어권 장악으로 이어질 수 있음을 보여줍니다. 또한 이미 공개된 취약점이라 하더라도 후속 모델과 동일 제품군에 대한 variant analysis와 지속적인 패치 관리가 중요하다는 점을 확인할 수 있었습니다.

저희 PetoWorks 는 차량 보안 및 임베디드 시스템에 대한 보안성 향상에 대한 여러 지식 및 경험을 갖고 있으며, 선행 연구 및 분석부터 기술 지원까지 전반적인 보안성 향상 프로세스를 지원합니다.


070-4110-1337 (대표번호)
02-861-1337 (세금계산서 문의)
02-861-1338 (Fax)

서울 금천구 가산디지털1로 205-15
SH드림타워 614호

(주) 글리치제로

함께 연구할 동료를 기다립니다

© PetoWorks Inc. 2025

070-4110-1337 (대표번호)
02-861-1337 (세금계산서 문의)
02-861-1338 (Fax)

서울 금천구 가산디지털1로 205-15
SH드림타워 614호

(주) 글리치제로

함께 연구할 동료를 기다립니다

© PetoWorks Inc. 2025

070-4110-1337 (대표번호)
02-861-1337 (세금계산서 문의)
02-861-1338 (Fax)

서울 금천구 가산디지털1로 205-15
SH드림타워 614호

(주) 글리치제로

함께 연구할 동료를

기다립니다

© PetoWorks Inc. 2025