캠퍼스 내 모든 프로젝터와 카메라 제어권 획득하기
미국 콜로라도 광물대학교(Colorado School of Mines) 학생이 학교 내 DNS 서버가 각 기기에 서브도메인을 자동 할당한다는 점을 악용해, 무차별 대입(Brute force) 공격으로 캠퍼스 내 프로젝터와 카메라를 비롯한 기기들을 추적하고 제어하는 방법을 다룬 해킹 사례입니다. 처음에는 Python으로 시작했으나 처리 속도의 한계에 부딪혔고, 결국 Rust와 36진수 변환 알고리즘을 도입하여 프로그램의 성능을 극대화하여 작업을 마무리했습니다. 이 글은 네트워크 인프라의 취약한 설정이 어떻게 전체 캠퍼스 기기의 보안 위협으로 이어질 수 있는지 보여주는 중요한 사례입니다.
돌아가기 ⬏ 캠퍼스 내 모든 프로젝터와 카메라 제어권 획득하기 게시일: 2026년 5월 13일
콜로라도 광물대학교(Colorado School of Mines)에서 첫 학년을 시작할 무렵, 꽤 흥미로운 사실을 하나 발견했습니다. 바로 로컬 DNS 서버가 네트워크에 연결되는 각 기기에 서브도메인을 할당한다는 것입니다. 즉, “meow”라는 이름의 기기는 캠퍼스 내 모든 Wi-Fi에서 “meow.mines.edu”로 보이게 됩니다. 물론 네트워크 자체에서 외부 트래픽은 차단하지만 말입니다. 이 사실은 제 머릿속에 남아 이를 통해 무엇을 할 수 있을지, 특히 이 방법을 통해 네트워크 내 기기를 역추적할 수 있을지 생각하게 만들었습니다.
여기서 가장 큰 문제는 특정 서브도메인을 특정 IP로 연결해 주는 근본적인 DNS 레코드에 접근하는 것입니다(실제로는 이보다 조금 더 복잡하지만, 요점은 그렇습니다). 이 문제는 몇 가지 방법으로 해결할 수 있습니다.
영역 전송 (Zone Transfer) 이것이 가장 간단한 옵션이겠지만, IT 부서가 저에게 간단히 영역 전송을 허용해 줄 것이라고는 생각하지 않습니다(그리고 그들은 누구에게나 영역 전송을 허용해서는 안 됩니다). 또한 이 방법은 네트워크에 새 기기가 추가되거나 제거될 때마다 제 목록이 업데이트되지 않는 단점이 있습니다. 게다가, 그게 뭐가 재미있겠습니까?
인증서 (Certificates) 많은 서브도메인이 데이터가 올바른 곳에서 오는지 확인하기 위해 인증서(TLS, HTTPS 인증서)를 등록합니다. 이러한 인증서는 Let's Encrypt의 CT 로그 같은 추가 전용 원장(Ledger)이나 로그에 기록됩니다. 이러한 시스템은 웹사이트에는 유용하고 필수적이지만, 대학이 Wi-Fi에 연결된 모든 기기에 대해 TLS 인증서를 등록할 이유가 없다고 생각합니다. 특히 그 기기들은 인터넷에서 접근조차 불가능하기 때문입니다.
무차별 대입 (Brute force) 제가 생각하는 마지막 접근법이자 이 블로그 글의 주제는 무차별 대입(Brute force)입니다. 가능한 모든 도메인을 검색하거나, 일반적인 호스트 이름 사전(Dictionary)을 사용하여 탐색 횟수를 줄이는 등 몇 가지 방법이 있습니다. 개인적으로 이 프로젝트에서는 사전 접근 방식이 마음에 들지 않았습니다. 실제 현실에서는 더 실용적일지 몰라도, 저는 모든 조합을 무차별 대입으로 찾아낼 만큼 충분히 빠른 프로그램을 작성하는 데 특별히 관심이 생렸기 때문입니다. 가능한 도메인의 수가 '37의 n승'(n은 서브도메인의 문자 길이)이기 때문에 이 작업은 기하급수적으로 어려워집니다.
무차별 대입을 통한 순열 생성을 선택한 후(아마도 최악의 선택이었을 수 있습니다), 본격적으로 작업에 들어갔습니다. 첫 번째 프로그램은 문제를 이해하기 위해 Python으로 작성했습니다. itertools의 순열 함수를 사용하여 서브도메인을 만들기 위한 모든 문자와 숫자의 조합을 찾았습니다(스포일러를 밝히자면, 이게 바로 병목이었습니다). 각 DNS 응답을 기다리느라 실행이 차단되는 것을 막기 위해 비동기(Async) 방식이 필요하다는 것을 알고 있었습니다. 프로그램 자체로는 괜찮았고 쓸만한 최소한의 TUI(텍스트 사용자 인터페이스)를 갖추고 있었지만, 비동기임에도 불구하고 너무 느렸습니다. 그럼에도 불구하고 합리적인 시간 내에 3개의 문자로 구성된 서브도메인을 나열하기에는 충분했습니다.
바로 이즈음에 저는 언어를 Rust로 옮기기 시작했습니다. 저는 Rust로 된 멋진 프로젝트들을 많이 알고 있었지만, 제가 직접 뭔가를 만들어야 할 필요성은 느끼지 못했습니다. 지금까지 제가 하는 일에는 항상 Python이 충분히 빨랐으니까요. 또한 모달 편집기인 Helix를 가지고 놀기 시작하면서 그것이 얼마나 마음에 드는지 깨달았습니다. 저는 Python을 쓸 때 구문 강조 이상의 기능을 가진 편집기를 거의 사용하지 않지만, Rust에서는 언어 서버(Language Server)가 필수적이게 됩니다.
첫 시도에서는 Rust의 itertools 크레이트(crate)에 있는 다중 카티션 곱(multi cartesian product) 함수를 사용했지만, 곧 정수를 증가시킨 다음 이를 36진수로 변환하는 것이 훨씬 더 빠를 것이라는 것을 깨달았습니다. 순열 스레드의 속도는 상당히 중요해졌는데, 이는 이 부분이 대량의 CPU 작업을 수행하는 유일한 요소이며 쉽게 병렬화할 수 없기 때문입니다. Python 버전에서는 동일한 순열 생성 방식을 사용해 접두사를 만들고 각각을 스레드에 할당했지만, Rust에서는 이런 방식을 다루고 싶지 않았습니다. 대신, Bash 스크립트를 사용해 프로그램에 여러 프로세스를 생성하도록 하고, 각 프로세스에 총 프로세스 수와 고유한 오프셋(Offset)을 알려주었습니다. 각 프로세스는 IP를 나타내는 정수를 1 대신 총 프로세스 수만큼 증가시키며 시작하게 했습니다.