1P by GN⁺ | ★ favorite | 댓글 1개
  • Randar는 Minecraft Beta 1.8~1.12.2에서 블록 파괴 시 생기는 아이템 드롭 좌표를 이용해 서버 java.util.Random 상태를 복원하고, 다른 플레이어의 위치를 역추적하는 익스플로잇임
  • 핵심 원인은 지형·구조물 생성과 채굴 이벤트가 같은 난수 생성기를 공유한 RNG 재사용이며, 관측 가능한 드롭 위치가 내부 상태 단서가 됨
  • 아이템 드롭의 X/Y/Z 오프셋은 World.rand.nextFloat() 세 번의 연속 출력이라, 48비트 시드의 상위 24비트들이 노출되고 LLL 격자 축소로 시드를 빠르게 복원할 수 있음
  • 복원한 시드는 거꾸로 되감아 Woodland Mansion 검사에서 나온 값인지 확인하며, 맞으면 최근 로드된 1280×1280 블록 Woodland region을 식별함
  • ReplayMod 같은 과거 패킷 기록에 드롭 데이터가 남아 있으면 서버가 패치된 뒤에도 Beta 1.8~1.12.2 시절의 활동 위치가 사후 노출될 수 있음

Randar가 노리는 정보

  • 목표는 같은 월드에 있는 다른 플레이어의 게임 내 좌표를 찾는 것임
  • 2b2t가 주요 사례로 쓰임
    • 2b2t는 규칙이 없는 Minecraft “anarchy” 서버임
    • 서버 맵은 3.6 quadrillion square tiles 규모라, 위치 비밀성이 아이템을 지키는 핵심 조건이 됨
  • Randar 이전에도 2b2t에는 2018~2021년에 사용된 좌표 익스플로잇 Nocom이 있었음

취약한 버전과 코드 실수

  • 문제는 Minecraft Beta 1.8 2011년 릴리스부터 1.12.2 2017년 릴리스까지 존재함
    • 2b2t는 2023년 8월 14일까지 1.12.2에 머물렀음
  • 핵심 실수는 java.util.Random 인스턴스를 여러 코드 경로에서 부주의하게 재사용한 점임
    • 지형 생성과 채굴 같은 게임 동작 사이에서 RNG가 공유됨
    • java.util.Random 자체도 보안용 RNG가 아님
  • Minecraft는 같은 월드 시드와 같은 위치에서 같은 지형이 나오도록 결정적 생성을 사용함
    • 이 목적에는 java.util.Random 사용이 자연스러움
    • 문제는 예측 가능해야 하는 월드 생성용 RNG 조작이 예측 불가능해야 하는 이벤트까지 흔든 점임

Woodland Mansion 검사와 전역 World.rand

  • Woodland Mansion 생성 위치를 확인하는 과정에서 World.rand가 재설정됨
    • Woodland region은 80×80 청크 단위로 계산됨
    • 해당 region 안에서 Mansion이 생길 청크를 고르기 위해 random.nextInt(60)이 네 번 호출됨
  • 취약한 흐름은 World.setRandomSeed(seedX, seedY, seedZ)가 전역 this.rand에 새 시드를 설정하고 같은 객체를 반환하는 구조임
  • 2b2t 전용 식은 다음과 같음
seed = x * 341873128712 + z * 132897987541 - 4172144997891902323 mod 2^48
  • setRandomSeed는 실제 Woodland Mansion 근처에 있을 때뿐 아니라 청크 로드마다 검사 목적으로 호출됨
  • 차원별 영향은 다름
    • Overworld가 주요 영향 대상임
    • Nether는 구조물 생성이 항상 안전한 RNG를 사용해 안전함
    • The End는 end city 때문에 초기 생성 시 영향을 받지만, 같은 청크가 이후 다시 로드될 때마다 영향을 주지는 않아 상대적으로 안전함

아이템 드롭 좌표가 RNG를 드러내는 방식

  • 블록을 채굴하면 아이템이 블록 내부의 무작위 위치에 드롭됨
    • 예를 들어 블록 좌표가 (10, 20, 30)이면 아이템은 (10.25, 20.25, 30.25)부터 (10.75, 20.75, 30.75) 사이에 나타남
  • 이 위치는 world.rand.nextFloat() 세 번으로 X, Y, Z 오프셋을 정함
  • 드롭 좌표에서 원래 nextFloat() 값으로 되돌릴 수 있음
    • float에 0.5를 곱하는 과정은 지수만 줄여 정보 손실이 없음
    • 이후 double로 변환되고 블록 좌표가 더해져 네트워크로 full precision 전송됨
  • java.util.Random.nextFloat()는 48비트 시드를 갱신한 뒤 상위 24비트를 정수로 꺼내 2^24로 나눔
    • LCG 식은 newSeed = oldSeed * 25214903917 + 11 mod 2^48
    • 세 번의 연속 float는 세 연속 시드의 상위 24비트를 제공함

LLL 격자 축소로 시드 복원

  • 단순한 방법은 첫 측정값에 맞는 하위 24비트 후보 2^24개를 모두 시도하는 것임
    • 이 방식도 동작하지만 느려서 격자 방법을 사용함
  • 세 측정값은 다음 세 값의 범위를 제공함
    • seed
    • nextSeed(seed)
    • nextSeed(nextSeed(seed))
  • 이 세 값을 3차원 점 (seed, nextSeed(seed), nextSeed(nextSeed(seed)))로 보면 가능한 모든 시드가 격자 구조를 이룸
  • 기본 벡터는 다음과 같이 잡힘
    • (1, a, a^2)
    • (0, c, 0)
    • (0, 0, c)
    • 여기서 a = 25214903917, c = 2^48
  • LLL basis reduction은 같은 격자를 만드는 더 짧고 거의 직교한 기저를 구함
    • Mathematica 예시는 LatticeReduce[{{1, a, a^2}, {0, c, 0}, {0, 0, c}}]
    • 결과 기저는 (1270789291, -2446815537, 2154219555), (-2355713969, 1026597795, 4110294631), (-3756485696, -2345310016, -2015749696)
  • 측정 큐브의 중심을 축소 기저 공간으로 변환한 뒤 각 계수를 가장 가까운 정수로 반올림하면 유효한 격자점이 나오며, 첫 좌표가 복원된 내부 시드가 됨
  • 최적화된 Java 코드 예시는 세 측정값에서 약 10ns 수준으로 시드를 복원할 수 있음

시드를 되감아 위치를 찾는 과정

  • java.util.Random의 LCG는 앞으로도 뒤로도 진행할 수 있음
    • 정방향: newSeed = oldSeed * 25214903917 + 11 mod 2^48
    • 역방향: oldSeed = (newSeed - 11) * 246154705703781 mod 2^48
  • 복원한 시드를 뒤로 되감으며 각 시드가 Woodland Mansion 검사에서 나온 시드일 수 있는지 확인함
  • Minecraft 월드 범위는 -30 million부터 +30 million 블록까지임
    • 구현은 각 축의 Woodland region 범위를 -23440부터 +23440까지로 둠
    • 가능한 Woodland region 수는 (23440*2+1)^2, 즉 2,197,828,161개
  • 22억 개 후보를 모두 비교하는 방식은 느리고, 대형 HashSet도 메모리를 많이 사용함
  • Z 계수 132897987541이 홀수라 mod 2^48에서 역원을 가짐
    • 역원은 211541297333629
    • 이를 이용하면 모든 X 후보 46,881개만 훑고 Z를 계산해 후보 region을 찾을 수 있음

GPU와 조회 테이블 최적화

  • X만 순회하는 방식도 단일 시드에는 합리적이지만, 많은 봇이 초당 여러 블록을 캐고 각 측정마다 수천 RNG step을 검사하면 저사양 VPS에서 실시간 처리가 어려웠음
  • 이후 구현은 CUDA 배치 작업과 조회 테이블로 바뀜
    • 조회 테이블 키는 mansion seed의 하위 32비트
    • 값은 Woodland region의 X 좌표
    • 하위 32비트 키에 충돌이 없었고, 이유는 이해하지 못했다고 적음
  • 테이블은 2^32개 엔트리와 엔트리당 2바이트를 사용해 약 9GB VRAM이 필요함
  • RTX 3090에서 초당 약 1천만 seeds를 크랙할 수 있었음
  • 복원 결과는 가장 최근 청크 로드가 발생한 1280×1280 블록 Woodland region을 알려주며, 그 정도면 몇 분 탐색으로 위치 파악이 가능함

실제 서버에서 관측된 step 분포

  • 이론적으로 Woodland seed 간 평균 간격은 약 128,000 RNG steps
  • 2b2t에서는 대부분 몇십 step 안에서 Woodland seed가 발견됨
    • 측정은 패킷 처리 시점상 tick의 매우 이른 시점에 일어남
    • 보통 직전 tick에 청크가 로드된 상태였음
  • 신뢰 가능한 측정은 최소 4 RNG steps부터 시작함
    • Woodland Mansion 코드는 관측 전에 rand.nextInt를 네 번 호출하기 때문임
  • 큰 spike는 1354 step 배수에서 나타남
    • end crystal 폭발 또는 wither skull 가능성이 제시됨
    • end crystal 폭발의 경우 블록 피해 계산 16^3-14^3=1352와 사운드 효과 2회로 1354 step이 맞음

ReplayMod와 사후 노출 위험

  • 서버가 최신 버전으로 업데이트됐거나 RNG 조작을 패치했더라도, 과거 데이터가 남아 있으면 Randar 위험이 남음
  • 일부 Minecraft 플레이어는 ReplayMod 같은 모드로 패킷을 기록함
    • 기록 파일에 아이템 드롭이 포함돼 있으면 당시 서버 RNG 상태를 복원할 수 있음
    • 블록 깨기는 매우 흔한 동작이라 기록에 포함됐을 가능성이 높음
  • Beta 1.8~1.12.2에서 활성화됐던 모든 위치는 서버가 오래전에 업데이트됐더라도 노출된 것으로 간주해야 함
  • Randar를 직접 실행해 볼 수 있는 클라이언트 사이드 웹 도구가 제공됨
    • hobune.stream/randar에서 1.12.2 ReplayMod 파일을 드래그해 좌표를 확인할 수 있음
    • 녹화 파일은 브라우저를 떠나지 않음

Randar 운용과 히트맵

  • SpawnMasons는 이미 다른 프로젝트 때문에 24/7로 stone/cobblestone을 캐던 계정들에서 아이템 드롭 좌표를 기록하기 시작함
  • Nocom에서 쓰던 headless Minecraft 시스템을 재사용하고, 측정값 저장을 위해 Postgres 데이터베이스를 추가함
  • RNG 측정값을 크랙하는 소프트웨어는 여러 번 개선됐고, 최종적으로 async CUDA batch job으로 정착함
  • 크랙된 측정값이 데이터베이스에 추가되면 heatmap 분석 테이블도 갱신됨
    • 전체 기간, 일별, 시간별 hit count를 저장함
    • Plotly Dash UI로 특정 시간 범위와 granularity를 선택해 브라우저에서 볼 수 있게 함
  • Elytra stash hunting으로 생기는 청크 로드 spam은 여러 distinct hour에 걸쳐 로드된 좌표만 고려하는 방식으로 제거함
  • 발견한 hotspot을 추적하기 위해 간단한 공유 annotation 시스템도 추가함
  • Nocom에서 가져온 Baritone bot으로 아이템 stash를 훔치고 정리하는 과정을 AFK 자동화함

보호용 decoy Woodland region

  • Randar가 항상 가장 최근 청크를 정확히 찾는 것은 아님
    • RNG를 뒤로 되감을 때 더 최근의 decoy Woodland region이 먼저 나오면 첫 match를 반환하는 익스플로잇은 오탐을 낼 수 있음
  • Woodland seed는 전체적으로 약 130,000개 RNG seed 중 하나꼴이지만, 분포에는 outlier가 있음
  • 2b2t에서는 약 2만 개 Woodland region 중 하나가 다음 4 RNG step 안에 다른 Woodland region을 갖는 특수한 hiding property를 가진다고 함
  • SpawnMasons는 이런 region에 stash를 만들었음
    • 렌더 거리 때문에 보호 region 밖 청크가 로드되지 않도록 구조물을 compact하게 지음
    • decoy 위치에는 AFK 계정과 작은 base를 둬 다른 Randar 사용자가 decoy 위치를 보게 만들려 함
  • 자체 Randar 로그상 이 stash들은 전체 기간 동안 인접 Woodland region을 실수로 로드하지 않은 “clean” 상태였음
  • 공개 시점에는 해당 stash들을 이미 옮겼다고 밝힘

완전한 예제와 버전별 제약

  • SPacketSpawnObject에서 채굴 드롭처럼 보이는 아이템을 감지하고, 드롭 좌표를 세 float 측정값으로 되돌린 뒤, LLL 기반 크랙과 Woodland region 역추적을 수행하는 Java 예제가 제공됨
  • 2b2t 실제 측정값 예시는 다음 결과를 냄
    • item drop: 0.41882818937301636, 0.6833633482456207, 0.46088552474975586
    • RNG measurements: 5664934 14541261 7076144
    • 내부 seed: 95041827771683
    • Woodland region: -12008 0
    • 위치 범위: -15370368,-128부터 -15369089,1151
  • 다이어그램용 예시는 Woodland Region 123,456을 찾음
    • 최종 위치 범위는 157312,583552부터 158591,584831
    • 원래 입력 좌표 x=157440 z=583680을 포함함
  • 1.11 이전 버전은 exploitable structure가 Woodland Mansion이 아니라 다른 구조물이므로 다른 코드가 필요함
  • 1.9 이전에는 아이템 위치가 double이 아니라 fractional part 5비트 fixed-point로 전송돼, 아이템 하나만으로 RNG 상태를 크랙하기는 비현실적이고 다른 측정 전략이 필요함

패치 방법

  • 쉬운 방법은 RNG manipulation을 비활성화하는 패치나 설정을 찾는 것임
  • 취약한 구현은 World.setRandomSeed가 전역 this.rand에 seed를 설정하고 반환함
public Random setRandomSeed(int seedX, int seedY, int seedZ) {
    this.rand.setSeed(seedX * 341873128712L + seedY * 132897987541L + seedZ + this.getWorldInfo().getSeed());
    return this.rand;
}
  • 완전한 보호를 원하면 호출마다 새 Random을 반환하도록 바꿀 수 있음
public Random setRandomSeed(int seedX, int seedY, int seedZ) {
    return new Random(seedX * 341873128712L + seedY * 132897987541L + seedZ + this.getWorldInfo().getSeed());
}
  • 성능이 걱정되면 월드 생성 전용 별도 RNG 필드 separateRandOnlyForWorldGen을 만들고, 다른 용도와 공유하지 않도록 할 수 있음
  • PaperMC 1.12.2용 패치는 PaperWithRandarPatched commit대체 patch 파일로 제공됨

n0pf0x의 부록: 다른 좌표 탐색 방식과 The End

  • n0pf0x는 Mason 측의 GPU 대형 조회 테이블 대신 캐시 기반 좌표 탐색을 사용함
    • hit가 발생하면 해당 좌표와 주변 radius 안 좌표를 HashMap에 넣음
    • 첫 번째 pass는 RNG를 뒤로 되감으며 캐시 hit 또는 직전 처리 seed와의 중복을 빠르게 확인함
    • 두 번째 pass는 첫 번째 pass가 실패할 때만 실행되며, 앞서 설명한 비용이 큰 좌표 찾기 알고리듬을 사용함
  • 이 캐시 방식은 덜 그럴듯한 valid location을 건너뛰는 효과가 있어 false positive 완화에 도움이 될 수 있음
  • The End에서는 청크가 처음 생성될 때만 RNG에 영향을 주므로 Overworld처럼 base 청크 로드를 반복 관측하기 어려움
  • The End에서 의존할 수 있는 상황은 두 가지임
    • base에 있던 플레이어가 돌아다니다 미생성 청크를 생성하는 경우
    • base로 이동하는 플레이어가 이동 경로에 새 청크 trail을 생성하는 경우
  • trail은 자동 식별 시스템을 만들 수 있지만 n0pf0x는 구현하지 않았고, 시각적으로 수동 추적함
  • 플레이어 식별에는 End Occupancy Tracker(EOT) 아이디어를 사용함
    • tick당 RNG 호출 수가 로드된 청크 수와 어느 정도 상관되고, 이는 해당 차원 플레이어 수와 연결된다는 가정에 기반함
    • 플레이어 join/leave 직후 RNG 호출 수가 급증하거나 감소하는지 보고 The End에 있는 플레이어를 추정함
  • EOT는 9b9t에서만 테스트됐고 2b2t 같은 다른 서버 조건에서는 성립하지 않을 수 있음
    • 매 tick 안정적으로 RNG를 샘플링할 수 있어야 함
    • The End의 플레이어 활동량이 훨씬 많으면 더 어려워질 수 있음

