ssl pinning은 HPKP (HTTP Public Key Pinning)에서 주로 사용되는 용어입니다. 

이미 잘 알려져 있다시피 SSL/TLS 로 이루어진 암호화 통신은 중간자 공격 (Man in the Middle) 에 취약합니다. 특히 요즘에는 여러 보안장비들이 SSL Decryption 기능을 제공하며 이 중간자 공격 (Man in the Middle) 형태로 SSL 및 TLS 세션을 복호화 하여 내용을 검증하도록 되어 있습니다. 이 때 보안장비는 공격자와 마찬가지로 암/복호화에서 사용할 인증서를 임의로 교체하여 중간에서 데이터를 복호화 하여 검증 하도록 구성되어 있습니다.

위 예제와 같이 클라이언트 (유저) 는 최종적으로 중간의 보안장비 또는 공격자가 제공한 인증서를 기반으로 암호화 통신을 진행하게 되며 이를 통하여 Man in the Middle 에 노출되게 됩니다. 

HKPK란 위와 같이 침해된 인증서를 동반한 공격을 막기 위해 고안됐습니다. 브라우저가 HPKP를 사용하는 웹사이트에 접속하면 브라우저는 특정 웹 서버에 어떤 공개 키가 사용되는지를 일정 기간 동안 기억할 수 있게 됩니다. 그 기간 동안 브라우저는 다른 모든 공개 키를 무시합니다. 현재 크롬, 파이어폭스, 오페라만이 이 HKPK 기능을 지원하고 있었으나 크롬은 이 대열에서 빠지게 됐습니다.

HPKP(HTTP Public Key Pinning)


클라이언트가 SSL/TLS 암호화 통신에 사용할 인증서를 최종서버의 인증서로 고정(Pinning) 하는 방식을 HPKP라 합니다. 이렇게 클라이언트가 최종서버의 인증서를 고정하면 중간에서 보안장비 또는 공격자가 제공한 임의의 인증서를 맞지 않는 인증서라 판단하여 거부할 수 있습니다. 

이처럼 특정 서버의 호스트를 확실히 알고 싶거나 공격이 발생할 것이라 예상되는 환경에서 작업할 때 사용하게 됩니다.

크롬은 HPKP를 왜 제거할까?

간단하게 더 이상 도움이 되지 않기 때문입니다.

HKPK는 가짜 인증서 공격에는 강력한 대응책이 되나, 공격자들이 악성 핀을 설치하거나 사이트 운영자가 실수나 고의로 방문자들을 차단할 수 있다는 결함이 있습니다. 공격자가 특정 웹 서버를 침해하는 데 성공한다면, 해당 웹사이트 방문자들에게 악성 HPKP 헤더를 전송할 수도 있으며 사이트 운영자가 다시 한 번 해당 웹사이트에 대한 통제권을 가져온다고 해도 공격자의 HPKP 정책 때문에 브라우저들로 접근하는 게 여전히 불가능해질 수도 있습니다. 또한 운영자가 HKPK를 적용할 때 실수를 하나만 해도 사용자들이 엉뚱한 키를 다운로드 받아 사이트에 며칠에서 몇 달씩 접속하지 못하도록 하는 등 커다란 피해가 발생해 도입이 부담이 될 수 있습니다. 이렇게 보안적으로는 완벽하지만 실제 운영에서는 유연성이 떨어진다는 면도 존재합니다. 

다른 이유로 공개 키 피닝(PKP) 자체의 도입률이 매우 저조하다는 것입니다. 탑 백만 사이트들 중 약 0.04%만 적용이 되어 있습니다. 따라서 구글이 HKPK를 폐지하기로 한 건 이런 기술적인 어려움과 완전하지 못한 보안성 때문입니다.


크롬에서 가짜 인증서를 통한 공격은 HPKP 대신 Expect-CT 헤더를 도입하여 방어를 진행하고 있습니다. Expect-CT는 사이트 운영자들이 설정 오류를 저질러도 유연하게 복구할 수 있게 해줘서 HPKP보다 훨씬 안전하고 다양한 인증기관과의 호환성을 갖추고 있습니다.

'보안' 카테고리의 다른 글

SSL Pinning  (0) 2018.12.18
TLS (Transport Layer Security)  (0) 2018.12.18
스니핑  (0) 2017.04.12
패스워드 크래킹  (0) 2017.03.28
알려진 평문 공격 (기지 평문 공격) - Known-plaintext attack  (0) 2017.03.27
무차별 대입 공격 (Brute Force Attack)  (0) 2017.03.27

TLS란?

인터넷에서의 정보를 암호화해서 송수신하는 프로토콜

넷스케이프 커뮤니케이션스사가 개발한 SSL(Secure Sockets Layer)에 기반한 기술로, 국제 인터넷 표준화 기구에서 표준으로 인정받은 프로토콜입니다. 표준에 명시된 정식 명칭은 TLS지만 아직도 SSL이라는 용어가 많이 사용되고 있습니다.


흔히 SSL이라 부르는 것들의 대부분은 TLS입니다. SSL은 POODLE, DROWN 등의 취약점이 발견되어 현재 사용되지 않는다고 보면 됩니다. TLS를 사용해 암호화된 연결을 하는 HTTP를 HTTPS(Secure)라고 하며, 웹사이트 주소는 HTTPS로 시작합니다. 기본 포트 또한 80번이 아닌 443번을 씁니다.

TLS와 HTTPS를 혼동하는 경우가 많은데, 둘은 유사하긴 하지만 다른 개념입니다. TLS는 다양한 종류의 보안 통신을 하기 위한 프로토콜이며, HTTPS는 TLS 위에 HTTP 프로토콜을 얹어 보안된 HTTP 통신을 하는 프로토콜입니다. 다시 말해 TLS는 HTTP뿐만이 아니라 FTPSMTP와 같은 프로토콜까지 포함하며, HTTPS는 TLS와 HTTP가 조합된 프로토콜만을 가리킵니다.


'보안' 카테고리의 다른 글

SSL Pinning  (0) 2018.12.18
TLS (Transport Layer Security)  (0) 2018.12.18
스니핑  (0) 2017.04.12
패스워드 크래킹  (0) 2017.03.28
알려진 평문 공격 (기지 평문 공격) - Known-plaintext attack  (0) 2017.03.27
무차별 대입 공격 (Brute Force Attack)  (0) 2017.03.27

스니핑은 네트워크 패킷을 가로채서 분석하는 해킹기법입니다. 아래는 파이썬을 사용한 간단한 스니핑 프로그램 예제입니다.

from socket import *
import os

def sniffing(host):
    # 아래 값들은 소켓을 생성할 때 프로토콜을 지정하는 세 번째 인자로 사용
    # 윈도우는 프로토콜에 관계없이 들어오는 모든 패킷을 가로채기 때문에 IP를 지정해도 무관하지만 유닉스나 리눅스는 ICMP를 가로채겠다는 것을 명시적으로 표시해야함
    if os.name == 'nt':
        socket_protocol = IPPROTO_IP
    else:
        socket_protocol = IPPROTO_ICMP
    # socket_protocol로 지정된 프로토콜을 이용하는 Raw 소켓을 만들고 호스트와 바인드
    sniffer = socket(AF_INET, SOCK_RAW, socket_protocol)
    sniffer.bind((host, 0))
    # 가로채는 패킷에 IP 헤더를 포함하라고 소켓의 옵션으로 지정
    sniffer.setsockopt(IPPROTO_IP, IP_HDRINCL, 1)

    # 윈도우인 경우 소켓을 promiscuous모드로 변경하여 호스트에 전달되는 모든 패킷을 수신.
    # 소켓이 promiscuous 모드가 아니면 코드가 구동되는 컴퓨터가 목적지가 아닌 패킷은 모두 버리게 됨
    # if os.name == 'nt':
    #     sniffer.ioctl(SIO_RCVALL, RCVALL_ON)
    # 소켓으로 패킷이 들어올 때까지 대기. 65565는 버퍼의 크기로 단위는 바이트
    packet = sniffer.recvfrom(65565)
    print(packet)

    # if os.name == 'nt':
    #     sniffer.ioctl(SIO_RCVALL, RCVALL_OFF)

print(gethostname())
host = gethostbyname(gethostname())
print('start sniffing {0}'.format(host))
sniffing('127.0.0.1') # 호스트 이름을 IPv4형식으로 변경한 ip를 했을 때 에러나서 임시 ip 지정

# 스니핑된 패킷 결과
# (b'E\x00$\x00\x1d\xc1\x00\x00@\x01\x00\x00\x7f\x00\x00\x01\x7f\x00\x00\x01\x03\x03\x07\xe2\x00\x00\x00\x00E\x00\xeb\x00)\xf2\x00\x00@\x11\x00\x00\x7f\x00\x00\x01\x7f\x00\x00\x01\xc7\xd9~x\x00\xd7\x00\x00', ('127.0.0.1', 0))

종류

스니핑에는 여러가지 종류가 있습니다.

  • IP Header 스니퍼
  • ICMP 스니퍼
    • IP 네트워크에서 진단이나 제어 용도로 사용되며, 오류에 대한 응답으로 생성.
  • 호스트 스캐너
    • ICMP 스니핑을 사용하면 해당 호스트가 살아있는지 아닌지 확인할 수 있음. 호스트 스캐너는 컴퓨터에 연결된 서브네트워크의 모든 호스트로 특정 메시지가 포함된 IP 데이터그램을 전송하고 이에 대한 응답 내용을 분석하여 호스트가 동작 중인지 알아내는 프로그램. 
  • PING을 사용한 호스트 스캐너

방어대책

  • 패킷 스니퍼가 설치될 수 없도록 네트워크 미디어에 대한 물리적 접근 제한
  • 중요 정보에 대해 암호화 사용
  • ARP 스푸핑 방지를 위해 정적 IP와 정적 ARP 테이블을 사용
  • ARP 캐시에 게이트웨이 영구 MAC 주소 설정
  • SSH나 SCP, SSL 등과 같은 암호화 세션 사용
  • 승인된 사용자로 네트워크 제한이 가능하다면 스니핑 도구가 패킷을 감지하지 못하도록 브로드캐스트 기능 오프


'보안' 카테고리의 다른 글

SSL Pinning  (0) 2018.12.18
TLS (Transport Layer Security)  (0) 2018.12.18
스니핑  (0) 2017.04.12
패스워드 크래킹  (0) 2017.03.28
알려진 평문 공격 (기지 평문 공격) - Known-plaintext attack  (0) 2017.03.27
무차별 대입 공격 (Brute Force Attack)  (0) 2017.03.27

1. 유닉스(리눅스) 패스워드 크래킹

유닉스나 리눅스는 기본적으로 사용자의 패스워드를 MD5 해시값으로 변경하여 관리하고 있습니다. 예를 들어, abcd 아이디의 패스워드가 1234라고 하면 1234에 대한 MD5 해시값인 81 dc 9d db 52 d0 4d c2 00 36 db d8 31 3e d0 55를 사용합니다. 그런데 test 아이디를 가진 사람의 패스워드도 1234라고 하면 문제가 발생할 수도 있습니다. abcd 아이디를 가진 사람이 우연히 test의 비밀번호 MD5값이 동일하다는 것을 안다면 비밀번호가 1234라는 것을 알 수 있기 때문입니다. 그래서 이런 문제를 해결하기 위해 salt라 부르는 2개의 문자를 원래 패스워드에 추가한 후 MD5 해시를 구성하는 매커니즘을 사용하고 있습니다. 

다시 예를 들어 abcd 아이디의 패스워드가 1234면 salt값로 fa를 앞에 추가하여 fa1234의 MD5 해시값을 07 9b 71 85 33 d9 9a fe 18 9a fb e2 bc 4a a3 58과 같이 만듭니다. 이 값에 salt인 fa를 추가합니다 . 문자 fa는 16진수 ASCII 값으로 66 61이므로 abcd의 1234는 66 01 07 9b 71 85 33 d9 9a fe 18 9a fb e2 bc 4a a3 58로 관리하게 됩니다. 동일한 원리로 test의 패스워드 1234에 salt로 f3을 추가했다고 하면 abcd와 test의 MD5 해시값은 다른 값이 생성됩니다.


리눅스는 사용자 인증에 필요한 정보를  /etc/passwd에 저장하고 관리합니다. 

root : x : 0 : 0 : root : /root : /bin/bash
#로그인 이름:패스워드:사용자아이디:그룹아이디:코멘트:홈디렉토리:기본쉘

두 번째 필드가 패스워드이지만 모두 x로 표시되어 있으며, 실제 패스워드는 /etc/shadow 파일에 저장되어 있습니다. 

root:$1$agjnf2382F32o9h#T2:14923:0:99999:7:	:	:
abcd:$1$fnafnQO'I2R28y:14945:0:99999:7:	:	: 

첫 번쨰 필드는 사용자계정이고 두 번째 필드는 salt가 포함된 사용자 패스워드 해시값입니다.

두 번째 필드 분류

$1$: MD5

$5$: SHA256

$6$: SHA512 

위에서 예로 든 /etc/shadow 파일의 내용에 접근하여 root와 abcd의 패스워드 해시값을 얻었다면 오프라인 공격 유형으로 패스워드 크래킹을 수행할 수 있습니다. 인터넷에는 패스워드 크래킹을 위한 사전을 텍스트 파일로 유통하는 사이트가 많이 있습니다. 보통 용량이 크기 때문에 아래와 같이 사전파일을 예로 만들고 패스워드 크래킹의 원리를 설명합니다.

apple
python
password
12345
secret
welcome
admin
pineapple
other
login
pokemon
iloveyou


/etc/shadow에서 패스워드 크래킹을 위해 획득했다고 가정하고 passwords.txt로 저장합니다.

root:$1$a3gSE1RAj6522:14923:0:99999:7:::
test:$1$zfti6chVSQLlQ:14945:0:99999:7:::


 아래 코드를 작성한 후 실행하면 다음의 결과가 생성됩니다.

import crypt


def find_pass(pass_hash, dictfile):
    salt = pass_hash[3:5]
    with open(dictfile, 'r') as dfile:
        for word in dfile.readlines():
            word = word.strip('\n')
            cryptwd = crypt.crypt(word, salt)
            if cryptwd == pass_hash[3:]:
                return word


dictfile = 'dictionary.txt'
with open('passwords.txt', 'r') as pass_file:
    for line in pass_file.readlines():
        data = line.split(':')
        user = data[0].strip()
        passwd = data[1].strip()
        word = find_pass(passwd, dictfile)

        if word:
            print('id: {0} password: {1}'.format(user, word))

        else:
            print('not found')
 
# 결과
# id: root password: iloveyou
# id: test password: python

2. zip 파일 패스워드 크래킹

zip 파일은 사전공격이나 무차별 대입 공격으로 ZIP 파일을 풀 수 있습니다. 아래는 사전공격으로 zip 파일을 푸는 파이썬 예시입니다.

import zipfile
from threading import Thread


def crackzip(zfile, passwd):
    try:
        zfile.extractall(pwd=passwd)
        print('zip file pass {0}'.format(passwd.decode()))
        return True

    except:
        pass
    return False


dictfile = 'dictionary.txt'
zipfilename = 'locked.zip'
zfile = zipfile.ZipFile(zipfilename, 'r')
pfile = open(dictfile, 'r')

for line in pfile.readlines():
    passwd = line.strip('\n')
    t = Thread(target=crackzip, args=(zfile, passwd.encode('utf-8')))
    t.start()

해당 파일의 같은 경로에 zip파일과 비밀번호가 있는 dictionary.txt 파일이 존재하면 압축파일이 해제되는 것을 확인할 수 있습니다.

3. 시스템 패스워드 크래킹 

수동적 온라인 공격

공격자가 대상 시스템에 직접 연결하거나 통신하지 않고 패스워드 크래킹을 수행하는 방법입니다. 유선 스니핑, 중간자 공격 등이 있습니다.

능동적 온라인 공격

공격자가 대상 시스템에 직접 접속하여 패스워드를 추측하여 입력함으로써 공격하는 방법입니다. 패스워드를 일일이 입력하지 않고 자동화된 도구를 활용하여 공격합니다. 자동화 도구로는 트로이 목마, 스파이웨어, 키로거 등이 있습니다.

