들어가며

SK텔레콤 해킹 사태 이후 이를 mitigate 하기 위해 SK텔레콤이 유심 “재설정” 을 도입했습니다. SK텔레콤 측 주장으로는 이 “유심 재설정” 절차가 물리적 심 카드 교체와 동일하다는 주장을 하고 있고, 이 글에서는 이 주장을 검증해 보고자 합니다.

읽기 귀찮으신 분들을 위한 세줄 요약

  1. 유심 재설정은 심 카드 교체와 동일한 효과가 아니다
  2. 재설정 받으신 분도 심 카드 교체 하십시오 (아니면 번이 하시거나)
  3. 이심이시면 재발급 하세요.

검증 계획

통신 인증에 사용되는 값들

심 카드 정보 교체가 얼마나 효과적인지를 확인하려면, 다음과 같은 계획을 세울 수 있습니다

  1. 심카드 내 인증에 관여하는 파라미터들을 확인한다
  2. “재설정” 이후 파라미터들을 원래 값과 비교할 방법을 생각해낸다
  3. 재설정 이후 파라미터 값들을 비교한다

어떤 값들을 비교해야 할 지를 확인하려면 우선 SIM 인증과 AKA 인증이 어떻게 작동하는지를 확인해야 합니다. 이를 위해서는 3GPP/ETSI 공식 문서를 보는 것이 가장 정확하겠지만, 두 공식 문서 모두 읽기가 쾌적하진 않기에, Cheatsheets for Authentication and Key Agreements in 2G, 3G, 4G, and 5G 페이퍼와 ETSI TS 135 206 를 함께 참고하여 어떤 값들이 사용되는지를 확인해 봅시다.

2.3 List of Variables
AK a 48-bit anonymity key that is the output of either of the functions f5 and f5*.
AMF a 16-bit authentication management field that is an input to the functions f1 and f1*.
c1,c2,c3,c4,c5 128-bit constants, which are XORed onto intermediate variables.
CK a 128-bit confidentiality key that is the output of the function f3.
IK a 128-bit integrity key that is the output of the function f4.
IN1 a 128-bit value constructed from SQN and AMF and used in the computation of the functions f1
and f1*.
K a 128-bit subscriber key that is an input to the functions f1, f1*, f2, f3, f4, f5 and f5*.
MAC-A a 64-bit network authentication code that is the output of the function f1.
MAC-S a 64-bit resynchronisation authentication code that is the output of the function f1*.
OP a 128-bit Operator Variant Algorithm Configuration Field that is a component of the functions f1,
f1*, f2, f3, f4, f5 and f5*.
OP C a 128-bit value derived from OP and K and used within the computation of the functions.
OUT1,OUT2,OUT3,OUT4,OUT5
128-bit computed values from which the outputs of the functions f1, f1*, f2, f3, f4, f5 and f5* are
obtained.
r1,r2,r3,r4,r5 integers in the range 0–127 inclusive, which define amounts by which intermediate variables are
cyclically rotated.
RAND a 128-bit random challenge that is an input to the functions f1, f1*, f2, f3, f4, f5 and f5*.
RES a 64-bit signed response that is the output of the function f2.
SQN a 48-bit sequence number that is an input to either of the functions f1 and f1*. (For f1* this input
is more precisely called SQN MS.)
TEMP a 128-bit value used within the computation of the functions
ETSI TS 135.206 섹션 2.3

해당 문서를 통해 우리는 검증 대상을 다음과 같이 정할 수 있습니다.

  1. 가입자 식별 번호 IMSI
  2. GSM 시절부터 사용된 심 인증 키 K
  3. UMTS 시절부터 들어온 오퍼레이터 인증 키 OPc
  4. MILENAGE 알고리즘 상수 c_i, r_i

값들 검증하기

위 세 값들 중 IMSI 의 경우 쉽게 변경 사항을 확인할 수 있습니다. 그냥 pySIM-shell 로 심 카드와 이야기한 뒤 EF.IMSI 파일을 덤프하라고 하면 끝이니까요.

하지만 K 와 OPc 는 다릅니다. 해당 값들은 심 카드 내부에만 머무르며, 인증 결과 값만이 심 바깥으로 나옵니다 (몇몇 경우에는 해당 키를 사이드 채널 어택으로 뽑아낼 수 있지만, 여기에 굳이 오실로스코프와 전류 프로브를 끌고 오진 말자구요). 더불어 MME 가 RES 와 XRES 를 비교하는 것에 더해 심 카드도 AUTN 값을 통해 올바른 HSS 의 요청인지를 검증한다는 것이죠.

