카테고리: Network

KCSC, Warning.or.kr에 적용된 필터링 방법과 사설

 

본래 방송통신심의위원회는 한국에서 ‘불법’으로 규정하는 사이트에 대한 접근을 차단하기 위하여 DPI 기반의 필터링을 도입합니다.
이 장비는 HTTP Request의 헤더를 분석하여 Host 필드의 값이 특정 도메인이라면 302 Redirect를 전송, warning.or.kr로 보내버립니다.

이 시스템은 2006년부터 동작하기 시작했는데, 이 시점에서 이미 기본권 침해 논란이 불거지기 시작하였습니다.
비록 Host 필드만을 확인하는 것이지만, 마음만 먹으면 특정 IP에서 어떠한 사이트에 들어갔는지 리스트를 작성할 수 있기 때문입니다.

사용자들은 이에 대응하여 DPI 장비가 필터링하지 못하도록 Host 필드의 뒤에 \n을 추가하거나, Host 대신 HoSt를 사용하는 등, HTTP 표준에는 부합하지만 DPI 장비의 필터에는 걸리지 않는 Request를 생성하여 우회하였습니다.

물론 KCSC가 DPI 장비를 개량하면서 다시 막혔습니다.

 

그러다 많은 사이트들이 HTTPS를 기본 지원하게 되면서, 기존의 HTTP 헤더 검사로는 차단이 불가능하게 되었습니다.
HTTPS 헤더를 까 봐야 암호화된 문자열들만이 나타나기 때문입니다.

그러자 KCSC는 DNS Spoofing을 시도합니다. 국내 ISP들의 DNS 서버에 특정 도메인 주소에 대한 응답을 warning.or.kr 서버로 돌리도록 한 것이죠.
물론 사용자들은 8.8.8.8과 1.1.1.1 등의 DNS 서버로 비교적 쉽게 우회할 수 있었고, 이에 한 때 1.1.1.1에 대한 접속을 차단하는 등의 강수를 두다가 철회하였습니다.

이 시점에서 KCSC가 취할 수 있는 대응 수단은 몇 가지가 있습니다.

 

1. DNS Request를 감시, 특정 도메인에 대한 요청을 찾으면 Request의 Source IP와 Response의 IP를 통해 TCP 커넥션을 식별, 차단
2. 특정 도메인에 대한 DNS 쿼리를 통해 IP Pool 확보, 해당 IP에 대한 접속을 차단
3. TLS의 Client Hello 메시지에서 암호화되지 않는 부분을 이용, Host 식별 후 차단
4. TLS의 Server Hello 메시지에서 Certificate를 확인, Server Name 필드를 식별 후 차단

 

1번은 기술적으로 구현이 힘들고 (컴퓨팅 파워 부족), DNS를 암호화하면 무력화됩니다
2번은 CloudFlare같은 접속 서비스를 사용하는 사이트에 대해서는 효과를 보기 힘든 데다(CloudFlare CDN 진입점을 차단할 수는 없으니), Virtual Host등을 이용하여 같은 서버를 사용할 경우 무고한 피해자가 발생할 수 있는 등의 문제가 있으며
3번은 현재 적용된 SNI 필터링입니다. 단, 이 문제점을 이미 인식하고 있기에 TLS 1.3에서 도입된 ESNI가 적용될 경우 무력화됩니다
4번은 ESNI가 보급된 이후에 적용될 것으로 예상되는 방법으로, 아직 대응방안이 마련되지 않았습니다

 

이 모든 것들을 한번에 해결할 수 있는 방법으로 VPN을 사용하는 것이 있으나, VPN 트래픽을 식별해낼 수 있으며, Packet을 Drop하는 방법으로 차단 또한 가능합니다.
이미 중국에서는 황금방패에 적용된 기법이고, VPN 트래픽 식별을 위해 머신러닝을 적용하고 있다는 이야기도 들려오고 있습니다.

결과적으로 창과 방패의 싸움이지만, 사법권력을 쥐고 있는 방패가 결국은 승리할 것으로 보입니다.

Windows 클라이언트에서 DNS Whitelist 적용하기

DNSCrypt를 이용하는 것으로 간단하게 구성할 수 있다.

https://github.com/jedisct1/dnscrypt-proxy/releases/tag/2.0.19

1. 위 주소에서 DNSCrypt for Windows를 다운로드 받은 뒤 적당한 경로에 압축을 푼다.

2. blacklist.txt에 “*.*”을 추가한다.

3. whitelist.txt에 원하는 도메인들을 추가한다.

4. dnscrypt-proxy.toml에서 whitelist_file, blacklist_file의 주석을 해제한다.

5. service-install.bat를 실행한다.

6. DNS 서버를 127.0.0.1로 설정한다.

 

이 구성이 실효성을 가지기 위해서는 제한을 받는 사용자가 서비스, DNS 설정과 dnscrypt 설정을 변경하지 못하도록 권한 제어가 이루어져야 할 것이다.

Linux Network Bridge Overview

 

리눅스에서 네트워크를 구성하다 보면 흔히 브리지라는 것을 접하게 된다. 여러개의 이더넷 포트를 하나의 세그먼트로 묶어주는 역할을 하는 이 소프트웨어 장치는 과연 어떤 것일까?
이 질문에 대답하려면 먼저 컴퓨터 네트워크의 역사에서 브리지의 위치를 알아볼 필요가 있다.

1. 네트워크 브리지

초창기 컴퓨터 네트워크는 여러 인터페이스들이 서로 경쟁 관계에 있었고(Ethernet, Token Ring, FDDI..) 대부분 하나의 회선을 여러 클라이언트가 나눠 쓰는 버스(Bus) 형태의 구조를 가지고 있었다.
버스 구조에서 두 개의 버스를 가진 네트워크를 서로 연결하려면 어떤 장치가 필요할까?

버스가 물리적으로 분리되어 있다면, 그 두 회선을 연결해주는 장치가 있어야 할 것이다. 그 결과 리피터(Repeater)가 탄생하였다. -허브(Hub)라고 부르기도 한다-
리피터는 아주 단순한 장비여서, 한 포트로 수신한 전기 신호를 다른 포트로 전송해주는 일밖에 하지 못한다.
때문에 CSMA/CD를 사용하는 초창기 이더넷에서는 Collision Domain이 커지는 효과를 가져왔고, 버스의 길이를 물리적으로 연장함으로써 Detection Gap을 넘는 전파 지연 가질 위험성도 내포하고 있었다.

일이 이렇게 되니, 이 문제를 해결할 수 있는 보다 지능적인 장비가 필요했고, 리피터에 MAC 주소 학습/포워딩 결정 기능을 더한 브리지가 탄생하였다.
브리지부터는 단순히 전기 신호를 재전송하는 것이 아닌, L2 프로토콜을 해석하고, 프레임의 정보를 얻을 수 있는(주로 MAC Address) 기능을 갖게 된다.

브리지는 클라이언트들의 MAC Address를 학습하고, 목적지 클라이언트 MAC이 존재하는 네트워크의 포트로만 패킷을 전송함으로써 리피터의 문제를 해결하였다.

브리지 동작은 크게 Transparent Bridging과 Source Routed Bridging으로 나뉘는데, 우리가 흔히 접하는 것이 Transparent Bridging, 내부에 홉 순서를 가지고 있는 프레임을 처리하는 것이 Source Routed Bridging이다.
토폴로지 구성 또한 두 종류가 있는데, 일반적으로 같은 세그먼트의 LAN을 서로 연결하는 LAN Bridging과 원격지 네트워크를 서로 연결하는 Remote Bridging이 바로 그것이다.

그리고 여기서 브리지의 한계가 드러나게 된다.
일반적으로 동일한 프로토콜을 사용하는 LAN과 달리, 원격지 네트워크는 LAN과 다른 프로토콜을 사용할 수 있으며, WAN 라인은 LAN에 비해 대역폭이 좁다.
그래서 LAN에서 발생한 트래픽이 WAN 회선을 타고 원격지 네트워크로 전송될 때, WAN 회선의 대역폭을 넘는 트래픽이 전달된다면 브릿지는 잉여 프레임을 버퍼에 저장할 수 밖에 없고, 버퍼의 용량이 초과된다면 나머지 프레임들은 모두 드랍될 수 밖에 없다. 때문에 패킷 드랍이 일어나지 않도록 브리지는 가장 작은 대역폭을 가진 포트에 맞춰 모든 포트의 전송률이 결정된다.

이런 한계점은 스위치의 등장과 함께 최종적으로 해결되었는데, 스위치에서는 링크가 1:1로 연결되므로 기본적으로 다른 포트의 전송 대역폭을 신경 쓸 필요가 없어졌다.

 

2. 리눅스의 소프트웨어 브리지

그렇다면 리눅스의 브리지는 어떤 기능을 가지고 있는 것일까.
결론부터 말하자면 리눅스의 브리지는 레거시 네트워크에서 흔히 말하는 브리지가 아니라, 소프트웨어적으로 구현된 스위치이다.
리눅스 브리지는 다수의 포트를 가질 수 있으며, STP가 동작하고, 인터페이스의 대역폭이 상호 독립적이기 때문에 브리지가 아니라 스위치라고 보아야 한다.

그럼 이제 리눅스 브리지의 동작에 대해 이야기해보도록 하자.

앞서 말했듯이, 브리지 동작에는 Transparent Bridging과 Source Routed Bridging이 존재한다.
리눅스의 브리지는 이 둘 중에서 Transparent Bridging을 수행한다. 이 때문에 다중 브리지가 존재하는 환경에서는 루핑이 발생할 수 있고, STP가 구현되었다.
그리고 리눅스의 브리지는 기본적으로 Ethernet을 사용하고, Remote Bridging을 적용할 수 없다. 또한, 하나의 포트는 한번에 하나의 브리지에만 할당될 수 있다.
상용 브리지 중에서는 하나의 포트를 여러 브리지에 할당하고 포워딩 정책을 통해 전송 포트를 결정하는 경우도 있으므로, 리눅스 브리지는 최대한 단순한 구성을 취하고 있음을 알 수 있다.

현재 리눅스 커널의 메인라인에는 802.1d Ethernet Bridging이 들어가 있으며, 커널을 컴파일 할 때 브리지 모듈을 탑재하는 것으로 활성화/비활성화를 결정할 수 있다.
브리지가 활성화된 커널에서 bridge-utils을 이용하는 것으로 브리지를 설정할 수 있다. 명령어는 brctl이다.

 

LoRa OTA Activation

LoRA UE(단말)을 네트워크에 조인시키기 위해서는 두 가지 방법이 사용될 수 있다. ABP(Activation By Personalization)와 OTAA(Over The Air Activation)이 바로 그것이다.

조인을 위해서는 다음과 같은 준비물이 필요하다.

