@shriyanss/js-recon 1.0.0 → 1.1.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/build-and-prettify.yaml +65 -0
- package/.github/workflows/npm-publish.yml +35 -0
- package/.prettierignore +2 -0
- package/.prettierrc +4 -0
- package/CHANGELOG.md +50 -0
- package/README.md +35 -139
- package/build/api_gateway/checkFeasibility.js +32 -0
- package/build/api_gateway/checkFeasibility.js.map +1 -0
- package/build/api_gateway/checkFireWallBlocking.js +24 -0
- package/build/api_gateway/checkFireWallBlocking.js.map +1 -0
- package/build/api_gateway/genReq.js +199 -0
- package/build/api_gateway/genReq.js.map +1 -0
- package/build/api_gateway/index.js +275 -0
- package/build/api_gateway/index.js.map +1 -0
- package/build/endpoints/gen_report/gen_json.js +22 -0
- package/build/endpoints/gen_report/gen_json.js.map +1 -0
- package/build/endpoints/gen_report/gen_markdown.js +66 -0
- package/build/endpoints/gen_report/gen_markdown.js.map +1 -0
- package/build/endpoints/gen_report/utility/iterate_n_store.js +46 -0
- package/build/endpoints/gen_report/utility/iterate_n_store.js.map +1 -0
- package/build/endpoints/index.js +89 -0
- package/build/endpoints/index.js.map +1 -0
- package/build/endpoints/next_js/client_jsFilesHref.js +91 -0
- package/build/endpoints/next_js/client_jsFilesHref.js.map +1 -0
- package/build/endpoints/next_js/client_jsonParse.js +78 -0
- package/build/endpoints/next_js/client_jsonParse.js.map +1 -0
- package/build/endpoints/next_js/client_subsequentRequests.js +199 -0
- package/build/endpoints/next_js/client_subsequentRequests.js.map +1 -0
- package/build/endpoints/next_js/getWebpacks.js +45 -0
- package/build/endpoints/next_js/getWebpacks.js.map +1 -0
- package/build/globalConfig.js +11 -0
- package/build/globalConfig.js.map +1 -0
- package/build/index.js +166 -0
- package/build/index.js.map +1 -0
- package/build/lazyLoad/downloadFilesUtil.js +128 -0
- package/build/lazyLoad/downloadFilesUtil.js.map +1 -0
- package/build/lazyLoad/downloadLoadedJsUtil.js +51 -0
- package/build/lazyLoad/downloadLoadedJsUtil.js.map +1 -0
- package/build/lazyLoad/globals.js +22 -0
- package/build/lazyLoad/globals.js.map +1 -0
- package/build/lazyLoad/index.js +170 -0
- package/build/lazyLoad/index.js.map +1 -0
- package/build/lazyLoad/next_js/next_GetJSScript.js +94 -0
- package/build/lazyLoad/next_js/next_GetJSScript.js.map +1 -0
- package/build/lazyLoad/next_js/next_GetLazyResources.js +202 -0
- package/build/lazyLoad/next_js/next_GetLazyResources.js.map +1 -0
- package/build/lazyLoad/next_js/next_SubsequentRequests.js +120 -0
- package/build/lazyLoad/next_js/next_SubsequentRequests.js.map +1 -0
- package/build/lazyLoad/nuxt_js/nuxt_astParse.js +188 -0
- package/build/lazyLoad/nuxt_js/nuxt_astParse.js.map +1 -0
- package/build/lazyLoad/nuxt_js/nuxt_getFromPageSource.js +75 -0
- package/build/lazyLoad/nuxt_js/nuxt_getFromPageSource.js.map +1 -0
- package/build/lazyLoad/nuxt_js/nuxt_stringAnalysisJSFiles.js +94 -0
- package/build/lazyLoad/nuxt_js/nuxt_stringAnalysisJSFiles.js.map +1 -0
- package/build/lazyLoad/svelte/svelte_getFromPageSource.js +68 -0
- package/build/lazyLoad/svelte/svelte_getFromPageSource.js.map +1 -0
- package/build/lazyLoad/svelte/svelte_stringAnalysisJSFiles.js +95 -0
- package/build/lazyLoad/svelte/svelte_stringAnalysisJSFiles.js.map +1 -0
- package/build/map/index.js +58 -0
- package/build/map/index.js.map +1 -0
- package/build/map/next_js/getFetchInstances.js +108 -0
- package/build/map/next_js/getFetchInstances.js.map +1 -0
- package/build/map/next_js/getWebpackConnections.js +227 -0
- package/build/map/next_js/getWebpackConnections.js.map +1 -0
- package/build/map/next_js/interactive.js +32 -0
- package/build/map/next_js/interactive.js.map +1 -0
- package/build/map/next_js/interactive_helpers/commandHandler.js +190 -0
- package/build/map/next_js/interactive_helpers/commandHandler.js.map +1 -0
- package/build/map/next_js/interactive_helpers/commandHelpers.js +91 -0
- package/build/map/next_js/interactive_helpers/commandHelpers.js.map +1 -0
- package/build/map/next_js/interactive_helpers/helpMenu.js +11 -0
- package/build/map/next_js/interactive_helpers/helpMenu.js.map +1 -0
- package/build/map/next_js/interactive_helpers/keybindings.js +80 -0
- package/build/map/next_js/interactive_helpers/keybindings.js.map +1 -0
- package/build/map/next_js/interactive_helpers/printer.js +17 -0
- package/build/map/next_js/interactive_helpers/printer.js.map +1 -0
- package/build/map/next_js/interactive_helpers/ui.js +81 -0
- package/build/map/next_js/interactive_helpers/ui.js.map +1 -0
- package/build/map/next_js/resolveFetch.js +201 -0
- package/build/map/next_js/resolveFetch.js.map +1 -0
- package/build/run/index.js +62 -0
- package/build/run/index.js.map +1 -0
- package/build/strings/index.js +238 -0
- package/build/strings/index.js.map +1 -0
- package/build/strings/openapi.js +55 -0
- package/build/strings/openapi.js.map +1 -0
- package/build/strings/permutate.js +55 -0
- package/build/strings/permutate.js.map +1 -0
- package/build/strings/secrets.js +89 -0
- package/build/strings/secrets.js.map +1 -0
- package/build/techDetect/index.js +229 -0
- package/build/techDetect/index.js.map +1 -0
- package/build/utility/ai.js +69 -0
- package/build/utility/ai.js.map +1 -0
- package/build/utility/globals.js +84 -0
- package/build/utility/globals.js.map +1 -0
- package/build/utility/interfaces.js +2 -0
- package/build/utility/interfaces.js.map +1 -0
- package/build/utility/makeReq.js +265 -0
- package/build/utility/makeReq.js.map +1 -0
- package/build/utility/resolvePath.js +44 -0
- package/build/utility/resolvePath.js.map +1 -0
- package/{utility → build/utility}/runSandboxed.js +10 -13
- package/build/utility/runSandboxed.js.map +1 -0
- package/{utility → build/utility}/urlUtils.js +9 -11
- package/build/utility/urlUtils.js.map +1 -0
- package/docs/CNAME +1 -0
- package/docs/README.md +20 -0
- package/docs/api-gateway.md +68 -0
- package/docs/endpoints.md +49 -0
- package/docs/example-scenario.md +258 -0
- package/docs/interactive-mode.md +76 -0
- package/docs/lazyload.md +56 -0
- package/docs/map.md +53 -0
- package/docs/run.md +54 -0
- package/docs/strings.md +75 -0
- package/package.json +50 -38
- package/api_gateway/checkFeasibility.js +0 -25
- package/api_gateway/checkFireWallBlocking.js +0 -17
- package/api_gateway/genReq.js +0 -214
- package/api_gateway/index.js +0 -325
- package/endpoints/index.js +0 -7
- package/globalConfig.js +0 -12
- package/index.js +0 -69
- package/lazyLoad/downloadFilesUtil.js +0 -122
- package/lazyLoad/downloadLoadedJsUtil.js +0 -54
- package/lazyLoad/globals.js +0 -15
- package/lazyLoad/index.js +0 -167
- package/lazyLoad/next_js/next_GetJSScript.js +0 -99
- package/lazyLoad/next_js/next_GetLazyResources.js +0 -201
- package/lazyLoad/next_js/next_SubsequentRequests.js +0 -138
- package/lazyLoad/nuxt_js/nuxt_astParse.js +0 -194
- package/lazyLoad/nuxt_js/nuxt_getFromPageSource.js +0 -77
- package/lazyLoad/nuxt_js/nuxt_stringAnalysisJSFiles.js +0 -99
- package/research/firewall_bypass.md +0 -38
- package/research/next_js.md +0 -116
- package/research/nuxt_js.md +0 -125
- package/research/vue_js.md +0 -9
- package/strings/index.js +0 -145
- package/techDetect/index.js +0 -156
- package/utility/globals.js +0 -6
- package/utility/makeReq.js +0 -179
- package/utility/resolvePath.js +0 -43
|
@@ -1,201 +0,0 @@
|
|
|
1
|
-
import chalk from "chalk";
|
|
2
|
-
import puppeteer from "puppeteer";
|
|
3
|
-
import parser from "@babel/parser";
|
|
4
|
-
import _traverse from "@babel/traverse";
|
|
5
|
-
const traverse = _traverse.default;
|
|
6
|
-
import inquirer from "inquirer";
|
|
7
|
-
import CONFIG from "../../globalConfig.js";
|
|
8
|
-
import makeRequest from "../../utility/makeReq.js";
|
|
9
|
-
import execFunc from "../../utility/runSandboxed.js";
|
|
10
|
-
import { getJsUrls, pushToJsUrls } from "../globals.js"; // Import js_urls functions
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Asynchronously fetches the given URL and extracts JavaScript file URLs
|
|
14
|
-
* from webpack's require.ensure() function.
|
|
15
|
-
*
|
|
16
|
-
* @param {string} url - The URL of the webpage to fetch and parse.
|
|
17
|
-
* @returns {Promise<string[]|undefined>} - A promise that resolves to an array of
|
|
18
|
-
* absolute URLs pointing to JavaScript files found in require.ensure()
|
|
19
|
-
* functions, or undefined if no webpack JS is found.
|
|
20
|
-
*/
|
|
21
|
-
const next_getLazyResources = async (url) => {
|
|
22
|
-
const browser = await puppeteer.launch({
|
|
23
|
-
headless: true,
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
const page = await browser.newPage();
|
|
27
|
-
|
|
28
|
-
await page.setRequestInterception(true);
|
|
29
|
-
|
|
30
|
-
page.on("request", async (request) => {
|
|
31
|
-
// get the request url
|
|
32
|
-
const req_url = request.url(); // Renamed to avoid conflict with outer 'url'
|
|
33
|
-
|
|
34
|
-
// see if the request is a JS file, and is a get request
|
|
35
|
-
if (
|
|
36
|
-
request.method() === "GET" &&
|
|
37
|
-
req_url.match(/https?:\/\/[a-z\._\-]+\/.+\.js\??.*/)
|
|
38
|
-
) {
|
|
39
|
-
if (!getJsUrls().includes(req_url)) {
|
|
40
|
-
pushToJsUrls(req_url);
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
await request.continue();
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
await page.goto(url);
|
|
48
|
-
|
|
49
|
-
await browser.close();
|
|
50
|
-
|
|
51
|
-
let webpack_js;
|
|
52
|
-
|
|
53
|
-
// iterate through JS files
|
|
54
|
-
for (const js_url of getJsUrls()) {
|
|
55
|
-
// match for webpack js file
|
|
56
|
-
if (js_url.match(/\/webpack.*\.js/)) {
|
|
57
|
-
console.log(chalk.green(`[✓] Found webpack JS file at ${js_url}`));
|
|
58
|
-
webpack_js = js_url;
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
if (!webpack_js) {
|
|
63
|
-
console.log(chalk.red("[!] No webpack JS file found"));
|
|
64
|
-
console.log(chalk.magenta(CONFIG.notFoundMessage));
|
|
65
|
-
return; // Return undefined as per JSDoc
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
// parse the webpack JS file
|
|
69
|
-
const res = await makeRequest(webpack_js);
|
|
70
|
-
const webpack_js_source = await res.text();
|
|
71
|
-
|
|
72
|
-
// parse it with @babel/*
|
|
73
|
-
const ast = parser.parse(webpack_js_source, {
|
|
74
|
-
sourceType: "unambiguous",
|
|
75
|
-
plugins: ["jsx", "typescript"],
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
let functions = [];
|
|
79
|
-
|
|
80
|
-
traverse(ast, {
|
|
81
|
-
FunctionDeclaration(path) {
|
|
82
|
-
functions.push({
|
|
83
|
-
name: path.node.id?.name || "(anonymous)",
|
|
84
|
-
type: "FunctionDeclaration",
|
|
85
|
-
source: webpack_js_source.slice(path.node.start, path.node.end),
|
|
86
|
-
});
|
|
87
|
-
},
|
|
88
|
-
FunctionExpression(path) {
|
|
89
|
-
functions.push({
|
|
90
|
-
name: path.parent.id?.name || "(anonymous)",
|
|
91
|
-
type: "FunctionExpression",
|
|
92
|
-
source: webpack_js_source.slice(path.node.start, path.node.end),
|
|
93
|
-
});
|
|
94
|
-
},
|
|
95
|
-
ArrowFunctionExpression(path) {
|
|
96
|
-
functions.push({
|
|
97
|
-
name: path.parent.id?.name || "(anonymous)",
|
|
98
|
-
type: "ArrowFunctionExpression",
|
|
99
|
-
source: webpack_js_source.slice(path.node.start, path.node.end),
|
|
100
|
-
});
|
|
101
|
-
},
|
|
102
|
-
ObjectMethod(path) {
|
|
103
|
-
functions.push({
|
|
104
|
-
name: path.node.key.name,
|
|
105
|
-
type: "ObjectMethod",
|
|
106
|
-
source: webpack_js_source.slice(path.node.start, path.node.end),
|
|
107
|
-
});
|
|
108
|
-
},
|
|
109
|
-
ClassMethod(path) {
|
|
110
|
-
functions.push({
|
|
111
|
-
name: path.node.key.name,
|
|
112
|
-
type: "ClassMethod",
|
|
113
|
-
source: webpack_js_source.slice(path.node.start, path.node.end),
|
|
114
|
-
});
|
|
115
|
-
},
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
let user_verified = false;
|
|
119
|
-
// method 1
|
|
120
|
-
// iterate through the functions, and find out which one ends with `".js"`
|
|
121
|
-
|
|
122
|
-
let final_Func;
|
|
123
|
-
for (const func of functions) {
|
|
124
|
-
if (func.source.match(/"\.js".{0,15}$/)) {
|
|
125
|
-
console.log(
|
|
126
|
-
chalk.green(`[✓] Found JS chunk having the following source`),
|
|
127
|
-
);
|
|
128
|
-
console.log(chalk.yellow(func.source));
|
|
129
|
-
final_Func = func.source;
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
if (!final_Func) { // Added check if final_Func was not found
|
|
134
|
-
console.log(chalk.red("[!] No suitable function found in webpack JS for lazy loading."));
|
|
135
|
-
return [];
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
// ask through input if this is the right thing
|
|
139
|
-
const askCorrectFuncConfirmation = async () => {
|
|
140
|
-
const { confirmed } = await inquirer.prompt([
|
|
141
|
-
{
|
|
142
|
-
type: "confirm",
|
|
143
|
-
name: "confirmed",
|
|
144
|
-
message: "Is this the correct function?",
|
|
145
|
-
default: true,
|
|
146
|
-
},
|
|
147
|
-
]);
|
|
148
|
-
return confirmed;
|
|
149
|
-
};
|
|
150
|
-
|
|
151
|
-
user_verified = await askCorrectFuncConfirmation();
|
|
152
|
-
if (user_verified === true) {
|
|
153
|
-
console.log(
|
|
154
|
-
chalk.cyan("[i] Proceeding with the selected function to fetch files"),
|
|
155
|
-
);
|
|
156
|
-
} else {
|
|
157
|
-
console.log(chalk.red("[!] Not executing function."));
|
|
158
|
-
return [];
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
const urlBuilderFunc = `(() => (${final_Func}))()`;
|
|
162
|
-
|
|
163
|
-
let js_paths = [];
|
|
164
|
-
try {
|
|
165
|
-
// rather than fuzzing, grep the integers from the func code
|
|
166
|
-
const integers = final_Func.match(/\d+/g);
|
|
167
|
-
if (integers) { // Check if integers were found
|
|
168
|
-
// iterate through all integers, and get the output
|
|
169
|
-
for (const i of integers) {
|
|
170
|
-
const output = execFunc(urlBuilderFunc, parseInt(i));
|
|
171
|
-
if (output.includes("undefined")) {
|
|
172
|
-
continue;
|
|
173
|
-
} else {
|
|
174
|
-
js_paths.push(output);
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
} catch (err) {
|
|
179
|
-
console.error("Unsafe or invalid code:", err.message);
|
|
180
|
-
return [];
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
if (js_paths.length > 0) {
|
|
184
|
-
console.log(chalk.green(`[✓] Found ${js_paths.length} JS chunks`));
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
// build final URL
|
|
188
|
-
let final_urls = [];
|
|
189
|
-
for (let i = 0; i < js_paths.length; i++) {
|
|
190
|
-
// get the directory of webpack file
|
|
191
|
-
const webpack_dir = webpack_js.split("/").slice(0, -1).join("/");
|
|
192
|
-
// replace the filename from the js path
|
|
193
|
-
const js_path_dir = js_paths[i].replace(/\/[a-zA-Z0-9\.]+\.js.*$/, "");
|
|
194
|
-
const final_url = webpack_dir.replace(js_path_dir, js_paths[i]);
|
|
195
|
-
final_urls.push(final_url);
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
return final_urls;
|
|
199
|
-
};
|
|
200
|
-
|
|
201
|
-
export default next_getLazyResources;
|
|
@@ -1,138 +0,0 @@
|
|
|
1
|
-
import chalk from "chalk";
|
|
2
|
-
import fs from "fs";
|
|
3
|
-
import path from "path";
|
|
4
|
-
import { getURLDirectory } from "../../utility/urlUtils.js";
|
|
5
|
-
// custom request module
|
|
6
|
-
import makeRequest from "../../utility/makeReq.js";
|
|
7
|
-
|
|
8
|
-
let queue = [];
|
|
9
|
-
let max_queue;
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Given a string of JS content, it finds all the static files used in the
|
|
13
|
-
* file, and returns them as an array.
|
|
14
|
-
*
|
|
15
|
-
* @param {string} js_content - The string of JS content to search through.
|
|
16
|
-
*
|
|
17
|
-
* @returns {string[]} An array of strings, each string being a static file
|
|
18
|
-
* path.
|
|
19
|
-
*/
|
|
20
|
-
const findStaticFiles = async (js_content) => {
|
|
21
|
-
// do some regex-ing
|
|
22
|
-
const matches = [
|
|
23
|
-
...js_content.matchAll(/\/?static\/chunks\/[a-zA-Z0-9\._\-\/]+\.js/g),
|
|
24
|
-
];
|
|
25
|
-
// return matches
|
|
26
|
-
|
|
27
|
-
let toReturn = [];
|
|
28
|
-
|
|
29
|
-
for (const match of matches) {
|
|
30
|
-
toReturn.push(match[0]);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
return toReturn;
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
const getURLDirectoryServer = (urlString) => {
|
|
37
|
-
const url = new URL(urlString);
|
|
38
|
-
const pathParts = url.pathname.split("/").filter(Boolean); // ['business', 'api']
|
|
39
|
-
pathParts.pop(); // Remove 'api'
|
|
40
|
-
|
|
41
|
-
const newPath = "/" + pathParts.join("/"); // '/business'
|
|
42
|
-
return `${url.origin}${newPath}`; // 'http://something.com/business'
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
const subsequentRequests = async (url, urlsFile, threads, output, js_urls) => {
|
|
46
|
-
max_queue = threads;
|
|
47
|
-
let staticJSURLs = [];
|
|
48
|
-
|
|
49
|
-
console.log(chalk.cyan(`[i] Fetching JS files from subsequent requests`));
|
|
50
|
-
|
|
51
|
-
// open the urls file, and load the paths (JSON)
|
|
52
|
-
const endpoints = JSON.parse(fs.readFileSync(urlsFile, "utf-8")).paths;
|
|
53
|
-
|
|
54
|
-
let js_contents = {};
|
|
55
|
-
|
|
56
|
-
// make requests to all of them with the special header
|
|
57
|
-
const reqPromises = endpoints.map(async (endpoint) => {
|
|
58
|
-
const reqUrl = url + endpoint;
|
|
59
|
-
try {
|
|
60
|
-
// delay in case over the thread count
|
|
61
|
-
while (queue >= max_queue) {
|
|
62
|
-
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
63
|
-
}
|
|
64
|
-
queue++;
|
|
65
|
-
|
|
66
|
-
const res = await makeRequest(reqUrl, {
|
|
67
|
-
headers: {
|
|
68
|
-
RSC: "1",
|
|
69
|
-
},
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
if (
|
|
73
|
-
res &&
|
|
74
|
-
res.status === 200 &&
|
|
75
|
-
res.headers.get("content-type").includes("text/x-component")
|
|
76
|
-
) {
|
|
77
|
-
const text = await res.text();
|
|
78
|
-
js_contents[endpoint] = text;
|
|
79
|
-
|
|
80
|
-
const { host, directory } = getURLDirectory(reqUrl);
|
|
81
|
-
|
|
82
|
-
// save the contents to "___subsequent_requests/"
|
|
83
|
-
// make the subsequent_requests directory if it doesn't exist
|
|
84
|
-
|
|
85
|
-
const output_path = path.join(
|
|
86
|
-
output,
|
|
87
|
-
host,
|
|
88
|
-
"___subsequent_requests",
|
|
89
|
-
directory,
|
|
90
|
-
);
|
|
91
|
-
if (!fs.existsSync(output_path)) {
|
|
92
|
-
fs.mkdirSync(output_path);
|
|
93
|
-
}
|
|
94
|
-
fs.writeFileSync(path.join(output_path, "index.js"), text);
|
|
95
|
-
|
|
96
|
-
// find the static ones from the JS resp
|
|
97
|
-
const staticFiles = await findStaticFiles(text);
|
|
98
|
-
|
|
99
|
-
// go through each file and get the absolute path of those
|
|
100
|
-
const absolutePaths = staticFiles.map((file) => {
|
|
101
|
-
// go through existing JS URLs found
|
|
102
|
-
let js_path_dir;
|
|
103
|
-
for (const js_url of js_urls) {
|
|
104
|
-
if (
|
|
105
|
-
!js_path_dir &&
|
|
106
|
-
new URL(js_url).host === new URL(url).host &&
|
|
107
|
-
new URL(js_url).pathname.includes("static/chunks/")
|
|
108
|
-
) {
|
|
109
|
-
js_path_dir = js_url.replace(/\/[^\/]+\.js.*$/, "");
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
return js_path_dir.replace("static/chunks", "") + file;
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
// Filter out paths that are already in js_urls before pushing to staticJSURLs
|
|
116
|
-
const newPaths = absolutePaths.filter(path => !js_urls.includes(path));
|
|
117
|
-
if (newPaths.length > 0) {
|
|
118
|
-
staticJSURLs.push(...newPaths);
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
queue--;
|
|
123
|
-
} catch (e) {
|
|
124
|
-
queue--;
|
|
125
|
-
console.log(chalk.red(`[!] Error fetching ${reqUrl}: ${e}`));
|
|
126
|
-
}
|
|
127
|
-
});
|
|
128
|
-
|
|
129
|
-
await Promise.all(reqPromises);
|
|
130
|
-
|
|
131
|
-
staticJSURLs = [...new Set(staticJSURLs)];
|
|
132
|
-
|
|
133
|
-
console.log(chalk.green(`[✓] Found ${staticJSURLs.length} JS chunks from subsequent requests`));
|
|
134
|
-
|
|
135
|
-
return staticJSURLs;
|
|
136
|
-
};
|
|
137
|
-
|
|
138
|
-
export default subsequentRequests;
|
|
@@ -1,194 +0,0 @@
|
|
|
1
|
-
import parser from "@babel/parser";
|
|
2
|
-
import _traverse from "@babel/traverse";
|
|
3
|
-
const traverse = _traverse.default;
|
|
4
|
-
import execFunc from "../../utility/runSandboxed.js";
|
|
5
|
-
import makeRequest from "../../utility/makeReq.js";
|
|
6
|
-
import chalk from "chalk";
|
|
7
|
-
import inquirer from "inquirer";
|
|
8
|
-
import t from "@babel/types";
|
|
9
|
-
import resolvePath from "../../utility/resolvePath.js";
|
|
10
|
-
|
|
11
|
-
const nuxt_astParse = async (url) => {
|
|
12
|
-
let filesFound = [];
|
|
13
|
-
const resp = await makeRequest(url);
|
|
14
|
-
const body = await resp.text();
|
|
15
|
-
|
|
16
|
-
let ast;
|
|
17
|
-
try {
|
|
18
|
-
ast = parser.parse(body, {
|
|
19
|
-
sourceType: "module",
|
|
20
|
-
plugins: ["jsx", "typescript"],
|
|
21
|
-
});
|
|
22
|
-
} catch (error) {
|
|
23
|
-
console.log(chalk.red("[!] Error parsing JS file: ", url));
|
|
24
|
-
return filesFound;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
let functions = [];
|
|
28
|
-
|
|
29
|
-
traverse(ast, {
|
|
30
|
-
FunctionDeclaration(path) {
|
|
31
|
-
functions.push({
|
|
32
|
-
name: path.node.id?.name || "(anonymous)",
|
|
33
|
-
type: "FunctionDeclaration",
|
|
34
|
-
source: body.slice(path.node.start, path.node.end),
|
|
35
|
-
});
|
|
36
|
-
},
|
|
37
|
-
FunctionExpression(path) {
|
|
38
|
-
functions.push({
|
|
39
|
-
name: path.parent.id?.name || "(anonymous)",
|
|
40
|
-
type: "FunctionExpression",
|
|
41
|
-
source: body.slice(path.node.start, path.node.end),
|
|
42
|
-
});
|
|
43
|
-
},
|
|
44
|
-
ArrowFunctionExpression(path) {
|
|
45
|
-
functions.push({
|
|
46
|
-
name: path.parent.id?.name || "(anonymous)",
|
|
47
|
-
type: "ArrowFunctionExpression",
|
|
48
|
-
source: body.slice(path.node.start, path.node.end),
|
|
49
|
-
});
|
|
50
|
-
},
|
|
51
|
-
ObjectMethod(path) {
|
|
52
|
-
functions.push({
|
|
53
|
-
name: path.node.key.name,
|
|
54
|
-
type: "ObjectMethod",
|
|
55
|
-
source: body.slice(path.node.start, path.node.end),
|
|
56
|
-
});
|
|
57
|
-
},
|
|
58
|
-
ClassMethod(path) {
|
|
59
|
-
functions.push({
|
|
60
|
-
name: path.node.key.name,
|
|
61
|
-
type: "ClassMethod",
|
|
62
|
-
source: body.slice(path.node.start, path.node.end),
|
|
63
|
-
});
|
|
64
|
-
},
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
// iterate through the functions, and find out the one that ends with ".js"
|
|
68
|
-
|
|
69
|
-
for (const func of functions) {
|
|
70
|
-
if (func.source.match(/"\.js".{0,15}$/)) {
|
|
71
|
-
console.log(
|
|
72
|
-
chalk.green(`[✓] Found JS chunk having the following source:`),
|
|
73
|
-
);
|
|
74
|
-
console.log(chalk.yellow(func.source));
|
|
75
|
-
|
|
76
|
-
// ask for confirmation, then proceed
|
|
77
|
-
const askCorrectFuncConfirmation = async () => {
|
|
78
|
-
const { value } = await inquirer.prompt([
|
|
79
|
-
{
|
|
80
|
-
type: "confirm",
|
|
81
|
-
name: "value",
|
|
82
|
-
message: "Is this the correct function?",
|
|
83
|
-
default: true,
|
|
84
|
-
},
|
|
85
|
-
]);
|
|
86
|
-
return value;
|
|
87
|
-
};
|
|
88
|
-
|
|
89
|
-
const user_verified = await askCorrectFuncConfirmation();
|
|
90
|
-
if (user_verified === true) {
|
|
91
|
-
console.log(
|
|
92
|
-
chalk.cyan(
|
|
93
|
-
"[i] Proceeding with the selected function to fetch files",
|
|
94
|
-
),
|
|
95
|
-
);
|
|
96
|
-
|
|
97
|
-
// get the value of the unknown vars
|
|
98
|
-
// first, get the name of the unknown function
|
|
99
|
-
const unknownVarAst = parser.parse(`(${func.source})`, {
|
|
100
|
-
sourceType: "script",
|
|
101
|
-
plugins: ["jsx", "typescript"],
|
|
102
|
-
});
|
|
103
|
-
let memberExpressions = [];
|
|
104
|
-
traverse(unknownVarAst, {
|
|
105
|
-
MemberExpression(path) {
|
|
106
|
-
// Only collect identifiers like f.p (not obj["x"])
|
|
107
|
-
if (
|
|
108
|
-
t.isIdentifier(path.node.object) &&
|
|
109
|
-
t.isIdentifier(path.node.property) &&
|
|
110
|
-
!path.node.computed // ignore obj["x"]
|
|
111
|
-
) {
|
|
112
|
-
const objName = path.node.object.name;
|
|
113
|
-
const propName = path.node.property.name;
|
|
114
|
-
memberExpressions.push(`${objName}.${propName}`);
|
|
115
|
-
}
|
|
116
|
-
},
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
const unknownVar = memberExpressions[0].split(".");
|
|
120
|
-
|
|
121
|
-
// now, resolve the value of this unknown var
|
|
122
|
-
let unknownVarValue;
|
|
123
|
-
|
|
124
|
-
traverse(ast, {
|
|
125
|
-
AssignmentExpression(path) {
|
|
126
|
-
const { left, right } = path.node;
|
|
127
|
-
|
|
128
|
-
if (
|
|
129
|
-
t.isMemberExpression(left) &&
|
|
130
|
-
t.isIdentifier(left.object, { name: unknownVar[0] }) &&
|
|
131
|
-
t.isIdentifier(left.property, { name: unknownVar[1] }) &&
|
|
132
|
-
!left.computed
|
|
133
|
-
) {
|
|
134
|
-
if (t.isStringLiteral(right)) {
|
|
135
|
-
unknownVarValue = right.value;
|
|
136
|
-
} else {
|
|
137
|
-
// fallback to source snippet
|
|
138
|
-
unknownVarValue = func.source.slice(right.start, right.end);
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
},
|
|
142
|
-
});
|
|
143
|
-
|
|
144
|
-
// replace the unknown var with the value
|
|
145
|
-
const funcSource = func.source.replace(
|
|
146
|
-
new RegExp(`${unknownVar[0]}.${unknownVar[1]}`),
|
|
147
|
-
`"${unknownVarValue}"`,
|
|
148
|
-
);
|
|
149
|
-
|
|
150
|
-
// continue to executing the function with all possible numbers
|
|
151
|
-
const urlBuilderFunc = `(() => (${funcSource}))()`;
|
|
152
|
-
let js_paths = [];
|
|
153
|
-
|
|
154
|
-
try {
|
|
155
|
-
// rather than fuzzing, grep the integers from the func code
|
|
156
|
-
const integers = funcSource.match(/\d+/g);
|
|
157
|
-
if (integers) {
|
|
158
|
-
// Check if integers were found
|
|
159
|
-
// iterate through all integers, and get the output
|
|
160
|
-
for (const i of integers) {
|
|
161
|
-
const output = execFunc(urlBuilderFunc, parseInt(i));
|
|
162
|
-
if (output.includes("undefined")) {
|
|
163
|
-
continue;
|
|
164
|
-
} else {
|
|
165
|
-
js_paths.push(output);
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
} catch (error) {
|
|
170
|
-
console.log(chalk.red("[!] Error executing function: ", error));
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
if (js_paths.length > 0) {
|
|
174
|
-
// iterate through the files, and resolve them
|
|
175
|
-
for (const js_path of js_paths) {
|
|
176
|
-
const resolvedPath = await resolvePath(url, js_path);
|
|
177
|
-
filesFound.push(resolvedPath);
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
} else {
|
|
181
|
-
console.log(chalk.red("[!] Not executing function."));
|
|
182
|
-
continue;
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
if (filesFound.length > 0) {
|
|
188
|
-
console.log(chalk.green(`[✓] Found ${filesFound.length} JS chunks`));
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
return filesFound;
|
|
192
|
-
};
|
|
193
|
-
|
|
194
|
-
export default nuxt_astParse;
|
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
import chalk from "chalk";
|
|
2
|
-
import makeRequest from "../../utility/makeReq.js";
|
|
3
|
-
import { getJsUrls, pushToJsUrls } from "../globals.js";
|
|
4
|
-
import * as cheerio from "cheerio";
|
|
5
|
-
|
|
6
|
-
const nuxt_getFromPageSource = async (url) => {
|
|
7
|
-
console.log(chalk.cyan("[i] Analyzing page source"));
|
|
8
|
-
|
|
9
|
-
// get the page source
|
|
10
|
-
const res = await makeRequest(url);
|
|
11
|
-
const pageSource = await res.text();
|
|
12
|
-
|
|
13
|
-
// cheerio to parse the page source
|
|
14
|
-
const $ = cheerio.load(pageSource);
|
|
15
|
-
|
|
16
|
-
// find all link tags
|
|
17
|
-
const linkTags = $("link");
|
|
18
|
-
|
|
19
|
-
// go through them, and find the ones which have `as=script` attr
|
|
20
|
-
for (const linkTag of linkTags) {
|
|
21
|
-
const asAttr = $(linkTag).attr("as");
|
|
22
|
-
if (asAttr === "script") {
|
|
23
|
-
const hrefAttr = $(linkTag).attr("href");
|
|
24
|
-
if (hrefAttr) {
|
|
25
|
-
// see if it starts with /_nuxt
|
|
26
|
-
if (hrefAttr.startsWith("/_nuxt")) {
|
|
27
|
-
// get the URL root, and append the hrefAttr to it
|
|
28
|
-
const urlRoot = new URL(url).origin;
|
|
29
|
-
pushToJsUrls(urlRoot + hrefAttr);
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
// now, search all the script tags
|
|
36
|
-
const scriptTags = $("script");
|
|
37
|
-
for (const scriptTag of scriptTags) {
|
|
38
|
-
const src = $(scriptTag).attr("src");
|
|
39
|
-
if (
|
|
40
|
-
src !== undefined &&
|
|
41
|
-
src.match(/(https:\/\/[a-zA-Z0-9_\_\.]+\/.+\.js\??.*|\/.+\.js\??.*)/)
|
|
42
|
-
) {
|
|
43
|
-
if (src.startsWith("http")) {
|
|
44
|
-
if (!getJsUrls().includes(src)) {
|
|
45
|
-
pushToJsUrls(src);
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
// if the src starts with /, like `/static/js/a.js` find the absolute URL
|
|
49
|
-
else if (src.startsWith("/")) {
|
|
50
|
-
const absoluteUrl = new URL(url).origin + src;
|
|
51
|
-
if (!getJsUrls().includes(absoluteUrl)) {
|
|
52
|
-
pushToJsUrls(absoluteUrl);
|
|
53
|
-
}
|
|
54
|
-
} else if (src.match(/^[^/]/)) {
|
|
55
|
-
// if the src is a relative URL, like `static/js/a.js` find the absolute URL
|
|
56
|
-
// Get directory URL (origin + path without filename)
|
|
57
|
-
const pathParts = new URL(url).pathname.split("/");
|
|
58
|
-
pathParts.pop(); // remove the filename from the path
|
|
59
|
-
const directory = new URL(url).origin + pathParts.join("/") + "/";
|
|
60
|
-
|
|
61
|
-
if (!getJsUrls().includes(directory + src)) {
|
|
62
|
-
pushToJsUrls(directory + src);
|
|
63
|
-
}
|
|
64
|
-
} else {
|
|
65
|
-
continue;
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
console.log(
|
|
71
|
-
chalk.green(`[✓] Found ${getJsUrls().length} JS files from the page source`),
|
|
72
|
-
);
|
|
73
|
-
|
|
74
|
-
return getJsUrls();
|
|
75
|
-
};
|
|
76
|
-
|
|
77
|
-
export default nuxt_getFromPageSource;
|
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
import chalk from "chalk";
|
|
2
|
-
import makeRequest from "../../utility/makeReq.js";
|
|
3
|
-
import { getJsUrls, pushToJsUrls } from "../globals.js";
|
|
4
|
-
import resolvePath from "../../utility/resolvePath.js";
|
|
5
|
-
|
|
6
|
-
// for parsing
|
|
7
|
-
import parser from "@babel/parser";
|
|
8
|
-
import _traverse from "@babel/traverse";
|
|
9
|
-
const traverse = _traverse.default;
|
|
10
|
-
|
|
11
|
-
let analyzedFiles = [];
|
|
12
|
-
let filesFound = [];
|
|
13
|
-
|
|
14
|
-
const parseJSFileContent = async (content) => {
|
|
15
|
-
try {
|
|
16
|
-
const ast = parser.parse(content, {
|
|
17
|
-
sourceType: "module",
|
|
18
|
-
plugins: ["jsx", "typescript"],
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
let foundJsFiles = {};
|
|
22
|
-
|
|
23
|
-
traverse(ast, {
|
|
24
|
-
StringLiteral(path) {
|
|
25
|
-
const value = path.node.value;
|
|
26
|
-
if (value.startsWith("./") && value.endsWith(".js")) {
|
|
27
|
-
foundJsFiles[value] = value;
|
|
28
|
-
} else if (value.startsWith("../") && value.endsWith(".js")) {
|
|
29
|
-
foundJsFiles[value] = value;
|
|
30
|
-
}
|
|
31
|
-
},
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
return foundJsFiles;
|
|
35
|
-
} catch (error) {
|
|
36
|
-
return {};
|
|
37
|
-
}
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
const nuxt_stringAnalysisJSFiles = async (url) => {
|
|
41
|
-
console.log(chalk.cyan("[i] Analyzing strings in the files found"));
|
|
42
|
-
|
|
43
|
-
while (true) {
|
|
44
|
-
// get all the JS URLs
|
|
45
|
-
const js_urls = getJsUrls();
|
|
46
|
-
|
|
47
|
-
if (js_urls.length === 0) {
|
|
48
|
-
console.log(chalk.red("[!] No JS files found for string analysis"));
|
|
49
|
-
break;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// if js_urls have everything that is in analyzedFiles, break
|
|
53
|
-
let everythingAnalyzed = true;
|
|
54
|
-
for (const url of js_urls) {
|
|
55
|
-
// if the url is not in analyzedFiles, set everythingAnalyzed to false
|
|
56
|
-
if (!analyzedFiles.includes(url)) {
|
|
57
|
-
everythingAnalyzed = false;
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
// break if everything is analyzed
|
|
62
|
-
if (everythingAnalyzed) {
|
|
63
|
-
break;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
// iterate through the JS URLs
|
|
67
|
-
for (const js_url of js_urls) {
|
|
68
|
-
if (analyzedFiles.includes(js_url)) {
|
|
69
|
-
continue;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
const response = await makeRequest(js_url);
|
|
73
|
-
const respText = await response.text();
|
|
74
|
-
const foundJsFiles = await parseJSFileContent(respText);
|
|
75
|
-
|
|
76
|
-
// iterate through the foundJsFiles and resolve the paths
|
|
77
|
-
for (const [key, value] of Object.entries(foundJsFiles)) {
|
|
78
|
-
const resolvedPath = await resolvePath(js_url, value);
|
|
79
|
-
if (analyzedFiles.includes(resolvedPath)) {
|
|
80
|
-
continue;
|
|
81
|
-
}
|
|
82
|
-
pushToJsUrls(resolvedPath);
|
|
83
|
-
filesFound.push(resolvedPath);
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
analyzedFiles.push(js_url);
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
filesFound = [...new Set(filesFound)];
|
|
91
|
-
|
|
92
|
-
console.log(
|
|
93
|
-
chalk.green(`[✓] Found ${filesFound.length} JS files from string analysis`),
|
|
94
|
-
);
|
|
95
|
-
|
|
96
|
-
return filesFound;
|
|
97
|
-
};
|
|
98
|
-
|
|
99
|
-
export default nuxt_stringAnalysisJSFiles;
|