@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.
Files changed (143) hide show
  1. package/.github/workflows/build-and-prettify.yaml +65 -0
  2. package/.github/workflows/npm-publish.yml +35 -0
  3. package/.prettierignore +2 -0
  4. package/.prettierrc +4 -0
  5. package/CHANGELOG.md +50 -0
  6. package/README.md +35 -139
  7. package/build/api_gateway/checkFeasibility.js +32 -0
  8. package/build/api_gateway/checkFeasibility.js.map +1 -0
  9. package/build/api_gateway/checkFireWallBlocking.js +24 -0
  10. package/build/api_gateway/checkFireWallBlocking.js.map +1 -0
  11. package/build/api_gateway/genReq.js +199 -0
  12. package/build/api_gateway/genReq.js.map +1 -0
  13. package/build/api_gateway/index.js +275 -0
  14. package/build/api_gateway/index.js.map +1 -0
  15. package/build/endpoints/gen_report/gen_json.js +22 -0
  16. package/build/endpoints/gen_report/gen_json.js.map +1 -0
  17. package/build/endpoints/gen_report/gen_markdown.js +66 -0
  18. package/build/endpoints/gen_report/gen_markdown.js.map +1 -0
  19. package/build/endpoints/gen_report/utility/iterate_n_store.js +46 -0
  20. package/build/endpoints/gen_report/utility/iterate_n_store.js.map +1 -0
  21. package/build/endpoints/index.js +89 -0
  22. package/build/endpoints/index.js.map +1 -0
  23. package/build/endpoints/next_js/client_jsFilesHref.js +91 -0
  24. package/build/endpoints/next_js/client_jsFilesHref.js.map +1 -0
  25. package/build/endpoints/next_js/client_jsonParse.js +78 -0
  26. package/build/endpoints/next_js/client_jsonParse.js.map +1 -0
  27. package/build/endpoints/next_js/client_subsequentRequests.js +199 -0
  28. package/build/endpoints/next_js/client_subsequentRequests.js.map +1 -0
  29. package/build/endpoints/next_js/getWebpacks.js +45 -0
  30. package/build/endpoints/next_js/getWebpacks.js.map +1 -0
  31. package/build/globalConfig.js +11 -0
  32. package/build/globalConfig.js.map +1 -0
  33. package/build/index.js +166 -0
  34. package/build/index.js.map +1 -0
  35. package/build/lazyLoad/downloadFilesUtil.js +128 -0
  36. package/build/lazyLoad/downloadFilesUtil.js.map +1 -0
  37. package/build/lazyLoad/downloadLoadedJsUtil.js +51 -0
  38. package/build/lazyLoad/downloadLoadedJsUtil.js.map +1 -0
  39. package/build/lazyLoad/globals.js +22 -0
  40. package/build/lazyLoad/globals.js.map +1 -0
  41. package/build/lazyLoad/index.js +170 -0
  42. package/build/lazyLoad/index.js.map +1 -0
  43. package/build/lazyLoad/next_js/next_GetJSScript.js +94 -0
  44. package/build/lazyLoad/next_js/next_GetJSScript.js.map +1 -0
  45. package/build/lazyLoad/next_js/next_GetLazyResources.js +202 -0
  46. package/build/lazyLoad/next_js/next_GetLazyResources.js.map +1 -0
  47. package/build/lazyLoad/next_js/next_SubsequentRequests.js +120 -0
  48. package/build/lazyLoad/next_js/next_SubsequentRequests.js.map +1 -0
  49. package/build/lazyLoad/nuxt_js/nuxt_astParse.js +188 -0
  50. package/build/lazyLoad/nuxt_js/nuxt_astParse.js.map +1 -0
  51. package/build/lazyLoad/nuxt_js/nuxt_getFromPageSource.js +75 -0
  52. package/build/lazyLoad/nuxt_js/nuxt_getFromPageSource.js.map +1 -0
  53. package/build/lazyLoad/nuxt_js/nuxt_stringAnalysisJSFiles.js +94 -0
  54. package/build/lazyLoad/nuxt_js/nuxt_stringAnalysisJSFiles.js.map +1 -0
  55. package/build/lazyLoad/svelte/svelte_getFromPageSource.js +68 -0
  56. package/build/lazyLoad/svelte/svelte_getFromPageSource.js.map +1 -0
  57. package/build/lazyLoad/svelte/svelte_stringAnalysisJSFiles.js +95 -0
  58. package/build/lazyLoad/svelte/svelte_stringAnalysisJSFiles.js.map +1 -0
  59. package/build/map/index.js +58 -0
  60. package/build/map/index.js.map +1 -0
  61. package/build/map/next_js/getFetchInstances.js +108 -0
  62. package/build/map/next_js/getFetchInstances.js.map +1 -0
  63. package/build/map/next_js/getWebpackConnections.js +227 -0
  64. package/build/map/next_js/getWebpackConnections.js.map +1 -0
  65. package/build/map/next_js/interactive.js +32 -0
  66. package/build/map/next_js/interactive.js.map +1 -0
  67. package/build/map/next_js/interactive_helpers/commandHandler.js +190 -0
  68. package/build/map/next_js/interactive_helpers/commandHandler.js.map +1 -0
  69. package/build/map/next_js/interactive_helpers/commandHelpers.js +91 -0
  70. package/build/map/next_js/interactive_helpers/commandHelpers.js.map +1 -0
  71. package/build/map/next_js/interactive_helpers/helpMenu.js +11 -0
  72. package/build/map/next_js/interactive_helpers/helpMenu.js.map +1 -0
  73. package/build/map/next_js/interactive_helpers/keybindings.js +80 -0
  74. package/build/map/next_js/interactive_helpers/keybindings.js.map +1 -0
  75. package/build/map/next_js/interactive_helpers/printer.js +17 -0
  76. package/build/map/next_js/interactive_helpers/printer.js.map +1 -0
  77. package/build/map/next_js/interactive_helpers/ui.js +81 -0
  78. package/build/map/next_js/interactive_helpers/ui.js.map +1 -0
  79. package/build/map/next_js/resolveFetch.js +201 -0
  80. package/build/map/next_js/resolveFetch.js.map +1 -0
  81. package/build/run/index.js +62 -0
  82. package/build/run/index.js.map +1 -0
  83. package/build/strings/index.js +238 -0
  84. package/build/strings/index.js.map +1 -0
  85. package/build/strings/openapi.js +55 -0
  86. package/build/strings/openapi.js.map +1 -0
  87. package/build/strings/permutate.js +55 -0
  88. package/build/strings/permutate.js.map +1 -0
  89. package/build/strings/secrets.js +89 -0
  90. package/build/strings/secrets.js.map +1 -0
  91. package/build/techDetect/index.js +229 -0
  92. package/build/techDetect/index.js.map +1 -0
  93. package/build/utility/ai.js +69 -0
  94. package/build/utility/ai.js.map +1 -0
  95. package/build/utility/globals.js +84 -0
  96. package/build/utility/globals.js.map +1 -0
  97. package/build/utility/interfaces.js +2 -0
  98. package/build/utility/interfaces.js.map +1 -0
  99. package/build/utility/makeReq.js +265 -0
  100. package/build/utility/makeReq.js.map +1 -0
  101. package/build/utility/resolvePath.js +44 -0
  102. package/build/utility/resolvePath.js.map +1 -0
  103. package/{utility → build/utility}/runSandboxed.js +10 -13
  104. package/build/utility/runSandboxed.js.map +1 -0
  105. package/{utility → build/utility}/urlUtils.js +9 -11
  106. package/build/utility/urlUtils.js.map +1 -0
  107. package/docs/CNAME +1 -0
  108. package/docs/README.md +20 -0
  109. package/docs/api-gateway.md +68 -0
  110. package/docs/endpoints.md +49 -0
  111. package/docs/example-scenario.md +258 -0
  112. package/docs/interactive-mode.md +76 -0
  113. package/docs/lazyload.md +56 -0
  114. package/docs/map.md +53 -0
  115. package/docs/run.md +54 -0
  116. package/docs/strings.md +75 -0
  117. package/package.json +50 -38
  118. package/api_gateway/checkFeasibility.js +0 -25
  119. package/api_gateway/checkFireWallBlocking.js +0 -17
  120. package/api_gateway/genReq.js +0 -214
  121. package/api_gateway/index.js +0 -325
  122. package/endpoints/index.js +0 -7
  123. package/globalConfig.js +0 -12
  124. package/index.js +0 -69
  125. package/lazyLoad/downloadFilesUtil.js +0 -122
  126. package/lazyLoad/downloadLoadedJsUtil.js +0 -54
  127. package/lazyLoad/globals.js +0 -15
  128. package/lazyLoad/index.js +0 -167
  129. package/lazyLoad/next_js/next_GetJSScript.js +0 -99
  130. package/lazyLoad/next_js/next_GetLazyResources.js +0 -201
  131. package/lazyLoad/next_js/next_SubsequentRequests.js +0 -138
  132. package/lazyLoad/nuxt_js/nuxt_astParse.js +0 -194
  133. package/lazyLoad/nuxt_js/nuxt_getFromPageSource.js +0 -77
  134. package/lazyLoad/nuxt_js/nuxt_stringAnalysisJSFiles.js +0 -99
  135. package/research/firewall_bypass.md +0 -38
  136. package/research/next_js.md +0 -116
  137. package/research/nuxt_js.md +0 -125
  138. package/research/vue_js.md +0 -9
  139. package/strings/index.js +0 -145
  140. package/techDetect/index.js +0 -156
  141. package/utility/globals.js +0 -6
  142. package/utility/makeReq.js +0 -179
  143. package/utility/resolvePath.js +0 -43
@@ -0,0 +1,65 @@
1
+ name: Build & Prettify Code
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - dev
7
+
8
+ jobs:
9
+ build:
10
+ runs-on: ubuntu-latest
11
+ steps:
12
+ - name: Checkout
13
+ uses: actions/checkout@v4
14
+ with:
15
+ # Make sure the action checks out the repository to the pull request branch
16
+ ref: ${{ github.ref_name }}
17
+
18
+ - name: Set up Node.js
19
+ uses: actions/setup-node@v4
20
+ with:
21
+ node-version: "22"
22
+ cache: "npm"
23
+ - name: Install dependencies
24
+ run: npm ci
25
+ - name: Build code
26
+ run: npm run build
27
+
28
+
29
+ prettier:
30
+ runs-on: ubuntu-latest
31
+ needs: build
32
+ permissions:
33
+ contents: write
34
+ steps:
35
+ - name: Checkout
36
+ uses: actions/checkout@v4
37
+ with:
38
+ # Make sure the action checks out the repository to the pull request branch
39
+ ref: ${{ github.ref_name }}
40
+
41
+ - name: Set up Node.js
42
+ uses: actions/setup-node@v4
43
+ with:
44
+ node-version: "22"
45
+ cache: "npm"
46
+
47
+ - name: Install dependencies
48
+ run: npm ci
49
+
50
+ - name: Install Prettier
51
+ run: npm install -g prettier
52
+
53
+ - name: Run Prettier
54
+ run: prettier --write . --tab-width 4 --trailing-comma es5 --no-color
55
+
56
+ - name: Remove node_modules
57
+ run: rm -rf node_modules
58
+
59
+ - name: Commit and push changes
60
+ run: |
61
+ git config user.name "prettier-action[bot]"
62
+ git config user.email "prettier-action[bot]@users.noreply.github.com"
63
+ git add .
64
+ git commit -m "chore: prettify code" || echo "No changes to commit"
65
+ git push
@@ -0,0 +1,35 @@
1
+ # This workflow will run tests using node and then publish a package to GitHub Packages when a release is created
2
+ # For more information see: https://docs.github.com/en/actions/publishing-packages/publishing-nodejs-packages
3
+
4
+ name: Node.js Package
5
+
6
+ on:
7
+ release:
8
+ types: [created]
9
+
10
+ jobs:
11
+ build:
12
+ runs-on: ubuntu-latest
13
+ steps:
14
+ - uses: actions/checkout@v4
15
+ - uses: actions/setup-node@v4
16
+ with:
17
+ node-version: 22
18
+ - run: npm ci
19
+ - run: npm run build
20
+ - run: npm run test
21
+
22
+ publish-npm:
23
+ needs: build
24
+ runs-on: ubuntu-latest
25
+ steps:
26
+ - uses: actions/checkout@v4
27
+ - uses: actions/setup-node@v4
28
+ with:
29
+ node-version: 22
30
+ registry-url: https://registry.npmjs.org/
31
+ - run: npm ci
32
+ - run: npm run build
33
+ - run: npm publish
34
+ env:
35
+ NODE_AUTH_TOKEN: ${{secrets.npm_token}}
@@ -0,0 +1,2 @@
1
+ .github/**
2
+ node_modules/**
package/.prettierrc ADDED
@@ -0,0 +1,4 @@
1
+ {
2
+ "tabWidth": 4,
3
+ "useTabs": false
4
+ }
package/CHANGELOG.md ADDED
@@ -0,0 +1,50 @@
1
+ # Change Log
2
+
3
+ ## 1.1.0-beta.2 - 2025.07.07
4
+
5
+ ### Added
6
+
7
+ ### Changed
8
+
9
+ ### Fixed
10
+
11
+ - Fix build errors (type errors)
12
+
13
+ ## 1.1.0-beta.1 - 2025.07.07
14
+
15
+ ### Added
16
+
17
+ - Svelte framework detection, and JS extraction
18
+ - JSON-based file cache
19
+ - Auto-approve executing JS code (`-y`/`--yes`)
20
+ - Added max threads for downloading JS files `-t`/`--threads`
21
+ - Add timeout handling and network idle check for page load in tech detection
22
+ - Parse script tags to extract additional JavaScript URLs from page
23
+ - Add secret scanning
24
+ - Add feasibility check to API gateway function
25
+ - Add endpoints module to support client-side path extraction
26
+ - Add subsequent-requests feature (`RSC: 1`) in Next.JS
27
+ - Add map module
28
+ - Webpack chunk parsing
29
+ - Interactive mode
30
+ - `fetch()` detection
31
+ - Permutation in `strings` module
32
+ - OpenAI and Ollama integration for AI descriptions
33
+
34
+ ### Changed
35
+
36
+ ### Fixed
37
+
38
+ - Standardize UTF-8 encoding and improve URL path handling in lazy load module
39
+
40
+ ## 1.0.0 - 2025.06.18
41
+
42
+ ### Added
43
+
44
+ - Lazy Load Support for Next.js and Nuxt.js
45
+ - JavaScript String Extraction from downloaded JS files
46
+ - API Gateway Proxying to rotate IP addresses
47
+
48
+ ### Changed
49
+
50
+ ### Fixed
package/README.md CHANGED
@@ -1,166 +1,62 @@
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
12
2
 
13
- JS Recon Tool
3
+ ![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)
14
4
 
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
- ```
5
+ 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
46
6
 
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
- ```
7
+ ## Installation
61
8
 
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
- ```
9
+ 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
10
 
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
- ```
11
+ To install the tool globally, run:
89
12
 
90
- For example, you can try this with [Vercel Docs](https://vercel.com/docs):
91
13
  ```bash
92
- js-recon lazyload -u https://vercel.com/docs
14
+ npm i -g @shriyanss/js-recon
93
15
  ```
94
16
 
95
- Currently, the following JS frameworks are supported:
96
- - Next.js (read research [here](research/next_js.md))
17
+ ## Quick Start
97
18
 
98
- ### Extract strings from JS files
99
- You can extract strings from JS files. To do so, you can run the following command
100
19
  ```bash
101
- js-recon strings -d <directory> -o <output>
102
- ```
103
-
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
107
- ```
108
-
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)*
20
+ # Get a list of all commands
21
+ js-recon --help
112
22
 
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
- ```bash
115
- js-recon lazyload -u <url> -o <output> --strict-scope -t 1
23
+ # Get help for a specific command
24
+ js-recon <command> --help
116
25
  ```
117
26
 
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
- ```
27
+ To launch a quick assesment against a target, the `run` module can be used to automate other modules
122
28
 
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
29
  ```bash
125
- js-recon endpoints -u <url> -o <output> --strict-scope -t 1 --subsequent-requests
30
+ js-recon run -u https://app.example.com
126
31
  ```
127
32
 
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.
33
+ ## Commands
130
34
 
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.
35
+ `js-recon` provides a suite of commands for comprehensive JavaScript analysis. For detailed usage and examples, please refer to its full documentation.
136
36
 
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.
37
+ **_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._**
138
38
 
139
- The user can list the API gateways generated by running the following command:
140
- ```bash
141
- js-recon api-gateway -l
142
- ```
39
+ | Command | Description | Documentation |
40
+ | ------------- | ----------------------------------------------------------------------------- | ---------------------------------- |
41
+ | `lazyload` | Downloads dynamically loaded JavaScript files from a target. | [Read Docs](./docs/lazyload.md) |
42
+ | `endpoints` | Extracts API endpoints and client-side paths from JS files. | [Read Docs](./docs/endpoints.md) |
43
+ | `strings` | Extracts strings, URLs, and potential secrets from JS files. | [Read Docs](./docs/strings.md) |
44
+ | `map` | Maps function calls and analyzes code, with optional AI-powered descriptions. | [Read Docs](./docs/map.md) |
45
+ | `api-gateway` | Manages AWS API Gateway for IP rotation to bypass rate limits. | [Read Docs](./docs/api-gateway.md) |
46
+ | `run` | Runs all analysis modules automatically on a target. | [Read Docs](./docs/run.md) |
143
47
 
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.
48
+ ## Key Features
145
49
 
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
- ```
50
+ - Downloads all dynamically loaded JS files (refered as `lazyload`) from website with supported frameworks
51
+ - Use API gateway to rotate IP addresses to bypass firewall
52
+ - Extract strings from the discovered JS files, and extract potential secrets, endpoints, etc. from them
53
+ - Endpoints modules extracts client-side paths from the app
54
+ - Map feature analyzes the JS files, and outputs it to a JSON file. An interactive mode can be then used to analyze it
150
55
 
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.
56
+ ## Example Scenario
152
57
 
153
- For example,
154
- ```bash
155
- js-recon lazyload -u <url> -o <output> --api-gateway
156
- ```
58
+ Refer to [this page](./docs/example-scenario.md) where an example scenario of running this tool against a target is demonstrated.
157
59
 
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
- ```
60
+ ## Documentation
162
61
 
163
- Alternatively, they can delete all the API gateways using the following command:
164
- ```bash
165
- js-recon api-gateway --destroy-all
166
- ```
62
+ 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,199 @@
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
+ });
105
+ const newMethodResponse = yield client.send(newMethodCommand);
106
+ yield sleep(100);
107
+ // create new integration
108
+ const newIntegrationCommand = new PutIntegrationCommand({
109
+ restApiId: config[apiGateway].id,
110
+ resourceId: newResourceResponse.id,
111
+ httpMethod: "GET",
112
+ integrationHttpMethod: "GET",
113
+ type: "HTTP",
114
+ timeoutInMillis: 29000,
115
+ uri: url,
116
+ });
117
+ const newIntegrationResponse = yield client.send(newIntegrationCommand);
118
+ yield sleep(100);
119
+ // create a new method response
120
+ const newMethodResponseCommand = new PutMethodResponseCommand({
121
+ httpMethod: "GET",
122
+ resourceId: newResourceResponse.id,
123
+ restApiId: config[apiGateway].id,
124
+ statusCode: "200",
125
+ });
126
+ const newMethodResponseResponse = yield client.send(newMethodResponseCommand);
127
+ yield sleep(100);
128
+ // put integration response
129
+ const putIntegrationResponseCommand = new PutIntegrationResponseCommand({
130
+ httpMethod: "GET",
131
+ resourceId: newResourceResponse.id,
132
+ restApiId: config[apiGateway].id,
133
+ statusCode: "200",
134
+ });
135
+ const putIntegrationResponseResponse = yield client.send(putIntegrationResponseCommand);
136
+ yield sleep(100);
137
+ }
138
+ // Generate dynamic stage name
139
+ // const dynamicStageName = `prod-${Date.now()}-${Math.random().toString(36).substring(2, 7)}`;
140
+ // console.log(chalk.blue(`[*] Using dynamic stage name: ${dynamicStageName}`));
141
+ // Create a deployment
142
+ // const createDeploymentCommand = new CreateDeploymentCommand({
143
+ // restApiId: config[apiGateway].id,
144
+ // stageName: dynamicStageName,
145
+ // description: `Deployment for ${url} at ${new Date().toISOString()} to stage ${dynamicStageName}`,
146
+ // });
147
+ // const deploymentResponse = await client.send(createDeploymentCommand);
148
+ // console.log(chalk.green("[+] Deployment created:"), deploymentResponse.id);
149
+ // await sleep(100);
150
+ const testInvokeMethodQuery = new TestInvokeMethodCommand({
151
+ httpMethod: "GET",
152
+ resourceId: newResourceResponse.id,
153
+ restApiId: config[apiGateway].id,
154
+ headers: headers || {},
155
+ });
156
+ const testInvokeMethodResponse = yield client.send(testInvokeMethodQuery);
157
+ yield sleep(100);
158
+ const body = yield testInvokeMethodResponse.body;
159
+ // check if any firewall is there in the way
160
+ const isFireWallBlocking = yield checkFireWallBlocking(body);
161
+ // delete the resource
162
+ const deleteResourceCommand = new DeleteResourceCommand({
163
+ restApiId: config[apiGateway].id,
164
+ resourceId: newResourceResponse.id,
165
+ });
166
+ try {
167
+ yield client.send(deleteResourceCommand);
168
+ }
169
+ catch (err) {
170
+ console.error(chalk.red(`[!] Error when sending delete resource command to AWS: ${err}`));
171
+ }
172
+ if (isFireWallBlocking) {
173
+ console.log(chalk.magenta("[!] Please try again without API Gateway"));
174
+ process.exit(1);
175
+ }
176
+ return body;
177
+ // create a new stage
178
+ // dynamicStageName = `prod-${Date.now()}-${Math.random().toString(36).substring(2, 7)}`;
179
+ // const newStageCommand = new CreateStageCommand({
180
+ // restApiId: config[apiGateway].id,
181
+ // stageName: dynamicStageName, // Use dynamic stage name
182
+ // deploymentId: deploymentResponse.id, // Use the ID from the deployment
183
+ // cacheClusterEnabled: false,
184
+ // // cacheClusterSize: "0", // Removed as cacheClusterEnabled is false
185
+ // methodSettings: [
186
+ // {
187
+ // httpMethod: "*",
188
+ // // resourceId: "*", // This might need to be more specific if you don't want it for all resources
189
+ // throttlingBurstLimit: 5,
190
+ // throttlingRateLimit: 10,
191
+ // },
192
+ // ],
193
+ // });
194
+ // const newStageResponse = await client.send(newStageCommand);
195
+ // await sleep(100);
196
+ // console.log(newStageResponse);
197
+ });
198
+ export { get };
199
+ //# 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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"}