@shriyanss/js-recon 1.0.0 → 1.1.0-beta.1

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.
Files changed (198) hide show
  1. package/.api_gateway_config.json +1 -0
  2. package/.github/workflows/npm-publish.yml +35 -0
  3. package/.github/workflows/prettier.yaml +44 -0
  4. package/.prettierignore +2 -0
  5. package/.prettierrc +4 -0
  6. package/.resp_cache.json +1 -0
  7. package/.vscode/launch.json +27 -0
  8. package/CHANGELOG.md +40 -0
  9. package/README.md +35 -140
  10. package/build/api_gateway/checkFeasibility.js +32 -0
  11. package/build/api_gateway/checkFeasibility.js.map +1 -0
  12. package/build/api_gateway/checkFireWallBlocking.js +24 -0
  13. package/build/api_gateway/checkFireWallBlocking.js.map +1 -0
  14. package/build/api_gateway/genReq.js +202 -0
  15. package/build/api_gateway/genReq.js.map +1 -0
  16. package/build/api_gateway/index.js +277 -0
  17. package/build/api_gateway/index.js.map +1 -0
  18. package/build/endpoints/gen_report/gen_json.js +22 -0
  19. package/build/endpoints/gen_report/gen_json.js.map +1 -0
  20. package/build/endpoints/gen_report/gen_markdown.js +66 -0
  21. package/build/endpoints/gen_report/gen_markdown.js.map +1 -0
  22. package/build/endpoints/gen_report/utility/iterate_n_store.js +46 -0
  23. package/build/endpoints/gen_report/utility/iterate_n_store.js.map +1 -0
  24. package/build/endpoints/index.js +89 -0
  25. package/build/endpoints/index.js.map +1 -0
  26. package/build/endpoints/next_js/client_jsFilesHref.js +91 -0
  27. package/build/endpoints/next_js/client_jsFilesHref.js.map +1 -0
  28. package/build/endpoints/next_js/client_jsonParse.js +75 -0
  29. package/build/endpoints/next_js/client_jsonParse.js.map +1 -0
  30. package/build/endpoints/next_js/client_subsequentRequests.js +199 -0
  31. package/build/endpoints/next_js/client_subsequentRequests.js.map +1 -0
  32. package/build/endpoints/next_js/getWebpacks.js +45 -0
  33. package/build/endpoints/next_js/getWebpacks.js.map +1 -0
  34. package/build/globalConfig.js +11 -0
  35. package/build/globalConfig.js.map +1 -0
  36. package/build/index.js +166 -0
  37. package/build/index.js.map +1 -0
  38. package/build/lazyLoad/downloadFilesUtil.js +128 -0
  39. package/build/lazyLoad/downloadFilesUtil.js.map +1 -0
  40. package/build/lazyLoad/downloadLoadedJsUtil.js +51 -0
  41. package/build/lazyLoad/downloadLoadedJsUtil.js.map +1 -0
  42. package/build/lazyLoad/globals.js +25 -0
  43. package/build/lazyLoad/globals.js.map +1 -0
  44. package/build/lazyLoad/index.js +171 -0
  45. package/build/lazyLoad/index.js.map +1 -0
  46. package/build/lazyLoad/next_js/next_GetJSScript.js +94 -0
  47. package/build/lazyLoad/next_js/next_GetJSScript.js.map +1 -0
  48. package/build/lazyLoad/next_js/next_GetLazyResources.js +202 -0
  49. package/build/lazyLoad/next_js/next_GetLazyResources.js.map +1 -0
  50. package/build/lazyLoad/next_js/next_SubsequentRequests.js +120 -0
  51. package/build/lazyLoad/next_js/next_SubsequentRequests.js.map +1 -0
  52. package/build/lazyLoad/nuxt_js/nuxt_astParse.js +188 -0
  53. package/build/lazyLoad/nuxt_js/nuxt_astParse.js.map +1 -0
  54. package/build/lazyLoad/nuxt_js/nuxt_getFromPageSource.js +75 -0
  55. package/build/lazyLoad/nuxt_js/nuxt_getFromPageSource.js.map +1 -0
  56. package/build/lazyLoad/nuxt_js/nuxt_stringAnalysisJSFiles.js +94 -0
  57. package/build/lazyLoad/nuxt_js/nuxt_stringAnalysisJSFiles.js.map +1 -0
  58. package/build/lazyLoad/svelte/svelte_getFromPageSource.js +68 -0
  59. package/build/lazyLoad/svelte/svelte_getFromPageSource.js.map +1 -0
  60. package/build/lazyLoad/svelte/svelte_stringAnalysisJSFiles.js +95 -0
  61. package/build/lazyLoad/svelte/svelte_stringAnalysisJSFiles.js.map +1 -0
  62. package/build/map/index.js +58 -0
  63. package/build/map/index.js.map +1 -0
  64. package/build/map/next_js/getFetchInstances.js +105 -0
  65. package/build/map/next_js/getFetchInstances.js.map +1 -0
  66. package/build/map/next_js/getWebpackConnections.js +224 -0
  67. package/build/map/next_js/getWebpackConnections.js.map +1 -0
  68. package/build/map/next_js/interactive.js +32 -0
  69. package/build/map/next_js/interactive.js.map +1 -0
  70. package/build/map/next_js/interactive_helpers/commandHandler.js +190 -0
  71. package/build/map/next_js/interactive_helpers/commandHandler.js.map +1 -0
  72. package/build/map/next_js/interactive_helpers/commandHelpers.js +91 -0
  73. package/build/map/next_js/interactive_helpers/commandHelpers.js.map +1 -0
  74. package/build/map/next_js/interactive_helpers/helpMenu.js +11 -0
  75. package/build/map/next_js/interactive_helpers/helpMenu.js.map +1 -0
  76. package/build/map/next_js/interactive_helpers/keybindings.js +80 -0
  77. package/build/map/next_js/interactive_helpers/keybindings.js.map +1 -0
  78. package/build/map/next_js/interactive_helpers/printer.js +17 -0
  79. package/build/map/next_js/interactive_helpers/printer.js.map +1 -0
  80. package/build/map/next_js/interactive_helpers/ui.js +81 -0
  81. package/build/map/next_js/interactive_helpers/ui.js.map +1 -0
  82. package/build/map/next_js/resolveFetch.js +201 -0
  83. package/build/map/next_js/resolveFetch.js.map +1 -0
  84. package/build/run/index.js +62 -0
  85. package/build/run/index.js.map +1 -0
  86. package/build/strings/index.js +235 -0
  87. package/build/strings/index.js.map +1 -0
  88. package/build/strings/openapi.js +55 -0
  89. package/build/strings/openapi.js.map +1 -0
  90. package/build/strings/permutate.js +55 -0
  91. package/build/strings/permutate.js.map +1 -0
  92. package/build/strings/secrets.js +89 -0
  93. package/build/strings/secrets.js.map +1 -0
  94. package/build/techDetect/index.js +224 -0
  95. package/build/techDetect/index.js.map +1 -0
  96. package/build/utility/ai.js +69 -0
  97. package/build/utility/ai.js.map +1 -0
  98. package/build/utility/globals.js +84 -0
  99. package/build/utility/globals.js.map +1 -0
  100. package/build/utility/interfaces.js +2 -0
  101. package/build/utility/interfaces.js.map +1 -0
  102. package/build/utility/makeReq.js +265 -0
  103. package/build/utility/makeReq.js.map +1 -0
  104. package/build/utility/resolvePath.js +44 -0
  105. package/build/utility/resolvePath.js.map +1 -0
  106. package/{utility → build/utility}/runSandboxed.js +10 -13
  107. package/build/utility/runSandboxed.js.map +1 -0
  108. package/{utility → build/utility}/urlUtils.js +9 -11
  109. package/build/utility/urlUtils.js.map +1 -0
  110. package/docs/README.md +20 -0
  111. package/docs/api-gateway.md +68 -0
  112. package/docs/endpoints.md +49 -0
  113. package/docs/example-scenario.md +258 -0
  114. package/docs/interactive-mode.md +76 -0
  115. package/docs/lazyload.md +56 -0
  116. package/docs/map.md +53 -0
  117. package/docs/run.md +54 -0
  118. package/docs/strings.md +75 -0
  119. package/endpoints.json +77 -0
  120. package/extracted_urls-openapi.json +225 -0
  121. package/extracted_urls-swagger.json +225 -0
  122. package/extracted_urls.json +47 -0
  123. package/extracted_urls.txt +296 -0
  124. package/mapped.json +3413 -0
  125. package/output/ss0x00.com/_next/data/k7xKVnxmboK4SktY2dZWt/index.json +971 -0
  126. package/output/ss0x00.com/_next/static/chunks/12.7e6d2ac6e1808fc2.js +247 -0
  127. package/output/ss0x00.com/_next/static/chunks/128.160aa801ef0445bc.js +1074 -0
  128. package/output/ss0x00.com/_next/static/chunks/132.55df84f7707fc278.js +102 -0
  129. package/output/ss0x00.com/_next/static/chunks/142.77038c55d9ec10ba.js +96 -0
  130. package/output/ss0x00.com/_next/static/chunks/215.321479e91d330bfa.js +228 -0
  131. package/output/ss0x00.com/_next/static/chunks/229.097c396d86b4a882.js +458 -0
  132. package/output/ss0x00.com/_next/static/chunks/257.5fd052aa4ef06ef9.js +1327 -0
  133. package/output/ss0x00.com/_next/static/chunks/268.72cb3779f66db70b.js +10520 -0
  134. package/output/ss0x00.com/_next/static/chunks/320.57d528b0e9bf86f0.js +186 -0
  135. package/output/ss0x00.com/_next/static/chunks/325.302a44b604c35f17.js +88 -0
  136. package/output/ss0x00.com/_next/static/chunks/328.e4a0307a4fddf318.js +248 -0
  137. package/output/ss0x00.com/_next/static/chunks/432.3621f17504ef18f2.js +443 -0
  138. package/output/ss0x00.com/_next/static/chunks/44.e90dd963003a3d43.js +1094 -0
  139. package/output/ss0x00.com/_next/static/chunks/442.8c054f100f9e5e50.js +1082 -0
  140. package/output/ss0x00.com/_next/static/chunks/460.f8db9a5142598e2c.js +466 -0
  141. package/output/ss0x00.com/_next/static/chunks/487.05ca55420459c002.js +78 -0
  142. package/output/ss0x00.com/_next/static/chunks/567.1909a6b0a920114b.js +1374 -0
  143. package/output/ss0x00.com/_next/static/chunks/586.802fc9214d87fb29.js +752 -0
  144. package/output/ss0x00.com/_next/static/chunks/620.a2a3a6b94d30a4c8.js +1037 -0
  145. package/output/ss0x00.com/_next/static/chunks/642.6b3e487c9604cbb8.js +1628 -0
  146. package/output/ss0x00.com/_next/static/chunks/673.e5d77887e5c6a68c.js +1045 -0
  147. package/output/ss0x00.com/_next/static/chunks/684.8b8e52baca70524b.js +96 -0
  148. package/output/ss0x00.com/_next/static/chunks/686.79480519e5ccfb77.js +296 -0
  149. package/output/ss0x00.com/_next/static/chunks/756.7a3878a2e6765be7.js +504 -0
  150. package/output/ss0x00.com/_next/static/chunks/761.7bea7516c5d22b2a.js +1485 -0
  151. package/output/ss0x00.com/_next/static/chunks/794.e079ef369b41a3c5.js +1350 -0
  152. package/output/ss0x00.com/_next/static/chunks/826.31ba213e1d023c68.js +1031 -0
  153. package/output/ss0x00.com/_next/static/chunks/847.d8397a73efc81848.js +1068 -0
  154. package/output/ss0x00.com/_next/static/chunks/848.5feaeee1e2624aea.js +132 -0
  155. package/output/ss0x00.com/_next/static/chunks/850.ecc7c3c3d787ee03.js +1472 -0
  156. package/output/ss0x00.com/_next/static/chunks/853.50b9eb60b7d0e83c.js +1472 -0
  157. package/output/ss0x00.com/_next/static/chunks/856.7a7bb6c3c7bfc2ba.js +1320 -0
  158. package/output/ss0x00.com/_next/static/chunks/859.df4bd45c03a65f53.js +1306 -0
  159. package/output/ss0x00.com/_next/static/chunks/867.e8633955a147c978.js +541 -0
  160. package/output/ss0x00.com/_next/static/chunks/921.c3123f20a4c8d53c.js +96 -0
  161. package/output/ss0x00.com/_next/static/chunks/932.25cb421c466c99cb.js +999 -0
  162. package/output/ss0x00.com/_next/static/chunks/framework-64ad27b21261a9ce.js +9189 -0
  163. package/output/ss0x00.com/_next/static/chunks/main-710ab85aa9a8f10d.js +6583 -0
  164. package/output/ss0x00.com/_next/static/chunks/pages/5D-af5a23529ce3c337.js +486 -0
  165. package/output/ss0x00.com/_next/static/chunks/pages/_app-c449865c8af1faa0.js +39 -0
  166. package/output/ss0x00.com/_next/static/chunks/polyfills-78c92fac7aa8fdd8.js +6383 -0
  167. package/output/ss0x00.com/_next/static/chunks/webpack-efff35ee26971294.js +271 -0
  168. package/output/ss0x00.com/_next/static/k7xKVnxmboK4SktY2dZWt/_buildManifest.js +8 -0
  169. package/output/ss0x00.com/_next/static/k7xKVnxmboK4SktY2dZWt/_ssgManifest.js +3 -0
  170. package/output/ss0x00.com/cdn-cgi/scripts/5c5dd728/cloudflare-static/email-decode.min.js +82 -0
  171. package/package.json +50 -38
  172. package/strings.json +7407 -0
  173. package/api_gateway/checkFeasibility.js +0 -25
  174. package/api_gateway/checkFireWallBlocking.js +0 -17
  175. package/api_gateway/genReq.js +0 -214
  176. package/api_gateway/index.js +0 -325
  177. package/endpoints/index.js +0 -7
  178. package/globalConfig.js +0 -12
  179. package/index.js +0 -69
  180. package/lazyLoad/downloadFilesUtil.js +0 -122
  181. package/lazyLoad/downloadLoadedJsUtil.js +0 -54
  182. package/lazyLoad/globals.js +0 -15
  183. package/lazyLoad/index.js +0 -167
  184. package/lazyLoad/next_js/next_GetJSScript.js +0 -99
  185. package/lazyLoad/next_js/next_GetLazyResources.js +0 -201
  186. package/lazyLoad/next_js/next_SubsequentRequests.js +0 -138
  187. package/lazyLoad/nuxt_js/nuxt_astParse.js +0 -194
  188. package/lazyLoad/nuxt_js/nuxt_getFromPageSource.js +0 -77
  189. package/lazyLoad/nuxt_js/nuxt_stringAnalysisJSFiles.js +0 -99
  190. package/research/firewall_bypass.md +0 -38
  191. package/research/next_js.md +0 -116
  192. package/research/nuxt_js.md +0 -125
  193. package/research/vue_js.md +0 -9
  194. package/strings/index.js +0 -145
  195. package/techDetect/index.js +0 -156
  196. package/utility/globals.js +0 -6
  197. package/utility/makeReq.js +0 -179
  198. package/utility/resolvePath.js +0 -43