댓글과 토론

Hacker News 의견들
  • 1999~2000년에 가위바위보 컴퓨터 봇들이 겨루는 International RoShamBo Programming Competition이 있었음 [1]
    기준 봇은 이론적으로 이길 수 없는 전략인 무작위 선택을 했는데, 장난성 참가작 하나는 난수 생성기의 상태를 역산해 무작위 플레이어가 낼 수를 100% 정확도로 예측하도록 설계됨
    수정: 그 봇은 Tim Dierks의 “Nostradamus”였고, 제1회 대회에서 “supermodified” 부문 우승자로 선언됨 [2]
    [1] https://web.archive.org/web/20180719050311/http://webdocs.cs...
    [2] https://groups.google.com/g/comp.ai.games/c/qvJqOLOg-oc

    • 그게 바로 나였음. 오래전 인용문을 다시 보니 반갑다: “뛰어난 기술력과 ‘일찍, 자주 속여라’ 태도로 Tim은 컴퓨터 게임 업계의 AI 프로그래머로 유망한 커리어를 가질 수 있을 것이다 :)”
      실제로는 보안 분야로 가서 TLS RFC를 작성했고 Google 보안 부문 수석 엔지니어가 됨. 추억을 되살려줘서 고맙다
    • 첫해에 최적으로 나쁜 참가작인 cheesebot을 제출했음
      https://web.archive.org/web/20180719050236/http://webdocs.cs...
    • “supermodified” 부문 참가작 해설 전체가 너무 웃김
      Nostradamus는 암호학 전문성이 높은 Certicom의 엔지니어링 VP Tim Dierks가 작성했고, random() 생성기의 내부 상태를 역공학해 최적 플레이어를 이김. 본인 말로는 “생각보다 쉽기도 하고 어렵기도 했다”고 함. 그래도 스포츠맨십 차원에서 다른 모든 상대에게는 최적으로 플레이함
      Fork Bot은 Dan Egnor가 대회 얘기를 듣고 몇 분 뒤 떠올린 아이디어에서 나왔고, “라이브러리 루틴 허용”을 이용해 fork()로 세 프로세스를 띄운 뒤 각각 다른 수를 내게 하고 진 두 개를 죽이는 방식이었음. Andreas Junghanns가 약 10줄 코드로 구현했지만, 첫 턴 이후 세 수가 모두 Psychic Friends Network에 져서 프로그램이 종료됐고 나머지 경기는 기권 처리됨
      Psychic Friends Network는 Michael Schatz와 RST Corporation 사람들이 작성한 정말 웃긴 난독화 C 코드였고, 좋은 카르마를 찾는 보조 함수, 별자리 상담, 스파게티와 신비한 피자 요리, #define으로 민주당원을 공산주의자로 만들기, 신을 undef하기 등을 함. 스택 프레임으로 정확히 뭘 하는지는 아직 파악 중이지만, 메타-메타-치터를 상대하지 않는 한 한 경기에서 +998 미만을 기록하지 않음
      The Matrix는 “Student for Life”라는 권위 있는 직함을 가진 Darse Billings가 작성했고, “숟가락은 없다”는 단순한 원칙으로 모든 상대를 완벽한 점수로 이김
      The Matrix는 토너먼트 프로그램이기도 해서 다른 모든 알고리즘, 자료구조, 출력 루틴에 완전 접근 가능하므로 앞으로도 추월될 가능성이 낮음. 따라서 이 부문은 해결된 것으로 선언되고 이후 대회에서 폐지됨
    • 투명성을 높이려는 칭찬할 만한 시도로 의사난수 생성기를 문서화해 둔 온라인 포커 사이트에 누군가 같은 일을 했던 기억이 있음
      결국 그 투명성 덕분에 보안이 개선되긴 했음
    • 그럼 의사난수 생성기를 쓰고 있었던 거네?
  • LLL 격자 축소는 며칠 전 CVE에서 편향된 논스로 PuTTY 키를 깨는 데도 쓰인 바로 그 알고리즘임
    tptacek가 공격을 조금 설명했고, 눈을 가늘게 뜨면 거의 이해하는 척할 수 있는 cryptopals 문제도 링크해 둠 https://news.ycombinator.com/item?id=40045377
    비슷하게 SciCraft Minecraft 서버에는 어떤 흑마법 같은 장치로 난수 생성기 상태를 결정적으로 조작해, 매 프레임 특정 블록에 “무작위” 번개가 치게 만들어 크리퍼 드롭을 더 좋게 하는 크리퍼 농장이 있었음 https://youtu.be/TM7SutJyDCk

    • Sean과 Kelby가 LLL이 무엇인지는 훨씬 잘 설명하지만, 왜 LLL이 존재하는지에 대해서는 이 글이 지금까지 본 것 중 최고에 가까움
      세 경우 모두 필요한 건 기초 선형대수 정도이고, 그것조차 많지 않음. Kelby는 그람-슈미트를 이해하길 바라는데, 학부 선형대수 입문 중간고사 직전쯤 나오는 내용임
      이 글이 얼마나 훌륭한지 표현할 말이 없다. 이번 주를 좋게 만들어줌
      나중에 Python으로 따라가 볼 수 있는 같은 과정의 아주 간결한 설명:
      https://crypto.stackexchange.com/questions/37836/problem-wit...
    • 블록이 항상 최대치로 떨어지게 만드는 난수 조작도 있고, 여기서 설명함
      https://youtu.be/ZcdN1wCJPqM?t=390
    • “흑마법 같은 장치”, “눈을 가늘게 뜨면 거의 이해하는 척할 수 있음”은 암호학을 볼 때의 내 모습임 :D
  • 아침에 일어났더니 전날 밤엔 없던 블록들이 하늘에 떠 있고, 처음엔 유령처럼 안개 같다가 곧 레드스톤, 관측기, 슬라임 블록으로 보이며 무한 TNT 낙하가 보이는 상황이 떠오름
    서버가 내 위치를 흘렸다는 이유만으로 그렇게 됨. 그래도 아직 도망칠 수는 있고, 상자에서 챙길 걸 몇 초 안에 꺼내 달아나거나 흑요석 대피소를 지을 시간은 있을지도 모름. 하지만 그게 전부임
    정밀 조준 대포를 만들 시간은 부족하고, 어차피 고도도 못 맞출 것임. 겉날개와 로켓이 있다면 방해하러 갈 수도 있겠지만, 바로 16청크 떨어진 곳에 거대한 월드이터 구멍이 있음. 근처 네더 포털마다 용암 함정을 깔아놨을까?

  • 흥미롭고 웃긴 난수 생성기 문제를 많이 봤지만, 이건 얻는 것에 비해 가장 정교한 익스플로잇 중 하나임. 멋진 예술 작품 같음

    • 아이템을 팔았다면 돈을 좀 벌었을 수도 있음, 아마 수천 달러 수준일지도 모름. 물론 들어간 작업량을 생각하면 여전히 작은 보상임
    • Mojang 개발자들의 겉보기엔 무해한 결정들이 여기서 악용되는 방식이 정말 좋음. 엄청 멋지다
  • 꽤 멋진 익스플로잇임
    버그 악용이 자유로운 서버라는 아이디어도 괜찮고, 게임의 완전히 다른 단계처럼 보임
    메타버스가 실제로 일어난다면, 단순히 게임 내 전투 메커니즘을 쓰는 게 아니라 “진짜로 싸운다”는 게 이런 모습일 것 같음

    • 2b2t 전투도 일반 Minecraft처럼 보이지 않음
      오래전부터 복제된 고가 아이템이 많아서 PvP는 부수면 막대한 피해를 주는 엔더 크리스털을 계속 뿌리는 방식이 됐고, 방어는 치명타 피해를 흡수하는 “불사의 토템”을 얼마나 많이 갖고 있느냐가 됨
      당연히 해킹 클라이언트들은 엔더 크리스털 배치, 토템 재장전, 약한 위치와 강한 위치 식별을 자동화하고, 플레이어는 그 안내를 따라 피해를 계속 넣음
      그보다 조금 전에는 서버에서 패치되기 전까지 즉사시키는 +32,767 피해 해킹 검도 있었음
    • 버그와 익스플로잇을 중심으로 균형이 수렴하는 건, 서버에서 허용하지 않더라도 치열한 PvP 샌드박스 게임에서는 꽤 전형적임
      ARK: Survival Evolved와 Eve Online은 수천 명 규모의 거대 클랜들이 메타게임과 버그 악용에 극단적으로 나서는 것으로 악명 높음
      항상 낭만적이진 않음. ARK에는 플레이어와 그들의 여러 Steam 계정을 신상털이할 수 있는 메커니즘이 있었고, Great War 중 게임 내 관계가 현실로 번진 일도 일부 있었던 것으로 보임
      때로는 아주 기본적인 수법도 있음. 예를 들어 습격당할 때 거대한 탑을 짓고 무너뜨려 서버에 서비스 거부를 일으켜 크래시를 내면, 서버가 10~20분 전 백업으로 롤백되어 활동 중인 플레이어가 있는 기지는 습격하기 매우 어려워졌음. 아주 오래된 수법이고 수년 전에 고쳐짐
      Rust는 버그와 익스플로잇을 YouTube에 퍼뜨리고 공개하도록 장려하는 정책도 있었는데, 목적은 달랐음. 개발자들이 더 빨리 알아차리고 패치하게 하려는 것이었음. 그 결과 실제 외부 핵을 쓰지 않으면 악용하기 매우 어려운 꽤 견고한 게임이 됨
    • 중간 지점으로 Super Smash Bros Melee가 있음. 대회에서 허용되는 많은 게임 내 전술이 버그에 의존함
      다만 일반 컨트롤러로 수동으로 악용할 수 있는 것들만이고, 실제 해킹은 아님. Wobbling이라는 익스플로잇 하나는 2019년에 금지됐는데, 이 게임은 2001년 게임
    • 게임플레이 관점에서는 진짜 무정부 서버라는 아이디어가 꽤 마음에 들었지만, 실제 2b2t에서는 채팅에 n-word가 너무 많이 나와서 그만뒀음
    • “버그 악용이 자유로운 서버”라는 건 사실상 VAC 없는 CS 1.6 서버 전부 아닌가?
  • 이 주제의 영상을 방금 봤음. 무작위성 출처들이 서로 상호작용할 때의 위험을 보여주는 확실한 경고 사례고, 중요한 시스템들에도 많이 적용됨
    성능 때문에 코드에서 난수 생성기를 공유할 때가 많은데, 이런 얘기를 보면 확실히 멈칫하게 됨

    • 진지한 소프트웨어에서 의사난수 생성기를 써본 적은 없는 것 같지만, 직관적으로는 같은 난수 생성기를 최대한 많은 곳에서 쓰면 이런 공격이 더 어려워질 거라고 생각했음
      업데이트되는 지점을 충분히 관찰하기 어려워질 것 같았기 때문임. 그런데 이 사례는 그 직관이 틀렸다는 걸 꽤 인상적이고 재미있게 보여줌
  • 이 영상이 놀라움: https://www.youtube.com/watch?v=maMpMOnIJDE
    커뮤니티가 이렇게 정교한 줄 몰랐음

  • 더 나아가 이런 방식의 난수 생성기 크래킹은 게임 안에서도 구현된 적이 있음
    https://youtu.be/FPmQ0rnJjNc?si=tTFObcfZ-ILanL_A

  • 놀랍게도 Minecraft 자체 안에 만든 기계인 Mess Detector가 있음. 블록 드롭 대신 점화된 TNT의 위치를 이용해 난수 생성기의 내부 상태를 예측함
    https://www.youtube.com/watch?v=FPmQ0rnJjNc

  • 이건 상태 손상 확장 공격처럼 보임 (https://en.wikipedia.org/wiki/Random_number_generator_attack)
    암호학적으로 안전한 의사난수 생성기(CSPRNG)가 아닌 PRNG가 당할 수 있는 공격임
    이제는 라이브러리에서 PRNG를 기본값으로 제공하는 것 자체가 그다지 안전하지 않게 느껴짐. 2024년에 TLSv1.0이나 blowfish를 기본 허용하는 것과 비슷함