1. JoinEUI: IEEE EUI64 타입의 식별자로, 자신의 루트 키를 가지고 있는 조인 서버를 식별하기 위해 사용된다.
2. DevEUI: IEEE EUI64 타입의 식별자로, 단말을 식별하기 위해 사용된다.
3. AppKey: Application Key. AES-128 키로, 조인 과정에서 AppSKey(Application Session Key)를 만드는 일에 사용된다.
4. NwkKey: Network Key. AES-128키로, 조인 과정에서 FNwkSIntKey, SNwkSIntKey, NwkSEncKey를 만드는 일에 사용된다.

LoRaWAN v1.0.2로 넘어오면서 AppKey가 추가되었기 때문에, 1.0이하의 LoRaWAN을 지원하는 서버/단말을 대상으로는 NwkKey만 사용된다.

OTA 장치는 여기서 두 개의 키를 더 가진다.

1. JSIntKey: MIC Rejoin-Request Type 1메시지와 Join-Accept 메시지의 암호화에 사용됨
2. JSEncKey: Rejoin-Request에 의해 만들어진 Join-Accept 메시지의 암호화에 사용됨

JSIntKey = aes128_encrypt(NwkKey, 0x06 | DevEUI | pad16)[1]
JSEncKey = aes128_encrypt(NwkKey, 0x05 | DevEUI | pad16)

단말은 Join을 시작하면서 Join Request를 전송한다. 그리고 Join Request의 구조는 다음 그림과 같다

Join Request의 처리를 위해서는 MAC Header를 처리한 뒤 페이로드에서 JoinEUI와 DevEUI, DevNonce를 읽어오면 된다. 여기서 DevNonce는 단말이 처음 가동될 때 0으로 세트되어, Join-Request를 전송할 때마다 하나씩 증가하는 값이다.

재전송 공격을 방지하기 위하여 조인 서버는 단말의 DevNonce를 저장하고 있다가, 저장된 DevNonce보다 작은 값이 들어오면 Join Request를 거부해야 한다.

다음으로 MIC(Message Integrity Code)는 CMAC(Chiper-based Message Authentication Code)[2](RFC4493)으로부터 추출되는데, CMAC의 첫 4비트를 가지고 Join Request의 무결성을 검증하게 된다.

 

LoRaWAN 1.1에서 JoinEUI가 이전까지 AppEUI라 불리던 것을 대체하였음을 참고해야 한다.

RAKWireless RAK831 사용기

RAK831은 Semtech SX1301을 기반으로 한 LoRa Gateway 모듈입니다. 중국의 RAKWireless에서 제작되었으며, LoRaP2P와 LoRaWAN을 지원합니다.
hackster.io에서는 RPi3을 사용한 The Things Network 게이트웨이 구성 튜토리얼을 제공하고 있으나, 제 목표는 조금 다릅니다.

바로 게이트웨이 모듈과 직접 통신할 수 있는 백엔드를 구축하는 것이 목표입니다. 호스트는 RPi B+로 정하였으나, 시작하기도 전에 문제가 발생했습니다.
SPI 핀을 연결하고 라즈베리 파이를 부팅하면 ‘sh: can’t access tty; job control turned off’라는 에러 메세지와 함께 부팅이 되지 않는 문제였고, 이 문제는 Noobs 없이 Raspbian을 클린 인스톨하는 것으로 해결되었습니다.

다음 단계로 넘어가기 위해, 먼저 LoRaWAN의 구성요소를 확인해야 합니다.

LoRaWAN 네트워크의 간단한 구성도를 만들어 보았습니다. 최하단에 노드가 위치하고, 그 위에 게이트웨이, 패킷 포워더, 인터넷 망, 네트워크 서버, 애플리케이션 서버가 올라갑니다.

이번에 구매한 RAK831은 게이트웨이로써, 서버와 노드로부터의 LoRa 패킷을 송/수신하는 역할만을 수행합니다. 그러므로 게이트웨이로부터 패킷 데이터를 읽고 해석하는 애플리케이션이 필요합니다.
그리고 이미 시장에는 TTN Gateway, Loriot 등의 좋은 솔루션들이 존재합니다.

하지만 남이 만들어놓은 물건을 그대로 가져다 쓰기만 해서는 재미가 없으니, 제가 구현하고자 하는 소규모 응용에 맞춰서 패킷 포워더와 네트워크 서버를 구현하기로 결정하였습니다.

 

게이트웨이와의 통신을 위해, SX1301을 만든 Semtech사에서 제공하는 libloragw 라이브러리를 이용합니다.

RAK831은 SPI를 통한 SX1301과의 직접 통신을 지원합니다. 그리고 라즈베리 파이 또한 SPI 인터페이스를 지원하니, 이 인터페이스들을 사용할 것입니다.

참고로 Semtech에서는 고부하시 성능 문제로 인해 libloragw의 V3.2.0에서 USB-SPI 컨버터의 지원을 중단하였습니다.

 

LoRa Concentrator의 초기화는 다음과 같은 순서로 진행됩니다.

 

0. RAK831 보드 리셋(Raspberry Pi용 확장 보드 사용 기준)

1. LoRa Concentrator Board Setup

– Syncword Setup
– Clock Source Setup

2. LBT Setup

– RSSI
– LBT Channel
– Period

3. TX Gain Setup (Look Up Table 사용)

– GA, DAC, MIX, DIG Gain
– RF Power

4. RF Chain Setup

– RSSI
– Radio Interface Type(SX1255, SX1257)
– Center Frequency
– Notch Filter Frequency (FPGA가 탑재된 보드에 한함) // LBT와 연관?

5. SF Channel Setup

– RF Chain(라디오 인터페이스 번호)
– Frequency
– Bandwidth(125… 500Khz)
– Spreading Factor(7~15)

6. Standard Channel Setup

– RF Chain
– Frequency
– Bandwidth
– Data Rate

7. FSK Channel Setup

– RF Chain
– Frequency
– Bandwidth
– Data Rate

이상의 설정이 끝나고 나면 Concentrator를 시작할 수 있습니다.

현대 CPU의 구조적 결함 – 멜트다운(Meltdown)과 스펙터(Spectre) 그리고 KAISER

 

지난 1월 2일, 미국의 인터넷 커뮤니티인 Reddit의 컴퓨터 서브레딧에 리눅스 커널에서 수상한 수정 작업이 이루어지고 있다는 소식이 올라왔습니다.

리눅스 커널에서 KASLR 관련 패치라는 코멘트를 달고 대규모의 수정과 백포팅이 이루어지고 있으며, 해당 패치를 적용할 시 시스템 콜 성능이 30%~70%까지 저하된다는 이야기였습니다. 이는 곧바로 이슈가 되었고, 그 다음날인 3일, 사태의 전모가 밝혀지게 되었습니다. 바로 멜트다운과 스펙터입니다.

여기서는 상기 링크에 게시된 멜트다운과 스펙터에 대한 논문과 멜트다운의 대응책으로 제시된 KAISER에 대한 논문을 참고하여, 공격 방법과 영향 범위에 대해 이야기해 볼 것입니다.

 

1. 멜트다운 공격

멜트다운과 스펙터는 모두 현대 CPU의 중요 구성요소 중 하나인 분기 예측기(Branch Predictor)의 결함에 근간을 두고 있습니다. 구글 프로젝트 제로(Project Zero)의 연구팀들은 이 결함을 총 3가지의 종류로 분류하였으며, 각각 경계값 검사 우회(CVE-2017-5753), 분기 목표 인젝션(CVE-2017-5715), 악의적인 데이터 캐시 로드(CVE-2017-5754)라는 이름을 붙였습니다. 이 중 앞의 두 가지는 Spectre 공격과 관련이 있고, 마지막 하나는 Meltdown 공격과 관련이 있습니다.

멜트다운 공격은 마이크로옵 단위에서의 레이스 컨디션 공격입니다. 현대 CPU는 길다란 명령어 파이프라인을 가지고 있고, 프론트엔드에서 해석된 명령어는 작은 단위의 명령어(μop)로 쪼개진 뒤 재정렬 버퍼(Re-Order Buffer)로 들어갑니다. 이를 통해 ALU가 데이터 병목 없이 최대한의 병렬성을 가질 수 있도록 합니다. 그리고 명령어 실행이 종료된 뒤, 실행 결과는 다시 정렬됩니다. 이러한 일련의 동작을 비순차적 실행(Out of Order Execution)이라고 합니다. 멜트다운은 인텔 CPU가 가지고 있는 분기 예측기의 결함과, Out-of-Order Execution 매커니즘의 결함을 악용하여 공격을 수행합니다.

멜트다운 공격은 다음과 같은 순서로 이루어집니다.

1. 공격자가 사용자 영역에서 접근이 불가능한 영역의 메모리(Ex. 커널 영역 메모리)를 참조하여 예외(Execption)를 일으킵니다.
2. 예외가 발생하였으므로, 코드의 실행 흐름은 예외 핸들러로 넘어가고, 분기 예측기의 투기적 실행과 비순차적 실행 매커니즘에 따라 로드된 메모리 값은 폐기됩니다.
2-1. 투기적 실행이 실패하였으므로, 파이프라인은 클리어되고 결과는 커밋되지 않습니다. 하지만 CPU의 캐시에는 해당 주소에서 불러온 값이 들어 있습니다.
3. 예외 핸들러가 코드의 실행 흐름을 물고 있는 동안, 다른 프로세스로 Flush+Reload 공격을 가해 캐시 데이터를 추측합니다.
4. 데이터 추출이 완료된 뒤 예외를 적절하게 처리하거나, 인텔의 TSX 명령어를 이용한 예외 억제(Exception suppression)를 통해 공격 속도를 증가시킬 수 있습니다.

결국, 멜트다운 공격은 CPU의 분기 예측기가 투기적인 명령어 실행을 수행할 때, 해당 메모리에 대한 접근 권한을 확인하지 않기에 발생하는 문제입니다. AMD는 이 문제에 대하여 ‘AMD 아키텍처의 분기 예측기 구조는 인텔의 것과는 다르기 때문에 안전하다’는 내용의 공식 성명을 내놓았습니다.

이 문제를 해결하기 위한 방법으로, 구글은 지금 즉시 모든 커널에 KAISER를 적용할 것을 권고하였습니다. KAISER는 본래 캐시 메모리 부채널 공격에 의해 KASLR이 무력화되는 것을 방지하기 위해 제안되었으나, 멜트다운 공격에도 역시 유효하다는 것이 확인되었습니다.

KAISER는 연속적으로 할당되어 있는 커널 영역 메모리와 유저 영역 메모리를 서로 분리하여 참조를 통해 접근하도록 수정하는 것을 골지로 하고 있습니다. 이러한 수정은 커널 영역 메모리에 접근할 때 오버헤드를 가져오게 되는데, CR3 레지스터의 PML4값을 변경하는 것과, TLB(Transaction Lookaside Buffer)의 초기화(Flush)가 그것입니다.

 