다행히도, 이를 검증하기 위해 (ab)use 할 수 있는 기능이 심 카드에 존재합니다. 바로 심 카드 인증 결과 코드 중 MAC 과 XMAC 이 불일치할 때 나오는 Authentication error 리플라이와 MAC 은 XMAC 과 일치하지만, SEQ 넘버가 시간 역행을 하여 생기는 Synch failure 오류 두 가지로 오류가 나눠진다는 점이죠.

4G/EPS AKA 인증 플로우챠트, arXiv:2107.07416 [cs.CR]
arXiv:2107.07416 [cs.CR] 4G/EPS AKA
pySIM-shell (00:MF/ADF.USIM)> authenticate b88dc61f07b5147cc9f545b2f7ddb1b8 [AUTN 검열됨]
EXCEPTION of type 'SwMatchError' occurred with message: SW match failed! Expected 9000 and got 9862: Security management - Authentication error, incorrect MAC
To enable full traceback, run the following command: 'set debug true'
pySIM-shell (00:MF/ADF.USIM)>
ADF.USIM Authcntication error 오류
ADF.USIM synchronization failure 메시지. AUTS 리턴 값을 보여준다.

이에 우리는 이러한 가정을 할 수 있습니다.

심 “재설정” 이전 실 네트워크 인증 시퀸스에서 RAND 와 AUTN 을 캡쳐하여 심 “재설정” 이후 ADF.USIM 에 인증 요청을 할 경우

  • 만약 SK텔레콤이 심 “재설정” 을 통해 K/OPc, c_i, r_i 중 어떤 것이라도 바꿨다면, Authentication error 가 발생할 것이다
  • SK텔레콤이 심 “재설정” 을 통해 해당 값을 리셋하지 않았다면, synchronization failure 와 AUTS 를 반환할 것이다

이 이외에도 SK텔레콤의 구형 심 카드는 GSM 인증을 허용하는 경우가 있는데, 이 경우에는 K값만의 변화를 체크할 수 있습니다.

arXiv:2107.07416 [cs.CR] 2G/GSM/GPRS/EDGE AKA

GSM 인증의 경우, AUTN 상호 인증 절차 없이, 임의의 RAND 값에 대해 계산된 CK 와 RES 값을 뱉도록 되어 있습니다. 이를 활용하면 임의의 RAND 값에 대해

  • SK텔레콤이 심 “재설정” 과정을 통해 K 값을 변경했다면, 같은 RAND 값에 대한 응답이 달라질 것이다

라는 가정을 하고 검증 절차를 진행할 수 있습니다.

실제 검증

준비물

  1. QCDIAG 인터페이스가 열리는 모뎀 혹은 휴대폰
  2. SKT 심 카드
  3. 스마트 카드 리더와 심 어댑터
  4. SKT PS&M 을 방문할 귀차니즘을 이겨낼 의지

이 글에서는 GSMTAP 캡쳐 과정에 대해 자세한 설명을 진행하지는 않겠습니다. 해당 부분은 잘 삽질해 보세요.

검증

LTE 캡쳐를 진행해 다음과 같이 프레임을 획득합니다.

LTE 통신의 GSMTAP 캡쳐 화면

해당 캡쳐에서 우리가 관심 있는 것은 Authentication Request 프레임입니다. 해당 프레임과 프레임의 응답을 필터해 봅시다.

LTE Authentication request 프레임들

해당 프레임에서 replay 를 위한 RAND값과 AUTN 을 캡쳐할 수 있습니다.

이제 UE 에서 심 카드를 빼서, 스마트 카드 리더에 셋업하고 pySIM-shell 을 실행합니다.

이후 EF.IMSI, EF.ICCID 파일의 내용과 DF.GSM, ADF.USIM 에 authenticate 쿼리를 한 내용을 기록합니다

(아래의 내용은 pySIM-shell 에서 불필요한 select 결과 응답을 자르고 붙여넣음)

Using reader PCSC[Alcor Micro AU9540 00 00]
Waiting for card...
Info: Card is of type: UICC
Detected UICC Add-on "SIM"
AIDs on card:
 USIM: a0000000871002ffffffff89040300ff (EF.DIR)
 unknown: a000000063504b43532d3135 (EF.DIR)
 unknown: a0000003420001ffffffff89040500ff (EF.DIR)
 ADF.ISD: a000000003000000
Welcome to pySim-shell!
(C) 2021-2023 by Harald Welte, sysmocom - s.f.m.c. GmbH and contributors
Online manual available at https://downloads.osmocom.org/docs/pysim/master/html/shell.html
pySIM-shell (00:MF)> select EF.ICCID
pySIM-shell (00:MF/EF.ICCID)> read_binary_decoded
{
    "iccid": "89820[ICCID 검열됨]2"
}
pySIM-shell (00:MF/EF.ICCID)> select DF.GSM
pySIM-shell (00:MF/DF.GSM)> select EF.IMSI
pySIM-shell (00:MF/DF.GSM/EF.IMSI)> read_binary_decoded
{
    "imsi": "45005[IMSI 검열됨]0"
}
pySIM-shell (00:MF/DF.GSM/EF.IMSI)> select DF.GSM
pySIM-shell (00:MF/DF.GSM)> authenticate 8188388ad5cdd481b02298ff29827791
"6b22e8416c38ae445619b72a"
pySIM-shell (00:MF/DF.GSM)> select ADF.USIM
pySIM-shell (00:MF/ADF.USIM)> authenticate b88dc61f07b5147cc9f545b2f7ddb1b8 944ced[AUTN 검열됨]
{
    "synchronisation_failure": {
        "auts": "f531af[AUTS 검열됨]"
    }
}
pySIM-shell (00:MF/ADF.USIM)>
Using reader PCSC[Alcor Micro AU9540 00 00]
Waiting for card...
Info: Card is of type: UICC
Detected UICC Add-on "SIM"
AIDs on card:
 USIM: a0000000871002ffffffff89040300ff (EF.DIR)
 unknown: a000000063504b43532d3135 (EF.DIR)
 unknown: a0000003420001ffffffff89040500ff (EF.DIR)
 ADF.ISD: a000000003000000
Welcome to pySim-shell!
(C) 2021-2023 by Harald Welte, sysmocom - s.f.m.c. GmbH and contributors
Online manual available at https://downloads.osmocom.org/docs/pysim/master/html/shell.html
pySIM-shell (00:MF)> select EF.ICCID
pySIM-shell (00:MF/EF.ICCID)> read_binary_decoded
{
    "iccid": "89820[ICCID 검열됨]2"
}
pySIM-shell (00:MF/EF.ICCID)> select DF.GSM
pySIM-shell (00:MF/DF.GSM)> select EF.IMSI
pySIM-shell (00:MF/DF.GSM/EF.IMSI)> read_binary_decoded
{
    "imsi": "45005[IMSI 검열됨]6"
}
pySIM-shell (00:MF/DF.GSM/EF.IMSI)> select DF.GSM
pySIM-shell (00:MF/DF.GSM)> authenticate 8188388ad5cdd481b02298ff29827791
"6b22e8416c38ae445619b72a"
pySIM-shell (00:MF/DF.GSM)> select ADF.USIM
pySIM-shell (00:MF/ADF.USIM)> authenticate b88dc61f07b5147cc9f545b2f7ddb1b8 944ced[AUTN 검열됨]
{
    "synchronisation_failure": {
        "auts": "f531af[AUTS 검열됨]"
    }
}
pySIM-shell (00:MF/ADF.USIM)>
pySIM-shell 로 작업한 모습. 좌 – 심 “재설정” 이전 우 – 심 “재설정” 이후

해당 결과를 보면 다음 결과를 확인할 수 있습니다

  • ICCID 는 변경되지 않았음
  • IMSI 는 변경됨
  • K/OPc/c_i/r_i 는 변경되지 않음 (변경되었으면 9862: Security management – Authentication error 응답이 돌아와야 함)

이 결과로써, 실제 누출 정보에서 제일 중요한 K/OPc 가 변경되지 않았음을 확인할 수 있으며, 이는 SKT 의 주장과 다르게 심 “재설정”은 심 교체와 동일한 효과가 아님을 의미합니다.

공격자의 공격 시나리오

지금까지 SKT 공격자에 대해 알려진 사실 중 하나는 state-backed actor 라는 것입니다. 이 유형의 공격자는 대체로 가용 가능한 자원이 풍부하며, 경우에 따라서는 근거리 공격 또한 수행할 수 있을 확률이 매우 높습니다.

