Skip to content

Commit f4c7bc4

Browse files
author
Marshall Lee Whittaker
committed
Initial commit.
0 parents commit f4c7bc4

File tree

10 files changed

+761
-0
lines changed

10 files changed

+761
-0
lines changed

LICENSE

Lines changed: 373 additions & 0 deletions
Large diffs are not rendered by default.

META-INF/manifest.mf

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
Manifest-Version: 1.0
2+
3+
Name: background.js
4+
Digest-Algorithms: MD5 SHA1 SHA256
5+
MD5-Digest: TP4S/BKQ1rWVYGRndhS2GA==
6+
SHA1-Digest: PCB97/Xkw75jDRhh0/2qXHEgNJM=
7+
SHA256-Digest: UvtG1GoFnRC2ZP1kcHtqQrQ9RANZuZ1AiP1CKDsY14E=
8+
9+
Name: clipboard-helper.js
10+
Digest-Algorithms: MD5 SHA1 SHA256
11+
MD5-Digest: tDFPztbqrF9ar9pR+aNm2g==
12+
SHA1-Digest: 39zXoXLRg2nZTruOlwjg5YwJ2FY=
13+
SHA256-Digest: axFhQX62MwNPnO8C9NClAveznGo1nYItAylvSTaTqDk=
14+
15+
Name: manifest.json
16+
Digest-Algorithms: MD5 SHA1 SHA256
17+
MD5-Digest: CoVNfHtG/hLZ1Ybd5m/a7g==
18+
SHA1-Digest: yTzLs8wi4Pxbbz4qEW7Z49IeWGM=
19+
SHA256-Digest: odUIevfgY1aTVweTRWmP0Da7qVFJUkXScUADXldYP/E=
20+
21+
Name: options.html
22+
Digest-Algorithms: MD5 SHA1 SHA256
23+
MD5-Digest: WlF6qQXvxJ4FeMG7eq/HzQ==
24+
SHA1-Digest: gffYdrKNKX6UHgSh7BqYYl0jK9I=
25+
SHA256-Digest: cO8Z3SYWD3SXBfmrPyRxtiXvnxY9VQjqhra8YU2gg9Q=
26+
27+
Name: options.js
28+
Digest-Algorithms: MD5 SHA1 SHA256
29+
MD5-Digest: Eudt0sct2Z8Kl2+lugNNNw==
30+
SHA1-Digest: mBy4IrKcyHWlHu1Fg/AF0kSrpEc=
31+
SHA256-Digest: MOrFbOKiab85MzFeDlucreD9fcI71hjQw6iIU1ZAYYE=
32+
33+
Name: README.md
34+
Digest-Algorithms: MD5 SHA1 SHA256
35+
MD5-Digest: TD6YsrFf1Eu5RqGdwnRGYA==
36+
SHA1-Digest: jAOgm/tfT9HqVS6siLTGX4vTq+Y=
37+
SHA256-Digest: PQlm6a4LrHUV0EcJtBIxGfD23ipPaGuQ1uFasLfAHHA=
38+
39+
Name: LICENSE
40+
Digest-Algorithms: MD5 SHA1 SHA256
41+
MD5-Digest: l0HDRu71YTEWPhO52xJBsw==
42+
SHA1-Digest: 0iFXq8D8C0rpY4DAlSjiPPdykKk=
43+
SHA256-Digest: HyVuytGSiAUQ6ErWBHTqt1iSGHhLmlC8fO7jTCuR8dU=
44+

META-INF/mozilla.rsa

4.24 KB
Binary file not shown.

META-INF/mozilla.sf

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Signature-Version: 1.0
2+
MD5-Digest-Manifest: f6AwJD0h0gVG9YEXiu9rlg==
3+
SHA1-Digest-Manifest: +sm5rqNMR8VbkyQ4qLW+9N4B5ug=
4+
SHA256-Digest-Manifest: 4N6wvE74sfZ1y+K2DhEgeWmpR+BPA81IBch96QaKirU=
5+

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
#sqlmap helper
2+
This is an extension for firefox to help generate sqlmap commands for web exploitation.

background.js

Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
/* Written by oxagast. Edited some things from mycliget to get this to work. */
2+
3+
/*
4+
* V: 0.0.9 - 3/25/2019
5+
*/
6+
7+
/*
8+
* clipboard function originated with mozilla webextension examples here:
9+
* https://github.com/mdn/webextensions-examples
10+
*/
11+
12+
13+
var quotesOption = false;
14+
var programOption = 'curl';
15+
var fileOption = 'auto';
16+
var verboseOption = false;
17+
var headers = '';
18+
var sqlmapheaders = '';
19+
var snackbarOption = false;
20+
var trigger;
21+
22+
23+
//Right click context adds for links + audio/video
24+
browser.contextMenus.create({
25+
id: "copy-link-to-clipboard",
26+
title: "Copy SQLMap command to clipboard",
27+
contexts: ["link"]
28+
});
29+
browser.contextMenus.create({
30+
id: "copy-media-to-clipboard",
31+
title: "Copy SQLMap command to clipboard",
32+
contexts: ['video', 'audio']
33+
});
34+
35+
//basic promisified xmlhttpreq, will be stopped at building the request
36+
let ajaxGet = (obj) => {
37+
return new Promise((resolve, reject) => {
38+
let xhr = new XMLHttpRequest();
39+
xhr.timeout = 5000;
40+
xhr.open(obj.method || "GET", obj.url);
41+
if (obj.headers) {
42+
Object.keys(obj.headers).forEach(key => {
43+
xhr.setRequestHeader(key, obj.headers[key]);
44+
});
45+
}
46+
xhr.send(obj.body || '');
47+
resolve(true);
48+
});
49+
};
50+
51+
// callback for onBeforeSendHeaders listener.
52+
// Returns a promise and adds cancel request to the xmlhttpreq
53+
// trigger now looped into main promise.all
54+
let getHeaders = (e) => {
55+
headers = '';
56+
sqlmapheaders = '';
57+
for (let header of e.requestHeaders) {
58+
sqlmapheaders += " --header '" + header.name + ": " + header.value + "'";
59+
}
60+
//console.log('headers: ' + headers.toString());
61+
62+
63+
var asyncCancel = new Promise((resolve, reject) => {
64+
resolve({cancel: true});
65+
});
66+
trigger(true);
67+
return asyncCancel;
68+
};
69+
70+
// main command builder function
71+
function assembleCmd(url, referUrl) {
72+
let sqlmapText = "sqlmap.py"; // sqlmap command holder
73+
if (verboseOption) {sqlmapText += " -v 4"; }
74+
// ######################################################################
75+
// use remote suggested filename, how safe is this? also only available in moderately up to date
76+
// ## replacement for -O -J, same security issues though, make optional
77+
// ## this version will accept filename or location header
78+
// curl -s -D - "$url" -o /dev/null | grep -i "filename\|Location" | (IFS= read -r spo; sec=$(echo ${spo//*\//filename=}); echo ${sec#*filename=});
79+
// ######################################################################
80+
81+
82+
sqlmapText += sqlmapheaders;
83+
try {
84+
if (sqlmapUserOption.replace(/\s/g,'')) { sqlmapText += " " + sqlmapUserOption; }
85+
}
86+
catch (e) {
87+
//ignore empty user option text inputs
88+
}
89+
sqlmapText += " -u '" + url + "'";
90+
91+
92+
93+
if (quotesOption) {
94+
sqlmapText = wgetText.replace(/'/g,'"');
95+
}
96+
const sqlmapCode = "copyToClipboard(" + JSON.stringify(sqlmapText) + ", " + snackbarOption + ");";
97+
98+
switch (programOption) {
99+
case "sqlmap":
100+
return (sqlmapCode);
101+
break;
102+
}
103+
//return (programOption === "curl") ? curlCode : wgetCode;
104+
};
105+
106+
function copyCommand(code, tab) {
107+
browser.tabs.executeScript({
108+
code: "typeof copyToClipboard === 'function';",
109+
}).then((results) => {
110+
// The content script's last expression will be true if the function
111+
// has been defined. If this is not the case, then we need to run
112+
// clipboard-helper.js to define function copyToClipboard.
113+
if (!results || results[0] !== true) {
114+
return browser.tabs.executeScript(tab.id, {
115+
file: "clipboard-helper.js",
116+
});
117+
}
118+
}).then(() => {
119+
return browser.tabs.executeScript(tab.id, {
120+
code,
121+
});
122+
}).catch((error) => {
123+
// This could happen if the extension is not allowed to run code in
124+
// the page, for example if the tab is a privileged page.
125+
console.error("Failed : " + error);
126+
});
127+
};
128+
129+
browser.contextMenus.onClicked.addListener((info, tab) => {
130+
131+
let url = (info.menuItemId === 'copy-media-to-clipboard') ? info.srcUrl : info.linkUrl
132+
let referUrl = info.pageUrl;
133+
let cleanedUrl = '';
134+
135+
let gettingHeaders = new Promise(function(resolve, reject) {trigger = resolve;});
136+
137+
// basic port num strip for certain urls
138+
// TODO more robust sanitize of url for match pattern
139+
if (RegExp('//').test(url)) {
140+
let temp = url.split('/');
141+
temp[2] = temp[2].replace(/:[0-9]+/, '');
142+
cleanedUrl = temp.join('/');
143+
}
144+
145+
// add onbeforesendheaders listener for clicked url
146+
browser.webRequest.onBeforeSendHeaders.addListener(
147+
getHeaders, {urls: [cleanedUrl]}, ["blocking","requestHeaders"]);
148+
149+
// workaround for xmlhttpget firing before addlistener is complete
150+
let gettingHtml = new Promise (function(resolve,reject) {
151+
setTimeout(function(){
152+
resolve(ajaxGet({url: url}));
153+
}, 1);
154+
});
155+
156+
// check the saved options each click in case they changed
157+
let gettingOptions = browser.storage.sync.get(
158+
['quotes','prog','file','filename','ratelimit','verbose','resume','wgetUser','curlUser', 'sqlmapUser', 'snackbar'])
159+
.then((res) => {
160+
quotesOption = res.quotes;
161+
programOption = res.prog;
162+
fileOption = res.file;
163+
filenameOption = res.filename;
164+
verboseOption = res.verbose;
165+
sqlmapUserOption = res.sqlmapUser;
166+
snackbarOption = res.snackbar;
167+
});
168+
let promiseCancel = new Promise(function(resolve,reject) {
169+
setTimeout(function() {
170+
reject(false);
171+
},2000);
172+
});
173+
174+
// 2s timeout if somehow the request was not caught on the
175+
// header generation.
176+
let cancelled = Promise.race([promiseCancel, gettingHeaders]);
177+
178+
// loop all requesite async functions into promise.all
179+
Promise.all([gettingOptions,gettingHtml,cancelled]).then(() => {
180+
let code = assembleCmd(url, referUrl);
181+
copyCommand(code,tab);
182+
183+
browser.webRequest.onBeforeSendHeaders.removeListener(getHeaders);
184+
},
185+
() => {
186+
// reset listener on reject
187+
browser.webRequest.onBeforeSendHeaders.removeListener(getHeaders);
188+
});
189+
190+
191+
});
192+

clipboard-helper.js

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// This function must be called in a visible page, such as a browserAction popup
2+
// or a content script. Calling it in a background page has no effect!
3+
function copyToClipboard(text, show) {
4+
function oncopy(event) {
5+
document.removeEventListener("copy", oncopy, true);
6+
// Hide the event from the page to prevent tampering.
7+
event.stopImmediatePropagation();
8+
9+
// Overwrite the clipboard content.
10+
event.preventDefault();
11+
event.clipboardData.setData("text/plain", text);
12+
13+
if (show == true) {
14+
var mydiv = document.getElementById('addon-clg-snackbar');
15+
// check for existing snackbar, if not found add stylesheet and bar
16+
if (!mydiv) {
17+
// push snackbar style into document
18+
var style = document.createElement('style');
19+
style.type = 'text/css';
20+
style.innerHTML = '.clg-snackbar { visibility: visible; min-width: 200px; background-color: #333; \
21+
border-style:solid; border-color: black; animation: fadeinout 3s ease-out forwards; \
22+
color: #fff; text-align: center; border-radius: 2px; padding: 16px; position: fixed; \
23+
z-index: 10000; left: 50%; bottom: 30px; } \
24+
@keyframes fadeinout { \
25+
0%,100% { opacity: 0; } \
26+
50% { opacity: 1; } }'
27+
28+
document.getElementsByTagName('head')[0].appendChild(style);
29+
30+
document.body.innerHTML += "<div class='clg-snackbar' id='addon-clg-snackbar'>Selected item added to copy buffer</div>";
31+
}
32+
else {
33+
mydiv.style.visibility = 'visible';
34+
// if bar exists, toggle classname to fire animation with minimal delay between states
35+
mydiv.className = '';
36+
setTimeout(function() {mydiv.className = 'clg-snackbar';}, 10);
37+
//hide div after fadeout so any underlying html is accessible
38+
setTimeout(function() {mydiv.style.visibility = 'hidden'; }, 3200);
39+
}
40+
41+
}
42+
43+
44+
45+
}
46+
document.addEventListener("copy", oncopy, true);
47+
48+
// Requires the clipboardWrite permission, or a user gesture:
49+
document.execCommand("copy");
50+
}

