심장 출혈 빈틈 HeartBleed CVE-2014-0160 코드 깊이 분석

3120 단어 OpenSSL
며칠 전에 어떤 분이 저한테 오픈스sl 보셨잖아요.오픈스sl의 빈틈에 대해 이야기하다가 나는 어리둥절한 표정을 지었다.나는 유명한 심장 적혈 구멍을 알고 있다고 말했지만, 구체적인 구멍이 어떤 원인으로 인해 생긴 것인지 대답하지 못했다.오픈스sl 원본을 봤다고 자부하는 사람들에게 코드에 대한 연구가 필요하다고 생각해서 본고가 생겼습니다.
심장 적혈에 대한 상세한 소개는 이 사이트를 참고하지만 여기는 주로 개술적인 성격으로 코드 차원까지 깊이 들어가지 않았다.실제로 제가 간단하게 검색해 봤는데 인터넷에서 많은 분석이 있었지만 코드를 깊이 파고든 글은 인터넷에 거의 없습니다. 아마도 저는 코드 차원에 깊이 파고들어 심장의 혈액 구멍을 해석하는 첫 번째 글이 될 것입니다.github에opnessl-1.0.1f 버전의 코드가 없기 때문에 1.0.1stable만 있습니다.따라서 이 코드를 다운로드할 때 이곳에서 다운로드할 수 있다.적혈구멍의 영향 범위는 오픈슬 1에 한정되기 때문이다.0.1~1.0.1f 사이의 버전입니다.
본고에서 비교한 것은 Openssl1.0.1f(심장 적혈 문제가 존재) 및 1.1.0f(이 구멍을 복구한) 코드 차이.
심장 출혈 빈틈은 본질적으로memcpy 복사된 메모리에 대한 합법성 검사를 하지 않았고, 인터넷에 떠도는 메모리를 신청할 때OPENSSL_malloc 합법성 검사를 하지 않은 것이 아니다.OPENSSL_malloc는 합법성 검사를 하지 않았지만 서버의 메모리 데이터를 누설하지 않았기 때문에 진정한 세로 데이터는memcpy 동작이기 때문이다.
심장 출혈 취약점은 하트비트(RFC6520이 정의하는 기능)에 도입됐으며, OpenSSL에서는 하트비트 기능을 켤지 여부를 결정하기 위해 컴파일 매크로OPENSSL_NO_HEARTBEATS를 사용했다.따라서 검색OPENSSL_NO _HEARTBEATS에서 관련 코드를 찾을 수 있다.사실 OpenSSL-1.01f 발송자 함수에서 발송의 길이에 제한이 있다.오픈스sl 라이브러리에서 생성된 메시지를 사용하면 길이에 문제가 없다는 뜻이다.1.0.1f에서 함수ssl3_ctrlcase SSL_CTRL_DTLS_EXT_SEND_HEARTBEAT 분기 호출 함수dtls1_heartbeat에서 다음과 같은 제한OPENSSL_assert(payload + padding <= 16381)을 했다. 즉, 보내는 최대 메시지의 길이는 16384(type 한 바이트, 길이는 두 바이트)이다.
서버 정보가 유출되었기 때문에 함수dtls1_process_heartbeat로 지정되었습니다.openssl1.0.1f와 이전 버전은 수신자 함수에서 길이에 제한을 두지 않았다.수신자가 심장 박동 메시지TLS1_HB_REQUEST를 받은 후 발송자에게 보내는 응답에 대한 메시지의 길이는 발송자가 전달하는 메시지의 길이이다.다음 코드:
buffer = OPENSSL_malloc(1 + 2 + payload + padding);
bp = buffer;

/* Enter response type, length and copy payload */
*bp++ = TLS1_HB_RESPONSE;
s2n(payload, bp);
memcpy(bp, pl, payload);

문제는 주로memcpy에서 발생한다. 그 중에서payload는 발송자가 가져온 메시지 길이이고pl는 수신자가 발송자가 보낸 하트비트 요청 부분의 메모리 공간을 저장하는 데 사용되며 bp는 발송할 버퍼이다.앞에서 언급한 송신자는 사실 전송할 수 있는 최대 길이를 규정했기 때문에 예를 들어 송신할 때 제한을 했다. 2^14-3=16381 즉 수신자 수조도 제한을 한다. 즉pl공간에 최대치가 있다.그러나 구성된 하트비트 요청 메시지의 길이가 16381(자체적으로 구성된 이상 메시지)을 넘으면pl는 메모리 공간이기 때문에 복제할 때 경계를 넘는다.payload는 unsigned int 유형이기 때문에 최대 유출 가능한 메모리 공간은 2^64, 즉 64K 크기의 데이터이다.bp는 발송할 버퍼입니다.pl와 인접한 메모리 데이터가 사이트 키라면 키가 클라이언트에게 되돌아와 사이트 키의 유출을 초래합니다.만약 인접한 메모리가 사용자 이름과 비밀번호라면 사이트의 사용자 이름과 비밀번호가 모두 유출될 것이다. 64K는 여전히 매우 큰 데이터 공간이기 때문에 만약에 끊임없이 사이트에 하트비트 요청을 한다면 사이트의 키, 사용자 정보의 유출은 가히 알 수 있기 때문에 이것은 심장 출혈의 빈틈이 이렇게 치명적인 원인이다.
왜 유출되었는지 알았으니 그에 상응하는 패치도 잘 됐다.송신단이 송신의 길이 크기를 어떻게 제한하는가에 따라 수신단은 같은 제한을 하면 된다.예를 들어 Openssl 1.1.0f에서 수정된 코드는 다음과 같습니다.
unsigned int write_length = HEARTBEAT_SIZE(payload, padding);
int r;

if (write_length > SSL3_RT_MAX_PLAIN_LENGTH)
    return 0;
SSL3_RT_MAX_PLAIN_LENGTH의 값은 16384로 송신자와 수신자의 길이가 일치한다.
이상은 심장 적혈구멍에 대한 CVE-2014-0160 코드 차원에서의 분석입니다.물론 문장에서dtls1_process_heartbeat와 같은 함수를 예로 들어 설명하자면dtls는 전송층이 UDP인 암호화이고 전송층이 TCP인 데 상응하는 함수는tls1_process_heartbeat이어야 한다. 물론 서로 다른 Openssl 버전은 약간의 차이가 있을 수 있지만 전체적으로 보면 DTLS와 TLS에 모두 이런 빈틈이 존재했다.
본고는 CSDN 마을의 소년 오리지널 문장으로 전재 기억에 작은 꼬리 인형을 추가하고 블로거가 이곳을 연결한다.

좋은 웹페이지 즐겨찾기