첫번째 문제를 해결하기 위해 KAISER는 Shadow Address Space라는 트릭을 제안합니다. 유저와 커널 메모리는 분리하지만, 물리 주소는 특정 값(12번째 비트)을 차로 가지도록 할당한다는 이야기입니다.
논문에서 제안된 대로 12번째 비트를 변경하여 메모리 페이지를 할당하게 된다면, 컨텍스트 스위칭이 발생할 때마다 전체 PML4 값을 갱신하는 것이 아니라, 1비트의 비트 연산을 수행하는 것 만으로 올바른 주소를 계산할 수 있게 됩니다.

다시 말해, CR3 레지스터는 변경되지만 변경에 필요한 연산과 클럭은 최소화될 수 있습니다.

두번째로 TLB에 대해 이야기하려면 먼저 IA-32e 아키텍처에서의 메모리 구조를 알아야 합니다. IA-32e 아키텍처에는 총 5단계에 걸친 메모리 페이지가 존재하고, 이러한 페이지 참조를 빠르게 하기 위해 CPU는 일종의 캐시인 TLB(Transaction Lookaside Buffer)를 가지고 있습니다.

TLB에는 페이지 번호와 페이지 프레임의 주소가 저장되고, TLB를 참조하게 되면 연산 유닛은 페이지 오프셋만을 가지고 정확한 물리 주소를 찾을 수 있게 됩니다. 이러한 이점을 최대화하기 위하여 현대 OS들은 TLB Flush가 최대한 발생하지 않도록 최적화가 이루어져 있습니다. 만약 KAISER를 적용한다면, 컨텍스트 스위칭마다 PML4 값이 변경되므로 TLB Flush가 필연적으로 발생하게 될 것입니다.

하지만, 최근의 연구에서 아키텍처 설명과는 달리 내부적으로 TLB에 대한 최적화가 이루어져서 CR3 레지스터의 변경이 TLB를 Flush하지 않는다는 사실이 밝혀졌습니다. 해당 논문은 이 사실에 근거하여 테스트를 진행, KAISER를 적용할 시의 성능 저하는 0.08%~0.68%에 불과하다고 결론짓습니다.

KAISER는 요청한 커널 페이지가 캐시에 로드되고, 두번째로 페이지 폴트가 발생할 때의 명령어 수행 시간의 차이를 탐지하여 올바른 커널 메모리 주소를 찾아내는 Double Page Fault 공격에 대한 대응책으로 제시되었지만, 결과적으로 커널 메모리 영역에 대한 시간차 기반 캐시 부채널 공격을 차단함으로써, 멜트다운 공격을 방어하는 것에도 역시 유효합니다. 하지만 유저 영역과 유저 영역에 남아있는 일부 커널 메모리 영역은 여전히 멜트다운의 영향을 받습니다.

 

2. 스펙터 공격

 

BlueBorne White Paper 번역

Armis Labs

Armis Labs은 안드로이드와 iOS, Windows, Linux를 사용하는 주된 모바일, 데스크탑, IoT 장치에 대한 새로운 공격 방법을 발견하였습니다. 이 공격은 “BlueBorne”(이하 블루본)이라 명명되었으며, 블루투스를 이용해 장치들을 공격합니다. 블루본은 공격자가 장치를 제어하고, 그것과 연결된 데이터와 네트워크에 접속하여 물리적으로 분리된 네트워크에 침입, 다른 장치들을 멀웨어에 감염시킬 수 있습니다. 이 공격은 목표 장치가 discoverable 모드로 설정되거나, 공격자의 장치와 페어링될 필요가 없습니다. 게다가 피해자가 공격자의 장치와 연결되는 것을 승인할 필요도 없습니다.

Armis Labs는 이 공격에 사용되는 8개의 취약점들을 발견하였습니다. 이 취약점들은 완전히 기능하고, 성공적으로 익스플로잇될 수 있습니다. 우리는 곧 블로그 포스트로 데모를 보여줄 것입니다. 다음의 취약점들입니다:

  1. Linux kernel RCE vulnerability – CVE-2017-1000251
  2. Linux Bluetooth stack (BlueZ) information Leak vulnerability – CVE-2017-1000250
  3. Android Information Leak vulnerability – CVE-2017-0785
  4. Android RCE vulnerability #1 – CVE-2017-0781
  5. Android RCE vulnerability #2 – CVE-2017-0782
  6. The Bluetooth Pineapple in Android – Logical Flaw CVE-2017-0783
  7. The Bluetooth Pineapple in Windows – Logical Flaw CVE-2017-8628
  8. Apple Low Energy Audio Protocol RCE vulnerability – CVE-2017-14315

이 연구논문은 각 취약점들의 공격면(attack surface)을 탐색하고, 취약점들이 발견된 블루투스 구현체의 부분을 설명합니다. 그리고 각 취약점의 자세한 내부 동작과 영향 분석을 제공합니다. 저희는 이  연구가 다른 블루투스 스택을 감사하고 구현체의 추가적인 취약 부분을 밝히는 것에 도움이 되기를 바랍니다.

알림

Linux RCE 익스플로잇을 개발한 Alon Livne에게 감사를 보냅니다.

 

블루투스에 대하여

블루투스는 근거리 통신 프로토콜의 선두주자이자 가장 널리 퍼진 프로토콜입니다. 조사에 따르면 82억개 이상의 블루투스 장치들이 현재 사용되고 있으며, 날마다 증가하고 있습니다. 블루투스는 매우 많은 종류의 장치들에 포함되어 있습니다. 스마트폰과 웨어러블 장치와 같은 일반적인 것에서부터, 엔터프라이즈에 널리 쓰이는 PC, 스마트 TV, 프린터와, 의료기기, 자동차와 같은 치명적인 것에 이르기까지 말입니다. 블루투스는 Bluetooth Special Interests Group(SIG)에 의해 라이선스되고, 관리됩니다. SIG에는 Microsoft, Intel, Apple, IBM과 같은 대기업들이 포함되어 있습니다.

블루투스가 세상에 처음으로 나온 1998년 이래로, 블루투스는 계속 발전되어 왔고, BLE와 메쉬 토폴로지가 그것의 가장 흥미로운 예시일 것입니다. BLE(Bluetooth Low Energy)는 블루투스의 새로운 변형입니다. BLE는 스마트 센서와 원격 제어 장치와 같이 제한된 전원과 대역폭을 가진 기기들이 스마트폰과 PC 등에 연결되기 위하여 탑재되었고, 빠르게 저변을 넓혀가고 있습니다.  그리고 Bluetooth 5.0에서 새로 등장한 기술로 Bluetooth Mesh가 있습니다. 이 새로운 기능은 블루투스 연결의 토폴로지를 바꾸어 저수준 장치들이 서로 연결되고, 더 정교하고 밀집된 네트워크를 형성할 수 있게 합니다. 메쉬 토폴로지는 블루투스 네트워크가 더 널리 확산되게 할 것입니다. Bluetooth SIG에 의해 시도되는 이러한 새로운 기술은 현재 촉망되는 새로운 단거리 통신 기술들(Zigbee, Z-Wave, LoRa 등)과 경쟁하며 스마트 IoT 장치와 그것의 응용들의 영역을 확장시킬 것입니다.

블루투스에 포함된 최근의 기술과, 블루투스의 역사를 돌아보면 무엇이 이 프로토콜이 근거리 통신의 뼈대가 될 수 있게 하였는지 알 수 있습니다. 우리의 삶에서 무선 연결은 점점 증가하였고, 블루투스가 우리가 사용하는 장치들에 포함될 수 있게 하였습니다.

 

그래서, 무엇이 문제인가?

블루투스는 복잡합니다. 사실, 지나치게 복잡합니다. 스택 계층에 너무 많은 구체적인 내용들이 있으며, 기능들은 끊임없이 중복됩니다. 이러한 과복잡성은 과중한 업무를 통해 직접적으로 나타나며, 블루투스 명세를 만드는 것에 있어 과다한 노력이 투입됩니다. 간단히 요점을 살펴보자면, Wi-Fi(802.11)의 명세가 450쪽인 반면 블루투스의 명세는 2822쪽에 달합니다.
이러한 블루투스의 복잡성은 다른 널리 퍼진 프로토콜에 비하여 구현체에 대한 감사를 힘들게 만듭니다. 그 덕에 외부(outwards-facing) 인터페이스는 위협받아 왔고, 이러한 재검토의 부재는 수많은 취약점들을 만들었습니다.

블루투스의 불필요한 복잡성의 예를 들자면, 분할이 있습니다. 많은 프로토콜에 존재하는 일반적인 개념이며, 모든 구현체의 취약한 부분이기도 하죠. 블루투스의 전체 스택 중 4개에 달하는 계층에서 분할이 이루어집니다. 아래의 도표는 블루투스 명세에서 가져온 것입니다.

호스트에만 존재하는 분할 계층(USB Driver 계층)을 제외하고도 Radio 계층(Link Controller)에서 L2CAP 계층에 이르기까지 블루투스는 총 3개의 분할 계층을 가집니다(일부 블루투스 서비스의 경우 추가적인 분할 계층이 있을 수 있습니다):

  • Link Controller에서 분할되는 Air Packet들
  • HCI 계층의 분할(ACL level continuation)
  • L2CAP 세그멘테이션

심지어 이러한 불합리함이 아직 남아 있습니다. 몇몇 블루투스 서비스에서는 분할 매커니즘이 각각의 블루투스의 계층에 존재할 수 있습니다.  SDP의 경우, 패킷은 SDP continuation 매커니즘에 의해 분할된 뒤 L2CAP의 세그멘테이션 매커니즘에 의해 분할되고, ACL continuation에 의해 분할됩니다. 그리고 마지막으로 Link Controller의 분할 매커니즘에 의해 분할됩니다.

 

불루투스에 대한 예전 연구들

예전의 작업들은 블루투스 명세 자체의 잠재적인 이슈를 발견하는 것에 초점을 맞추었습니다. 이를테면 블루투스 v2.1까지 존재하였던 암호화 키 교환 취약점 말이죠. 블루투스가 “Secure Simple Pairing” -알려진 수많은 페어링 이슈들을 해결한 기능-을 소개하자 보안 커뮤니티의 관심은 블루투스에서 벗어났습니다. 그리고 최근 들어 Bluetooth Low Energy가 대두되자, 그것은 블루투스에 대한 커뮤니티의 관심을 다시 불러일으켰습니다.  그렇기는 하지만 아직 블루투스의 다양한 구현체에 대한 총체적인 분석은 수행된 적이 없습니다.

이 작업은 블루투스 스택의 잠재적인 결함을 밝히는 첫번째 발걸음이 될 것입니다. 하지만 블루투스 스택이 너무나 많은 코드 조각들로 이루어져 있기에, 저희가 밝혀낸 것은 아마도 빙산의 일각에 불과할 것입니다.

 

발견의 용이함

