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;
}
})();
@flappyflappyfishy
Copy link

hey! thanks for OSS this solution, does this still work to bypass Vercel's Security Checkpoint?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment