2P by GN⁺ | ★ favorite | 댓글 1개
  • Electron 기반 데스크톱 앱인 디스코드는 내부적으로 Chromium 창으로 동작해 웹 개발자 도구를 열 수 있으며, 이를 통해 클라이언트 측 코드 수정이 가능
  • 일부 모드 클라이언트와 플러그인은 Nitro 유료 구독이 필요한 기능 일부를 클라이언트 단에서 해제
  • Webpack code splitting으로 분할된 모듈을 webpackChunkdiscord_app 변수에 주입해 내부 함수를 탐색·교체하는 방식이 핵심
  • 화면 공유 화질 검사 함수는 클라이언트에서만 검증돼 우회 가능하지만, 프리미엄 테마는 서버 동기화 검증이 추가로 작동
  • 데모 기법은 모두 디스코드 이용약관 위반이며 계정 정지 위험과 미검증 코드 실행에 따른 계정 탈취 위험 존재

개요

  • 외형을 변경하거나 기능을 추가하는 모드 디스코드 클라이언트가 다수 존재하며, 일부 플러그인은 Nitro 유료 구독이 필요한 기능까지 해제
  • 이러한 동작이 가능한 기술적 원리를 클라이언트 구조 분석을 통해 설명

개발자 도구 활성화

  • 디스코드는 웹 기술로 크로스플랫폼 앱을 만드는 Electron 프레임워크로 개발되어, 웹 브라우저 안에서 실행되는 웹사이트와 유사
  • 본질적으로 Chromium 창이므로 개발자 도구를 열 수 있으나, 기본적으로 비활성화 상태
    • 다수 사용자가 위협 행위자의 사회공학적 유도로 악성 명령어를 붙여넣어 계정이 탈취된 사례가 있어 차단됨
  • 위험을 이해한 경우 %appdata%/discord/settings.json 설정 파일에 DANGEROUS_ENABLE_DEVTOOLS_ONLY_ENABLE_IF_YOU_KNOW_WHAT_YOURE_DOING 값을 true로 추가해 활성화
    • 이후 ctrl + shift + i로 개발 콘솔 실행

디스코드 함수 패칭

  • 초기 로딩 최적화를 위해 코드가 여러 청크로 분할되어 병렬 또는 지연 로딩(lazy-loaded)되며, Webpack의 code splitting 기능 사용
  • 로드된 모든 청크는 webpackChunkdiscord_app 변수에 저장
  • 디스코드 변수·함수를 사용하는 코드를 실행하려면 이 변수에 코드를 주입(inject) 해야 함
    • a.c는 모든 모듈을 담은 객체이며, 각 모듈은 chunk_id, loaded, exports 형태로 구성
    • exports에는 모듈에서 내보낸 함수·객체·원시값이 포함
  • 여러 JavaScript 모듈을 순회하는 find 함수를 만들어 특정 함수를 탐색하고 호출 가능
    • 예: getCurrentUser() 함수를 찾아 호출
  • 원본 함수를 다른 함수로 교체(replace) 해 동작을 변경할 수 있어, 직접적인 코드 수정이 가능

고화질 스트리밍 해제

  • 이 시점 이후의 내용은 디스코드 이용약관에 명백히 위배되며 계정 정지로 이어질 수 있어 위험을 감수해야 함
  • 사용자의 구독 등급을 확인하는 canStreamMidQuality, canStreamHighQuality 두 함수가 화면 공유 화질 선택 화면 직전에 호출됨
    • 두 함수의 반환값을 true로 강제하면, Nitro 미구독 상태에서도 원본 해상도 60 FPS 화면 공유 선택 가능
  • 현재 디스코드는 전송되는 스트림이 미구독자 기준을 실제로 준수하는지 서버에서 검증하지 않는 것으로 보임
    • 다만 디스코드는 아직 종단간 암호화(End-to-End encryption) 를 사용하지 않아 탐지 가능성 존재
    • 참조 글에 따르면 디스코드는 이미 사용자의 오디오·비디오 콘텐츠를 검사하며, 향후 화면 공유 전 서버 측 검증을 추가할 수 있음

프리미엄 테마 해제

  • 사용자가 Nitro 테마를 사용할 수 있는지를 반환하는 canUseClientThemes 함수의 값을 true로 바꾸면 프리미엄 테마 선택 버튼이 해제됨
  • 그러나 테마가 잠깐 적용된 뒤 곧바로 기본 테마로 되돌아감
    • 클라이언트가 테마 변경을 저장하려 하지만 서버가 권한 없음을 검증하고, 응답 수신 시 기본 테마를 재적용하기 때문
  • 외형 설정 동기화만 차단하도록 shouldSync 함수를 패칭해 appearance 값일 때 false를 반환시키면 테마 변경이 유지됨
  • 테마는 전적으로 클라이언트 측에서 관리되고 CSS를 직접 수정하는 것도 항상 가능해, 디스코드가 이를 막기는 어려움

결론

  • 시연된 해킹을 손쉽게 적용하는 코드가 있으나, 클라이언트 수정이나 모드 사용 전 신중함이 중요
  • 디스코드는 이용약관 위반 계정을 언제든 정지할 수 있으며, 계정 접근 권한을 가진 미검증 코드 실행은 매우 위험
    • 글 내 인코딩된 메시지: "이해하지 못한 코드를 개발 콘솔에 붙여넣지 말 것 — 계정을 탈취당하는 가장 쉬운 방법"

댓글과 토론

Hacker News 의견들
  • 끝에 붙은 단순한 base64 인코딩 blob을 실행하면 모든 기능이 켜지게 만드는 식이면 꽤 쉬운 공격 벡터가 될 수 있지 않나 싶음
    작성자를 의심한다는 뜻은 아니었고, 방금 디코딩해 보니 한 방 먹었음

    • base64 --decode를 돌리기 귀찮은 사람들을 위해 결과를 붙이면 이렇다:
      // Here's a cake if you thought about inspecting the code before executing it:
      let css = 'font-size: 36px; font-weight: bold; color: red';
      console.log("%cNEVER paste code you don't understand into the development console.", css);
      console.log("%cThis is the best way to compromise your account.", css);
  • “현재 Discord는 전송 중인 스트림이 실제로 비구독자 기준을 지키는지 서버에서 검증하지 않는 것으로 보인다”니, 누가 이걸 좋은 구현이라고 생각했는지 궁금함
    클라이언트 측 검증은 정말 초보적인 실수처럼 보임

    • “이건 훌륭한 구현이야”라기보다는 “누가 깨는 법을 알아내면 그때 패치하자”에 가까웠을 듯함
      Discord를 몇 년 쓰면서 Nitro의 접근 권한 구조를 우회하려는 시도 자체를 처음 들어봤고, 널리 퍼진 일이 아니라면 굳이 신경 쓸 이유도 없어 보임
    • 완성된 기능만, 바라던 최종 형태 그대로 구현해서 PR을 올리는 입장이라 왜 그랬는지 전혀 모르겠음
      별개로 이번 달에만 다섯 번째 새 직장을 시작했는데, 프로젝트 매니저들과는 도무지 잘 맞지 않는 듯함
    • 요즘 사람들, 특히 아이들이 돈을 꽤 쉽게 쓰는 걸 생각하면 이 정도로도 충분할 수 있음
      이런 해킹을 이해하고 Nitro에 돈도 낼 의향이 있는 사람이 얼마나 되겠나 싶음. Nitro 기능 일부나 전부를 켜 주는 여러 Discord 클라이언트 모드를 쓰는 사람이 수천, 어쩌면 수만 명은 되겠지만, 이걸 막는다고 실제 매출이 얼마나 생길지는 의문임
      개인적으로는 그 기능이 필요하거나 원한다면 월 10달러를 내는 편이 훨씬 덜 번거로움. Discord 업데이트 때마다 깨질 모드를 계속 따라가고, 유지관리자가 악성 코드를 넣지 않길 바라는 것보다 낫다고 봄
    • API를 통해 숨겨진 채널의 이름, 주제, 마지막 메시지의 시각도 볼 수 있음
      채널은 클라이언트에서만 숨겨져 있음. 분명히 하자면, 그래도 그 채널의 메시지 내용까지 볼 수 있는 것은 아님
    • 이건 Discord API 구성요소가 아니라 전 세계에 수백 대 배포된 음성 서버 쪽이기 때문임
      음성 서버는 입장 권한이 있는지만 API에 확인하고, 그 이후에는 일대다 패킷 브로드캐스터처럼 동작함
  • 이건 호기심 많고 숙련된 의미에서의 고전적인 해커에 가까움
    심각한 피해도 없고, 앱이 마법이 아니며 코드가 멋지다는 걸 다시 떠올리게 해 줌

    • “크래커”에 더 가까울 수도 있지만, 기업들이 우리가 알지 못하길 바라는 종류의 지식이라는 점에는 동의함
      그래야 저항 없이 우리에게서 더 많은 돈을 짜내려 할 수 있으니까
  • 다시 상기하자면 Discord로 보내는 모든 것, DM 포함, Discord에 평문으로 기록되고 Discord 및 그 회사를 사는 주체가 접근할 수 있게 됨
    한때 Microsoft가 살 것처럼 보였고, 지금은 IPO 쪽으로 가는 듯함
    계정이 있다는 것만으로도 AI용 데이터 마이닝이나 Discord 및 데이터베이스/시스템 관리자의 이용이 쉬운 개인 대화가 정상화됨. FISA Amendments Act의 Section 702(FAA702)는 연방 수사기관이 영장 없이도 그런 데이터에 접근할 수 있게 함
    암호화폐 선행매매 가능성만 해도 하루 수천만 달러 가치는 될 듯함
    친구라면 친구에게 종단 간 암호화가 아닌 채팅 시스템을 쓰라고 권하지 말아야 함. 덫 속의 꿀이 되지 말자

    • 다시 상기하자면 포럼으로 보내는 모든 것, DM 포함, 평문으로 기록되고 관리자에게 접근 가능함
      사용자가 직접 키를 관리하는 진짜 제로 트러스트 모델을 구현한 몇 안 되는 서비스를 쓰는 게 아니라면 당연한 일임. 메시지를 저장하는 이유는 사용자가 다시 접근할 수 있게 하기 위해서임
      Matrix처럼 비교적 친화적인 방식으로 종단 간 암호화 그룹 메시징을 해내는 서비스도 있지만 예외에 가깝다. 전자 통신 플랫폼의 95%가 해 온 방식과 같다고 해서 Discord만 특별히 악의적이라고 몰아가는 건 공정하지 않음
    • “계정이 있다는 것만으로 정상화된다”지만, 이미 오래전에 정상화됐고 Discord는 이겼음
      좋다는 뜻은 아니지만, 어떤 커뮤니티에서는 참여하지 않는 것 말고 선택지가 없음
      예전의 “모두가 WhatsApp을 쓴다”보다도 더 나쁨. 그때는 상대의 번호가 있어서 다른 방식으로 연락하기 쉬웠지만, Discord의 매력은 개인 대화가 아니라 반공개 공간을 가진 커뮤니티임. 여기서 공개란 모두에게 열린다는 뜻이 아니라 100명쯤 읽는다는 의미에 가까움
    • 다행히 Discord에는 흔적 없는 메시지 삭제가 있음
      메시지를 지우면 더 이상 데이터베이스에 저장되지 않음
  • 최근 OpenAI가 베타 테스터용 Discord를 갑자기 비활성화해서, 우리가 누구와 무엇을 논의했는지 더 이상 볼 수 없게 됨
    서버 관리자가 기록을 훑어볼 방법도 남기지 않고 커뮤니티를 서로 끊어 버리지 못하게 채팅을 내보내는 방법이 있나 궁금했음
    Discord 채팅을 내보내는 Chrome 확장 프로그램은 꽤 있지만, 대부분 일부 기능을 유료로 잠가 둔 듯함
    알고 보니 Chrome 폴더에서 확장 소스를 복사해 is_pro 같은 불리언 검사를 JavaScript에서 수정한 뒤 압축 해제 확장으로 다시 로드하는 게 아주 쉬웠음

  • 이런 트릭을 쓰면 차단당할 수 있다고 올바르게 경고하긴 하는데, Discord가 이런 일로 사용자를 차단한 전례가 있나?

    • Discord는 뭐든 이유로 사람을 차단하는 데 거리낌이 없음
      대체 클라이언트를 쓰는 것도 막음. 계정이 중요하다면 Discord를 건드리지 않는 게 좋음
    • 가장 인기 있는 모드 중 하나인 Vencord의 README에는 이렇게 적혀 있음:
      “클라이언트 수정은 Discord 이용약관에 위배됩니다.”
      다만 Discord는 이에 꽤 무관심하고, 클라이언트 모드를 썼다는 이유로 차단된 알려진 사례는 없음. 그러니 남용 행위를 구현한 플러그인만 쓰지 않는다면 대체로 괜찮을 것임. 걱정하지 않아도 되는 게, 내장 플러그인은 모두 안전하다고 함
  • 일부 테마가 이런 식으로 켜지는 건 이해하겠지만, 스트리밍 품질을 서버 측이 아니라 클라이언트 측 검사로 결정하게 한 건 꽤 이해하기 어려움

    • 특히 입출력 비트레이트만 확인해도 되기 때문에 더 그렇음
      실제 영상에 접근할 필요도 없고, 완전히 암호화되어 있어도 전송 데이터량을 보면 어떤 품질로 스트리밍 중인지 알 수 있음
  • 프론트엔드 엔지니어링의 대원칙이 또다시 맞아떨어짐
    “절대로, 절대로 클라이언트를 믿지 말라”

  • 클라이언트 측에서만 처리할 수 있다는 걸 본 뒤로 계속 개발자 도구와 1080p60 스트리밍 버튼을 켜서 써 왔고, 실제로 동작함
    몇 년째인지는 모르겠지만 Discord 쪽에서는 아무도 신경 쓰지 않는 듯함

  • 예전에 이 길을 가 보려 했지만, 특히 업데이트 이후 클라이언트를 일관되게 패치하는 방법을 못 찾아서 결국 포기했음
    그런데 이 방법을 보니 다시 “까서 찔러보고 싶다”는 충동이 생김
    이 방식으로 사용 가능한 API를 훑어볼 간단한 방법이 있을까? 전부 로깅해 보려 했지만 맵, 국제화 등으로 너무 난장판이었음. 누가 고생해서 역공학 문서 같은 걸 만들어 뒀는지 궁금함