@@ -8,57 +8,27 @@ import chalk from "chalk";
88import CONFIG from "../globalConfig.js" ;
99import analyze from "../analyze/index.js" ;
1010import report from "../report/index.js" ;
11+ import { clearJsUrls , clearJsonUrls } from "../lazyLoad/globals.js" ;
1112
12- export default async ( cmd ) => {
13- globalsUtil . setApiGatewayConfigFile ( cmd . apiGatewayConfig ) ;
14- globalsUtil . setUseApiGateway ( cmd . apiGateway ) ;
15- globalsUtil . setDisableCache ( cmd . disableCache ) ;
16- globalsUtil . setRespCacheFile ( cmd . cacheFile ) ;
17- globalsUtil . setYes ( cmd . yes ) ;
13+ const processUrl = async ( url , outputDir , workingDir , cmd , isBatch ) => {
14+ const targetHost = new URL ( url ) . host . replace ( ":" , "_" ) ;
1815
19- // check if the given URL is a file
20- if ( fs . existsSync ( cmd . url ) ) {
21- console . log ( chalk . red ( `[!] Please provide a single URL. Parsing a list of URLs isn't available` ) ) ;
22- console . log (
23- chalk . yellow (
24- `To run the tool against, a list of targets, pass the file in '-u' flag of 'lazyload' module, and it will download the JS files`
25- )
26- ) ;
27- return ;
28- }
16+ console . log ( chalk . bgGreenBright ( `[+] Starting analysis for ${ url } ...` ) ) ;
2917
30- // check if output directory exists. If so, ask the user to switch to other directory
31- // if not done, it might conflict this process
32- // for devs: run `npm run cleanup` to prepare this directory
33- if ( fs . existsSync ( cmd . output ) ) {
34- console . log (
35- chalk . red (
36- `[!] Output directory ${ cmd . output } already exists. Please switch to other directory or it might conflict with this process.`
37- )
38- ) ;
39- console . log (
40- chalk . yellow (
41- `[i] For advanced users: use the individual modules separately. See docs at ${ CONFIG . modulesDocs } `
42- )
43- ) ;
44- return ;
18+ if ( isBatch ) {
19+ clearJsUrls ( ) ;
20+ clearJsonUrls ( ) ;
4521 }
4622
47- const targetHost = new URL ( cmd . url ) . host . replace ( ":" , "_" ) ;
48-
49- console . log ( chalk . bgGreenBright ( "[+] Starting analysis..." ) ) ;
50-
5123 console . log ( chalk . bgCyan ( "[1/8] Running lazyload to download JavaScript files..." ) ) ;
52- await lazyLoad ( cmd . url , cmd . output , cmd . strictScope , cmd . scope . split ( "," ) , cmd . threads , false , "" , cmd . insecure ) ;
24+ await lazyLoad ( url , outputDir , cmd . strictScope , cmd . scope . split ( "," ) , cmd . threads , false , "" , cmd . insecure ) ;
5325 console . log ( chalk . bgGreen ( "[+] Lazyload complete." ) ) ;
5426
55- // if tech is undefined, i.e. it can't be detected, quit. Nothing to be done :(
5627 if ( globalsUtil . getTech ( ) === "" ) {
5728 console . log ( chalk . bgRed ( "[!] Technology not detected. Quitting." ) ) ;
5829 return ;
5930 }
6031
61- // since the app only supports next.js now, move ahead only if the tech is next
6232 if ( globalsUtil . getTech ( ) !== "next" ) {
6333 console . log (
6434 chalk . bgYellow (
@@ -68,57 +38,141 @@ export default async (cmd) => {
6838 return ;
6939 }
7040
71- // run strings
41+ const stringsFile = isBatch ? `${ workingDir } /strings.json` : "strings.json" ;
42+ const extractedUrlsFile = isBatch ? `${ workingDir } /extracted_urls` : "extracted_urls" ;
43+ const mappedFile = isBatch ? `${ workingDir } /mapped` : "mapped" ;
44+ const mappedJsonFile = isBatch ? `${ workingDir } /mapped.json` : "mapped.json" ;
45+ const endpointsFile = isBatch ? `${ workingDir } /endpoints` : "endpoints" ;
46+ const openapiFile = isBatch ? `${ workingDir } /mapped-openapi.json` : "mapped-openapi.json" ;
47+ const analyzeFile = isBatch ? `${ workingDir } /analyze.json` : "analyze.json" ;
48+ const reportDbFile = isBatch ? `${ workingDir } /js-recon.db` : "js-recon.db" ;
49+ const reportFile = isBatch ? `${ workingDir } /report` : "report" ;
50+
7251 console . log ( chalk . bgCyan ( "[2/8] Running strings to extract endpoints..." ) ) ;
73- await strings ( cmd . output , "strings.json" , true , "extracted_urls" , false , false , false ) ;
52+ await strings ( outputDir , stringsFile , true , extractedUrlsFile , false , false , false ) ;
7453 console . log ( chalk . bgGreen ( "[+] Strings complete." ) ) ;
7554
76- // run lazyload with subsequent requests
7755 console . log ( chalk . bgCyan ( "[3/8] Running lazyload with subsequent requests to download JavaScript files..." ) ) ;
7856 await lazyLoad (
79- cmd . url ,
80- cmd . output ,
57+ url ,
58+ outputDir ,
8159 cmd . strictScope ,
8260 cmd . scope . split ( "," ) ,
8361 cmd . threads ,
8462 true ,
85- "extracted_urls .json" ,
63+ ` ${ extractedUrlsFile } .json` ,
8664 cmd . insecure
8765 ) ;
8866 console . log ( chalk . bgGreen ( "[+] Lazyload with subsequent requests complete." ) ) ;
8967
90- // run strings again to extract endpoints from the files that are downloaded in the previous step
9168 console . log ( chalk . bgCyan ( "[4/8] Running strings again to extract endpoints..." ) ) ;
92- await strings ( cmd . output , "strings.json" , true , "extracted_urls" , cmd . secrets , true , true ) ;
69+ await strings ( outputDir , stringsFile , true , extractedUrlsFile , cmd . secrets , true , true ) ;
9370 console . log ( chalk . bgGreen ( "[+] Strings complete." ) ) ;
9471
95- // now, run map
9672 console . log ( chalk . bgCyan ( "[5/8] Running map to find functions..." ) ) ;
9773 globalsUtil . setOpenapi ( true ) ;
98- await map ( cmd . output + "/" + targetHost , "mapped" , [ "json" ] , globalsUtil . getTech ( ) , false , false ) ;
74+ if ( isBatch ) {
75+ globalsUtil . setOpenapiOutputFile ( openapiFile ) ;
76+ }
77+ await map ( outputDir + "/" + targetHost , mappedFile , [ "json" ] , globalsUtil . getTech ( ) , false , false ) ;
9978 console . log ( chalk . bgGreen ( "[+] Map complete." ) ) ;
10079
101- // now, run endpoints
10280 console . log ( chalk . bgCyan ( "[6/8] Running endpoints to extract endpoints..." ) ) ;
103- // check if the subsequent requests directory exists
104- if ( fs . existsSync ( `${ cmd . output } /${ targetHost } /___subsequent_requests` ) ) {
105- await endpoints ( cmd . url , `${ cmd . output } /${ targetHost } /` , "endpoints" , [ "json" ] , "next" , false , "mapped.json" ) ;
81+ if ( fs . existsSync ( `${ outputDir } /${ targetHost } /___subsequent_requests` ) ) {
82+ await endpoints ( url , `${ outputDir } /${ targetHost } /` , endpointsFile , [ "json" ] , "next" , false , mappedJsonFile ) ;
10683 } else {
107- await endpoints ( cmd . url , undefined , "endpoints" , [ "json" ] , "next" , false , "mapped.json" ) ;
84+ await endpoints ( url , undefined , endpointsFile , [ "json" ] , "next" , false , mappedJsonFile ) ;
10885 }
10986 console . log ( chalk . bgGreen ( "[+] Endpoints complete." ) ) ;
11087
111- // run the analyze module now
11288 console . log ( chalk . bgCyan ( "[7/8] Running analyze to extract endpoints..." ) ) ;
113- // since the thirs argument is tech, and it can't be "all", so adding type ignore
11489 // @ts -ignore
115- await analyze ( "" , "mapped.json" , globalsUtil . getTech ( ) , false , "mapped-openapi.json" , false , "analyze.json" ) ;
90+ await analyze ( "" , mappedJsonFile , globalsUtil . getTech ( ) , false , openapiFile , false , analyzeFile ) ;
11691 console . log ( chalk . bgGreen ( "[+] Analyze complete." ) ) ;
11792
118- // run the report module now
11993 console . log ( chalk . bgCyan ( "[8/8] Running report module..." ) ) ;
120- await report ( "js-recon.db" , "mapped.json" , "analyze.json" , "endpoints .json" , "mapped-openapi.json" , "report" ) ;
94+ await report ( reportDbFile , mappedJsonFile , analyzeFile , ` ${ endpointsFile } .json` , openapiFile , reportFile ) ;
12195 console . log ( chalk . bgGreen ( "[+] Report complete." ) ) ;
12296
123- console . log ( chalk . bgGreenBright ( "[+] Analysis complete." ) ) ;
97+ console . log ( chalk . bgGreenBright ( `[+] Analysis complete for ${ url } .` ) ) ;
98+ } ;
99+
100+ export default async ( cmd ) => {
101+ globalsUtil . setApiGatewayConfigFile ( cmd . apiGatewayConfig ) ;
102+ globalsUtil . setUseApiGateway ( cmd . apiGateway ) ;
103+ globalsUtil . setDisableCache ( cmd . disableCache ) ;
104+ globalsUtil . setRespCacheFile ( cmd . cacheFile ) ;
105+ globalsUtil . setYes ( cmd . yes ) ;
106+
107+ // check if the given URL is a file
108+ if ( ! fs . existsSync ( cmd . url ) ) {
109+ // check if output directory exists. If so, ask the user to switch to other directory
110+ // if not done, it might conflict this process
111+ // for devs: run `npm run cleanup` to prepare this directory
112+ if ( fs . existsSync ( cmd . output ) ) {
113+ console . log (
114+ chalk . red (
115+ `[!] Output directory ${ cmd . output } already exists. Please switch to other directory or it might conflict with this process.`
116+ )
117+ ) ;
118+ console . log (
119+ chalk . yellow (
120+ `[i] For advanced users: use the individual modules separately. See docs at ${ CONFIG . modulesDocs } `
121+ )
122+ ) ;
123+ return ;
124+ }
125+
126+ let urlTest = new URL ( cmd . url ) ;
127+ if ( ! urlTest ) {
128+ console . log ( chalk . red ( "[!] Invalid URL" ) ) ;
129+ return ;
130+ }
131+
132+ await processUrl ( cmd . url , cmd . output , "." , cmd , false ) ;
133+ } else {
134+ // since this is a file, we need to first load the URLs in the memory remove empty strings
135+ const urls = fs
136+ . readFileSync ( cmd . url , "utf-8" )
137+ . split ( "\n" )
138+ . filter ( ( url ) => url !== "" ) ;
139+
140+ // iterate through the URLs, and make sure they are valid URLs
141+ let allPassed = true ;
142+ for ( const url of urls ) {
143+ try {
144+ let urlTest = new URL ( url ) ;
145+ } catch ( e ) {
146+ console . log ( chalk . red ( `[!] Invalid URL: ${ url } ` ) ) ;
147+ allPassed = false ;
148+ }
149+ }
150+ if ( ! allPassed ) {
151+ return ;
152+ }
153+
154+ // first of all, make a new directory for the tool output
155+ const toolOutputDir = "js_recon_run_output" ;
156+ if ( fs . existsSync ( toolOutputDir ) ) {
157+ console . log (
158+ chalk . red (
159+ `[!] Output directory ${ toolOutputDir } already exists. Please switch to other directory or it might conflict with this process.`
160+ )
161+ ) ;
162+ console . log (
163+ chalk . yellow (
164+ `[i] For advanced users: use the individual modules separately. See docs at ${ CONFIG . modulesDocs } `
165+ )
166+ ) ;
167+ return ;
168+ }
169+ fs . mkdirSync ( toolOutputDir ) ;
170+
171+ for ( const url of urls ) {
172+ const thisTargetWorkingDir = toolOutputDir + "/" + new URL ( url ) . host . replace ( ":" , "_" ) ;
173+ fs . mkdirSync ( thisTargetWorkingDir ) ;
174+ const outputDir = thisTargetWorkingDir + "/output" ;
175+ await processUrl ( url , outputDir , thisTargetWorkingDir , cmd , true ) ;
176+ }
177+ }
124178} ;
0 commit comments