오프라인 공격

오프라인 패스워드 공격은 공격자가 시스템이 관리하는 패스워드 파일에 접근할 수 있을 경우 가능한 공격 방법입니다. 오프라인 공격에 보편적으로 활용되는 해킹 기법은 무차별 대입 공격, 사전공격, 음절 공격, 레인보우 테이블 공격 등과 같은 암호 공격입니다.

'보안' 카테고리의 다른 글

TLS (Transport Layer Security)  (0) 2018.12.18
스니핑  (0) 2017.04.12
패스워드 크래킹  (0) 2017.03.28
알려진 평문 공격 (기지 평문 공격) - Known-plaintext attack  (0) 2017.03.27
무차별 대입 공격 (Brute Force Attack)  (0) 2017.03.27
SSL (Secure Socket Layer)  (0) 2017.03.27

기지 평문 공격은 공격자가 평문과 그를 암호화한 암호문을 모두 알고 있을 때 사용할 수 있는 암호 해독 기법들을 가리킵니다. 이 경우 이미 알고 있는 평문을 크립(crib)이라고 부르기도 합니다. 이미 알고 있는 평문과 암호문을 바탕으로 비밀 키를 알아내기 위해 사용합니다. 암호해독가가 암호를 해독하기 위해 의미 없어보이는 암호문만 보아서는 많은 정보를 얻기 힘들지만 암호문 안에 이미 알고 있는 평문이 포함되어 있다면, 그 사실이 암호문과 평문 사이의 관계를 추정하기 위한 단서가 될 수 있습니다.

AES 등의 현대 암호체계는 기지 평문 공격의 영향을 받지 않는 것으로 알려져 있지만 예전 버전의 ZIP 파일 포맷에 사용되는 PKZIP 스트림 암호화 알고리즘은 기지 평문 공격에 취약합니다. 이 알고리즘으로 암호화된 압축 파일은 압축 파일 안에 들어있는 파일의 일부라도 알아낼 수 있으면 전체 압축 파일을 해독할 수 있습니다.

개요

무차별 대입 공격이란 조합 가능한 모든 문자열을 하나씩 대입해 보는 방식으로 문제를 푸는 것인데, 얼핏 무식하다고 생각할 수도 있겠지만 항상 정확도 100%를 보장한다는 점에서, 자원만 충분하면 가장 무서운 방법입니다. 이론적으로 가능한 모든 경우의 수를 다 검색해 보는 것이라 정확도 100%가 항상 보장되니, 암호학에서는 가장 확실한 방법으로 통용되고 있습니다. 무엇보다도 암호 확인 작업이라는 것이 손으로 입력한 문자열의 동일 여부를 확인하는 것이기 때문에, 가능한 경우를 하나씩 대입하다 보면 언젠가는 암호를 찾을 수 있게 되는 식입니다. 다만 정말로 그냥 무식하게 하는건 아니고, 숫자만 섞어서 대입해보기 한번, 로마자만 섞어서 대입해보기 한번 이런식으로 하다가 안되면 나머지를 순차적으로 하는 식으로 특정 규칙에 따라 우선순위를 두고 하기도 합니다.

또한 브루트 포스의 특장점은 거의 완벽하게 병렬 작업이 가능하다는 점입니다. 이 때문에 병렬 프로그래밍 기법을 사용하거나, GPGPU를 이용하기도 하며, 여러 대의 컴퓨터를 연결해서 동시에 작업할 수도 있습니다. 이렇게 하면 투자 자원에 비례해서 문제를 해결하는 시간을 줄일 수 있습니다. 즉, 컴퓨터를 10대 쓰면 10일 걸릴 작업을 1일만에 끝낼 수 있습니다.(다만 암달의 법칙 때문에 이런 식으로 병렬화가 잘 되는 작업은 흔치 않음)

단점

자원이 가장 큰 문제이며, 브루트 포스 방법에는 문제의 복잡도에 매우 민감하다는 치명적인 단점을 지니고 있습니다. 문제가 조금만 복잡해져도 매우 비효율적인 알고리즘이 될 수 있다는 것입니다. 특히 경우의 수가 문제의 복잡도에 따라 기하급수적으로 증가하는 경우, 문제를 해결하는 데에 필요한 자원 역시 기하급수적으로 증가합니다.

