
Linux, Windows, macOS에서의 파일 알림 부채널 공격에 대한 연구 자료로, inotify/FSEvents 누출, 키 입력 타이밍, 웹사이트 핑거프린팅을 시연합니다.
이 저장소는 CCS '26에 채택된 논문 "File Notification Attacks: Templating and Exploiting Side-Channel Leakage from the File-Notification Systems on Linux, Windows, and macOS"의 (아직 심사 중인!) 아티팩트를 포함하고 있습니다.
데모가 있는 웹사이트를 방문하세요: https://inoti.fyi/
논문 읽기: https://snee.la/pdf/pubs/file-notification-attacks.pdf 또는 http://inoti.fyi/pubs/file-notification-attacks.pdf
CCS'26의 아티팩트 평가 (아직 진행 중!)의 일환으로, 우리는 사전 패치된 커널이 포함된 Debian 13 + KDE Plasma 6 VM을 제공했습니다. 이 VM은 논문의 평가 결과를 산출하는 데 사용되지 않았으며, 그 정확한 규모를 재현하기 위한 것도 아닙니다. 이 저장소는 아티팩트 평가자들의 리뷰와 피드백을 반영하여 업데이트될 수 있습니다. 아티팩트 평가가 완료되면 VM을 공개적으로 접근 가능하게 만들 것입니다.
우리는 코드를 적절히 잘 문서화되고 고성능인 아티팩트로 감싸기 위해 Claude (Opus 4.8)를 사용했습니다 (예를 들어, Windows용은 약간 느렸습니다). 그러나 그것이 생성한 코드, 스크립트, makefile은 다음을 기반으로 했습니다
아래의 Linux 코드 테스트 지침은 VM에서 명령을 실행하는 것에 특화되어 있습니다. 대신
Linux/에 있는 코드를 살펴보세요.
VM은 순전히 편의를 위해 존재하며, 각 공격을 마운트할 때 처음부터 환경을 설정하거나 커널을 다운그레이드할 필요가 없도록 합니다. VM에서 시연되는 기본 메커니즘은 논문에서 설명된 것과 동일하지만, 우리가 논문에 보고된 수치를 산출하기 위해 VM을 사용하지 않았다는 점에 유의하시기 바랍니다. 절대적인 타이밍은 가상화 환경과 기반 하드웨어로 인해 다를 수 있습니다.
결과는 Debian 13 VM (linux-vm/) 내에서 재현되며, 공식 라이브 Debian ISO에서 KDE Plasma 6
(Wayland)와 함께 설치되었고, fsnotify
수정 이전의
커널을 사용합니다. inotify-tools, Qt6 개발 헤더, pkexec가 설치되어 있습니다. 그 외에는
아무것도 업그레이드되지 않으며, 설치 후 커널은 절대 건드리지 않습니다. 절대 apt upgrade를
실행하거나 커널을 업그레이드하려고 시도하지 마세요. 이 VM 이미지는 의도적으로 오래되었고,
최신 상태가 아니며, 최신 보안 패치가 없습니다. 이 VM 이미지는 빠른 검증과 테스트만을 위한
것입니다!
VM 내에 위치한 코드, 공격, 데모는 Linux/에 미러링되어 있습니다.
참고: 각 명령 블록 상단에 명령을 실행할 사용자를 명시합니다. VM을 실행하는 호스트
머신인 [host], VM 내 공격의 피해자인 [user], 설정이 필요하며 대부분의 Linux 공격에서
공격자가 될 [spyuser]가 있습니다.
디스크 이미지는 linux-vm-upload.qcow2로 제공되며, zstd로 압축되어 있습니다. run.sh를
실행하기 전에 linux-vm.qcow2로 이름을 바꾸세요 (해당 파일명을 기대합니다):
# Run As: [host]
cd linux-vm/
mv linux-vm-upload.qcow2 linux-vm.qcow2
./run.sh
zstd로 압축된 qcow2를 읽으려면 qemu-img/qemu-system-x86_64 버전 5.2 이상 (2020년 이후)이
필요합니다. qemu-img --version으로 확인하세요. 구버전 QEMU를 사용 중이고 이미지를 열지
못한다면, 먼저 플랫 qcow2로 압축을 해제하세요:
qemu-img convert -O qcow2 linux-vm-upload.qcow2 linux-vm.qcow2
4 코어, 4GB RAM, GUI 디스플레이. 로그인 정보:
root, 비밀번호 password,user, 비밀번호 password,spyuser, 비밀번호 password (spyuser로 로그인하지 마세요!)제공된 VM은 이미 취약한 사전 패치된 커널 (6.12.43+deb13-amd64)을 실행하므로, 사용하기 위해
다운그레이드할 필요가 없습니다. 이 이미지 (GUI 포함)를 실행하려면 QEMU가 필요합니다.
아티팩트는 VM 내 /home/user/Linux-File-Notification-Attacks에 있습니다.
하나의 명령으로 VM에서 처음부터 설정합니다: (i) 비특권 spyuser 계정 (비-sudo), (ii) 자체
아티팩트 디렉터리 사본 (별도의 비특권 계정은 그렇지 않으면 user의 홈 디렉터리로 들어갈 수
없습니다), (iii) 두 사본 모두에서 모든 스크립트를 실행 가능하게 만듭니다.
# In the VM, Run As: [user]
sudo bash ~/Linux-File-Notification-Attacks/setup_attacks.sh
아래의 모든 공격은 spyuser로 실행됩니다 (su - spyuser, 비밀번호 password), 단
auth-ui-redress는 user로 실행됩니다 (아래에서 설명).
부모 디렉터리를 읽을 수 있는 한, 직접 읽을 수 없는 파일에 대해서도 파일 작업 알림이 전달됨을 증명합니다.
# Run As: [spyuser]
# To switch to spyuser, in a new terminal type `su - spyuser`. The password
# is `password`.
cd ~/Linux-File-Notification-Attacks/unreadable-file-bypass
./watch-syslog.sh
실행 상태로 두고, 다른 터미널에서 user로 로그 줄을 생성하세요:
# Run As: [user]
logger "hello"
이 Debian 13 이미지에는 rsyslog가 없으므로, 논문에 나온 것처럼 /var/log/syslog 파일이
없습니다. 스크립트는 대신 /var/log/journal/<machine-id>/를 감시하는 것으로 대체합니다.
이는 동일한 아이디어인데, 감시되는 .journal 파일들이 root (사용자)와 systemd-journal
(그룹) 소유이며, 둘 다 spyuser가 아니기 때문입니다.
inotify의 알림 지연을 측정합니다.
# Run As: [user], ensure numpy is installed (or pip3)
sudo apt install python3-numpy
# Run As: [spyuser]
cd ~/Linux-File-Notification-Attacks/temporal-resolution
./run.sh
watcher는 테스트 파일에 inotify 감시를 열고 수신하는 모든 IN_ACCESS에 타임스탬프를
기록합니다. accessor는 동일한 파일을 읽기 사이에 무작위 5-10ms 지연을 두고 1000번 읽으며,
각 읽기에 자체적으로 타임스탬프를 기록합니다. stats.py는 두 타임스탬프 기록을 비교하여
읽기가 발생한 시점과 알림이 도착한 시점 사이의 평균/표준편차/최소 지연, 즉 inotify의 시간
해상도를 출력합니다.
논문의 전체 공격은 아니고, 공격이 기반으로 하는 필터링 개념 증명 프리미티브일 뿐입니다:
시스템 어디에서든 눌린 모든 키에 대해, /dev/input을 직접 읽지 않고 타임스탬프가 찍힌
알림 하나를 출력합니다.
# Run As: [spyuser]
cd ~/Linux-File-Notification-Attacks/inter-keystroke-timing
make
./find-keyboard.sh
아무 창에서나 입력하세요 (아마도 user로 새 터미널). 각 키 입력은 하나의 KEYPRESS 줄을
출력합니다. 억제 윈도우 (이 데모를 위해 우리가 휴리스틱하게 선택한 130ms)는 단일 물리적 키
누름에 의해 생성된 여러 IN_ACCESS 이벤트를 병합합니다. 실제로 우리는 이 윈도우가 하드웨어마다
(예: 기계식 키보드, 타이핑 스타일) 다르다는 것을 관찰했습니다.
자동 감지가 잘못된 장치 (또는 아무것도)를 선택하면, /proc/bus/input/devices를 확인하고
./build/keystroke-notify /dev/input event4로 직접 실행하세요.
우리는 (pkexec)[https://polkit.pages.freedesktop.org/polkit/]가 실행되는 시점을 감지하고,
그 위에 가짜 창을 그릴 수 있음을 시연합니다. 섹션 4.4.3에서 보여준 것처럼, 이 '인증 UI
리드레스 공격'은 Wayland를 사용하는 KDE Plasma 5 및 6에서 가능합니다. 우리는 이 공격을
동일 사용자 공격자 위협 모델에서 실행합니다: Wayland 소켓은 로그인 세션에 범위가 지정되며,
별도의 비특권 계정은 그 위에 그릴 수 없습니다.
기본 KDE 설치에서는 pkexec가 데스크톱에 의해 끌어와지지만, 이 라이브 ISO는 더 간소한
이미지이므로 설치되어 있지 않습니다. 따라서 우리는 VM 이미지를 작게 유지하려고 (노력하면서)
수동으로 설치했습니다.
# Run As: [user]
cd ~/Linux-File-Notification-Attacks/auth-ui-redress
make
./inotify-watcher-with-gui
터미널에서 실행 상태로 두세요. 다른 터미널에서 (디렉터리는 상관없음) 실제 pkexec 프롬프트를
트리거하세요, 예: pkexec ls. 감시자는 /usr/bin/pkexec에 대한 접근을 보고 가짜
"Authentication Required" 대화상자 (window-launcher)를 실제 대화상자 위에 화면에 그립니다.
가짜 대화상자에 입력하고 Authenticate를 누르면 입력한 텍스트가 감시자의 터미널에 출력된 후
창이 닫힙니다. 가짜 창은 쉽게 비교할 수 있도록 실제 창과 의도적으로 다르다는 점에
유의하세요.
페이지가 로드되는 동안 폰트 디렉터리를 감시하면 어떤 폰트 파일을 건드렸는지 드러납니다. 사이트마다 다른 폰트를 끌어오므로, 페이지가 로드되는 동안 출력되는 경로 집합은 그 자체로 핑거프린트이며, 이 최소 버전에는 타이밍이나 분류기가 필요하지 않습니다.
먼저, 사용자로서 Firefox를 열고 (화면 하단의 작업 관리자 독에 있는 아이콘을 클릭), 열려 있는
웹사이트가 없는지 확인하세요. 그런 다음, spyuser로서 터미널에서:
# Run As: [spyuser]
cd ~/Linux-File-Notification-Attacks/website-fingerprinting-fonts
./compare-fonts.sh
이것은 Firefox가 사용하는 폰트 디렉터리 모니터링을 시작하는 font-spy를 빌드합니다.
compare-fonts 스크립트는 두 개의 웹사이트를 방문하라고 안내합니다.
먼저, 한 웹사이트 (아마도 wikipedia.com)를 방문하고 로드될 때까지 몇 초 기다린 후, 새 탭을 열고, (웹사이트가 있는) 이전 탭을 닫은 다음, 터미널에서 ENTER를 누르세요.
둘째, 다른 웹사이트 (아마도 reddit.com)로 동일하게 하세요: 웹사이트를 방문하고 로드될 때까지 몇 초 기다린 후, 새 탭을 열고, 이전 탭을 닫은 다음, 터미널에서 ENTER를 누르세요.
스크립트는 웹사이트별로 접근된 폰트의 차이를 출력해야 합니다. 논문에서는 우리가 시간 정보, 즉 폰트가 언제 접근되었는지도 사용했다는 점에 유의하세요. 간단한 개념 증명을 위해 우리는 이 정보를 무시하고 단순히 두 폰트 접근 집합 간의 차이를 출력합니다. 정확한 폰트 접근 집합은 실행마다 다를 수 있지만, 웹사이트에 의해 항상 그리고 고유하게 접근되는 특정 폰트 파일들이 있습니다.
웹사이트는 시간이 지남에 따라 변경될 수 있으므로, 폰트 파일 접근이 다를 수 있다는 점에
유의하세요. 이 아티팩트를 작성할 당시, 우리는 Wikipedia가 항상
/usr/share/fonts/truetype/liberation/LiberationSans-Bold.ttf에 접근하고 Reddit이 항상
/usr/share/fonts/truetype/vlgothic/VL-Gothic-Regular.ttf에 접근한다는 것을 관찰했습니다.
Scoped Storage 모델이 여전히 WhatsApp의 공유 미디어 디렉터리에 FileObserver (inotify의
Java 수준 래퍼)를 등록하는 것을 허용하는 Android 버전을 실행하는 물리적 장치 또는 에뮬레이터,
그리고 메시지 발신자 역할을 할 두 번째 장치/계정. 제공된 소스 (Android/source/)를
빌드하거나 제공된 APK (Android/app-release.apk)를 직접 설치하세요.
Android는 Linux 결과 전반에 사용된 것과 동일한 inotify 프리미티브를
android.os.FileObserver를 통해 노출합니다. 섹션 5.4.3은 비특권의 권한 없는 앱이 WhatsApp의
미디어 디렉터리에 그러한 옵저버를 등록하고, 결과적인 open/close/access 이벤트 스트림만으로
콘텐츠 자체를 읽을 수 있게 해주는 어떤 권한도 보유하지 않고 사적인 미디어가 수신되었음을
추론할 수 있음을 보여줍니다.
앱을 실행하고 새로 고침 동작을 트리거하세요; 옵저버 서비스가 연결되고 주기적인 활성 상태
항목을 내보내기 시작합니다. 로그 뷰의 하단으로 스크롤하고 반복적인 ObserverService: Still Running 항목이 나타날 때까지 계속 새로 고침하여 감시가 활성화되고 안정적임을 확인하세요.
두 번째 계정에서, 감시 중인 대화로 이미지나 문서를 보내고, 아직 캐시되지 않았다면 감시 중인
장치에서 다운로드하세요. 이것은 파일 이벤트 로그 줄의 폭주를 생성합니다; 폭주 직전의 마지막
ObserverService: Still Running 항목 바로 뒤에, 로그는 수신된 파일에 해당하는 경로의
open/close/access 이벤트를 보여주어야 하며, 이는 파일 시스템 알림 메타데이터만으로 그 도착이
관찰 가능함을 보여줍니다.
우리는 msys2로 컴파일할 수 있는 소스 코드를 제공합니다. 그렇지 않으면 exe 파일 (Windows/firefox-fingerprint/monitor.exe)도 사용할 수 있습니다.
MSYS2가 설치된 Windows 머신 (또는 VM), 그리고 MinGW-w64 g++
툴체인 (MSYS2 셸에서 pacman -S mingw-w64-ucrt-x86_64-gcc 실행). Firefox 설치.
이 개념 증명은
ReadDirectoryChangesW를
사용하여 C:\ 전체를 재귀적으로 감시하고, 경로에 http가 포함된 이벤트만 출력합니다
(Firefox가 사이트의 스킴/호스트 이름을 따서 명명하는 출처별 저장 디렉터리, 예: 캐시/IndexedDB
폴더 아래). 나열할 수 있는 디렉터리를 감시하는 데 관리자 권한은 필요하지 않습니다. 이 출처별
저장소는 모든 페이지 로드 시 기록되므로, 브라우저 프로세스 외부에서 감시해도 방금 방문한
사이트가 드러납니다.
우리가 제공하는 exe (Windows/firefox-fingerprint/monitor.exe)를 사용하거나 MSYS2 UCRT64 셸에서 컴파일하세요:
# Run in an MSYS2 UCRT64 shell
cd Windows/firefox-fingerprint
g++ -municode -static -O2 -o monitor.exe monitor.cpp
gcc가 아니라 g++를 사용하세요. 또한 monitor.exe를 (더블 클릭이 아니라) 터미널에서
실행하세요, 그렇지 않으면 출력할 콘솔이 연결되지 않습니다.
감시자는 브라우징하는 계정과 별개의 두 번째 비특권 로컬 계정으로 실행됩니다. 먼저, 설정을 통해 해당 계정을 만드세요:
attacker, 그리고 비밀번호를 입력한 후 Next를 클릭합니다.이것은 로컬 계정 (Microsoft 계정에 연결되지 않고, 네트워크 로그인 없음)을 만들며, 기본적으로 표준 (비관리자) 권한입니다.
다음으로, monitor.exe를 새 계정이 실제로 읽고 실행할 수 있는 곳에 두세요. 빌드된 바이너리를
대신 공용의 모든 사용자가 읽을 수 있는 디렉터리에 복사하세요:
copy monitor.exe C:\Users\Public\monitor.exe
이제, 메인 (피해자) 계정에서, 데스크톱을 전환하거나 로그아웃하지 않고 runas를 사용하여
attacker 계정으로 실행하세요:
runas /user:attacker "cmd /k C:\Users\Public\monitor.exe"
메시지가 표시되면 attacker의 비밀번호를 입력하세요. (monitor.exe를 직접 실행하는 대신)
cmd /k는 콘솔 창을 열어 두어 출력을 볼 수 있게 하며, 단순히
runas /user:attacker C:\Users\Public\monitor.exe도 작동하지만 프로세스가 종료되는 순간
창이 닫힙니다. 이것은 순전히 편의를 위한 것입니다.
monitor.exe 창을 실행 상태로 두고, 메인 계정으로 돌아가 Firefox를 열고 몇 개의 다른
웹사이트를 방문하세요, 예:
arstechnica.com과 reddit.com. 출력되는 각
줄은 http와 일치하는 저장 경로 아래의 파일 생성/수정/이름 변경입니다. 사이트마다 다른 출처
디렉터리를 가지므로, 페이지가 로드되는 동안 건드린 경로 집합은 그 자체로 핑거프린트입니다.
간단하게 하기 위해, 우리는 네이티브 FSEvents API를 감싸는 기존의 최소한의 널리 사용되는 CLI
도구인 fswatch를 사용합니다. 공격자는 이 도구
없이도 FSEvents API를 사용할 수 있습니다.
fswatch를 설치하거나 소스에서 빌드하세요:
brew install fswatch
비특권 사용자로서 /Applications를 재귀적으로 감시하세요:
fswatch -xr /Applications
실행 상태로 두고, Finder 또는 브라우저에서 Zoom (또는 다른 애플리케이션)을 다운로드하여
설치한 다음 제거하세요 (휴지통도 비워야 할 수 있습니다). fswatch는 FSEvents가
/Applications 아래에서 보고하는 모든 경로를 발생하는 대로 출력합니다. 빠른 평가를 위해,
동일한 사용자가 디렉터리를 모니터링할 수 있습니다. 그렇지 않으면, 새 사용자를 설정하고 그
사용자로 fswatch를 사용할 수 있습니다.
MIT 라이선스에 따라 배포됩니다.