Mullvad exit IP는 놀라울 정도로 식별 가능함
1 hour ago
1
Mullvad 는 서버 하나에 여러 exit IP를 두지만, WireGuard 키 기반으로 결정적으로 배정해 접속마다 무작위로 바뀌지 않음
9개 서버에서 pubkey를 반복 변경해 모은 3,650개 데이터 포인트 는 가능한 8.2조 개 조합 중 284개 조합에만 배정됨
각 서버의 exit IP는 풀 안에서 비슷한 백분위 위치 에 놓이며, 한 조합은 여러 서버에서 대체로 81번째 백분위에 맞춰짐
원인은 pubkey나 터널 주소를 seed로 쓰고 풀 크기를 상한으로 넣는 seed 기반 RNG 로 exit IP index를 고르는 구조로 보임
IP 로그의 float 범위가 겹치면 서로 다른 Mullvad 서버를 써도 계정 간 상관관계가 가능해져 익명성 위험 이 커짐
Mullvad exit IP가 식별 벡터가 되는 구조
Mullvad 는 서버 하나에 여러 exit IP를 제공하며, 같은 서버에 연결한 두 사용자가 보통 서로 다른 공개 IP를 받음
서버 수는 578대 로, Proton VPN의 20,000대 보다 적어 한 IP에 사용자를 몰아넣지 않는 수직 확장이 과도한 IP 차단·속도 제한을 피하는 데 유리함
하지만 서버에 연결할 때마다 exit IP가 무작위로 바뀌지 않고, WireGuard 키를 기반으로 결정적으로 선택 됨
WireGuard 키는 1~30일마다 회전 하지만, 서드파티 클라이언트에서는 회전하지 않음
서버마다 독립적으로 고정 exit IP가 배정된다면, 몇 개 서버의 IP 조합만으로 다른 Mullvad 사용자와 구분될 수 있음
9개 서버에서 관찰한 exit IP 조합
pubkey를 반복 변경 하며 9개 서버의 exit IP를 수집하는 스크립트를 밤새 실행해 3,650개 pubkey 데이터 포인트를 얻음
각 서버의 exit IP 범위는 다음처럼 관찰됨
Hostname
Start IP
End IP
# IPs
au-syd-wg-101
103.136.147.5
103.136.147.64
60
cl-scl-wg-001
149.88.104.4
149.88.104.14
11
de-ber-wg-007
193.32.248.245
193.32.248.252
8
dk-cph-wg-002
45.129.56.196
45.129.56.226
31
fi-hel-wg-201
185.65.133.10
185.65.133.75
66
us-lax-wg-001
23.234.72.36
23.234.72.126
91
us-nyc-wg-602
146.70.168.132
146.70.168.190
59
us-sjc-wg-302
142.147.89.212
142.147.89.224
13
za-jnb-wg-002
154.47.30.145
154.47.30.155
11
이 서버들의 풀 크기를 곱하면 8.2조 개 이상 의 exit IP 조합이 가능해 보임
실제 테스트된 모든 pubkey는 그중 284개 조합 중 하나에만 배정됨
가능한 조합 수에 비해 관찰된 조합 수가 매우 적어, 서버별 IP 선택이 독립적이지 않다는 단서가 됨
서로 다른 IP가 같은 백분위에 놓이는 패턴
exit IP는 풀 시작 IP에서 얼마나 떨어져 있는지로 숫자 위치 를 계산할 수 있음
예를 들어 au-syd-wg-101에서 103.136.147.53은 103.136.147.5부터 세면 1-based index가 49임
관찰된 조합의 IP 위치를 각 서버의 풀 크기로 나누면, 서로 다른 서버에서도 거의 같은 비율 이 나타남
Server
IP
Position
Pool size
Ratio
au-syd-wg-101
103.136.147.53
49
60
0.816
cl-scl-wg-001
149.88.104.12
9
11
0.818
de-ber-wg-007
193.32.248.251
7
8
0.875
dk-cph-wg-002
45.129.56.220
25
31
0.806
fi-hel-wg-201
185.65.133.63
54
66
0.818
us-lax-wg-001
23.234.72.109
74
91
0.813
us-nyc-wg-602
146.70.168.179
48
59
0.813
us-sjc-wg-302
142.147.89.222
11
13
0.846
za-jnb-wg-002
154.47.30.153
9
11
0.818
각 IP는 해당 풀의 비슷한 백분위에 놓이며, 위 예시는 대체로 81번째 백분위 에 해당함
이 패턴 때문에 Mullvad는 모든 서버에서 서로 이웃한 위치의 exit IP만 배정하는 것처럼 보임
seed 기반 난수 선택으로 보이는 원인
cl-scl-wg-001과 za-jnb-wg-002는 관찰된 284개 IP 조합 전체에서 항상 같은 IP index를 공유함
두 서버의 공통점은 풀 크기 11 이며, 동일한 seed와 동일한 bounds를 가진 난수 호출이 같은 결과를 내는 구조와 맞음
정적 seed로 RNG를 초기화한 뒤 같은 범위에서 난수를 뽑으면 같은 결과가 반복됨
Mullvad는 pubkey 또는 터널 주소를 seed로 쓰고, 풀 크기를 상한값으로 넣는 seed 기반 RNG 로 exit IP index를 고르는 것으로 보임
bounds가 바뀌어도 RNG의 엔트로피 풀은 영향을 받지 않으며, Rust에서는 첫 호출에서 같은 float가 생성되어 bounds에 곱해지는 방식과 맞아떨어짐
이 동작은 min + round((max - min) * float)처럼 단순화해 볼 수 있지만, 크게 단순화한 표현일 수 있음
이런 특성 때문에 풀 크기가 달라도 같은 seed에서 나온 float가 각 서버 풀의 비슷한 비율 지점으로 매핑됨
Mullvad 클라이언트 가 Rust로 작성되어 있어 Rust가 백엔드 언어일 가능성도 있지만, 이는 클라이언트 구현에 근거한 판단에 그침
random_range가 bounds 변화에 따라 어떻게 동작하는지 정확히 예상하기 어렵고, bounds 증가가 엔트로피와 섞여 다른 수를 만들 것이라고 생각하기 쉽지만 실제 관찰과는 다름
IP 로그 상관관계로 생기는 익명성 위험
특정 IP 조합에서 가능한 float 값의 최솟값과 최댓값을 추정하는 도구가 mullvad-seed-estimator 로 제공됨
스크린샷의 특정 IP 집합은 0.2909~0.2943 사이의 float 값으로 해석되며, 차이는 0.0034임
이는 Mullvad 사용자 중 0.34% 가 이 IP들을 공유한다는 뜻이고, 활성 사용자 100,000명이라는 대략적 추정에서는 340명에 해당함
처음 예상한 수준만큼 고유하지는 않지만, 99% 이상 정확도 는 낮지 않음
예를 들어 포럼 관리자가 전날 차단한 사용자의 sockpuppet으로 의심되는 새 계정을 확인할 때, 두 계정이 서로 다른 Mullvad 서버를 써도 IP 로그가 0.4334 - 0.4428과 0.4358 - 0.4423처럼 겹치는 float 범위에 있으면 같은 사람일 확률이 99%를 넘음
데이터 유출이나 법적 절차로 확보한 IP 로그에도 같은 방식의 상관관계를 적용하면, VPN 뒤의 사용자가 익명성을 잃을 수 있음
보호 방법
pubkey 하나당 서버를 한 번 이상 바꾸지 않는 것 이 권장됨
Mullvad 앱에서 로그아웃해 pubkey를 강제 회전 할 수 있음
Homepage
개발자
Mullvad exit IP는 놀라울 정도로 식별 가능함
🔉 볼륨 줄이기
🔊 볼륨 키우기
🔇 음소거
⏭️ 다음 곡