블루투스는 많은 장치들에서 기본적으로 활성화되어 있습니다. 그리고 많은 사용자들은 헤드폰, 키보드와 다른 다양한 IoT 장치들에 연결하기 편하다는 이유로 블루투스를 그냥 켜 둡니다. 서로 다른 종류의 블루투스 연결들이 존재하면, 그 중 하나가 서로 페어링됩니다.

많은 OS에서 사용자가 장치와 페어링을 시도하면 그의 장치는 근처의 피어들에게 발견 가능한 상태가 됩니다. 다른 경우, discoverability는 비활성화됩니다. 하지만 블루투스는 장치가 거의 항상 자신을 목표로 한 유니캐스트 트래픽을 수신할 수 있도록 (장치를)활성화해둡니다. discoverable mode로 설정되어 있지 않더라도 말이죠. 이것은 “Page scan Mode”라고 불립니다. 이러한 이유로 커넥션을 성립시키기 위해 필요한 것은 오직 타겟의 BDADDR(Bluetooth Device Address, MAC Address)뿐입니다. 일단 공격자가 그것을 획득하고 거리가 가깝다면 그/그녀는 listening Bluetooth service에 대한 놀라우리만큼 넓은 공격면에 접근할 수 있습니다.

non-discoverable 장치에 대한 BDADDR을 찾아내는 것은 몇몇에게는 어려운 일로 간주됩니다. 명세에서 스스로 “4가지의 서로 다른 항목들이 링크 계층의 보안을 유지하는 것에 사용된다”(Bluetooth Specification Core v5.0, 1649쪽)이라고 밝혔듯이 말이죠. 이러한 난이도에 대한 추측은 블루투스 프로토콜의 하위 계층의 복잡성과, 하드웨어가 전파를 “스니핑”할 수 없다는 추측에서 비롯됩니다. 하지만 BDADDR을 찾는 것은 아주 쉬운 일입니다. 심지어 non-discoverable 장치라도 말입니다.

Ubertooth와 같은 오픈소스 하드웨어들을 수 년 전부터 사용할 수 있었습니다. 이 툴은 연구원들이 프로토콜의 물리 계층과 링크 계층을 스니핑하고 모니터링 할 수 있게 해줍니다.  블루투스의 ‘모니터 모드’는 연구원들이 흔히 접할 수 있는 장비들에서는 제한적으로 제공되어왔지만, Ubertooth는 우리 자신을 포함한 연구원들의 진입 장벽을 낮추었습니다.

블루투스 연결들이 암호화됨에도 불구하고 평문인 패킷 헤더는 통신중인 장비의 BDADDR에 대한 정보를 충분히 가지고 있습니다. 만약 장치가 어떤 블루투스 트래픽이라도 만들어낸다면 물리적으로 근접한 공격자는 그 장치의 BDADDR을 얻어낼 수 잇고, 장치를 향한 유니캐스트 트래픽을 보낼 수 있습니다.

만약 장치가 어떤 트래픽도 만들어내지 않고 오로지 수신만 하고 있다 하더라도 여전히 BDADDR을 ‘추측’할 수 있습니다. 장치의 Wi-Fi 트래픽을 이용해서 말이죠. Wi-Fi MAC 주소는 암호화되지 않은 채로 날아다니며, 많은 OEM과 하드웨어 제조사들이 채택하고 있는 규칙은 서로 마지막 한 자리만 다른 것(MAC의 +1)입니다.

 

공격면 분석

상대적으로 간단한 편인 장치의 블루투스 주소를 획득하는 것을 성공했다면, 우리는 이제 각 블루투스 스택마다 존재하는, 전체 프로토콜 계층의 다양한 공격면에 접근할 수 있습니다. 우리는 블루투스 계층들을 확인할 것입니다. L2CAP에서 SMP로, 다시 SDP로, 그리고 우리가 검토했던 더 높은 계층-BNEP와 PAN-으로. 각 계층에서 우리는 우리의 발견을 서술하고, 우리가 밝혀낸 취약점들을 설명할 것입니다.


다양한 취약점들의 위치를 표시한, 블루투스의 기본적인 구성요소들

 

널리 퍼진 블루투스 스택들

어떠한 면에서는 블루투스 스택은 TCP/IP 스택과 동일합니다. 블루투스 커뮤니케이션에 한해서 말이죠. Wi-Fi, Ethernet, 6LoWPAN과 같은 저수준 통신 프로토콜과는 달리 블루투스는 응용 프로토콜들을 위해 TCP/IP 스택에 의존하지 않습니다. 대신 넓은 범위의 프로토콜들과 응용들은 Bluetooth SIG에 의해 정의됩니다. 그리고 그것들이 모여 ‘Bluetooth Stack’이 됩니다.

블루투스 스택은 TCP/IP의 7계층 스택을 완전히 대신합니다. 물리 계층에서 응용 계층까지 말입니다. 스택의 낮은 계층들 -물리와 링크 계층-은 블루투스 칩에 내장되어 있습니다.  이 칩들은 디바이스에 대한 실제 OS를 탑재하고 있는 ‘호스트’와 블루투스 HCI(Host-Controller Interface)를 통해 통신합니다. 이 계층 위의 모든 프로토콜들(L2CAP, AMP, SMP, SDP, RFCOMM 등)은 호스트에 탑재되어 있습니다. 서로 다른 하드웨어마다 서로 다른 종류의 드라이버를 사용하는 NIC와는 달리, 현대 OS는 각각 하나의 블루투스 스택을 가지고 있습니다. 즉, 이런 스택들에서 발견된 어떤 취약점이라도 그 스택을 사용하는 모든 OS와 그 OS가 탑재된 수많은 장치들에게 영향을 미칠 수 있습니다.

가장 눈에 띄는 스택은 리눅스의 BlueZ 스택입니다. 초기 안드로이드 버젼들에서 사용되었고, 리눅스와 삼성 타이젠과 같은 다른 OS들도 사용합니다. 안드로이드는 4.2부터 Bluedroid와 Fluoride라 불리는 블루투스 스택을 새로 개발하여 사용합니다. 윈도우도 Windows XP부터 자신의 블루투스 스택을 가지고 있습니다. 그리고 애플은 OSX와 iOS에 사용되는 2종류의 블루투스 스택을 만들었습니다.

 

L2CAP

개요

호스트에서 보면, 블루투스 스택의 가장 낮은 계층은 L2CAP입니다. 이 계층은 다양한 블루투스 서비스들의 연결을 관리합니다. L2CAP의 전송 방식은 ACL-비동기 연결 지향적 논리 전송-입니다. 거의 모든 블루투스 데이터가 지나가는 ACL은 간단한 패킷 기반 비신뢰 통신 레이어입니다. L2CAP는 ACL 위에서 연결 지향적인 채널들을 관리합니다. 그리고 논리적 단대단 전송자들은 패킷 몸체의 Channel ID를 통해 식별됩니다. 이 Channel ID들의 역할은 TCP의 포트에 비유될 수 있습니다. 블루투스에서 L2CAP는 TCP와 동등하지만, ACL은 QoS와 흐름 제어 기능도 가지고 있습니다. 그리고 분할과 재조립 매커니즘도 가지고 있죠. 덕분에 많은 L2CAP 기반 서비스들이 큰 사이즈의 SDU(Service Data Units)을 전송할 수 있습니다.

블루투스 명세는 특정 CID(Channel ID)들을 정해진 목적을 위해 예약했습니다. 예를 들어, CID 1은 항상 컨트롤 패킷들이 전달되는 시그널링 채널을 의미합니다. 다른 CID들은 동적으로 할당 및 관리될 수 있습니다. 블루투스의 다양한 서비스들은 종종 고정된 PSM(Protocol/Service Multiplexer -포트 번호를 의미하는 다른 L2CAP 용어)를 사용합니다. 그리고 이러한 서비스들과 연결하고 싶은 단말은 특정 PSM으로 L2CAP ConnectionRequest 메시지를 전송합니다. 이 메시지에 응답하면서 해당 서비스에 대한 연결을 식별하기 위하여 동적 CID가 할당됩니다.

새로운 L2CAP 연결을 형성할 때, 두 단말은 설정 요청(configuration request)과 설정 응답(configuration response)이라 불리는 패킷을 서로 주고받으며 연결을 조정합니다. 설정 요청은 정확한 종류의 연결 기능을 결정할 수 있는 몇 가지의 요소들을 포함합니다.

상호간의 설정

설정 프로세스는 명세에서 L2CAP_ConfReq와 L2CAP_ConfResp라 불린 설정 요청과 응답 메시지를 이용해 이루어집니다. 이 메시지들은 시그널링 채널을 통해 전송되며, 양쪽 단말 모두 최초의 핸드쉐이크의 부분으로써 설정 요청을 보낼 수 있습니다. 그리고 (수신자는) 설정 응답을 다시 보냅니다. 설정 요청은 그 요청이 받아들여졌거나 거절되었음을 나타내는 상태 코드를 포함합니다. 각 단말은 자신의 설정을 협상합니다. 다시 말해, 양 단말간의 설정 패러메터들은 상호간의 동의를 얻어야만 합니다.

 

상기 예시를 보면, 장치 A는 MTU(Maximum Transmission Unit)을 0x100으로 요청합니다. 그리고 B는 그것을 받아들입니다. 이어서 B가 MTU로 0x200을 요청하고, A가 그것을 받아들입니다. 두 개의 MTU 패러메터가 이 트랜젝션에서 상호간의 동의를 얻었으며, 장치 A에서 B로 가는 메시지의 최대 크기는 0x100, 장치 B에서 A로 가는 메시지의 최대 크기는 0x200이 됩니다.

위의 예시는 패러메터 교환의 단순한 예시입니다. 장치는 “받아들일 수 없는 패러메터”라는 이유로 설정 요청을 거부할 수도 있습니다. 재협상을 쉽게 하기 위하여 거부한 당사자의 응답 메시지에는 자신이 받아들일 수 있는 패러메터값이 들어갈 수 있습니다. 예를 들어, 다음 코드 조각(Linux 블루투스 스택인 BlueZ에서 발췌한)을 보면 요청받은 MTU  값은 최대값과 비교됩니다. (chan->omtu는 연결이 수립되면 기본값으로 사용됩니다)

<net/bluetooth/l2cap_core.c로부터 발췌됨>

요청받은 MTU값이 유효하다면, 이 코드는 현재의 연결 설정을 저장하고 채널 오브젝트의 MTU 설정 상태를 “완료”로 표시합니다. 반면에, 응답값이 UNACCEPT로 세트되어 있으면 값은 폐기됩니다. 두 경우 모두 상대방에게 유효한 설정값을 알리기 위하여, 혹은 요청이 거부되었음을 알리기 위하여 MTU 요소가 설정 응답에 포함됩니다.

