Skip to content

Instantly share code, notes, and snippets.

@AzureFlow
Created March 14, 2024 01:39
Show Gist options
  • Save AzureFlow/e25555ba8e92987ca32f55640247329f to your computer and use it in GitHub Desktop.
Save AzureFlow/e25555ba8e92987ca32f55640247329f to your computer and use it in GitHub Desktop.
const { webcrypto: crypto } = require("crypto");
// https://vercel.com/docs/security/attack-challenge-mode
(async () => {
const hostname = "https://vercel-debug-xi.vercel.app";
const _vcrct = await getReqToken();
const solution = await computePOW(_vcrct);
const resp = await postChallenge(hostname, _vcrct, solution);
const solutionCookie = resp.headers.get("set-cookie").split("; ")[0];
// console.log("solutionCookie:", solutionCookie);
console.log("page:", await (await fetch(hostname, {
headers: {
"cookie": solutionCookie,
},
})).text());
/**
* @param {string} input
* @returns {Promise<string>}
*/
async function sha256(input) {
const rawData = new TextEncoder().encode(input);
const hashedData = await crypto.subtle.digest("SHA-256", rawData);
const hashedDataArr = Array.from(new Uint8Array(hashedData));
return hashedDataArr
.map(x => x.toString(16).padStart(2, "0"))
.join("");
}
/**
* @param {string} prefix
* @param {string} searchString
* @returns {Promise<{key: string, hash: string}>}
*/
async function computeSolution(prefix, searchString) {
while(true) {
const rnd = Math.random().toString(36).substring(2, 15);
const hash = await sha256(prefix + rnd);
if(hash.startsWith(searchString)) {
return {
key: rnd,
hash: hash,
};
}
}
}
/**
* @param {string} vcrct
* @returns {Promise<string>}
*/
async function computePOW(vcrct) {
// "0.1709267488.60.ZjM0Y2Y0YjkxODZkMzZiMzBjZjE1YWRjNGNiZTZhNWU7NDRlNjQwNzk7MDAwMDsz.0a9072dba7fa6e57595d3d9cc6f98ca6"
// ZjM0Y2Y0YjkxODZkMzZiMzBjZjE1YWRjNGNiZTZhNWU7NDRlNjQwNzk7MDAwMDsz
const paramsString = atob(vcrct.split(".")[3]);
// f34cf4b9186d36b30cf15adc4cbe6a5e;44e64079;0000;3
const [, prefix, startSearchString, numSolutions] = paramsString.split(";");
const results = [];
let searchString = startSearchString;
for(let i = 0; i < Number(numSolutions); i++) {
const solution = await computeSolution(prefix, searchString);
results.push(solution.key);
searchString = solution.hash.slice(-searchString.length);
}
return results.join(";");
}
/**
* @param {string} hostname
* @param {string} token
* @param {string} solution
* @returns {Promise<Response>}
*/
async function postChallenge(hostname, token, solution) {
return fetch(hostname + "/.well-known/vercel/security/request-challenge", {
method: "POST",
headers: {
"x-vercel-challenge-token": token,
"x-vercel-challenge-solution": solution,
},
});
}
/**
* @returns {Promise<string>}
*/
async function getReqToken() {
const initResp = await fetch(hostname);
const initContent = await initResp.text();
const initContentRe = initContent.match(/window\._vcrct="(?<token>.*?)"/);
if(initContentRe === null) {
return null;
}
const { token } = initContentRe.groups;
return token;
}
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment