Hacker News

A 32-year-old bug walks into a Telnet server

32년 묵은 버그가 Telnet 서버에 걸어 들어왔다 — GNU inetutils telnetd CVE-2026-32746

watchTowr가 GNU inetutils telnetd의 LINEMODE SLC 협상 처리 코드에서 1994년부터 존재해 온 pre-authentication BSS 버퍼 오버플로우(CVE-2026-32746)를 심층 분석했습니다. 인증 없이 인접 전역 변수 약 400바이트를 덮을 수 있고 Debian, FreeBSD, NetBSD, Citrix NetScaler, macOS 등 다수 구현이 같은 코드에서 파생됐지만, 트리플릿 바이트 제약과 0xFF 이스케이핑 때문에 실제 RCE는 상당히 까다롭습니다.

본문

watchTowr Labs가 DREAM Security Research Team이 발견한 CVE-2026-32746을 분석한 글입니다. 이 취약점은 GNU inetutils telnetd의 LINEMODE SLC(Set Linemode Characters) 협상 핸들러에 존재하는 BSS 기반 버퍼 오버플로우로, 공격자가 인증 전 단계에서 인접 전역 변수 약 400바이트를 손상시킬 수 있습니다. 1994년, 즉 영화 'Hackers'가 개봉한 해에 태어난 버그이며 32년간 발견되지 않았습니다. 패치는 inetutils-telnetd에 적용됐지만 수많은 fork가 같은 코드를 복사해 왔기 때문에 blast radius가 넓습니다. 글에서 확인한 영향 대상만 Ubuntu, Debian, FreeBSD 13/15 Port, NetBSD 10.1, Citrix NetScaler, Apple Mac Tahoe, Haiku, TrueNAS Core, uCLinux, libmtev, DragonFlyBSD에 달합니다. 재미있는 사실은 2005년에 Telnet 클라이언트 쪽에서 사실상 동일한 취약점(CVE-2005-0469, slc_add_reply의 경계 검사 누락)이 이미 수정됐다는 점인데, 20년이 지나서야 누군가 서버 쪽을 확인한 셈입니다.

취약점의 메커니즘

Telnet은 단순한 TCP 스트림이 아니라 echo 제어, 윈도우 크기 협상, 인증, 암호화까지 지원하는 프로토콜이며, 기능이 많다는 것은 공격 표면이 넓다는 뜻입니다. 이번 취약점은 RFC 1184의 LINEMODE 기능에 있습니다. 연결 수립 시 서버와 클라이언트는 IAC(Interpret As Command, 0xFF) 바이트로 인밴드 시그널링을 하는데, 서버가 'IAC DO LINEMODE'(0xFF 0xFD 0x22)를 보내고 클라이언트가 'IAC WILL LINEMODE'로 응답하면 기능이 활성화됩니다. 이후 SLC 트리플릿 — 특수 문자를 나타내는 func, 지원 수준 flag, 문자 값 val로 구성된 3바이트 단위 — 목록이 'IAC SB LINEMODE LM_SLC <triplets> IAC SE' 형태로 교환됩니다. 문제는 서버가 이 값들을 고정 크기 전역 배열 slcbuf에 경계 검사 없이 저장한다는 점입니다.

익스플로잇이 까다로운 이유

오버플로우는 가능하지만 입력에 제약이 많습니다. process_slc에서 func가 NSLC(0x1e)보다 크면 나머지 바이트가 0으로 폐기되고, func가 0이면 트리플릿이 버퍼에 들어가지 않습니다. change_slc에서는 flag 하위 2비트가 SLC_NOSUPPORT(0)이면 flag에 SLC_ACK(0x80)가 설정됩니다. 또한 각 바이트가 0xFF이면 0xFF 0xFF로 이스케이핑되어 트리플릿이 3바이트에서 4~6바이트로 확장됩니다. 이 때문에 홀수 개의 연속된 0xFF를 쓸 수 없는 대신, 이스케이핑을 이용해 트리플릿의 정렬을 +0/+1/+2 바이트씩 밀어서 원하는 바이트를 특정 오프셋(예: 포인터의 LSB)에 맞추는 정렬 테크닉이 가능합니다. 전체 데이터는 하나의 subnegotiation 패킷(0x200바이트)에 들어가야 하고, slcbuf는 0x6C바이트(헤더 4바이트 포함)라 실제 덮을 수 있는 범위는 약 0x190바이트입니다. 게다가 전역 변수 배치는 컴파일마다 달라져 바이너리별 분석이 필요합니다. 64비트 x86에서는 포인터에 연속된 NULL 바이트가 많아 full overwrite가 불가능하고 little-endian 부분 덮기만 가능해 다른 아키텍처보다 훨씬 어렵습니다.

Debian 32비트: arbitrary free까지의 경로

Debian은 32비트 x86 지원을 중단했기 때문에 이 취약점은 사실상 영구적입니다. 32비트를 지원하는 마지막 버전인 bookworm(12.13.0)의 telnetd를 분석한 결과, slcbuf 뒤에는 slcptr, slcchange, 그리고 def_slcbuf라는 포인터가 위치합니다. do_opt_slc에서 terminit()가 아직 false이면 SLC 데이터를 처리하지 않고 def_slcbuf에 malloc으로 복사해 두었다가, 터미널 초기화가 끝나면 deferslc가 do_opt_slc를 재호출하고 마지막에 free(def_slcbuf)를 호출합니다. 공격자가 TTYPE 응답보다 LINEMODE SLC를 먼저 보내 defer를 유도한 뒤 오버플로우로 def_slcbuf를 덮으면, 임의 주소에 대해 free를 호출하는 강력한 프리미티브를 얻습니다. 여기서부터는 libc에 따라 갈리는데, 가벼운 임베디드 시스템에서는 임의 쓰기를 통한 RCE로 빠르게 이어지지만 glibc의 힙 검사는 장벽입니다. 다만 Kerberos 인증을 쓰는 telnetd처럼 동적 할당이 많은 환경에서는 기회가 더 많습니다. 저자들은 테스트한 시스템에서 직접적인 RCE 경로는 찾지 못했지만 노출 정도는 다양했다고 밝힙니다.

탐지 방법

패치는 버퍼를 초과하는 데이터를 조용히 무시하는 방식이라 클라이언트에 피드백이 없습니다. 대신 서버는 클라이언트가 보낸 SLC 입력을 자신의 환경과 병합해 다시 응답하므로, 버퍼를 채우는 더미 데이터 뒤에 특이한 값을 보내 응답에 그 값이 포함되는지 확인하면 취약 여부를 판별할 수 있습니다. 취약 서버는 오버플로우된 값까지 저장해 돌려주고, 패치된 서버는 조용히 버립니다. watchTowr는 slcbuf를 정확히 1바이트만 넘는 최소 침습 방식의 Detection Artifact Generator와, LINEMODE 광고 여부만 확인하는 probe 모드를 함께 제공합니다. 단, 취약 서버에서는 1바이트 오버플로우가 segfault를 일으킬 가능성이 있지만, telnetd는 보통 inetd 아래에서 세션별로 spawn되므로 데몬 자체나 다른 세션에는 영향이 없다고 설명합니다. LINEMODE를 지원하지 않는 단순한 임베디드 구현은 이 취약점에 노출되지 않으므로, Telnet 포트가 열린 호스트가 많아도 우선 probe로 노출 여부를 빠르게 평가할 수 있습니다.

Hacker News 반응

  • @collinfunk — 이 이슈의 수정을 작성한 사람으로서(원래 코드를 쓴 사람이 아니라) 한 가지만 말하면, 이 문단은 저자가 엄청나게 무례한 사람처럼 들리게 만듭니다: '부끄럽게도 inetutils 프로젝트는 (적어도 발행 시점에는) 수정된 버전을 릴리스하지 않았다.' 버그는 공개 메일링 리스트에 보고됐는데 요즘 흔한 일이라 안타깝습니다. 보고서를 검토하지 못한 근무 시간이 끝난 뒤, 당시 너무 많은 slop 보고서를 받고 있었기에 버그가 실재하는지 확인하는 스크립트를 작성했고, 자러 가기 전에 패치를 보냈습니다.
  • @taftster — 불행한 표현입니다. 당신과 당신 같은 분들의 영웅적인 노력을 폄하하는 느낌도 줍니다. 다만 글의 센세이셔널리즘 정도로 용서될 수는 있을 겁니다. 저자를 변호하는 건 아니지만 이런 writeup은 너무 이른 시점에 손가락질로 흐르곤 합니다. 'Shamefully'는 확실히 잘못된 단어입니다.
  • @JoshTriplett — '센세이셔널리즘으로 용서될 수 있다'고요? 애초에 글에서의 센세이셔널리즘을 왜 용서해야 합니까?
  • @x______________ — HN에 상주하는 조용하지 않은 소수는, 진짜 영웅이란 시간을 내고 노력을 쏟은 뒤 여기에 와서 글까지 올리며 더 노력하는 사람들이라는 걸 압니다. OP를 포함한 모든 영웅에게 감사합니다.
  • @TacticalCoder — AI 무브먼트 전체가 Linux 같은 오픈소스 프로젝트와 터미널·커맨드라인 유틸리티 위에 세워져 있고, (에이전트를 격리하는 같은) 신의 작업을 하는 QEMU 같은 프로젝트 안에서 돌아간다는 걸 우리는 압니다. AI는 오픈소스 영웅들의 작업 안에 살고 있으며 그들 없이는 아무것도 아니었을 겁니다.

원문: watchTowr Labs / 번역·요약: Trawling