@@ -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;
@@ -1,38 +0,0 @@
1
- # Firewall Bypass
2
- While the development of this tool, the tester came across several websites using firewall, majorly Cloudflare. A technique has to be developed to bypass this blockage, and to download the JS files.
3
-
4
- ## Cloudflare
5
- ### Detection
6
- Whenever the client is restricted by Cloudflare, it returns a HTML page with a JS challenge to be solved. However, the JS is can't be executed by Node.JS. It would need a browser environment. Sample HTML page is shown below:
7
-
8
- ```html
9
- <meta http-equiv="refresh"
10
- content="5; URL='/?bm-verify=--snip--'" />
11
- --snip--
12
- <script> var i = 1749580415; var j = i + Number("7341" + "47171"); </script>
13
- --snip--
14
- <script> var xhr = new XMLHttpRequest(); xhr.withCredentials = true; xhr.addEventListener("loadend", function () { try { var data = JSON.parse(xhr.responseText); if (data.hasOwnProperty('reload')) { if (data["reload"] == true) { window.location.replace(window.location.href.replace(/[&?]bm-verify=[^#]*/, "")); if (window.location.hash) { window.location.reload(); } } } else if (data.hasOwnProperty(--snip </script>
15
- ```
16
-
17
- ### Bypass
18
- #### #1
19
- The most common way to bypass this is to use a browser environment, such as a headless browser.
20
-
21
- To achive this task, a detection mechanism is added in the custom function to make HTTP requests. If CF is detected, it will load the page in a headless browser, and then return the content.
22
-
23
- #### #2
24
- Utilizing a browser plugin to fetch the contents is a more advanced way to bypass this. The user can install the plugin in their testing browser/proxy, and as they navigate the site, the plugin will get the contents and send then to the server for processing (it would be like a caching system).
25
-
26
- #### #3
27
- The `makeRequest()` can be modified to send headers that a browser would send. These include:
28
- - `User-Agent` of a browser
29
- - `Accept`
30
- - `Accept-Language`
31
- - `Sec-Fetch-Site: same-origin`
32
- - `Sec-Fetch-Mode: cors`
33
- - `Sec-Fetch-Dest: empty`
34
- - `Referer`
35
- - `Origin`
36
-
37
- #### #4
38
- Utilizing AWS API Gateway or similar services to rotate IP addresses can help in bypassing the firewall. This, however, could be blocked by the by CF if it is configured to block requests from AWS or similar ISPs.
@@ -1,116 +0,0 @@
1
- # Next.js Research
2
- ## Tech Detection
3
- To detect Next.js, following technique(s) can be used:
4
- - Iterate through all the HTML tags, and find `src`, `srcSet` or `imageSrcSet` attribute with value starting with`/_next/` in the page source
5
-
6
- ## Embedded JS files
7
- A lot of JS files were identified from the page source by inspecting the value of `src` attribute of `script` tags. These included files like `main.js`, `polyfills.js`, `webpack.js` etc.
8
-
9
- ## Lazy Loaded Files
10
- ### Analysis of [Vercel Docs](https://vercel.com/docs)
11
- Upon analysis of page source and HTTP requests, it was found that the webpack filename had a pattern of `webpack-<hash>.js`. So, webpack JS files were identified and fetched.
12
-
13
- Upon inspection of the webpack JS file, it was found that code was distributed into several functions. It was observed that the function responsible for returning the JS path ended with `".js"`. This observation was seen multiple times in the Next.js apps by the developer (aka web researcher), hence it bacame a standard method to get the path of the JS files.
14
-
15
- ### Analysis of [X.ai](https://x.ai)
16
- It was found that most of the things were done in a similar way, however, some extra chars were present after `".js"` in the function responsible for returning JS path in the webpack JS file.
17
-
18
- To handle this, the regex was modified to also include some additional characters at the end.
19
- ```js
20
- .match(/"\.js".{0,15}$/)
21
- ```
22
-
23
- Also, it was found that very less URLs were present in the `webpack.js` file (4 at the time of analysis). Upon further inspection, it was found that the URLs are present in the inline `<script>` tags returned in the page source. For example:
24
- ```
25
- self.__next_f.push([1,"14:I[41498,[\"3867\",\"static/chunks/b6d67c9f-618ea7c61a79562d.js\",\"5017\",\"static/chunks/622eaf3d-350d2142e11f9e13.js\",\"1889\",\"static/chunks/0fd4459a-4e25f772815e6f19.js\",\"4406\",\"static/chunks/4406-fdbbb31c90e98725.js\",\"8627\",\"static/chunks/8627-54829c23d6b1a53f.js\",\"6520\",\"static/chunks/6520-f51ddcfa4e30ebc8.js\",\"1296\",\"static/chunks/1296-b8c2dd03773a40db.js\",\"8922\",\"static/chunks/8922-f01acc4fc5fecfad.js\",\"6929\",\"static/chunks/6929-a636a59ffdb51b17.js\",\"2601\"......snip....../chunks/b6d67c9f-"])
26
- ```
27
-
28
- To handle this, a feature was implemented to get the JS files from the inline `<script>` tags as well.
29
-
30
- Upon researching further, it was found that additional JS files were being returned in the subsequent HTTP requests. For example, the file at `https://x.ai/_next/static/chunks/app/careers/page-9e04dce6fed05790.js` was loaded from a request to `https://x.ai/careers?_rsc=jwl50`.
31
-
32
- Request to `https://x.ai/careers?_rsc=jwl50` should be made with a special header called `RSC: 1` in order to get access to additional JS file paths. This request can be also sent to `/` with the same header to get more files.
33
-
34
- Possible solution: To handle this, the strings can be extracted from the page sources, and then requests to them can be made along with this request header. If it returns a `200 OK`, then it can be also added to the list of JS files.
35
-
36
- ### Analysis of [OpenAI](https://openai.com)
37
- Upon inspection of HTTP requests, a similar behavior of sending the requests with `RSC: 1` header to get additional JS files was found.
38
-
39
- However, a slight difference was found. When sending the request to `/business` with the same header, the server returned a different (`308 Permanent Redirect` to `/business/`) response. This can be handled by sending the request to `/business/` with the same header.
40
-
41
- Additionally, it was noticed that when the requests were sent without the `RSC: 1` header, the request got blocked by Cloudflare, and it resulted in a `403 Forbidden` response with a message `Just a moment...`. This could indicate a potential firewall bypass
42
-
43
- ## Client-Side Paths/URLs
44
- Client-side paths/URLs are web addresses handled by the browser using JavaScript, usually without reloading the page. They are used for navigation, API requests, and loading resources dynamically within the client environment.
45
-
46
- ### Analysis of [X.ai](https://x.ai)
47
- Upon inspection of the client side paths, it was found that they are present in `href` across JS chunks.
48
-
49
- These are a part of a list, which contains objects with keys like `href` (string), `label` (string), `active` (boolean) and `children` (array of objects of the same type).
50
-
51
- For instance, here's a example of such a list:
52
- ```js
53
- let L = [
54
- {
55
- href: "/grok",
56
- label: "Grok",
57
- active: e.startsWith("/grok"),
58
- children: [
59
- { href: "/grok", label: "For Everyone", active: "/grok" == e },
60
- {
61
- href: "/grok/business",
62
- label: "For Business",
63
- active: "/grok/business" == e,
64
- },
65
- ],
66
- },
67
- {
68
- href: "/api",
69
- label: "API",
70
- active: e.startsWith("/api"),
71
- children: [
72
- { href: "/api#capabilities", label: "Overview" },
73
- {
74
- href: "https://docs.x.ai/docs/models?cluster=us-east-1#detailed-pricing-for-all-grok-models",
75
- label: "Pricing",
76
- external: !0,
77
- },
78
- {
79
- href: "https://console.x.ai",
80
- label: "API Console Login",
81
- external: !0,
82
- },
83
- {
84
- href: "https://docs.x.ai",
85
- label: "Documentation",
86
- external: !0,
87
- },
88
- ],
89
- },
90
- { href: "/company", label: "Company", active: "/company" == e },
91
- { href: "/colossus", label: "Colossus", active: "/colossus" == e },
92
- {
93
- href: "/careers",
94
- label: "Careers",
95
- active: e.startsWith("/careers"),
96
- },
97
- { href: "/news", label: "News", active: e.startsWith("/news") },
98
- ]
99
- ```
100
-
101
- Possible methodology: The tool can iterate over all the JS chunks, and find the list of objects with keys like `href` (string), `label` (string), `active` (boolean) and `children` (array of objects of the same type). Then, it can organize them in a report.
102
-
103
- ### Analyis of [1Password](https://1password.com)
104
- It was found that the client-side paths were stored in mostly stored in a way like:
105
- ```js
106
- let s = JSON.parse(
107
- '["/state-of-enterprise-security-report/thank-you/",......"/webinars/1p-quarterly-security-spotlight-and-roadmap-review/thank-you/"]',
108
- )
109
- ```
110
-
111
- Some similar pattern was also observed in [OpenAI](https://openai.com), however, the full analysis of OpenAI's client-side paths is not done at the time of writing this.
112
-
113
- It was also found that some paths were stored directly as a list. For example:
114
- ```js
115
- let n = ["/pricing/xam", "/pricing/password-manager"];
116
- ```