이 가정 하에서 공격 시나리오를 작성해보면 다음과 같습니다

공격자는 다음 정보/장비에 대해 접근이 가능하다고 가정할 수 있습니다.

  • 공격 대상의 물리적 위치 (아래의 불특정 다수 대량 공격 시나리오에는 필요 없음)
  • 공격 대상의 K/OPc/c_i/r_i, IMEI 정보
  • 심 에뮬레이팅 툴(SIMurai) 혹은 개발용 심 카드 (e.g. SysmoISIM)
  • 소프트웨어 라디오 프론트엔드 (대충 300$ 근처면 쓸만한 USRP 클론을 한 대 뽑습니다)
  • 디버그 인터페이스 접근 가능한 UE (현재 SKT가 무엇으로 땜빵하려 하는지와 이를 우회하려면 무엇을 바꿔야 할 지는 잘 상상해 보세요. 힌트: 언론사에서 하는 주장과 달리 이 값을 바꾸는 게 쉽다는 건 XDA 일주일 눈팅한 사람도 알 것입니다.)

해당 공격자는 다음 절차를 거쳐 공격을 수행할 수 있습니다.

  1. 공격 대상의 물리적 위치에 접근합니다.
  2. (SKT는 진짜 5G SA 같은 거 안 하니까) LTESniffer 혹은 기타 방법으로 IMSI 를 캡쳐합니다.
  3. Fake BTS 혹은 Fake AP (EAP-AKA) 를 사용해 K/OPc 페어에 맞는 IMSI 를 찾아냅니다
  4. 심 에뮬레이팅 툴을 이용해 심을 에뮬레이션 하거나 개발용 심에 새 K/OPc/c_i/r_i 를 프로그램합니다
  5. ???
  6. PROFIT!

** AKA 인증은 stateful 하기 때문에 공격자는 이 부분에 대한 workaround 또한 준비해야 할 수 있습니다

더불어, 공격자가 불특정 다수를 향해 공격을 목표로 할 경우 (IMSI-K/OPc 쌍 재 빌드) 다음과 같은 공격이 가능합니다.

  1. 공격 대상이 대량으로 지나갈 만한 곳에 자리를 잡습니다. (예: 강남)
  2. Fake BTS 를 이용, UE 가 Attach request 에 IMSI 를 disclose 하도록 강제합니다.
    • 와이파이 EAP-AKA 캡쳐 또한 사용 가능하지만… 요즘 통신사 와이파이 쓰는 사람이 별로 없으므로…
  3. UE 의 Auth request 를 캡쳐한 후, 기 K/OPc 데이터 중 올바른 데이터가 있는지 검색합니다
  4. 해당 정보를 이용해 깨진 IMSI-K/OPc 쌍을 다시 생성합니다.
  5. 이후는 일반 심 복제 공격 시나리오와 같습니다.

일반 유저 레벨에서 가능한 mitigation

사실 이번 사태에서는 (HSS 가 털릴 거라고 누가 상상이라도 했겠습니까) 일반 사용자가 할 수 있는 조치가 별로 많지는 않습니다. 심 카드 재고는 없고, 심 카드 교체 큐는 쭉 밀렸고 이 와중에 SKT 는 신규 받으려고 눈 돌아갔으니까요.

  1. (사심이 들어간 추천 – vote with your wallet) 번호 이동을 하세요
  2. 심 카드를 교체하세요. 가능한 한 빨리요.

정도의 대응 방법이 있습니다.

마치며

이번 사태와 이 글을 통해 더 많은 사람들이 모바일 이동통신 인증 과정에 대해 조금이나마 알아갔으면 하며 글을 마칩니다.

더불어, 이번 사태에 대해 추측성 글이 난무하는 사태는 언론사들이 불확실한 정보를 전달해서 생기는 문제 또한 매우 큽니다. 이를 막기 위해서는 언론사가 “유심 인증 키” (유심 인증 키라고 부를 만한 건 ADM/OTA/K/OPc 등등 많기 때문에, 그리고 이 중 무엇이 털렸는가에 따라 어떤 절차가 안전해지지 않을 수 있기 때문에) 같은 모호한 단어 대신 어떤 정보가 아직 안전하다고 추정되는지, 어떤 데이터가 유출되었다고 생각되는지에 대해 정확히 전달하는 게 필요합니다. (하지만 개선은 요원하겠지…)