manifest.json

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
{
2+
"manifest_version": 2,
3+
"name": "SQLMap Helper",
4+
"description": "Adds a helper menu for SQLMap.",
5+
"version": "0.0.9",
6+
"homepage_url": "https://github.com/oxagast/sqlmap-helper",
7+
8+
"background": {
9+
"scripts": [
10+
"background.js"
11+
]
12+
},
13+
14+
"options_ui": {
15+
"page": "options.html"
16+
},
17+
18+
"permissions": [
19+
"activeTab",
20+
"contextMenus",
21+
"clipboardWrite",
22+
"cookies",
23+
"<all_urls>",
24+
"storage",
25+
"webRequest",
26+
"webRequestBlocking"
27+
],
28+
"applications": {
29+
"gecko": {
30+
"id": "sqlmaphelper@maskster.site",
31+
"strict_min_version": "55.0"
32+
}
33+
}
34+
}

options.html

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<!DOCTYPE html>
2+
3+
<html>
4+
<head>
5+
<meta charset="utf-8">
6+
</head>
7+
8+
<body>
9+
<form id='optionsForm'>
10+
Use double quotes::
11+
<input type="checkbox" name="quotes" id="quotes"><br>
12+
<input visibility="hidden" type="radio" name="prog" id="prog" value="sqlmap"> SQLMap <br>
13+
Show Message on Copy: <input type="checkbox" name="snackbar" id="snackbar" checked="checked"><br>
14+
Verbose output: <input type="checkbox" name="verbose" id="verbose"><br><br><br>
15+
Any input in the boxes below will be inserted as options for the respective commands<br>
16+
SQLMap Options: <input type="text" name="sqlmapUser" id="sqlmapUser" ><br><br><br>
17+
18+
<button type="submit">Save</button>
19+
</form>
20+
<script src="options.js"></script>
21+
</body>
22+
23+
</html>