상기 과정이 L2CAP 연결의 “표준 설정 프로세스”입니다. 이 설정 프로세스에서 종단은 설정 요청에 대하여 그것이 받아들여졌건, 거부되었건 간에 설정 응답을 보냅니다. 설정이 거부되었다면, 종단은 상호간의 합의에 이를 때까지 협상을 계속합니다.

하지만 다른 종류의 설정 프로세스가 존재합니다. 바로 lockstep 설정 프로세스죠. 이 프로세스는 L2CAP의 Extended Flow Specification(EFS)를 만족할 필요가 있습니다. EFS는 장치들이 보다 포괄적인 연결을 수립할 수 있게 합니다.  EFS 기능 패러메터는 각 종단의 로컬 블루투스 컨트롤러에 의해 승인되어야 하며, 그 결과 단말들이 설정 요청에 응답하는 것이 “Pending”될 수 있습니다. 일단 EFS 패러메터들이 서로 교환되고, EFS의 승인이 이루어지면 최종 응답이 각 종단에 전달됩니다.

Linux kernel RCE vulnerability – CVE-2017-1000251
Bluez vulnerability – configuration response parsing

L2CAP의 EFS 기능에 대한 BlueZ 구현체의 l2cap_parse_conf_rsp에서 발견된 취약점은 커널 버젼 v3.3-rc1 이후의 모든 버젼에 영향을 미칩니다.
여기 l2cap_parse_conf_rsp의 축약된 코드가 있습니다.

<l2cap_parse_conf_rsp (net/bluetooth/l2cap_core.c) 로부터 발췌됨>

이 함수는 설정 응답 버퍼를 rsp 인수를 통해 전달받습니다. 그리고 그것의 길이는 len 인수입니다.이 함수는 l2cap_get_conf_opt 함수를 통해 len이 다할 때까지 버퍼로부터 구성요소를 하나씩 뽑아냅니다. 설정 응답의 구성요소들은 검증되고, data 인수를 통해 지정된  응답 버퍼에 다시금 패킹됩니다.
하지만 이 응답 버퍼의 크기는 함수로 전달되지 않습니다.

근본적으로, rsp의 모든 구성요소들은 &ptr(l2cap_conf_req.data를 가리키는)에 의해 목표 버퍼의 크기와 상관없이 복사됩니다. 이 때, 들어오는 응답의 크기는 제한되지 않았음을 알 필요가 있습니다. 구성요소들은 중복될 수 있고, 공격자로 하여금 rsp 버퍼의 크기를 제어할 수 있게 합니다. 그리고 그 결과, 큰 데이터가 data로 복사됩니다. data 버퍼의 기원인 l2cap_parse_conf_rsp는 두 곳에서 호출됩니다. 그 이름이 암시하듯이, 연결 응답 메시지를 처리하는 곳입니다. 두 호출은 서로 비슷합니다. 그러므로 둘 다 이 취약점을 악용하기 위해 사용될 수 있습니다.

<l2cap_config_rsp (net/bluetooth/l2cap_core.c)로부터 발췌됨>

switch문이 이전에 공격자가 제어할 수 있는 설정 응답 패킷으로부터 언팩된 result 값을 검사합니다. 응답 버퍼는 if 구문 내부에 선언되어 있는 buf라 이름붙여진 작은 스택 버퍼입니다. 현재 채널에 대한 설정이 “Pending” 상태로 확인되면(위에서 이야기한 lockstep 설정 프로세스) 이 구문으로 들어갑니다. 그러므로, 공격자는 그의 타깃이 “Pending”상태가 되도록 유도해야 합니다. 그것은 다음 코드를 통해 이루어질 수 있습니다:

<l2cap_parse_conf_req (net/bluetooth/l2cap_core.c)로부터 발췌됨>

이 동작은 간단합니다. 공격자는 stype 필드를 L2CAP_SERV_NOTRAFIC으로 설정하고, EFS 구성요소가 들어간 패킷을 보내기만 하면 됩니다.

“Pending” 상태가 이루어지면, result 필드가 L2CAP_CONF_PENDING으로 세트된 다음 설정 응답이 buf[64]가 임의의 크기를 가진 버퍼로 덮어쓰일 수 있는 취약점을 발동시킵니다.
이 취약점은 공격자로 하여금 64바이트의 커널 스택 버퍼를 무제한의 크기를 가진 데이터로 덮어쓸 수 있게 합니다. 그것이 올바른 L2CAP 설정 응답 패킷의 구조를 가지고 있으면 됩니다.

 

악용 가능성

오늘날, 위에서 서술한 바와 같은 스택 오버플로우 취약점은 코드 실행으로 바로 이어지지는 않습니다. 현대 운영체제는 코드 실행으로 이어질 수 있는 메모리 오염 취약점을 방지하는 기능들을 가지고 있습니다. 하지만 리눅스 커널의 경우, 기본 설정에서는 이러한 기능을 사용하지 않습니다. 다시 말해, 현재 리눅스를 사용하는 대부분의 기기들은 스택 오버플로우를 방지하는 기능과 KASLR(Kernel Address Space Layout Randomization)을 사용하지 않습니다. 이 말인즉슨 상기 스택 오버플로우는 쉽게 악용될 수 있다는 것입니다.

이 취약점을 시험하고 발생시키는 일은 쉬운 일이 아님을 언급해야 할 듯 합니다. 이 취약점은 조작된 L2CAP 패킷들을 전송하기 위하여 ACL의 직접 조작을 필요로 합니다. 하지만 어떤 블루투스 스택도 유저에게 최하단에 이식된 HCL, ACL, L2CAP 계층에 대한 이러한 기능을 제공하지 않습니다. 이러한 커널 코드 경로를 테스트하는 것에 대한 높은 장벽은 보안에도 해를 끼칩니다. 우리는 곧 블로그에서 우리가 개발한 시험용 프레임워크를 이 취약점에 대한 익스플로잇 코드와 함께 공개할 것입니다. 이 테스트용 프레임워크는 연구원들이 블루투스 스택에 대한 공격 테스트를 수행하는 것에 도움이 될 것입니다.

 

영향

BlueZ의 경우, L2CAP는 리눅스 커널 코드의 일부로서 포함되어 있습니다. 이것은 꽤 위험한 일입니다. 완전히 개방된 통신 프로토콜과 EFS, 커널 공간의 조작이 조합되면 문제를 일으키기에 충분합니다. 이 취약점은 커널 스레드에서 일어나는 고전적인 스택 오버플로우며, 공격자는 블루투스가 켜져 있고, 리눅스를 사용하는 어떠한  기기라도 추가적인 단계 없이 완전한 커널 레벨 익스플로잇을 얻을 수 있습니다. 게다가, 공격당한 호스트는 2차 공격에 이용될 수도 있습니다. 즉, 이 취약점은 웜을 만드는 것에 사용될 수 있습니다.

 

SDP

개요

SDP(Service Discovery Protocol)은 블루투스의 코어 계층으로서, 모든 스택에 존재합니다. SDP의 목적은 장치들이 블루투스를 지원하는 다양한 서비스와 응용들을 발견할 수 있도록 하는 것입니다. 그리고 SDP는 블루투스 서비스의 고정된 UUID(Universal Unique Identifier)들을 해석할 책임이 있으며, PSM(Protocol Service Multiplexer – L2CAP의 포트 번호)로 하여금 동적으로 번호를 설정할 수 있게 합니다. 획득한 PSM은 발견된 서비스에 대하여 L2CAP 연결을 형성하는 일에 사용됩니다.

서비스 검색을 위해 SDP 클라이언트는 SDP Request를 전송합니다. 그리고 적절한 응답이 돌아옵니다. SDP는 서버로부터 되돌아오는 SDP 응답에 대하여 “SDP Continuation”이라 불리는 분할 매커니즘을 정의합니다.

SDP Continuation은 일반적인 분할과는 다소 다르게 동작합니다.

  1. SDP 클라이언트가 SDP Request를 전송합니다.
  2. 응답이 L2CAP 연결을 통해 협상된 MTU를 초과하면 응답의 조각이 반환됩니다. 그리고 SDP 응답에 “continuation state” 구조체가 덧붙여집니다.
  3. “continuation state”인 응답의 나머지 조각을 수신하기 위하여 SDP 클라이언트는 동일한 요청을 다시 보냅니다. (이런 형식의 요청을 continuation request라 부릅니다)
  4. SDP 서버는 응답의 다음 조각을 반환합니다.
  5. 이 과정이 모든 조각들이 전달될 때 까지 계속 반복됩니다.

블루투스가 SDP 하단에 두 가지의 서로 다른 분할 레이어-L2CAP에 내장된 것(“segmentation”이라 불리는)과 ACL 레이어에 포함된 것- 를 정의한 이유는 모호합니다. 게다가 블루투스 명세는 SDP continuation 매커니즘의 한 중요한 세부사항을 구현자에게 위임했습니다. continuation state의 구체적인 구조가 바로 그것입니다. 명세는 이것을 다소 건조하게 서술합니다.

“continuation information의 포맷은 SDP 서버에서 표준화되지 않습니다. 각 continuation state parameter는 오직 그것이 만들어진 SDP 서버에서만 유효합니다” (Bluetooth Specification v5.0, Vol 3, Part B, 페이지 1926)

명세의 SDP에 대한 이 결정은 상당히 이상합니다. 왜냐하면, 반환된 continuation state는 SDP 클라이언트에 의해 직접적으로 사용되지 않고, continuation request들의 처리 과정에서 서버 내부적으로 사용되는 것이기 때문입니다. 이것은 클라이언트가 각 continuation request를 변경하지 않고 다시 반환함으로써 continuation state을 악용하는 것을 가능케 합니다. 두 종류의 비슷한 악용 방법이 Linux와 Android의 블루투스 스택에서 발견된 두 종류의 정보 누출 취약점을 만듭니다.

Linux Bluetooth stack (BlueZ) information Leak vulnerability – CVE-2017-1000250

이 취약점은 상기 시나리오의 직접적인 결과입니다. 그리고 이것은 분할 메커니즘의 구현체에 있어서 흔한 실수이기도 합니다. SDP continuation 구조체가 구현체에서 정의되기에, BlueZ는 continuation state를 나타내는 다음 구조체를 정의하였습니다.

<SDP Continuation 구조체, BlueZ에서 정의됨 (src/sdpd-request.c)>

이 구조체는 기기의 타임스탬프를 간편히 누출시킬 수 있는 타임스탬프를 가지고 있습니다. 그리고 색인이 지금까지 보내진 전체 바이트 수를 나타냅니다. 공격자가 매 요청마다 보내지는 continuation state를 조작할 수 있기에, 그는 continuation 구조체의 색인을 변경할 수 있습니다. 그럼으로써 SDP 서버가 response buffer를 벗어난 부분을 읽고, 반환하도록 할 수 있습니다.

<SDP Search Attribute Request handler – service_search_attr_req (src/sdpd-request.c)로부터 발췌됨>

