80 Days Reversing an IoT DVR: Stripped ARM32 Firmware, Hardcoded AES Keys & Post-Mortem here is my write up love yall.
IoT DVR 펌웨어를 80일간 역공학한 기록: 하드코딩된 AES 키와 ARM32 명령 주입
작성자는 여러 세대의 ARM32 DVR 펌웨어를 분석해 하드코딩된 AES 키를 이용한 인증 우회와 펌웨어 업그레이드 경로의 명령 주입을 보고합니다. 다만 실제 장비는 취약 코드가 빠진 최신 버전이었고, 인터넷에 노출된 구형 기기에는 시험하지 않아 원격 악용은 확인하지 못했습니다.
- 주제
AI 요약
작성자는 HiSilicon Hi3521a 기반 DVR의 펌웨어와 네트워크 프로토콜을 약 80일간 역공학했다고 설명합니다. Shodan에서 로그인 화면의 HTML 해시를 기준으로 인터넷에 노출된 장비 28,006대를 찾았고, 이 가운데 2,956대가 취약 코드가 포함된 2.3.7.x 버전을 실행 중인 것으로 파악했다고 합니다. 분석 대상 서비스는 웹 관리 화면이 열린 TCP 80번 포트와 영상 스트리밍·장비 관리용 바이너리 데몬이 열린 8000번 포트입니다.
분석 과정과 잘못 짚은 단서
펌웨어 두 세대의 파일 시스템을 풀어 Qt 기반 UI와 네트워크 이벤트 처리 코드, 부팅 스크립트, 하드웨어 추상화 라이브러리를 살폈습니다. 초기에 iSCSI 명령 문자열에서 셸 명령 삽입 가능성을 의심했지만, Ghidra와 radare2로 호출 지점을 추적한 결과 해당 기능은 로컬 UI에서만 호출됐습니다. 네트워크에서 접근할 수 없다는 사실을 확인하고 처음 판단을 철회했다고 밝힙니다.
보고된 인증 우회와 명령 주입
TCP 8000번 포트의 프로토콜은 8바이트 헤더와 명령 코드, 길이 정보로 패킷을 구성합니다. 로그인 명령 0x8100을 분석하자 AES-256-CBC 키와 IV가 바이너리에 고정돼 있었습니다. 작성자는 이 키로 로그인 요청을 암호화해 실험용 장비에서 인증을 통과하고, 장비 정보와 세션 토큰을 받았다고 합니다. 따라서 이 키를 아는 공격자는 해당 프로토콜을 쓰는 장비에 비밀번호 없이 로그인할 수 있다는 주장입니다.
펌웨어 업데이트 처리에서는 명령 0x220이 입력 문자열을 sscanf로 읽고, 0x221이 그 경로를 셸 명령에 넣는 흐름을 발견했다고 설명합니다. 경로를 mv 명령에 이어 붙이는 과정에서 필터는 백틱과 달러 기호만 거르고 세미콜론, 파이프, 리디렉션 문자는 막지 않았습니다. 작성자는 Unicorn Engine으로 실제 ARM32 바이너리를 메모리에 올리고 레지스터와 문맥 구조체를 설정해, 공격자 입력이 system() 호출까지 전달되는 것을 확인했다고 합니다. 이 에뮬레이션은 코드 경로의 실행을 보여주지만, 구형 펌웨어를 구동하는 원격 장비에서 실제 셸을 얻었다는 뜻은 아닙니다.
부팅 스크립트에는 /dvr/fwr 파일이 있으면 압축을 풀고 내부의 ./upgrade를 root 권한으로 실행하는 흐름도 있었습니다. 작성자는 서명 검증이나 해시 확인이 없다고 보고합니다. 다만 댓글에서는 이 업그레이드 경로로 실험 장비를 구형 펌웨어로 되돌려 테스트하지 않은 이유와, 인증 우회 및 임의 코드 실행 가능성이 있는데도 취약점의 실제 영향을 더 구체적으로 입증하지 않은 이유를 묻습니다.
확인하지 못한 원격 악용과 공개 과정
실험용 장비는 3.1.14.0 버전이었습니다. 이 버전에서는 0x220·0x221 코드가 네트워크 명령 처리 경로에서 빠져 있어, 작성자가 가진 장비로는 해당 명령 주입을 원격에서 재현하지 못했습니다. 구형 버전의 장비에 접근해 시험하지 않았다고 밝혔으며, 그래서 인터넷에 노출된 2,956대에 실제 공격을 시도하지 않았습니다.
NTP 설정값을 이용한 별도 명령 주입도 발견했지만, 값은 NVRAM에 남아도 해당 펌웨어의 부팅 과정에서 NTP 동기화 코드가 실행되지 않아 페이로드가 발동하지 않았다고 합니다. 제조사에는 보안 연락처가 없었고 안내서의 연락처에도 답이 없었습니다. Zero Day Initiative(ZDI)에 분석 자료를 제출했지만 받아들여지지 않았으며, 작성자는 소비자용 DVR이 해당 프로그램의 주요 구매 대상이 아니라고 설명합니다.
Reddit 반응
댓글은 기술 성과 자체보다 글의 신뢰성과 설명 방식에 집중했습니다. 여러 사용자는 AI로 다듬은 문장이 이해하기 어렵고, 주장한 취약점의 재현 절차와 펌웨어 버전 차이를 충분히 보여주지 않는다고 지적했습니다. 작성자는 글을 AI로 구조화하고 문장을 정리했으며, 분석 작업은 직접 했다고 답했습니다. 원시 디스어셈블리와 패킷 형식, 추적 로그 중심의 후속 글을 올리겠다는 말도 덧붙였습니다.
- @u/frankster — Python 코드를 역공학했다고요? 대단합니다. 공개되지 않은 발견을 노트에서 공식적으로 철회했다는 건 무슨 뜻인가요? 노트에서 몇 번 삭제 키를 누르면 공식 철회가 되나요? 글에 AI가 쓴 헛소리가 섞인 것 같아, 말이 되는 부분도 실제로 믿어도 되는지 궁금합니다.
- @u/LeviathanX_Cloud — 같은 해시와 같은 3세대 Hikvision 계열의 하드코딩된 항목입니다. 테스트 파일이 너무 많아 마지막 수단으로 가진 걸 그냥 올리기로 했습니다. Raspberry Pi 5에서 직접 풀고 역공학해 보세요. pwneye는 인증 없는 특정 ONVIF 해시를 시험하고 오래된 DVR에서 버퍼 오버플로 RCE를 찾아보려던 것이었습니다. 저는 초보입니다.
- @u/big_trike — 이 답글을 읽으니 머리가 아픕니다. 왜 AI에게 글을 쓰게 했는지 이제 알겠습니다.
- @u/Ill-Quit6803 — AI 문장 대신 본인 목소리로 발견 과정을 들려줬으면 합니다. 글이 이해하기 어렵습니다. 공개하지 않은 발견을 왜 철회하는지, 하드코딩된 비밀 키를 이용한 인증 우회가 왜 CVE 심각도 10점이 아닌지 궁금합니다. 인증 없이 펌웨어를 다시 쓸 수 있다면 왜 업데이트 단계의 명령 주입을 찾았나요? NTP를 본 이유는 무엇인가요? 장비에 지속적으로 접근할 방법은 없었나요? 기술 내용도 얕고 설명이 서로 맞지 않습니다.
- @u/LeviathanX_Cloud — 맞습니다. 글은 AI 보조를 받았습니다. 저는 18살이고 첫 큰 글이라 구조를 잡고 문장을 다듬는 데 AI를 썼습니다. 기술 작업은 제 몫입니다. 바이너리, ASAN 로그, Unicorn 추적, PoC가 저장소에 있습니다. 원한다면 서사와 다듬은 문장 없이 디스어셈블리와 패킷 형식만 담은 후속 글을 쓰겠습니다.
- @u/Ill-Quit6803 — 많은 작업을 한 것 같고 암호화된 펌웨어 추출, Unicorn 에뮬레이션, 취약점 분석에는 배울 점이 있어 보입니다. 하지만 글의 서사가 앞서 언급한 이유로 이해되지 않습니다. 인증 우회와 임의 코드 실행 펌웨어 업데이트가 가능하다면 CVE 10.0처럼 들립니다. 실제로 어떻게 분석했는지 보여주는 기술 글이었다면 좋았겠습니다.
- @u/Lower_Compote_6672 — 이 글이 좋았습니다. 유튜브 영상으로 만들지 않은 점에 가산점을 주고 싶습니다.
- @u/LeviathanX_Cloud — 질문에 답하자면, Tor는 장비를 벽돌로 만들지 않고 펌웨어 업데이트를 시험하려고 썼습니다. 당시 자원이 부족했고, 이 장비는 제 소유가 아니라 테스트 브리지를 거쳐 접근했습니다. 며칠 잠을 못 자고 Tor 브리지를 써보자고 생각했습니다. 멍청한 선택이었고 죄송합니다.
- @u/Ill-Quit6803 — Tor 사용에 대한 답변인지 명확하지 않고 글을 읽기 어렵습니다. 소유하지 않은 장비에 Tor로 업데이트를 보낸 것처럼 들립니다. 펌웨어 업데이트가 설명처럼 간단하다면 왜 테스트 장비를 다운그레이드하지 않았나요? Tor로 0-day를 던지면 판매하기 전에 이미 n-day가 될 수 있습니다.
- @u/LeviathanX_Cloud — 제 장비에서 테스트 브리지를 사용한 것이지 다른 사람의 장비가 아닙니다. Tor는 다른 작업에서 쓰던 습관이었고, 돌이켜보면 글을 혼란스럽게 만들었습니다. 제3자를 대상으로 공격하지 않았습니다. 원시 기술 자료를 서사나 AI 문장 없이 쓰는 편이 나았을 겁니다. 죄송합니다.
원문: Leviathan / 번역·요약: Trawling