Skip to content
KitploitKITPLOIT
도구블로그
제출
도구블로그
제출

해킹, 침투 테스트 및 사이버 보안 도구를 당신의 보안 무기고에!

Kitploit은 해킹, 사이버 보안 및 침투 테스트 도구 디렉토리입니다. 최신 프로젝트 업데이트를 발견하여 취약점을 찾고, 시스템을 분석하고, 테스트를 자동화하고, 보안을 강화하세요.

··피드·문의·개인정보·© 2026 Kitploit

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
도구/GitHubGitHub/farazsth98/freebsd-dirent-info-leak-bugs
Memory ForensicsVulnerability AnalysisExploitationInformation GatheringBinary Analysis
GitHubfarazsth98/freebsd-dirent-info-leak-bugs

freebsd-dirent-info-leak-bugs

CVE-2020-25578 및 CVE-2020-25579: 2020년에 제가 발견한 일부 FreeBSD 정보 유출 버그입니다.

저장소 보기

인기

모두 보기 →

커뮤니티에서 가장 많이 사용되는 도구를 찾아보세요.

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
공유
7225년 전아직 검토되지 않음

어떻게 버그를 찾았는가?

  1. 무작위로 FreeBSD의 파일 시스템을 감사하기로 결정
  2. 조사 결과 기본 파일 시스템이 FFS와 UFS의 조합임을 발견
  3. ufs_create를 감사하는 데 시간을 투자했지만 버그 0개 발견
  4. 여기로 가서 UFS 파일 시스템 함수의 커밋 기록을 살펴봄
  5. 스택에 할당된 struct dirent 객체의 패딩 바이트를 통해 정보가 유출되는 이 커밋 발견
  6. 패치를 분석한 결과 msdosfs_readdir에 대한 패치가 불완전함을 발견. 한 인스턴스의 버그는 패치했지만 두 번째는 패치하지 않음.
  7. PoC를 작성하여 패딩에서 3바이트를 유출할 수 있음을 확인. 그런 다음 변형을 찾기 시작.
  8. mqueuefs, autofs, smbfs, tmpfs에서 전체 8바이트 포인터를 유출할 수 있는 변형을 발견. PoC 작성 및 확인.

원본 버그

위에서 언급했듯이, 원래 발견한 버그는 위 링크의 패치를 분석하던 중 msdosfs_readdir에서 발견했습니다.

FreeBSD에서 readdir을 호출하는 기본 흐름은 다음과 같습니다:

root@kitploit:~
#include <dirent.h>

int main(void) {
    struct dirent *dp;
    DIR *dirp;

    dirp = opendir("./somedir");
    dp = readdir(dirp);
}

somedir이 위치한 파일 시스템에 따라 FreeBSD 커널의 여러 *_readdir 함수 중 하나가 호출될 수 있습니다.

위 패치는 dirent_terminate라는 함수를 추가하여, struct dirent 객체가 사용자 공간으로 반환되기 전(주로 uiomove 함수를 사용하여 수행)에 패딩 바이트와 구조체의 d_name 필드에 남은 바이트를 0으로 설정합니다. struct dirent의 정의는 여기 있습니다.

패치를 보면, 1562번째 줄에서 dirbuf 변수를 인자로 dirent_terminate가 호출되는 것을 볼 수 있습니다. 이후 uiomove가 호출되어 dirbuf의 내용을 사용자 공간으로 복사합니다. 그러나 이 코드 줄들은 이 if 문 블록 안에 있습니다. 이 if 문 위의 주석은 이 분기가 MSDOS 파일 시스템의 루트에서 readdir이 호출될 때만 실행된다고 설명하므로, 파일 시스템의 루트가 아닌 하위 디렉터리에서 readdir을 호출하면 이 if 문을 간단히 건너뛸 수 있습니다.

더 아래로 내려가면, 1691번째 줄에서 uiomove에 대한 또 다른 호출이 있습니다. 하지만 코드를 자세히 읽어보면 이 인스턴스에서는 dirent_terminate가 호출되지 않으며, 이는 패딩 바이트가 초기화되지 않은 상태로 남는다는 것을 의미합니다. 불행히도 d_name 필드는 이 함수의 시작 부분(여기)에서 0으로 설정되었기 때문에 더 큰 유출은 얻을 수 없습니다.

PoC

먼저 USB 드라이브가 없었기 때문에 MSDOS 파일 시스템을 마운트할 방법을 찾아야 했습니다. 다음이 작동합니다:

root@kitploit:~
$ dd if=/dev/zero of=test.img bs=512 count=256000
$ sudo mdconfig -a -t vnode -f test.img
$ sudo newfs_msdos -s 131072000 /dev/md1 # My mdconfig returned md1
$ mkdir ./temp
$ sudo mount -t msdosfs /dev/md1 ./temp
$ mkdir ./temp/test_dir

PoC는 original_poc.c에서 찾을 수 있습니다. clang으로 컴파일한 후 위 명령어와 동일한 디렉터리에서 실행하면 유출된 바이트가 출력되는 것을 볼 수 있습니다.

변형

이 버그의 변형을 찾기 시작했습니다. uiomove\(&.*,를 grep한 것 같으며 약 15-20개의 결과가 나왔고, 모두 수동으로 확인했습니다. 불행히도 변형 중 어느 것도 FreeBSD에 기본적으로 존재하지 않습니다(파일 시스템을 수동으로 활성화하거나 커널에 컴파일해야 합니다). 변형이 있는 함수는 다음과 같습니다:

  1. mqfs_readdir
  2. tmpfs_dir_getdotdent
  3. tmpfs_dir_getdotdotdent
  4. smbfs_readvdir
  5. autofs_readdir_one

이 모든 함수에서 버그는 정확히 동일하므로, mqfs_readdir만 다루겠습니다.

  1. 먼저, 스택에 struct dirent entry가 할당됩니다.
  2. 다음으로, dirent_terminate가 호출되어 구조체의 패딩 + d_name 필드를 0으로 설정합니다.
  3. 마지막으로, vfs_read_dirent가 호출됩니다. 이 함수는 uiomove를 호출하여 구조체를 사용자 공간으로 복사합니다.

지금까지는 모든 것이 괜찮아 보이죠? 꼭 그렇지만은 않습니다. 구조체의 모든 필드가 초기화되었는지 확인해야 합니다. 코드를 자세히 보면 d_off 필드가 초기화되지 않은 채 남아 있음을 알 수 있습니다. 이 필드의 타입은 off_t이며, 본질적으로 int64_t입니다. 구조체가 사용자 공간으로 복사될 때 이 필드에서 초기화되지 않은 데이터를 얻게 됩니다.

PoC

이 PoC는 모든 변형에 대해 동일하게 작동하며, 다른 파일 시스템에서 실행하기만 하면 됩니다. mqueuefs의 경우 다음을 수행합니다(먼저 mqueuefs를 활성화하거나 커널에 컴파일해야 함):

root@kitploit:~
$ mkdir ./temp
$ sudo mount -t mqueuefs null ./temp

PoC 자체는 variants_poc.c에서 찾을 수 있습니다. clang으로 컴파일한 후 위 명령어와 동일한 디렉터리에서 실행하면 커널 포인터가 출력되는 것을 볼 수 있습니다(아마도 스택 포인터 하나와 코드 섹션/힙 포인터 하나일 것입니다. 확인하지 않았습니다).

도구 다운로드