
CVE2021-38297 GO WASM buffer-overflow의 익스플로잇을 위한 개념 증명 시나리오
WebAssembly (WASM)는 대부분의 최신 웹 브라우저에서 실행 가능한 바이너리 명령어 형식입니다. 이는 C, C++, Rust, GO와 같은 다양한 고급 언어를 위한 컴파일 대상으로 작동하며, 이러한 언어로 작성된 코드를 WASM으로 컴파일할 수 있게 해줍니다.
CVE-2021-38297은 GO가 컴파일하고 로드하는 GO 컴파일 WASM 바이너리 내의 심각한 버그를 강조합니다. 이 취약점은 GO가 제공하는 JS wasm 로더(wasm_exec.js)에 존재하며, argv 인수에 제한 없는 데이터를 사용하여 WASM 바이너리를 로드할 수 있게 합니다. argv는 WASM의 선형 메모리에 저장되므로, 악의적인 공격자는 이를 이용해 지나치게 큰 argv 입력으로 GO 컴파일 WASM 프로그램의 선형 메모리를 덮어쓸 수 있습니다.
이 취약점은 GO 버전 1.17.2 이전에 존재했습니다.
이 개념 증명은 여러 사용자가 게시물과 댓글을 게시할 수 있는 소셜 미디어 애플리케이션인 Vuln-Twitter를 보여줍니다. Node.js 기반의 웹 서버는 SQLite를 사용하여 게시물과 댓글 데이터를 저장합니다.
프론트엔드는 일반 JS와 wordprocessor.wasm이라는 GO WASM 모듈을 사용합니다. 이 모듈은 toLeetSpeak와 같은 메서드를 노출하며, 입력 문자열을 "LeetSpeak"으로 변환합니다 (예: "Hello!" → "h3ll0!").
GO WASM 모듈은 게시물과 댓글을 LeetSpeak으로 렌더링하는 데 도움을 줍니다.

프론트엔드 렌더링 과정에서 서버로부터 게시물과 댓글을 받을 때, 각 댓글은 GO WASM 모듈을 사용하여 "LeetSpeak"으로 렌더링됩니다. 각 게시물의 댓글은 GO WASM 모듈을 로드한 후 argv 변수의 일부로 전달됩니다.
또한 GO 모듈에는 processSharedVar()라는 메서드가 있으며, 주소 0x5000에 있는 문자열을 읽어 간략화된 문장으로 변환합니다 (예: "How are you?" → "How r u?"). 원본 게시물은 이 메서드가 접근할 수 있도록 선형 메모리의 0x5000에 명시적으로 추가되어 게시물 내용을 변경합니다.
이를 수행하는 코드 섹션을 참조하십시오:

댓글 렌더링 시 WASM 선형 메모리 다이어그램:

요약하자면:
argv 변수를 통해 댓글을 처리하고 메모리 주소 0x5000에 있는 게시물을 처리합니다.toLeetSpeak 및 processSharedVar와 같은 함수가 각각 댓글 및 게시물 내용에 사용됩니다.CVE-2021-38297에 기반한 argv의 크기 검사 부재를 고려할 때 잠재적인 위협이 발생합니다. 악성 사용자가 자신이 소유하지 않은 게시물에 과도하게 큰 댓글을 달면, 이 댓글은 렌더링 중 argv를 통해 전달됩니다. 크기 제한이 없기 때문에 주소 0x5000에 있는 내용(원본 게시물)이 덮어쓰여질 수 있습니다.
이 결함을 악용하여 악성 사용자는 저장형 XSS 공격처럼 원본 게시물 내용을 효과적으로 변경합니다. 이후 다른 사용자가 해당 페이지를 볼 때 변경된 내용이 표시되며, 공유된 프론트엔드 로직이 모든 사용자에게 동일하게 적용되므로 덮어쓰여진 게시물이 모두에게 보여집니다.

참고: 재현을 위해 로컬에 Go 버전 go1.17.1(이 시나리오에서 사용된 취약한 버전)을 설치해야 합니다. 특정 Go 버전 설치 방법은 공식 Go 문서를 참조하십시오.
이제 위 시나리오를 재현해 보겠습니다:
git clone [email protected]:gkrishnan724/CVE-2021-38297.git && cd vuln-twitternpm install을 실행하여 모든 종속성을 설치합니다.npm run resetDB를 실행하면 데이터베이스가 몇 개의 게시물과 댓글로 초기화됩니다.npm run dev를 실행하면 로컬 서버가 시작되며, 브라우저에서 localhost:3000을 열면 로그인 페이지가 보여야 합니다.이제 악성 계정으로 로그인합니다. 사용자 이름: I_CANT_HACK, 비밀번호: hacker를 사용하여 로그인하면 몇 개의 게시물이 있는 피드가 보여야 합니다.
이 게시물이 꽤 흥미로워 보입니다:
Amazon: ready 4 black friday? https://www.amazon.com/blackfriday
위 기법을 사용하여 Amazon.com의 게시물을 악성 링크를 가리키도록 덮어쓸 수 있다면 어떨까요?
exploit.txt 파일을 참조하십시오. 이 파일에는 주소 0x5000까지 모든 것을 덮어쓰기 위해 "A"로 채워진 패딩이 포함된 댓글이 들어 있습니다. 끝 부분에 ready for black friday? https://evil.com/blackfriday 텍스트가 보입니다. 이 텍스트를 복사하여 위 게시물에 댓글로 달면 원본 게시물을 해당 텍스트로 덮어쓸 수 있습니다.
직접 시도해 보세요 :)

이 애플리케이션에는 패치 스크립트도 제공했습니다. 최신 Go 버전을 사용합니다:
npm run patchServer 타겟을 실행합니다.이렇게 하면 새로운 버전으로 Go 파일을 다시 컴파일하고 패치 버전으로 서버를 시작합니다.
이제 게시물이 더 이상 덮어쓰여지지 않는 것을 확인할 수 있으며, 콘솔을 보면 대신 Argument length too long 오류가 표시됩니다.

선형 메모리의 WASM 버퍼 오버플로우를 활용하여 저장형 XSS 공격을 실행할 수 있는 시나리오를 시연했습니다. 그러나 이 악용의 특수성을 주목해야 합니다: 선형 메모리의 하드코딩된 주소에 있는 텍스트를 조작해야 했습니다. 실제 웹 애플리케이션에서 이러한 취약점을 발견하는 것은 이러한 특수성 때문에 극도로 어려울 수 있습니다. 게다가 GO의 내부 모듈 및 데이터를 다룰 때 시스템 충돌 없이 선형 메모리의 임의 데이터를 덮어쓰는 것은 복잡하며, 이는 대부분 GO의 메모리 레이아웃에 대한 포괄적인 문서 부족 때문입니다.
우리의 이해에 따르면 GO 선형 메모리 레이아웃은 아래와 같다고 생각합니다:

이러한 악용은 웹 개발에서 특히 WASM 내에서 흥미로운 공격 벡터를 도입하지만, 프로그래밍 언어와 관련된 고유한 보안 위험도 함께 가져옵니다. 예를 들어, C 프로그램이 WASM으로 컴파일되는 경우를 생각해 보십시오. 원본 C 프로그램에 오버플로우나 취약점이 있다면 이러한 위험은 WASM 환경으로 전이되어 유사한 취약점과 위협에 노출됩니다.
우리는 Carnegie Mellon University의 학생이며, 한 수업(18-739D Hacking101)에서 이 CVE 개념 증명을 발표했습니다. 슬라이드 덱은 여기에서 확인할 수 있습니다: GOWasm.pptx