@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
@@ -0,0 +1,27 @@
1
+ {
2
+ // Use IntelliSense to learn about possible attributes.
3
+ // Hover to view descriptions of existing attributes.
4
+ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5
+ "version": "0.2.0",
6
+ "configurations": [
7
+ {
8
+ "type": "node",
9
+ "request": "launch",
10
+ "name": "Launch Program",
11
+ "skipFiles": [
12
+ "<node_internals>/**"
13
+ ],
14
+ "program": "${workspaceFolder}/build/index.js",
15
+ "outFiles": [
16
+ "${workspaceFolder}/build/**/*.js"
17
+ ],
18
+ "args": [
19
+ "map",
20
+ "-d",
21
+ "output/ss0x00.com",
22
+ "-t",
23
+ "next"
24
+ ]
25
+ }
26
+ ]
27
+ }
package/CHANGELOG.md ADDED
@@ -0,0 +1,40 @@
1
+ # Change Log
2
+
3
+ ## 1.1.0-beta.1 - 2025.07.07
4
+
5
+ ### Added
6
+
7
+ - Svelte framework detection, and JS extraction
8
+ - JSON-based file cache
9
+ - Auto-approve executing JS code (`-y`/`--yes`)
10
+ - Added max threads for downloading JS files `-t`/`--threads`
11
+ - Add timeout handling and network idle check for page load in tech detection
12
+ - Parse script tags to extract additional JavaScript URLs from page
13
+ - Add secret scanning
14
+ - Add feasibility check to API gateway function
15
+ - Add endpoints module to support client-side path extraction
16
+ - Add subsequent-requests feature (`RSC: 1`) in Next.JS
17
+ - Add map module
18
+ - Webpack chunk parsing
19
+ - Interactive mode
20
+ - `fetch()` detection
21
+ - Permutation in `strings` module
22
+ - OpenAI and Ollama integration for AI descriptions
23
+
24
+ ### Changed
25
+
26
+ ### Fixed
27
+
28
+ - Standardize UTF-8 encoding and improve URL path handling in lazy load module
29
+
30
+ ## 1.0.0 - 2025.06.18
31
+
32
+ ### Added
33
+
34
+ - Lazy Load Support for Next.js and Nuxt.js
35
+ - JavaScript String Extraction from downloaded JS files
36
+ - API Gateway Proxying to rotate IP addresses
37
+
38
+ ### Changed
39
+
40
+ ### Fixed
package/README.md CHANGED
@@ -1,166 +1,61 @@
1
- # js-recon
2
- ## Installation
3
- To install the tool, run:
4
- ```bash
5
- npm i -g @shriyanss/js-recon
6
- ```
7
-
8
- ## Usage
9
- ```
10
- $ js-recon -h
11
- Usage: js-recon [options] [command]
1
+ # JS Recon
2
+ ![NPM Licence](https://img.shields.io/npm/l/%40shriyanss%2Fjs-recon) ![GitHub repo size](https://img.shields.io/github/repo-size/shriyanss/js-recon) ![NPM Downloads](https://img.shields.io/npm/dm/%40shriyanss%2Fjs-recon) ![GitHub commit activity (dev)](https://img.shields.io/github/commit-activity/w/shriyanss/js-recon/dev) ![NPM Last Update](https://img.shields.io/npm/last-update/%40shriyanss%2Fjs-recon) ![CodeRabbit Pull Request Reviews](https://img.shields.io/coderabbit/prs/github/shriyanss/js-recon)
12
3
 
13
- JS Recon Tool
4
+ A powerful tool for JavaScript reconnaissance. `js-recon` helps you discover, download, and analyze JavaScript files to uncover endpoints, secrets, and other valuable information from any web application running supported frameworks
14
5
 
15
- Options:
16
- -V, --version output the version number
17
- -h, --help display help for command
18
-
19
- Commands:
20
- lazyload [options] Run lazy load module
21
- endpoints [options] Extract API endpoints
22
- strings [options] Extract strings from JS files
23
- api-gateway [options] Configure AWS API Gateway to rotate IP addresses
24
- help [command] display help for command
25
- ```
26
-
27
- ### Lazy load
28
- ```
29
- $ js-recon lazyload -h
30
- Usage: js-recon lazyload [options]
31
-
32
- Run lazy load module
33
-
34
- Options:
35
- -u, --url <url/file> Target URL or a file containing a list of URLs (one per line)
36
- -o, --output <directory> Output directory (default: "output")
37
- --strict-scope Download JS files from only the input URL domain (default: false)
38
- -s, --scope <scope> Download JS files from specific domains (comma-separated) (default: "*")
39
- -t, --threads <threads> Number of threads to use (default: 1)
40
- --subsequent-requests Download JS files from subsequent requests (default: false)
41
- --urls-file <file> Input JSON file containing URLs (default: "extracted_urls.json")
42
- --api-gateway Generate requests using API Gateway (default: false)
43
- --api-gateway-config <file> API Gateway config file (default: ".api_gateway_config.json")
44
- -h, --help display help for command
45
- ```
46
-
47
- ### Strings
48
- ```
49
- $ js-recon strings -h
50
- Usage: js-recon strings [options]
51
-
52
- Extract strings from JS files
53
-
54
- Options:
55
- -d, --directory <directory> Directory containing JS files
56
- -o, --output <file> JSON file to save the strings (default: "strings.json")
57
- -e, --extract-urls Extract URLs from strings (default: false)
58
- --extracted-url-path <file> Output JSON file for extracted URLs and paths (default: "extracted_urls.json")
59
- -h, --help display help for command
60
- ```
6
+ ## Installation
61
7
 
