From 625b17fe27f26ac3563a2ada4c43a33208f59f6b Mon Sep 17 00:00:00 2001 From: sairuss7 Date: Sun, 5 May 2024 18:18:42 +0000 Subject: [PATCH] add test and support url with port --- docs/shady-link.md | 32 +++++++++++++++--- src/probes/isLiteral.js | 12 +++++-- test/probes/isLiteral.spec.js | 62 +++++++++++++++++++++++++++++++++++ 3 files changed, 98 insertions(+), 8 deletions(-) diff --git a/docs/shady-link.md b/docs/shady-link.md index 9ec867f..a422604 100644 --- a/docs/shady-link.md +++ b/docs/shady-link.md @@ -5,13 +5,35 @@ ## Introduction -Identify when a Literal (string) contains an URL to a domain with a **suspicious extension**. +Identify when a literal (string) contains a suspicious URL: + - To a domain with a **suspicious** extension. + - URLs with a raw **IP address**. -> [!IMPORTANT] -> Credit goes to the [guarddog](https://github.dev/DataDog/guarddog) team. - -## Example +## A suspicious domain ```js const foo = "http://foo.xyz"; ``` + +## URL with a dangerous raw IP address + +URLs containing raw IP addresses can be considered potentially dangerous for several reasons: + + - **Phishing and social engineering**: Attackers can use raw IP addresses in URLs to hide the true destination of the link. + + - **Malware and code injection attacks**: Raw IP addresses can point to malicious websites that host malware or use compromising code injection techniques. + + - **Privacy violations**: Bypass proxy servers or firewalls designed to block access to certain websites, thereby exposing users. + +```js +const IPv4URL = "http://77.244.210.247/script"; + +const IPv6URL = "http://2444:1130:80:2aa8:c313:150d:b8cf:c321/script"; +``` + +
+
+ +> [!IMPORTANT]\ +> Credit goes to the [guarddog](https://github.dev/DataDog/guarddog) team.\ +> Credit goes to the [ietf.org](https://www.ietf.org/rfc/rfc3986.txt). \ No newline at end of file diff --git a/src/probes/isLiteral.js b/src/probes/isLiteral.js index 709717d..81b3748 100644 --- a/src/probes/isLiteral.js +++ b/src/probes/isLiteral.js @@ -4,15 +4,21 @@ import { builtinModules } from "repl"; // Import Third-party Dependencies import { Hex } from "@nodesecure/sec-literal"; + +const kMapRegexIps = Object.freeze({ + regexIPv4With: /^(https?:\/\/)(?!127\.)(?!.*:(?:0{1,3}|25[6-9])\.)(?!.*:(?:25[6-9])\.(?:0{1,3}|25[6-9])\.)(?!.*:(?:25[6-9])\.(?:25[6-9])\.(?:0{1,3}|25[6-9])\.)(?!.*:(?:25[6-9])\.(?:25[6-9])\.(?:25[6-9])\.(?:0{1,3}|25[6-9]))((?:\d{1,2}|1\d{2}|2[0-4]\d|25[0-5])\.){3}(?:\d{1,2}|1\d{2}|2[0-4]\d|25[0-5])(?::\d{1,5})?(\/[^\s]*)?$/, + regexIPv6With: /^(https?:\/\/)(\[[0-9A-Fa-f:]+\])(?::\d{1,5})?(\/[^\s]*)?$/ +}) + + // CONSTANTS const kNodeDeps = new Set(builtinModules); const kShadyLinkRegExps = [ - /^(https?:\/\/)(?!127\.)((?!0{2,3}\.)(?!0{1,3}\.0{1,3}\.)(?!25[6-9]\.)(?!25[6-9]\.25[6-9]\.)(?!25[6-9]\.25[6-9]\.25[6-9])((?:\d{1,2}|1\d{2}|2[0-4]\d|25[0-5])\.){3}(?:\d{1,2}|1\d{2}|2[0-4]\d|25[0-5]))(\/[^\s]*)?$/, - /^(https?:\/\/)((?!\[::1\])(?!.*:[a-fA-F\d]+:[a-fA-F\d]+:[a-fA-F\d]+:[a-fA-F\d]+:[a-fA-F\d]+:[a-fA-F\d]+:[a-fA-F\d]+)(?:(?:[a-fA-F\d]{1,4}:){7}[a-fA-F\d]{1,4}))(\/[^\s]*)?$/, + kMapRegexIps.regexIPv4With, + kMapRegexIps.regexIPv6With, /(http[s]?:\/\/bit\.ly.*)$/, /(http[s]?:\/\/.*\.(link|xyz|tk|ml|ga|cf|gq|pw|top|club|mw|bd|ke|am|sbs|date|quest|cd|bid|cd|ws|icu|cam|uno|email|stream))$/ ]; - /** * @description Search for Literal AST Node * @see https://github.com/estree/estree/blob/master/es5.md#literal diff --git a/test/probes/isLiteral.spec.js b/test/probes/isLiteral.spec.js index 6fcdea8..5512be4 100644 --- a/test/probes/isLiteral.spec.js +++ b/test/probes/isLiteral.spec.js @@ -99,3 +99,65 @@ test("should detect shady link when an URL has a suspicious domain", () => { const warning = sastAnalysis.getWarning("shady-link"); assert.strictEqual(warning.value, "http://foobar.link"); }); + + +test("should not mark suspicious links the IPv4 address range 127.0.0.0/8 (localhost 127.0.0.1)", () => { + const str = "const IPv4URL = ['http://127.0.0.1/script', 'http://127.7.7.7/script']"; + const ast = parseScript(str); + const sastAnalysis = getSastAnalysis(str, isLiteral).execute(ast.body); + + assert.ok(!sastAnalysis.warnings().length); +}); + + +test("should not be considered suspicious a link with a raw IPv4 address 127.0.0.1 and a port", () => { + const str = "const IPv4URL = 'http://127.0.0.1:80/script'"; + const ast = parseScript(str); + const sastAnalysis = getSastAnalysis(str, isLiteral).execute(ast.body); + + assert.ok(!sastAnalysis.warnings().length); +}); + +test("should detect the link as suspicious when a URL contains a raw IPv4 address", () => { + const str = "const IPv4URL = 'http://77.244.210.247/burpcollaborator.txt'"; + const ast = parseScript(str); + const sastAnalysis = getSastAnalysis(str, isLiteral).execute(ast.body); + + assert.strictEqual(sastAnalysis.warnings().length, 1); + const warning = sastAnalysis.getWarning("shady-link"); + assert.strictEqual(warning.value, "http://77.244.210.247/burpcollaborator.txt"); +}); + + + +test("should detect suspicious links when a URL contains a raw IPv4 address with port", () => { + const str = "const IPv4URL = 'http://77.244.210.247:8080/script'"; + const ast = parseScript(str); + const sastAnalysis = getSastAnalysis(str, isLiteral).execute(ast.body); + + assert.strictEqual(sastAnalysis.warnings().length, 1); + const warning = sastAnalysis.getWarning("shady-link"); + assert.strictEqual(warning.value, "http://77.244.210.247:8080/script"); +}); + + +test("should detect suspicious links when a URL contains a raw IPv6 address", () => { + const str = "const IPv6URL = 'http://[2001:0db8:85a3:0000:0000:8a2e:0370:7334]/index.html'"; + const ast = parseScript(str); + const sastAnalysis = getSastAnalysis(str, isLiteral).execute(ast.body); + + assert.strictEqual(sastAnalysis.warnings().length, 1); + const warning = sastAnalysis.getWarning("shady-link"); + assert.strictEqual(warning.value, "http://[2001:0db8:85a3:0000:0000:8a2e:0370:7334]/index.html"); +}); + + +test("should detect suspicious links when a URL contains a raw IPv6 address with port", () => { + const str = "const IPv6URL = 'http://[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:100/script'"; + const ast = parseScript(str); + const sastAnalysis = getSastAnalysis(str, isLiteral).execute(ast.body); + + assert.strictEqual(sastAnalysis.warnings().length, 1); + const warning = sastAnalysis.getWarning("shady-link"); + assert.strictEqual(warning.value, "http://[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:100/script"); +}); \ No newline at end of file