Skip to content

Commit

Permalink
Merge branch 'dev' into github
Browse files Browse the repository at this point in the history
  • Loading branch information
ignis-sec committed Jul 5, 2020
2 parents 042f9f0 + 1a04116 commit f25c654
Show file tree
Hide file tree
Showing 10 changed files with 461 additions and 321 deletions.
123 changes: 123 additions & 0 deletions SingleUrlFuzzer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@

const {fail,succ,warn,info,gstart,bstart,ystart,rstart,colstop} = require('./pretty.js')
const fs = require('fs')
function replaceKeyword(url,pld){
pld = pld.replace(/ /g, '%20')
var t=url;
t = t.replace(/FUZZ/g,pld.replace(/\n|\r/g,''))
return t;

}


class SingleUrlFuzzer{
/*
* Fuzzer for when both wordlist and url parameter is supplied.
* Read url from the parameter, and read
*
*/
constructor(url,cbhandler, threadHandler, terminator, wordlist, verbose){
this.url = url
this.wlistFpointer=0;
this.cbHandler=cbhandler
this.terminator = terminator
this.verbose = verbose
this.threadHandler = threadHandler;
this.wordlist = wordlist;

//read wordlist
if(this.verbose) console.log(`${warn} Reading Wordlist`)
try{
this.wlistContent = fs.readFileSync(wordlist).toString().split("\n")
}catch(e){
console.log(`${fail} Wordlist file was not found`)
console.log(e)
process.exit(1)
}
if(this.verbose) console.log(`${succ} Wordlist loaded, ${this.wlistContent.length} lines.`)

}

async acquire(){
/*
* Acquire next url from wordlist
*/
this.wlistFpointer+=1
return this.wlistContent[this.wlistFpointer];
}

async checkFinished(){
/*
* Check if wordlist finished
*/

//if this thread is done
if(this.wlistFpointer>=this.wlistContent.length){
this.terminator.terminatedCount+=1
this.wlistFpointer+=1
if(this.verbose){
outputHandler.deleteLastLine()
console.log("Thread finished")
}

//Only terminate program if all the threads have finished, so it doesn't lose the progress on those pending requests.
if(this.terminator.terminatedCount==threadHandler.workerCount){
//TODO, timeout possible idle/stuck threads and terminate
if(this.verbose){
outputHandler.deleteLastLine()
outputHandler.write('Last url checked, waiting for all threads to finish')
}

this.terminator.terminate()
}
}
}

async loadNextUrl(thread){
/*
* Load next url from from the wordlist
*/
this.checkFinished()
var line = await this.acquire()
thread.url = await replaceKeyword(this.url, line)
thread.pld = line
this.processURL(thread,thread.url)
}


async processURL(thread, url){
/*
* Process url, visit, try to trigger events etc.
*/
try{
thread.goto(thread.url)

//capture window response
const response = await thread.waitForNavigation();

//acquire possible redirect chain
var chain = (response.request().redirectChain())

//get http response
thread.status = response.status();

//if there was a redirect chain, output it. If not, its a normal response
if(chain.length){
thread.wasHTTPRedirect = true;
this.cbHandler.catchRedirect(thread, chain)
}else{
this.cbHandler.catchNormal(thread)
}
}catch(e){
//Not properly implemented yet, dom-errors, http timeouts
this.cbHandler.catchLoadFailure(thread)
}

//recurses
this.loadNextUrl(thread)
}
}

module.exports = {
SingleUrlFuzzer:SingleUrlFuzzer
}
78 changes: 78 additions & 0 deletions callbacks.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@


const {fail,succ,warn,info,gstart,bstart,ystart,rstart,colstop} = require('./pretty.js')


class TriggerHandler{
/*
* This class contains and handles events triggered by the document.
* catchRedirect, catchRedirectJS, catchXSS, catchLoadFailure, catchNormal
*
*/
constructor(oHandler){
this.outputHandler = oHandler
}

catchRedirect(thread, chain){
this.outputHandler.write(`${ystart}[${thread.status}] [REDIRECT-HTTP] ${thread.url}${thread.pld}`)
for(var i=0;i<chain.length;i++){
this.outputHandler.write(` ${" ".repeat(i)}|--> ${chain[i].response().url()}`)
}
this.outputHandler.write(colstop)
this.outputHandler.bLastOutputImportant=true

}

//not implemented yet, lost when refactoring from electron to puppeteer
catchRedirectJS(thread, target){
return
if(thread.wasHTTPRedirect){
thread.wasHTTPRedirect=false;
return
}
initCallback('redirect-js')
this.outputHandler.write(`${bstart}[200] [REDIRECT-JS] ${thread.url}${thread.pld}`)
this.outputHandler.write(` |--> ${target}`)
this.outputHandler.write(colstop)

}


catchXSS(thread, href){
this.outputHandler.write(`${rstart}[${thread.id}][${200}] [XSS] ${thread.url} ${colstop}`)
this.outputHandler.bLastOutputImportant=true
pendingOutput.push({
url:thread.url,
payload:thread.pld
})

//xss windows tend to get load looped, but not sure if needed
//thread.evaluate(() => window.stop());
}

catchLoadFailure(thread){
this.outputHandler.write(`${bstart}[${thread.status}] [FAILURE] ${thread.pld} ${colstop}`, 5000)
this.outputHandler.bLastOutputImportant=true
}

catchNormal(thread){

if(thread.justRedirected){
thread.justRedirected=false
return
}
this.outputHandler.write(`${gstart}[${thread.id}][${thread.status}] ${colstop} ${thread.url}`)
if(thread.status==200){
this.outputHandler.bLastOutputImportant=false
}else{
if(status)this.outputHandler.bLastOutputImportant=true
else this.outputHandler.bLastOutputImportant=false
}
return
}
}


