id: js-libraries-detect info: name: Common JS Libraries - Detection author: adamparsons,cbadke,ChetGan,ErikOwen,jacalynli severity: info description: Checks a target web app for inclusion of common JavaScript libraries metadata: max-request: 1 tags: headless,tech,js headless: - steps: - action: navigate args: url: "{{BaseURL}}" - action: waitload - action: script name: fingerprintAxios args: code: | () => { //check for axios if (!window.axios) { return "" } try { // check for version // only works on some websites return window.axios.VERSION } catch (e) {} return "Version not found" } - action: script name: fingerprintBootstrap args: code: | () => { try { // if not using jQuery return bootstrap.Tooltip.VERSION || "" } catch (e) {} try { // if using jQuery return $.fn.tooltip.Constructor.VERSION || "" } catch (e) {} return "" } - action: script name: fingerprintJQuery args: code: | () => { let version = ""; try { if(window.jQuery) { version = jQuery.fn.jquery; } if(window.$) { version = $.fn.jquery; } version = version.replace(".min", ""); version = version.replace(".slim", ""); return version; } catch (e) {} return ""; } - action: script name: fingerprintLodash args: code: | () => { try { return _.VERSION || ""; } catch (e) {} return ""; } - action: script name: fingerprintMomentJs args: code: | () => { try { return moment.version || ""; } catch (e) {} return ""; } - action: script name: fingerprintReact args: code: | () => { try { return window.React.version || ""; } catch (e) {} return ""; } - action: script name: fingerprintReactDOM args: code: | () => { try { if (window.ReactDOM) { return window.React.version || ""; } } catch (e) {} return ""; } - action: script name: fingerprintAngular args: code: | () => { try { // Angular Version 1 return angular.version.full } catch (e) {} try { // Angular Version 2+ return getAllAngularRootElements()[0].attributes["ng-version"].value } catch (e) {} return "" } - action: script name: fingerprintBackboneJs args: code: | () => { try { return window.Backbone.VERSION || "" } catch (e) {} return "" } - action: script name: fingerprintEmberJs args: code: | () => { try { return Ember.VERSION || "" } catch (e) {} return ""; } - action: script name: fingerprintVue args: code: | () => { //method 1 (simple) try { return Vue.version } catch (e) {} //method 2 (checks if Nuxt exists) try { const nuxtDetected = Boolean(window.__NUXT__ || window.$nuxt) if (nuxtDetected) { let Vue } if (window.$nuxt) { Vue = window.$nuxt.$root.constructor } return Vue.version } catch (e) {} //method 3 (go through all elements) try { const all = document.querySelectorAll('*') let flag for (let i = 0; i < all.length; i++) { if (all[i].__vue__) { flag = all[i] break } } if (flag) { let Vue = Object.getPrototypeOf(flag.__vue__).constructor while (Vue.super) { Vue = Vue.super } return Vue.version } return "" } catch (e) {} return "" } - action: script name: fingerprintDojoJs args: code: | () => { try { return ([dojo.version.major, dojo.version.minor, dojo.version.patch].join(".")) } catch (e) {} return "" } - action: script name: fingerprintDomPurify args: code: | () => { try { return DOMPurify.version || "" } catch (e) {} return "" } - action: script name: fingerprintModernizr args: code: | () => { try { return Modernizr._version || "" } catch (e) {} return "" } matchers-condition: or matchers: - type: dsl dsl: - len(fingerprintAxios) > 0 - len(fingerprintBootstrap) > 0 - len(fingerprintJQuery) > 0 - len(fingerprintLodash) > 0 - len(fingerprintMomentJs) > 0 - len(fingerprintReact) > 0 - len(fingerprintReactDOM) > 0 - len(fingerprintAngular) > 0 - len(fingerprintBackboneJs) > 0 - len(fingerprintEmberJs) > 0 - len(fingerprintVue) > 0 - len(fingerprintDojoJs) > 0 - len(fingerprintDomPurify) > 0 - len(fingerprintModernizr) > 0 extractors: - name: axios type: regex part: fingerprintAxios regex: - ^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$ - name: bootstrap type: regex part: fingerprintBootstrap regex: - ^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$ - name: jquery type: regex part: fingerprintJQuery regex: - ^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$ - name: lodash type: regex part: fingerprintLodash regex: - ^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$ - name: moment type: regex part: fingerprintMomentJs regex: - ^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$ - name: react type: regex part: fingerprintReact regex: - ^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$ - name: reactdom type: regex part: fingerprintReactDOM regex: - ^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$ - name: angular type: regex part: fingerprintAngular regex: - ^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$ - name: backbone type: regex part: fingerprintBackboneJs regex: - ^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$ - name: emberjs type: regex part: fingerprintEmberJs regex: - ^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$ - name: vuejs type: regex part: fingerprintVue regex: - ^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$ - name: dojo type: regex part: fingerprintDojoJs regex: - ^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$ - name: dompurify type: regex part: fingerprintDomPurify regex: - ^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$ - name: modernizr type: regex part: fingerprintModernizr regex: - ^(0|[1-9]\d*)(?:\.(0|[1-9]\d*))?(?:\.(0|[1-9]\d*))?(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$ # digest: 4a0a004730450220451c605a35e3b3a0bb15c0b3af18d432417660d1ceb67d64d5412ced6d2a58d0022100bae60594c866a2cab9623cefdb57b536383227050ed923361241a58746568210:922c64590222798bb761d5b6d8e72950