이러한 단점은 대부분의 암호화 알고리즘에서 역이용하고 있는데, 무어의 법칙 덕분에 컴퓨터 성능이 꾸준히 개선되고 있다 해도 그만큼 더 복잡한 암호화 기법을 이용하면 되기 때문입니다. 현 세대의 암호화 기법을 브루트 포스로 다 뚫는다 해도, 그 시간이 지나고 나면 이미 구식도 아닌 구석기 알고리즘으로 전락해 있을 법하니 그만큼 시간을 충분히 벌 수 있는 것입니다

실제로 현재 가장 흔하게 사용되는 블럭암호인 AES 기반 암호화들의 경우에는 Weak Key를 사용하지 않는 이상 키를 모르면 유의미한 시간 내에 풀 수 없으며, AES-256의 경우는 초당 100(10^18) 개의 키 대입을 하는 슈퍼컴퓨터로도 3000(3 * 10^51)년은 족히 잡아먹습니다. 아직 AES-128이 완전히 깨졌다는 보고가 없는데도 하나둘씩 AES-256으로 갈아타는 이상, AES-128이 다 깨질 때 쯤이면 이미 대다수가 AES-32k, 많이 봐 줘도 AES-2k를 쓰고 있을 판이 되는 것입니다.

방어방법

  • 암호는 최소 10자리 이상을 사용. 암호가 12자리를 넘어간다면 슈퍼 컴퓨터를 가져와도 안전. 숫자만으로 이루어져있다 해도 암호 한 자리당 경우의 수가 10배씩 늘어나고 12자리이면 10^12.

  • 암호에 특수문자를 사용하면 좀더 좋겠지만, 특수 문자 안 쓰고 그냥 암호가 길기만 해도 됨. 아무리 특수 문자를 써도 암호가 6자리 이하라면 털릴 것을 각오해야 함.

  • 대부분 사전 공격부터 가하기 때문에 최소한 다음과 같은 단어들을 쓰는 것은 자살행위. 브루트 포스 툴인 John The Ripper의 내장 사전 파일의 맨 앞의 일부는 다음과 같음. 123456, abc123, password, computer, a1b2c3, qwerty, secret. q1w2e3r4! 이것 말고도 3천여개 정도 더 존재.

  • 사전 공격에서도 브루트 포스 기술을 동시 적용하면 단어 몇개 배열해놓은 건 뚫리는 건 금방.

  • 단어조합이 힘들다면, 외국계 해커 상대로는 한타를 영타 그대로 치는 것도 좋은 방법. 중간에 쉬프트가 필요한 쌍자음이 있으면 금상첨화. 숫자랑 특문을 넣으면 거의 뚫리지 않는다고 보면 됨.

  • 웬만한 사이트나 전자거래에서는 일정 횟수 이상 암호를 잘못 입력할 경우 계정이 일시동결. 민감한 분야에서는 대면적 방법으로 새로 인증을 받지 않고서는 다시 서비스를 사용할 수 없게 해 놓기까지 함. 이럴 경우는 브루트 포스가 쉽지 않음.

  • 브루트 포스의 경우 마구 대는 게 아닌 비트 순서대로 대는 것인데, 이를 역이용해서 첫 글자의 비트 크기에 따라 비밀번호가 뚫리는 시간은 크게 차이남. 예를 들어서 아스키 코드 65인 대문자 A로 시작하는 비밀번호와 아스키 코드 122인 소문자 z로 시작하는 비밀번호는 깨지는 속도가 두 배 가까이 차이남. 심지어는 프로그램에서 로마자만 따질 경우 A보다 z로 하는 것이 50배 넘게 이득이 된다. 거의 글자 하나 있고 없고의 차이. 다만 이 방법은 현실적으로 힘든 편. 자신의 비밀번호가 원래부터 이랬다면 좋았겠지만 이미 쓰던 비밀번호를 바꾸는 것은 심히 좋지 않음.


+ Random Posts