module.exports ={
TriggerHandler: TriggerHandler
}
38 changes: 38 additions & 0 deletions configwiz.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@

const path = require('path')
const fs = require('fs')
const glob = require('glob')
module.exports={

setChromePath: function(new_path){
/*
* Set the chrome path in the config.json file
*/
var conf_temp = require(path.join(__dirname,'/config.json'))
console.log("Chrome path changing from '" + conf_temp.chromium_path + "' to '" + new_path + "'")
conf_temp.chromium_path = new_path
fs.writeFileSync(path.join(__dirname,'/config.json'), JSON.stringify(conf_temp), 'utf8');
},

resolveChromiumPath: function(config){
/*
* Resolve wildcards in the chromium path.
* Also resolves keyword 'default'
* For now, default maps to '/node_modules/puppeteer/.local-chromium/*\/*\/chrome(.exe?)'
* If default keyword is used, resolved path will be written to the config file after calling.
*/
var chromium_path = '';
if(!config.chromium_path) config.chromium_path='default';
else if(config.chromium_path.includes('*')) chromium_path = glob.sync(config.chromium_path, {})[0];
else chromium_path = config.chromium_path;

if(chromium_path=='default'){//resolve default path
if(process.platform=='win32') chromium_path = glob.sync(path.join(__dirname, "/node_modules/puppeteer/.local-chromium/*/*/chrome.exe"))[0]
else chromium_path = glob.sync(path.join(__dirname, "/node_modules/puppeteer/.local-chromium/*/*/chrome"))[0]
config.chromium_path=chromium_path
fs.writeFileSync(path.join(__dirname,'/config.json'), JSON.stringify(config), 'utf8'); //NEEDS FIX // CAUSING TROUBLE FOR OSX
}
return chromium_path;
}

}
54 changes: 54 additions & 0 deletions io.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
//responsible for writing request output




class ResponseWriter{
/*
* This class is responsible for outputting the http request responses to the terminal.
*
*/
constructor(demo,oa){
this.bLastOutputImportant=true;
this.demo = demo;
this.oa=oa;
}

write(message, clamp=process.stdout.columns-2){
/*
* write the message, delete last line if it was marked not important.
* Clamp to the length of second parameter if passed.
*/

//if message is longer than the clamp length, clamp it and append ...
if(message.length >=clamp)
message = (message.substring(0, clamp - 3) + "...")

//if demo mode is activated, hide base url
if(this.demo){
message = message.replace(/http(s)?:\/\/.*?\//, "https://[REDACTED]/")
}

//output all mode, write every response, even normal ones
if(this.oa){
process.stdout.write("\n" + message)
}else{
//if last output wasn't registered as important, delete the last line
if(!this.bLastOutputImportant){
this.deleteLastLine(true)
process.stdout.write(message)
}else{
process.stdout.write("\n" + message)
}
}
}

deleteLastLine(force=false){
if(!force && this.bLastOutputImportant) return
process.stdout.write("\r\x1b[K")
}
}

module.exports ={
OutputHandler: ResponseWriter
}
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
{
"name": "puff-fuzz",
"version": "0.0.6",
"version": "0.1.0",
"description": "Simple Clientside vulnerability/xss fuzzer",
"main": "puff.js",
"repository":"https://github.com/FlameOfIgnis/puff/issues",
"repository": "https://github.com/FlameOfIgnis/puff",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
Expand Down
17 changes: 17 additions & 0 deletions pretty.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@



module.exports = {
/*
* Pretty output colors
*/
fail: "[\033[91m+\033[0m]",
succ: "[\033[92m+\033[0m]",
warn: "[\033[93m+\033[0m]",
info: "[\033[94m+\033[0m]",
gstart: "\033[92m",
bstart: "\033[94m",
ystart: "\033[93m",
rstart: "\033[91m",
colstop:"\033[0m"
}
Loading

0 comments on commit f25c654

Please sign in to comment.