BlueZ SDP 서버의 Search Attribute Request Handler로부터 발췌된 이 코드는 cstate(continuation state)의 maxBytesSent를 검증하는 않으며, 공격자로 하여금 memcpy를 통해 할당된 pResponse의 크기를 넘어서는 데이터를 복사하게 할 수 있습니다. 공격자가 이 정보 누출을 달성하기 위하여 필요한 것은 모든 데이터가 전송되었는지 검증하는 if 구문 (maxBytesSent == data_size)을 피하는 것 뿐입니다. 그리고 이것은 maxBytesSent를 조작하는 것으로 간단히 이루어질 수 있습니다. pResponse가 힙에 할당되기에, 이 정보 누출은 매우 민감한 데이터의 유출로 이어질 수 있습니다.

BlueZ는 두 파트로 이루어져 있는데, 첫번째는 커널에서 구동되는 것(L2CAP 취약점에서 보았듯이)과 두번째는 사용자 공간에서 구동되는 것입니다. bluetoothd 프로세스는 BlueZ의 모든 사용자 파트를 담고 있으며, bluetoothd는 이 취약점에 의해 누출될 수 있는 블루투스 연결의 암호화 키와 같은 민감한 정보들을 가지고 있습니다.

 

Android information Leak vulnerability – CVE-2017-0785

안드로이드의 SDP 서버도 비슷한 continuation state 구조체를 가지고 있습니다.

안드로이드의 경우, continuation offset(BlueZ의 index와 비슷한)만이 continuation struct를 통해 보내집니다. 안드로이드 SDP 서버의 search request handler가 cont_offset에 대한 검증을 어느 정도 수행함에도 불구하고 정보 누출은 여전히 가능합니다.  다음 코드를 보면 num_rsp_handles는 SDP 응답의 전체 핸들의 갯수(sdp 레코드들)를 가지고 있습니다.

<SDP Search Request handler – process_service_search (stack/sdp/sdp_server.c)로부터 발췌됨>

이 코드는 connection object(p_ccb)에 cont_offset의 사본을 보관합니다. 그리고 수신된 cont_offset이 연결의 현재 상태와 일치하는지 비교합니다. 그러므로 BlueZ에서 이루어졌던 것과 같은 간단한 악용은 불가능합니다.

중국의 만리방화벽(Great Filrewall)과 VPN 서비스 차단 우회

최근 들어 중국의 인터넷 검열이 강화되고 있는 추세이다. 철저한 필터링 능력으로 유명한 만리방화벽(Great Firewall)이 이 역할을 수행한다.
만리방화벽은 중국 정부의 전면적인 인터넷 검열 시스템인 황금 방패 프로젝트(Golden Shield Project)의 일환으로, DPI 및 휴리스틱 분석을 통해 중국 정부에서 접속을 막은 사이트와 정보를 실시간으로 검열한다.

VPN은 이러한 만리방화벽을 우회하기 위한 수단으로 많이 사용되었는데, VPN에 대한 검열은 예전부터 계속되어 왔으나, 특히 2017년 9월부로 강화된 검열이 적용되고 있는 듯 하다. 기존에는 차단되지 않았던 중소규모 사업자들의 서비스도 차단되었으니 말이다.

 

VPN 연결을 테스트하면서 발견한 만리방화벽의 특징은 다음과 같다.

1. 시그니쳐 기반으로 차단을 수행한다
2. 연결을 차단하기 위하여 TCP RST를 전송, 세션을 끊어버린다
3. 일반적인 TLS 연결은 차단되지 않는다

 

나는 이 중에서 특히 1번에 주목하였는데, 이것은 만리방화벽의 한계를 드러내는 것이기 때문이다.
아무리 중국 정부가 많은 자원을 투입하여 패킷을 분석한다 한들, 대상이 인터넷 백본인 이상 검열 장비는 필연적으로 전체 패킷을 들여다볼 수 없다. 그러니 시그니쳐 분석을 통한 패턴 매칭으로 타겟 세션을 걸러내는 것이다.

다시 말해, VPN이 차단된 경우라도 사업자를 변경하거나, VPN 서버의 설정을 변경하는 등의 방법으로 시그니쳐를 뒤틀어놓으면 VPN 차단을 우회할 수 있다. 그리고 시그니쳐를 저장하고 매칭하는 시스템의 자원에도 한계가 있는 이상, 시그니쳐 데이터는 일정 기간동안 보존되어 사용되다가 만료될 것임을 쉽게 추론할 수 있다.

 

하지만 이러한 방법을 통한 우회는 결국 하나의 방편에 불과하다. VPN의 사용량이 많다면 시그니쳐는 빠르게 수집, 업데이트 될 것이고, 그 때마다 시그니쳐를 흔들어놓을 수준의 변경을 가하는 것은 쉽지 않은 일이기 때문이다.
그래서 근본적인 해결법으로 제시되는 것이 VPN 트래픽을 TLS로 캡슐화하는 것이다.

널리 알려진 바와 같이, 일단 TLS 세션이 성립되고 나면 회선을 감시하는 제 3자가 TLS 세션의 내용을 들여다보는 것은 MITM 공격을 수행하지 않는 이상 불가능하다. 그렇기 때문에 HTTPS를 이용하여 Warning.or.kr을 회피하는 것이 가능하고.
하지만 OpenVPN의 기본적인 암호화 프로토콜도 TLS이다. 그리고 중국 정부는 OpenVPN의 트래픽을 탐지, 차단하는 것에 성공하였다.

이것이 가능했던 이유는 OpenVPN의 TLS 세션 형성을 위한 핸드쉐이크가 시그니쳐로서 탐지되었기 때문이다. 이것을 특정함으로써 일반적인 TLS 트래픽과 OpenVPN 트래픽을(비록 내용은 모를지라도) 구분하는 것이 가능하다.
그렇다면 우리는 어떻게 이것을 우회할 수 있을까?
아주 단순한 결론이다. TLS 핸드쉐이크를 탐지한다면, ‘일반적인’ TLS로 한번 더 캡슐화해주면 될 뿐인 것이다.

 

이것을 위해 필요한 것이 stunnel이라는 프로그램이 되겠다. stunnel은 여기에서 다운로드 할 수 있으며, 임의의 서버-클라이언트 간 TLS 터널링을 제공한다.

 

stunnel을 서버/클라이언트에 인스톨하고, OpenVPN을 stunnel 터널을 통해 연결하면, 만리방화벽을 우회한 접속이 가능하다.
혹여나 중국에서 VPN 접속이 안 되어서 골머리를 앓고 있는 분이 계시다면, 한번 사용해 보기를 권한다.

Microsoft PowerShell을 이용한 DNS 서버 레코드 갱신

 

네트워크 관련 작업을 하다 보면 (주로 비용상의 문제로) 유동 IP를 사용해야 하는 경우가 생기곤 한다.
유동 IP 환경에서 서비스를 제공하기 위하여 주로 DDNS를 사용하게 되는데, 웬만한 도메인 서비스들은 DDNS 서비스를 자체적으로 제공하지만, 만약 자체 도메인 서버를 운용하는 경우라면 어떨까?

리눅스라면 BIND와 쉘 스크립트라는 걸출한 물건이 존재한다. 그리고 윈도우에서는 PowerShell을 이용하여 DNS 서버를 관리할 수 있다.

 

PowerShell로 서버를 관리하기 위해서는 몇 가지 전제 조건이 필요하다.

1. WinRM 서비스가 활성화되어 있어야 한다.
2. PSRemoting이 활성화되어 있어야 한다.
3. WinRM 서비스에서 클라이언트/서버가 각각 신뢰하는 호스트로 등록되어 있어야 한다.
4. WinRM 서비스 포트인 TCP 5985/5986이 열려있어야 한다.
5. 클라이언트에서 파워 쉘 스크립트 실행 권한(Set-ExecutionPolicy)이 주어져 있어야 한다.

 

먼저 서버에서 PSRemoting을 활성화해야 한다. 파워 쉘을 관리자 권한으로 열고, 다음 명령을 입력한다.

기본적으로 PSRemoting은 같은 홈/도메인 네트워크 안, 동일한 서브넷 내에서만 허용되어 있다.
이 제약을 풀기 위하여 다음과 같은 명령어를 입력한다.

이제 서버와 클라이언트에서 서로를 신뢰하는 호스트로 지정해주어야 한다.

호스트 이름은 IP 혹은 FQDN이 될 수 있으며, ‘,'(콤마)로 구분된다. 만약 모든 호스트에 대하여 허용하고 싶다면 *(와일드카드 문자열)을 사용하자.

 

이 시점에서 WinRM 서비스가 시작되어 있지 않다면 등록 과정에서 에러가 발생한다. 경고 메시지에서는 자동으로 WinRM 서비스를 시작한다고 하지만, 실제로는 실행되지 않는다.
그러므로 수동으로 시작해준다.

WinRm 서비스가 시작된 후 정상적으로 신뢰하는 호스트 등록이 가능할 것이다.

 

이렇게 서버-클라이언트의 설정이 마무리되면, 접속을 테스트 해 본다.

접속이 정상적으로 이루어진다면 이러한 메시지가 나올 것이다. 만약 접속되지 않는다면 방화벽과 신뢰하는 호스트의 설정을 다시 살펴보자.

접속에 성공하였다면 원격 세션을 통하여 PowerShell을 실행할 준비가 되었다는 뜻이다.

 

이제 실제로 원격 세션을 열어보자. PowerShell에서 원격 세션을 얻을 수 있는 명령어는 크게 두 가지가 있다.

둘 다 원격 세션을 생성하지만, Enter-PSSession은 프롬프트에 직접 로그인하고, New-PSSession은 세션 객체를 만든다는 차이가 있다.

단순히 명령어를 실행하는 것은 Enter-PSSession이 더 간단하지만, 명령을 수행한 결과를 Return한다거나, 로컬 변수를 이용하여 명령을 수행해야 하는 경우에는 New-PSSession이 더 적합하다.

 

New-PSSession을 이용하여 원격 세션을 만드는 것은 아주 간단하다.

여기서 Credential 옵션은 인증 정보를 제공한다. 공란으로 두거나 String을 입력하였을 경우, 윈도 로그인 창이 팝업되고 인증 정보를 입력할 수 있다.
하지만 우리의 목적은 스크립트를 이용한 자동화이므로 수동으로 자격 증명을 입력하는 것은 바람직하지 않다. 그렇다면 어떻게 인증 정보 입력을 자동화 할 수 있을까?

 

정답은 Credential 옵션에 PSCredential 오브젝트를 넘겨주는 것이다. 단, 이 때 주의할 것은 PowerShell Credential에서 패스워드는 암호화 된 스트링으로 지정된다는 점이다.
Plain String을 넣을 경우 인증이 이루어지지 않는다. 그러므로 먼저 Plain-Text를 SecureString으로 변환해주어야 한다.

새로운 secureString 객체를 만들고 password를 SecureString으로 변환하였다.

 

그리고 PSCredential 오브젝트를 만들 때 아이디와 SecureString을 인자로 넘겨주고, PSCredential로 인증을 수행한다.
이것으로 새로운 PSSession 객체를 얻었다.

 

원격 접속이 성립하였으니, 원격으로 명령어를 실행해야 할 것이다. 원격 명령어 실행을 위해 사용하는 것이 바로 Invoke-Command 명령어다.

Invoke-Command 명령어의 문법은 다음과 같다.

여기서 지역 변수를 전달하고 싶다면 params()와 -ArgumentList 옵션을 사용한다.

 

이 명령어를 이용해 가장 먼저 할 일은 DNSServer 모듈이 존재하는지 확인하는 것이다.

DNSServer Cmdlet이 존재한다면 모듈 목록에 DnsServer가 나올 것이다.

 

DNSServer Cmdlet이 있다면 실제로 DNS 서버의 레코드를 읽고, 변경할 수 있다.
지금은 DDNS를 적용할 것이므로, 레코드의 값을 변경하는 명령어인 Set-DnsServerResourceRecord를 이용해야 한다.

Set-DnsServerResourceRecord cmdlet은 목표 레코드를 리소스 레코드 오브젝트를 통하여 검색한다. 즉, 그 오브젝트와 일치하는 대상을 수정할 수 있다.
그러므로 우리는 먼저 Get-DnsServerResourceRecord를 통하여 목표 리소스 레코드 오브젝트를 얻고, 그것을 수정하여 새로운 변수에 담고, 원본 리소스 레코드를 트리거로 삼아 목표 값을 갱신할 수 있다.

이 때, IPv4 Address의 경우 String을 직접 입력하지 못하므로, System.Net.IPAddress 객체로 변환해주어야 한다는 점에 유의하자.

 

백문이 불여일견, 샘플 소스를 하나 올려두겠다.

 

마지막 줄의 Get-PSSession | Remove-PSSession을 통해 사용이 끝난 세션은 반드시 종료하자.

Network Study – 6주차 : VPN(Virtual Private Network) 프로토콜

VPN(Virtual Private Network, 가상 사설망)은 본래 전용 회선(Leased-Line)을 사용하던 기업체들이 인터넷의 확산과 더불어 비용 절감을 꾀하기 위해 만들어낸 기술이다.
전용 회선을 임대하거나, 속도가 보장된 가상 회선을 임대하는 경우(MPLS)와 달리 VPN은 인터넷 망을 그대로 이용한다는 차이점이 있다. 이를 통해서 일반적인 인터넷 회선 사용료를 지불하는 것으로 본-지사간의 네트워크를 구성할 수 있었으나, 전용 회선 혹은 MPLS에서 보장하던 QoS등의 서비스를 제공받을 수 없게 되었다.

또한, 물리적 혹은 논리적으로 하나의 회선을 독점하였던 기존의 서비스와는 달리 인터넷 망을 사용하기에 외부로부터의 접근에 취약해진다는 문제가 있었다. 이를 해결하기 위해 모든 VPN 프로토콜들은 사용자를 인증하고 전송하는 모든 패킷을 암호화한다.
물론 사용하는 암호화 알고리즘과, VPN 터널 생성 방법은 프로토콜마다 다르다.

그리고 개발 목적이 본-지사간의 네트워크를 연결하는 것이었기에, 물리적으로 연결되어 직접 있지 않은 네트워크와 직접 통신할 수 있다는 특징을 가진다.

 

1. VPN 프로토콜의 종류

흔히 사용되는 VPN 프로토콜들은 다음과 같다.

– Internet Protocol Security(IPSec)
– Transport Layer Security(SSL/TLS)
– Datagram Transport Layer Security(DTLS)
– Point to Point Tunneling Protocol(PPTP)
– Secure Socket Tunneling Protocol(SSTP)
– Secure Socket Shell VPN(SSH-VPN)

이제 각 프로토콜의 알고리즘을 살펴 보자.

1-1. IPSec

IPSec은 AH(Authentication Header), ESP(Encapsulating Security Payload), IKE(Internet Key Exchange)로 구성되어 있다. AH는 인증 과정을, ESP는 페이로드의 암호화와 흐름 제어를 제공한다. 그리고 IKE는 키 매니지먼트를 제공한다.
IPSec은 고품질의 통합된 암호화 기반의 보안을 IPv4와 v6에 제공하기 위해 디자인되었고, 접근 제어, 비연결형 무결성(Connectionless Integrity), 데이터 출처 인증(Data Origin Authentication)과 재전송 공격의 차단, 암호화에 의한 기밀성, 제한적인 흐름 제어 무결성(Limited Flow Control Integrity)를 제공한다. 이러한 서비스들은 IP레이어에서 제공되며, IP 자신을 포함한 상위 프로토콜들에게 보호를 제공한다.

IPSec은 또한 최소한의 방화벽 기능을 포함한다. 이것은 IP 레이어에서의 접근 제어 측면에서 필수불가결한데, 만약 좀 더 정교한 방화벽 메커니즘을 제공할 수 있다면 그것을 사용하면 될 것이다(다만, IPSec 구현체에 의해 방화벽의 흐름 제어 기능이 강제되고, 트래픽 선택자(Traffic Selector)기능이 IKEv2에 의해 협상되지 않는다면 상호 운용성 측면에서 문제가 생길 것이다.)
IPSec 방화벽 기능은 강제 암호화된 인증과 무결성을 모든 IPSec 트래픽에게 제공할 수 있으며, 이것은 방화벽에 암호화에 의한 보호를 더하는 것 보다 나을 것이다.

IPSec이 성공적으로 적용되고 배포된 뒤, IPSec의 보호를 적용받지 않는 유저와 호스트, 그리고 다른 네트워크 구성요소들에게 영향을 미쳐서는 안 된다. AH와 ESP, 그리고 필요하다면 IKE는 독립적인 암호화 알고리즘으로 개발되었으며, 이것은 다른 구현 부분에 영향을 미치지 않고 적절한 암호화 알고리즘을 선택할 수 있도록 한다. 광역 인터넷에서의 상호 운용성을 만족하기 위하여, AH와 ESP에 쓰이는 기본 암호화 알고리즘이 RFC 4305에 정의되었다. 그리고 IKEv2를 위해 반드시 구현되어야 하는 암호화 알고리즘이 RFC 4307에 정의되었다. 이 알고리즘들은 암호화 기술의 발전에 따라 주기적으로 업데이트 될 수 있으며, 이러한 표준 암호화 알고리즘들을 분리함으로써 각 프로토콜들은 서로에게 영향을 미치지 않고 알고리즘을 갱신할 수 있다.

 

IPSec 보안 서비스는 IP레이어에서 Security Protocol, 암호화 알고리즘과 암호화 키를 선택할 수 있게 한다. IPSec은 (1) 호스트와 호스트 간의 경로를 보호하거나, (2) 보안 게이트웨이 사이의 연결을 보호하거나, (3) 보안 게이트웨이와 호스트 사이의 연결을 보호할 수 있다. 호스트 구현체들은 반드시 (1)(3)을 구현해야 하며, 보안 게이트웨이의 구현체는 3가지의 연결을 모두 구현해야 한다.
앞서 말했듯이 IPSec은 보안 기능을 제공하기 위해 AH, ESP 프로토콜을 사용하는데, 각각의 역할은 다음과 같다.

– AH(Authentication Header) : 무결성과 데이터 출처 인증을 제공한다. 옵션으로 재전송 공격을 차단하는 기능을 제공한다(수신자 단에서 구현한다)
– ESP(Encapsulating Security Payload) : AH의 기능과 더불어 기밀성을 제공한다. 무결성 없이 기밀성을 사용하는 것은 권장되지 않는다. 그리고 ESP의 기밀성이 활성화되면 제한된 트래픽 흐름 기밀성을 제공한다. 예를 들어 패킷 길이를 감추고, 효율적으로 더미 패킷을 생성하고 파기할 수 있다.

AH와 ESP 모두 접근 제어를 제공한다. 이것은 SPD(Security Policy Database)에 서술되어 있는 암호화 키의 분배와 프래픽 흐름 관리에 의해 강제된다.
두 프로토콜들은 모두 개별/통합적으로 제공될 수 있다. 하지만 대부분의 경우 ESP만을 사용하는 것으로 보안 요구사항이 충족될 것이다.
그리고 각 프로토콜들은 Transport Mode와 Tunnel Mode를 지원한다. Transport 모드의 경우 AH와 ESP는 다음 레이어의 프로토콜에 보안성을 제공한다. 그리고 Tunnel 모드에서는 IP 자신도 함께 보호한다.
이 두 모드의 차이점에 대해서는 추후 좀 더 자세히 다루겠다.

IPSec에서 제공하는 대부분의 보안 기능들이 암호화 키를 필요로 하기에, IPSec은 적절한 곳에 적절한 키를 입력해주는 매커니즘을 필요로 한다. IPSec은 수동과 자동 입력을 모두 지원하지만, 그 중 자동화된 공개키 기반의 키 관리 방법이 IKEv2로 정의되었으며, RFC 4306으로 배포되었다. 하지만 다른 자동 키 분배 메커니즘도 사용될 수 있을 것이다.

1-1.1. Security Associations

이 단락에서는 AH와 ESP를 포함한 IPv6, IPv4 구현체가 필요로 하는 IPSec fundamental에 대하여 다룬다. SA를 구성하기 위해 AH와 ESP가 사용되며, IKE의 주된 기능 또한 SA를 형성하고 유지하는 데 이용된다.
모든 AH와 ESP의 구현체는 SA의 개념을 만족해야 한다.
SA는 간단히 말해 보안 기능을 제공하고 트래픽을 옮기는 “연결”을 말한다. 보안 기능은 AH나 ESP를 사용함으로써 SA에 의해 제공되고, AH와 ESP의 보호가 동시에 적용되는 경우, 두 개의 SA가 형성되어 보호를 두 번 적용하는 것으로 동시에 사용된다. 일반적으로, 양방향 통신이 이루어질 때 한 쌍의 SA가 필요하다.

SA가 유니캐스트 트래픽 전달에 사용될 경우 SPI(Security Parameters Index)만으로 SA를 나타내기에 충분하다. 하지만 지역적인 문제로(SPI Collision?) IPSec 구현체들은 SA인증을 위해 SPI와 IPSec 프로토콜을 함께 사용해야 할 것이다. 만약 구현체가 멀티캐스트를 지원한다면, 그것은 멀티캐스트 SA를 지원하기 위해 de-multiplexing 알고리즘을 지원해야 한다.

많은 안전한 멀티캐스트 알고리즘들이 있지만, 그 중에서 RFC 3740에서 정의된 중앙 그룹 컨트롤러/일방적으로 할당된 GSA의 SPI를 가지는 키 서버 모델은 키 매니지먼트 서브시스템에 의해 협상될 수 없고, 그렇기에 GSA와 유니캐스트 SA가 동시에 같은 SPI를 사용할 수 있다. 멀티캐스트 지원 IPSec 구현체는 반드시 de-multiplex 인바운드 트래픽을 SPI 충돌이 발생하는 상황에서도 올바르게 전달하여야 한다.

 

여기서 IPSec에서 사용하는 데이터베이스의 개념을 짚고 가자.
IPSec은 크게 두 종류의 데이터베이스를 사용하는데, 하나는 SAD(Security Association Database), 다른 하나는 SPD(Security Policy Database)이다.

SAD는 SA의 집합체인데, IPSec이 적용되는 특정 Connection에 대하여 SA가 정의되고, 그것의 집합이 SAD가 된다. Incoming, Outgoing 트래픽에 따라 각각 정의된다.
SAD에는 다음과 같은 내용이 포함된다.

– AH Parameter : AH 사용시 이와 관련된 인증 알고리즘 및 관련 Key
– ESP Parameter : ESP 사용시 이와 관련된 인증 알고리즘 및 관련 Key
– Mode : Transport Mode / Tunnel Mode
– Destination IP Addr, IPSec Protocol (AH or ESP), SPI : SPI는 하나의 목적지에 대해 다수의 SA가 정의되어 있을 경우 사용하는 식별자(Index)이다.
– Lifetime : SA의 생존시간

SPD는 System Manager에 의해 정의되며, 어떠한 트래픽에 IPSec 서비스가 적용될지 정의한다. 참고로 IPSec의 동작에는 Discard, Protection, Passthrough가 있음을 미리 밝혀 둔다.
이러한 Policy의 적용은 다음과 같은 항목에 의하여 결정된다.

– Source / Destination Address
– Name : DNS 사용자 식별자 / FQDN
– Transport Layer Protocol : TCP or UDP
– Source / Destination Port

SPD는 조건에 맞는 SAD의 SA들을 지정하고, 트래픽이 IPSec 레이어를 통과할 때 정책을 적용한다.

다시 원점으로 돌아가, SAD의 각 엔트리는 반드시 Source/Destination IP Address를 표시해야 한다. 이것은 멀티캐스트의 경우 SPI가 중복될 수 있기 때문에, SPI가 중복될 경우 Destination IP Address로 목적지를 결정하기 위함이다.
이렇게 SA와 Source-Destination Address를 매칭하는 것은 들어오는 IPSec 트래픽과 SA를 매핑해야 한다는 것을 의미한다.

그리고 제한적인 QoS의 경우, DSCP(Differentiated Service Code Point) 비트가 같은 SA로 전송되고, 수신자가 재전송 방지 기능을 AH와 ESP에서 활성화해 놓았다면 그 결과 더 낮은 우선순위의 패킷이 Windowing 메커니즘에 의해 파기되게 된다.
그렇기 때문에 송신자는 반드시 트래픽을 다른 클래스로 보내고, 같은 셀렉터 값을 지정한 뒤 다른 SA를 할당해야 한다. 이 기능을 지원하기 위해 IPSec 구현체는 송신자와 수신자 사이에 다수의 SA를 만들고 유지할 수 있어야 한다.
이러한 병렬 SA를 통한 트래픽 분산은 송신자에 의해 지엽적으로 결정되며, IKE에 의한 교섭을 거치지 않는다. 수신자는 다른 SA들로 들어오는 트래픽을 편견 없이 처리해야 한다.

앞서 서술했듯이, Transport Mode와 Tunnel Mode. 두 종류의 SA가 정의된다. IKE가 한 쌍의 SA를 만들고, 처리의 단순화를 위해 한 쌍의 SA는 반드시 같은 모드여야만 한다.
Transport Mode SA는 주로 한 쌍의 호스트가 종단간 보안을 제공해야 할 경우 사용된다. Transport Mode가 Security Gateway간, Host-Security Gate간에서 사용될 경우 Transport Mode는 in-IP Tunneling이나 GRE(Generic Routing Encapsulation)을 사용할 것이다. 상황을 명확하게 하기 위해, Intermediate System에 의한 Transport Mode 사용은 인바운드의 Destination Address 아웃바운드의 Source Address가 Intermediate System에 속해있는 경우로 한한다. 그리고 Transport Mode의 경우 종단간 패킷 헤더에는 적용되지 않는다. 그러므로 이 모드의 IPSec은 신중히 적용되어야 할 것이다.

Tunnel Mode SA의 경우,  SA는 IP tunnel을 적용받는다. 접근 제어가 헤더와 트래픽에 모두 적용되며, 두 호스트는 반드시 서로에게 Tunnel SA를 만들어야 한다. 아래의 두 예외를 제외하고, Tunnel SA의 종단은 Security Gateway가 된다. 그러므로 두 Security Gateway 사이의 연결은 보통 Tunnel Mode SA이며, 그렇지 않은 두 종류의 예외는 다음과 같다.

–  트래픽이 Security Gateway를 지나갈 때 : 예를 들어 SNMP 프로토콜의 경우 Security Gateway가 호스트처럼 동작하고, Transport Mode가 허용된다. 이 경우 SA는 Security Gateway내의 호스트(매니지먼트) 기능에서 종단된다.
– 앞서 말했듯이 Security Gateway들은 경로 상의 IP 트래픽에게 보안을 제공하기 위하여 Transport Mode를 지원할 수 있다.

이러한 보안 서비스의 집합들은 SA 모드와 프로토콜의 선택에 달렸다.
예를 들어, AH와 ESP 둘 다 무결성과 인증 기능을 제공하지만, 적용 범위는 각각의 프로토콜마다 다르며, Transport/Tunnel 모드에 따라서도 다르다. 만약 IPv4옵션과 IPv6 확장 헤더의 무결성이 보장되어야 한다면, 옵션이 예키치 못하게 수정될 수 있는 AH 대신 ESP를 사용해야 할 것이다.
접근 제어를 쪼개보면, 가장 먼저 어떠한 셀렉터를 고르느냐에 따라 결정된다. 예를 들어, IKE와 Child에 따라서 다른 접근 제어 방법을 가진다.

일단 암호화에 사용되는 프로토콜이 결정되면, ESP SA는 양쪽 끝단에서 부분적인 트래픽 흐름 기밀성을 제공할 수 있다. 터널 모드를 사용하는 것은 내부 IP 헤더를 암호화하고, 트래픽의 발신지와 수신지를 감춘다. 거기에 ESP 페이로드의 패딩은 패킷 사이즈를 감추어 트래픽의 특정을 어렵게 만들 수도 있다.
IPSec 구현체들은 반드시 ESP SA가 암호화와 무결성 알고리즘을 사용하지 않고는 설정될 수 없도록 만들어야 한다.

 

1-1.2. AH(Authentication Header)

AH는 IP Extension Header로서, IP Packet에 대한 인증을 제공한다. 암호화를 수행하지 않기에 데이터그램의 기밀성은 보장하지 않으며, 앞서 말했듯이 IP 패킷 인증, 무결성 검증, 출발지 기반 인증과 재전송 공격의 방어를 제공할 수 있다.

IPSec Transport Mode와 Tunnel Mode에서의 패킷 구조를 나타낸 것이다. Transport Mode를 사용할 경우 IPv4 헤더의 뒤에 AH가 오고, Tunnel Mode를 사용할 경우 IPv4 헤더의 앞에 위치하여 IPv4 데이터그램을 캡슐화한다.

AH의 상세 구조를 나타낸 것이다. Payload Length는 IPv4 페이로드의 길이를, SPI는 앞서 설명한 SA 식별자를, Sequence Number는 AH Processing을 수행할 때마다 1씩 증가하며, 재전송 공격의 방어에 사용된다.
마지막으로 Authentication Data는 패킷 데이터 전체에 대한 해쉬 값으로, 변하기 쉬운(Mutable) 값들은 0으로 세팅하여 계산한다.

1-1.3. ESP(Encapsulating Security Payload)

ESP는 AH의 기능에 덧붙여 암호화를 제공한다. 때문에 대부분의 IPSec 연결들은 ESP를 사용하며, VPN에서 사용되는 것도 ESP이다.

ESP 또한 Transport Mode와 Tunnel Mode를 지원한다. AH와는 달리 ESP 헤더가 오고, ESP Auth Data가 마지막에 위치하는 것을 알 수 있다. 이는 ESP 헤더 ~ ESP Auth Data 사이의 페이로드만이 암호화 되기 때문이다.

ESP 패킷의 상세 구조이다. 페이로드 뒤에 패딩이 오고, 패딩을 포함하여 암호화를 하는 것에 주목하자. 패딩이 적용될 경우 원본 데이터그램의 길이를 유추하는 것이 불가능하기에 패킷 분석에 어려움을 더한다.
따라서 공격자로부터 더 안전한 프로토콜이 되겠다.

1-2. PPTP

PPTP는 인터넷의 초창기에 등장한 암호화 프로토콜로, Microsoft와 Ascend Communications, 3Com에 의하여 개발되었다.
PPTP의 프로토콜 명세는 1999년, RFC 2637로 배포되었으며, Microsoft Windows에 기본적으로 내장되어 있기에 가장 널리 쓰이는 VPN 프로토콜이 되었다.

하지만 RC4 해쉬 알고리즘이 Bias를 가진다는 것이 널리 알려져 있으며, 인증 프로토콜로 사용되었던 MS-CHAPv1이 56-Bit DES 암호화를 사용하기에 현대의 컴퓨팅 기술로는 비밀키를 손쉽게 추론할 수 있게 되어서 더 이상 안전하지 않은 프로토콜로 분류, IPSec, L2TP 등의 더 안전한 프로토콜을 사용할 것을 권고하고 있다.

 

PPTP는 터널 형성을 위해 PPP(Point-to-Point Protocol)과 GRE(Generic Routing Encapsulation)을 사용한다.
PPP가 Data-Link 계층에서 사용하기 위해 개발되었기에, PPP를 캡슐화하기 위해서 GRE가 사용되며, IP 패킷은 PPP로 캡슐화된 뒤 GRE로 다시 캡슐화된다. 따라서 아래와 같은 패킷 구조를 갖는다.

그리고 PPTP는 데이터 전송 채널과 제어 채널이 분리되어 있는데, 제어 채널은 TCP 연결을 사용하고, 캡슐화되지 않는다.

그리고 GRE-PPP만으로는 터널은 구성되지만 페이로드에 대한 암호화가 수행되지 않기에, 따로 MPPE(Microsoft Point-to-Point Encryption)을 이용하여 암호화를 수행한다.
MPPE는 RFC 3078로 출판되었으며, PPP Payload에 대한 암호화를 수행한다.

MPPE는 Keberos나 TLS 등의 방법으로 세션 키를 교환하고, 세션 키를 이용해 RC4 암호화를 수행함으로써 동작한다.