options.js

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
function saveOptions(e) {
2+
browser.storage.sync.set({
3+
quotes: document.querySelector('input[name=quotes]').checked,
4+
prog: document.querySelector('input[name=prog]:checked').value,
5+
file: document.querySelector('input[name=file]:checked').value,
6+
filename: document.querySelector('input[name=filename]').value,
7+
verbose: document.querySelector('input[name=verbose]').checked,
8+
sqlmapUser: document.querySelector('input[name=sqlmapUser]').value,
9+
snackbar: document.querySelector('input[name=snackbar]').checked,
10+
11+
});
12+
if (typeof(e) !== "undefined") {
13+
e.preventDefault();
14+
}
15+
16+
}
17+
18+
function restoreOptions() {
19+
var gettingItem = browser.storage.sync.get(
20+
['quotes', 'prog','verbose','resume','sqlmapUser','snackbar']);
21+
gettingItem.then((res) => {
22+
23+
if (Object.keys(res).length > 0 && res.constructor === Object) {
24+
document.querySelector('input[name=quotes]').checked = res.quotes ? res.quotes : false;
25+
document.querySelector('input[name=prog][value=' + res.prog + ']').checked = true;
26+
document.querySelector('input[name=verbose]').checked = res.verbose ? res.verbose : false;
27+
document.querySelector('input[name=sqlmapUser]').value = res.sqlmapUser ? res.sqlmapUser : '';
28+
document.querySelector('input[name=snackbar]').checked = res.snackbar ? res.snackbar : false;
29+
}
30+
// if no saved info save the defaults to initialize
31+
else {
32+
saveOptions();
33+
}
34+
});
35+
}
36+
37+
document.addEventListener('DOMContentLoaded', restoreOptions);
38+
document.querySelector("form").addEventListener("submit", saveOptions);

0 commit comments

Comments
 (0)