62
- ### API Gateway
63
- ```
64
- $ js-recon api-gateway -h
65
- Usage: js-recon api-gateway [options]
66
-
67
- Configure AWS API Gateway to rotate IP addresses
68
-
69
- Options:
70
- -i, --init Initialize the config file (create API) (default: false)
71
- -d, --destroy <id> Destroy API with the given ID
72
- --destroy-all Destroy all the API created by this tool in all regions (default: false)
73
- -r, --region <region> AWS region (default: random region)
74
- -a, --access-key <access-key> AWS access key (if not provided, AWS_ACCESS_KEY_ID environment variable will be used)
75
- -s, --secret-key <secret-key> AWS secret key (if not provided, AWS_SECRET_ACCESS_KEY environment variable will be used)
76
- -c, --config <config> Name of the config file (default: ".api_gateway_config.json")
77
- -l, --list List all the API created by this tool (default: false)
78
- --feasibility Check feasibility of API Gateway (default: false)
79
- --feasibility-url <url> URL to check feasibility of
80
- -h, --help display help for command
81
- ```
8
+ This tool requires Node.JS and `npm` to be installed. The [official download page](https://nodejs.org/en/download) can be referred. Please install **22.17.0 (LTS)** or later. Downloading older versions might break the tool.
82
9
 
83
- ## Features
84
- ### Download lazy loaded JS files
85
- You can download the lazy loaded files. To do so, you can run the following command
86
- ```bash
87
- js-recon lazyload -u <url> -o <output>
88
- ```
10
+ To install the tool globally, run:
89
11
 
90
- For example, you can try this with [Vercel Docs](https://vercel.com/docs):
91
12
  ```bash
92
- js-recon lazyload -u https://vercel.com/docs
13
+ npm i -g @shriyanss/js-recon
93
14
  ```
94
15
 
95
- Currently, the following JS frameworks are supported:
96
- - Next.js (read research [here](research/next_js.md))
16
+ ## Quick Start
97
17
 
98
- ### Extract strings from JS files
99
- You can extract strings from JS files. To do so, you can run the following command
100
18
  ```bash
101
- js-recon strings -d <directory> -o <output>
102
- ```
19
+ # Get a list of all commands
20
+ js-recon --help
103
21
 
104
- For example, you can try this with [1Password](https://1password.com):
105
- ```bash
106
- js-recon strings -d output/1password.com -o strings.json
22
+ # Get help for a specific command
23
+ js-recon <command> --help
107
24
  ```
108
25
 
109
- ## Examples
110
- ### Get all possible JS files for a Next.js app
111
- *You can read the full research for the same [here](research/next_js.md#lazy-loaded-files)*
26
+ To launch a quick assesment against a target, the `run` module can be used to automate other modules
112
27
 
113
- First of all, run the lazy load module (strict scope and 1 thread for accurate results) [research1](research/next_js.md#analysis-of-vercel-docs):
114
28
  ```bash
115
- js-recon lazyload -u <url> -o <output> --strict-scope -t 1
29
+ js-recon run -u https://app.example.com
116
30
  ```
117
31
 
118
- Then, get all the strings from the JS files found. Also, extract URLs and paths found in those JS files.:
119
- ```bash
120
- js-recon strings -d <directory> -o <output> -e
121
- ```
32
+ ## Commands
122
33
 
123
- Finally, parse those URLs and paths to get more JS files (note the `--subsequent-requests` flag apart from `--strict-scope` and `--threads`) [research](research/next_js.md#analysis-of-xai):
124
- ```bash
125
- js-recon endpoints -u <url> -o <output> --strict-scope -t 1 --subsequent-requests
126
- ```
34
+ `js-recon` provides a suite of commands for comprehensive JavaScript analysis. For detailed usage and examples, please refer to its full documentation.
127
35
 
128
- ### Use AWS API Gateway to rotate IP address on each request
129
- First of all, the user has to configure the API keys for AWS with right permissions to use the API Gateway module of the tool. The access key and the secret key can be stored in the environment variables `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` respectively. Alternatively, these can be provided as command line argument to the tool.
36
+ **_The `lazyload` module will work on Next.JS, Nuxt.JS, and Svelte apps. All other modules are only expected to work on Next.JS apps._**
130
37
 
131
- Once this is done, the configuration file can be generated. The configuration file is a JSON file that contains the API Gateway information, including the API Gateway ID, region, access key, and secret key. This file is used by the tool in the runtime. The configuration file can be generated by running the following command:
132
- ```bash
133
- js-recon api-gateway -i -r <region> -a <access-key> -s <secret-key>
134
- ```
135
- If the region is not provided, the tool will select a random region from a pre-defined list. If the `-a` and `-s` flags aren't provided, it will default to the environment variables `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` respectively.
38
+ | Command | Description | Documentation |
39
+ | ------------- | ----------------------------------------------------------------------------- | ---------------------------------- |
40
+ | `lazyload` | Downloads dynamically loaded JavaScript files from a target. | [Read Docs](./docs/lazyload.md) |
41
+ | `endpoints` | Extracts API endpoints and client-side paths from JS files. | [Read Docs](./docs/endpoints.md) |
42
+ | `strings` | Extracts strings, URLs, and potential secrets from JS files. | [Read Docs](./docs/strings.md) |
43
+ | `map` | Maps function calls and analyzes code, with optional AI-powered descriptions. | [Read Docs](./docs/map.md) |
44
+ | `api-gateway` | Manages AWS API Gateway for IP rotation to bypass rate limits. | [Read Docs](./docs/api-gateway.md) |
45
+ | `run` | Runs all analysis modules automatically on a target. | [Read Docs](./docs/run.md) |
136
46
 
137
- This command will generate a new API gateway in the specified region, which can be inspected on the AWS console. The API gateway ID will be stored in the configuration file. The configuration file can be found at `./.api_gateway_config.json` by default.
47
+ ## Key Features
138
48
 
139
- The user can list the API gateways generated by running the following command:
140
- ```bash
141
- js-recon api-gateway -l
142
- ```
49
+ - Downloads all dynamically loaded JS files (refered as `lazyload`) from website with supported frameworks
50
+ - Use API gateway to rotate IP addresses to bypass firewall
51
+ - Extract strings from the discovered JS files, and extract potential secrets, endpoints, etc. from them
52
+ - Endpoints modules extracts client-side paths from the app
53
+ - Map feature analyzes the JS files, and outputs it to a JSON file. An interactive mode can be then used to analyze it
143
54
 
144
- The user can generate as many API gateways as they want. The tool will automatically select a random API gateway from the configuration file to make requests to. Creating multiple gateways in different region can help in changing the region of the IP address on each request, however, **creating multiple gateways in the same region is not recommended** as AG will rotate the IP address on each request.
55
+ ## Example Scenario
145
56
 
146
- It is recommended to check if the firewall is blocking the requests from the API gateway. The user can do so by running the following command:
147
- ```bash
148
- js-recon api-gateway --feasibility --feasibility-url <url>
149
- ```
150
-
151
- Next, the API gateway can be utilized for rotating the IP address on each request. To do so, the user can add the `--api-gateway` flag to the lazy load module. The user can also provide the API gateway config file using the `--api-gateway-config` flag if they have changed the defaults.
152
-
153
- For example,
154
- ```bash
155
- js-recon lazyload -u <url> -o <output> --api-gateway
156
- ```
57
+ Refer to [this page](./docs/example-scenario.md) where an example scenario of running this tool against a target is demonstrated.
157
58
 
158
- Now that the user has completed their task, they can delete the API gateway using the following command:
159
- ```bash
160
- js-recon api-gateway -d <api-gateway-id>
161
- ```
59
+ ## Documentation
162
60
 
163
- Alternatively, they can delete all the API gateways using the following command:
164
- ```bash
165
- js-recon api-gateway --destroy-all
166
- ```
61
+ For detailed guides, command options, and advanced usage examples, please check out the **[full documentation here](./docs/README.md)**.
@@ -0,0 +1,32 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import { get } from "./genReq.js";
11
+ import chalk from "chalk";
12
+ import checkFireWallBlocking from "./checkFireWallBlocking.js";
13
+ const checkFeasibility = (url) => __awaiter(void 0, void 0, void 0, function* () {
14
+ console.log(chalk.cyan(`[i] Checking feasibility of API Gateway with ${url}`));
15
+ try {
16
+ // send 10 requests, and check if any of those contain any signs of blocking
17
+ for (let i = 0; i < 10; i++) {
18
+ const response = yield get(url);
19
+ const isFireWallBlocking = yield checkFireWallBlocking(response);
20
+ if (isFireWallBlocking) {
21
+ console.log(chalk.magenta("[!] Please try again without API Gateway"));
22
+ return;
23
+ }
24
+ }
25
+ console.log(chalk.green("[✓] Feasibility check passed."), chalk.dim("However, this doesn't represent the true nature of the firewall used."));
26
+ }
27
+ catch (error) {
28
+ console.log(chalk.red(`[!] An error occured in feasibility check: ${error}`));
29
+ }
30
+ });
31
+ export default checkFeasibility;
32
+ //# sourceMappingURL=checkFeasibility.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"checkFeasibility.js","sourceRoot":"","sources":["../../src/api_gateway/checkFeasibility.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAClC,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,qBAAqB,MAAM,4BAA4B,CAAC;AAE/D,MAAM,gBAAgB,GAAG,CAAO,GAAG,EAAE,EAAE;IACnC,OAAO,CAAC,GAAG,CACP,KAAK,CAAC,IAAI,CAAC,gDAAgD,GAAG,EAAE,CAAC,CACpE,CAAC;IACF,IAAI,CAAC;QACD,4EAA4E;QAC5E,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC;YAC1B,MAAM,QAAQ,GAAG,MAAM,GAAG,CAAC,GAAG,CAAC,CAAC;YAChC,MAAM,kBAAkB,GAAG,MAAM,qBAAqB,CAAC,QAAQ,CAAC,CAAC;YACjE,IAAI,kBAAkB,EAAE,CAAC;gBACrB,OAAO,CAAC,GAAG,CACP,KAAK,CAAC,OAAO,CAAC,0CAA0C,CAAC,CAC5D,CAAC;gBACF,OAAO;YACX,CAAC;QACL,CAAC;QACD,OAAO,CAAC,GAAG,CACP,KAAK,CAAC,KAAK,CAAC,+BAA+B,CAAC,EAC5C,KAAK,CAAC,GAAG,CACL,uEAAuE,CAC1E,CACJ,CAAC;IACN,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACb,OAAO,CAAC,GAAG,CACP,KAAK,CAAC,GAAG,CAAC,8CAA8C,KAAK,EAAE,CAAC,CACnE,CAAC;IACN,CAAC;AACL,CAAC,CAAA,CAAC;AAEF,eAAe,gBAAgB,CAAC"}
@@ -0,0 +1,24 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import chalk from "chalk";
11
+ const checkFireWallBlocking = (body) => __awaiter(void 0, void 0, void 0, function* () {
12
+ // check common signs of CF first
13
+ if (body.includes("<title>Just a moment...</title>")) {
14
+ console.log(chalk.red("[!] Cloudflare detected"));
15
+ return true;
16
+ }
17
+ else if (body.includes("<title>Attention Required! | Cloudflare</title>")) {
18
+ console.log(chalk.red("[!] Cloudflare detected"));
19
+ return true;
20
+ }
21
+ return false;
22
+ });
23
+ export default checkFireWallBlocking;
24
+ //# sourceMappingURL=checkFireWallBlocking.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"checkFireWallBlocking.js","sourceRoot":"","sources":["../../src/api_gateway/checkFireWallBlocking.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,MAAM,qBAAqB,GAAG,CAAO,IAAY,EAAoB,EAAE;IACnE,iCAAiC;IACjC,IAAI,IAAI,CAAC,QAAQ,CAAC,iCAAiC,CAAC,EAAE,CAAC;QACnD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,yBAAyB,CAAC,CAAC,CAAC;QAClD,OAAO,IAAI,CAAC;IAChB,CAAC;SAAM,IACH,IAAI,CAAC,QAAQ,CAAC,iDAAiD,CAAC,EAClE,CAAC;QACC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,yBAAyB,CAAC,CAAC,CAAC;QAClD,OAAO,IAAI,CAAC;IAChB,CAAC;IAED,OAAO,KAAK,CAAC;AACjB,CAAC,CAAA,CAAC;AAEF,eAAe,qBAAqB,CAAC"}
@@ -0,0 +1,202 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import { APIGatewayClient, CreateResourceCommand, GetResourcesCommand, PutMethodCommand, PutIntegrationCommand,
11
+ // CreateDeploymentCommand,
12
+ // CreateStageCommand,
13
+ PutIntegrationResponseCommand, PutMethodResponseCommand, TestInvokeMethodCommand, DeleteResourceCommand, } from "@aws-sdk/client-api-gateway";
14
+ import fs from "fs";
15
+ import md5 from "md5";
16
+ import chalk from "chalk";
17
+ import * as globals from "../utility/globals.js";
18
+ import checkFireWallBlocking from "./checkFireWallBlocking.js";
19
+ const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
20
+ /**
21
+ * Given a URL, generates a new API Gateway for it and returns the response of the URL.
22
+ * @param {string} url The URL to generate an API Gateway for.
23
+ * @param {object} [headers] The headers to include in the request.
24
+ * @returns {Promise<string>} The response of the URL.
25
+ */
26
+ const get = (url_1, ...args_1) => __awaiter(void 0, [url_1, ...args_1], void 0, function* (url, headers = {}) {
27
+ // read the config file
28
+ // Load and parse API Gateway config with error handling
29
+ let config;
30
+ try {
31
+ config = JSON.parse(fs.readFileSync(globals.apiGatewayConfigFile, "utf8"));
32
+ }
33
+ catch (error) {
34
+ throw new Error(`Failed to read or parse API Gateway config file: ${error.message}`);
35
+ }
36
+ // select a random api gateway
37
+ let apiGateway = Object.keys(config)[Math.floor(Math.random() * Object.keys(config).length)];
38
+ const client = new APIGatewayClient({
39
+ region: config[apiGateway].region,
40
+ credentials: {
41
+ accessKeyId: config[apiGateway].access_key,
42
+ secretAccessKey: config[apiGateway].secret_key,
43
+ },
44
+ });
45
+ // get the root resource id
46
+ const getResourceCommand = new GetResourcesCommand({
47
+ restApiId: config[apiGateway].id,
48
+ limit: 999999999,
49
+ });
50
+ const getResourceResponse = yield client.send(getResourceCommand);
51
+ yield sleep(200);
52
+ // before creating a resource, check if the resource already exists
53
+ const resourceExists = getResourceResponse.items.find(
54
+ // file deepcode ignore InsecureHash: False positive
55
+ (item) => item.pathPart === md5(url));
56
+ let newResourceResponse;
57
+ if (resourceExists) {
58
+ // console.log(chalk.yellow("[!] Resource already exists"));
59
+ newResourceResponse = {
60
+ id: resourceExists.id,
61
+ };
62
+ }
63
+ else {
64
+ // create a new resource
65
+ let rootId;
66
+ if (getResourceResponse.items.find((item) => item.path === "/")) {
67
+ rootId = getResourceResponse.items.find((item) => item.path === "/").id;
68
+ }
69
+ else {
70
+ rootId = getResourceResponse.items[0].parentId;
71
+ }
72
+ const newResourceCommand = new CreateResourceCommand({
73
+ restApiId: config[apiGateway].id,
74
+ parentId: rootId,
75
+ pathPart: md5(url), // md5 of the url
76
+ });
77
+ newResourceResponse = yield client.send(newResourceCommand);
78
+ yield sleep(200);
79
+ // add a new method
80
+ const newMethodCommand = new PutMethodCommand({
81
+ restApiId: config[apiGateway].id,
82
+ resourceId: newResourceResponse.id,
83
+ httpMethod: "GET",
84
+ authorizationType: "NONE",
85
+ requestParameters: {
86
+ "method.request.header.RSC": false,
87
+ "method.request.header.User-Agent": false,
88
+ "method.request.header.Referer": false,
89
+ "method.request.header.Accept": false,
90
+ "method.request.header.Accept-Language": false,
91
+ "method.request.header.Accept-Encoding": false,
92
+ "method.request.header.Content-Type": false,
93
+ "method.request.header.Content-Length": false,
94
+ "method.request.header.Origin": false,
95
+ "method.request.header.X-Forwarded-For": false,
96
+ "method.request.header.X-Forwarded-Host": false,
97
+ "method.request.header.X-IP": false,
98
+ "method.request.header.X-Forwarded-Proto": false,
99
+ "method.request.header.X-Forwarded-Port": false,
100
+ "method.request.header.Sec-Fetch-Site": false,
101
+ "method.request.header.Sec-Fetch-Mode": false,
102
+ "method.request.header.Sec-Fetch-Dest": false,
103
+ },
104
+ integrationHttpMethod: "GET",
105
+ type: "HTTP",
106
+ timeoutInMillis: 29000,
107
+ });
108
+ const newMethodResponse = yield client.send(newMethodCommand);
109
+ yield sleep(100);
110
+ // create new integration
111
+ const newIntegrationCommand = new PutIntegrationCommand({
112
+ restApiId: config[apiGateway].id,
113
+ resourceId: newResourceResponse.id,
114
+ httpMethod: "GET",
115
+ integrationHttpMethod: "GET",
116
+ type: "HTTP",
117
+ timeoutInMillis: 29000,
118
+ uri: url,
119
+ });
120
+ const newIntegrationResponse = yield client.send(newIntegrationCommand);
121
+ yield sleep(100);
122
+ // create a new method response
123
+ const newMethodResponseCommand = new PutMethodResponseCommand({
124
+ httpMethod: "GET",
125
+ resourceId: newResourceResponse.id,
126
+ restApiId: config[apiGateway].id,
127
+ statusCode: "200",
128
+ });
129
+ const newMethodResponseResponse = yield client.send(newMethodResponseCommand);
130
+ yield sleep(100);
131
+ // put integration response
132
+ const putIntegrationResponseCommand = new PutIntegrationResponseCommand({
133
+ httpMethod: "GET",
134
+ resourceId: newResourceResponse.id,
135
+ restApiId: config[apiGateway].id,
136
+ statusCode: "200",
137
+ });
138
+ const putIntegrationResponseResponse = yield client.send(putIntegrationResponseCommand);
139
+ yield sleep(100);
140
+ }
141
+ // Generate dynamic stage name
142
+ // const dynamicStageName = `prod-${Date.now()}-${Math.random().toString(36).substring(2, 7)}`;
143
+ // console.log(chalk.blue(`[*] Using dynamic stage name: ${dynamicStageName}`));
144
+ // Create a deployment
145
+ // const createDeploymentCommand = new CreateDeploymentCommand({
146
+ // restApiId: config[apiGateway].id,
147
+ // stageName: dynamicStageName,
148
+ // description: `Deployment for ${url} at ${new Date().toISOString()} to stage ${dynamicStageName}`,
149
+ // });
150
+ // const deploymentResponse = await client.send(createDeploymentCommand);
151
+ // console.log(chalk.green("[+] Deployment created:"), deploymentResponse.id);
152
+ // await sleep(100);
153
+ const testInvokeMethodQuery = new TestInvokeMethodCommand({
154
+ httpMethod: "GET",
155
+ resourceId: newResourceResponse.id,
156
+ restApiId: config[apiGateway].id,
157
+ headers: headers || {},
158
+ });
159
+ const testInvokeMethodResponse = yield client.send(testInvokeMethodQuery);
160
+ yield sleep(100);
161
+ const body = yield testInvokeMethodResponse.body;
162
+ // check if any firewall is there in the way
163
+ const isFireWallBlocking = yield checkFireWallBlocking(body);
164
+ // delete the resource
165
+ const deleteResourceCommand = new DeleteResourceCommand({
166
+ restApiId: config[apiGateway].id,
167
+ resourceId: newResourceResponse.id,
168
+ });
169
+ try {
170
+ yield client.send(deleteResourceCommand);
171
+ }
172
+ catch (err) {
173
+ console.error(chalk.red(`[!] Error when sending delete resource command to AWS: ${err}`));
174
+ }
175
+ if (isFireWallBlocking) {
176
+ console.log(chalk.magenta("[!] Please try again without API Gateway"));
177
+ process.exit(1);
178
+ }
179
+ return body;
180
+ // create a new stage
181
+ // dynamicStageName = `prod-${Date.now()}-${Math.random().toString(36).substring(2, 7)}`;
182
+ // const newStageCommand = new CreateStageCommand({
183
+ // restApiId: config[apiGateway].id,
184
+ // stageName: dynamicStageName, // Use dynamic stage name
185
+ // deploymentId: deploymentResponse.id, // Use the ID from the deployment
186
+ // cacheClusterEnabled: false,
187
+ // // cacheClusterSize: "0", // Removed as cacheClusterEnabled is false
188
+ // methodSettings: [
189
+ // {
190
+ // httpMethod: "*",
191
+ // // resourceId: "*", // This might need to be more specific if you don't want it for all resources
192
+ // throttlingBurstLimit: 5,
193
+ // throttlingRateLimit: 10,
194
+ // },
195
+ // ],
196
+ // });
197
+ // const newStageResponse = await client.send(newStageCommand);
198
+ // await sleep(100);
199
+ // console.log(newStageResponse);
200
+ });
201
+ export { get };
202
+ //# sourceMappingURL=genReq.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"genReq.js","sourceRoot":"","sources":["../../src/api_gateway/genReq.ts"],"names":[],"mappings":"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"}