-
Notifications
You must be signed in to change notification settings - Fork 0
xd #2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
xd #2
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,138 @@ | ||
| "use stricts"; | ||
|
|
||
| /** | ||
| * Module dependencies. | ||
| */ | ||
|
|
||
| var express = require("../.."); | ||
| var hash = require("pbkdf2-password")(); | ||
| var path = require("node:path"); | ||
| var session = require("express-session"); | ||
|
|
||
| var app = (module.exports = express()); | ||
|
|
||
| // config | ||
|
|
||
| app.set("view engine", "ejs"); | ||
| app.set("views", path.join(__dirname, "views")); | ||
|
|
||
| // middleware | ||
|
|
||
| app.use(express.urlencoded()); | ||
| app.use( | ||
| session({ | ||
| resave: false, // don't save session if unmodified | ||
| saveUninitialized: false, // don't create session until something stored | ||
| secret: "shhhh, very secret", | ||
| }) | ||
| ); | ||
|
|
||
| // Session-persisted message middleware | ||
|
|
||
| app.use(function (req, res, next) { | ||
| var err = req.session.error; | ||
| var msg = req.session.success; | ||
| delete req.session.error; | ||
| delete req.session.success; | ||
| res.locals.message = ""; | ||
| if (err) res.locals.message = '<p class="msg error">' + err + "</p>"; | ||
| if (msg) res.locals.message = '<p class="msg success">' + msg + "</p>"; | ||
| next(); | ||
| }); | ||
|
|
||
| // dummy database | ||
|
|
||
| var users = { | ||
| tj: { name: "tj" }, | ||
| }; | ||
|
|
||
| // when you create a user, generate a salt | ||
| // and hash the password ('foobar' is the pass here) | ||
|
|
||
| hash({ password: "foobar" }, function (err, pass, salt, hash) { | ||
| if (err) throw err; | ||
| // store the salt & hash in the "db" | ||
| users.tj.salt = salt; | ||
| users.tj.hash = hash; | ||
|
Comment on lines
+51
to
+56
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Severity: Medium A user credential is embedded directly in code by hashing a hard-coded password. This creates a default/backdoor account that attackers can exploit if the application is deployed with this code. DetailsA default credential is created by hashing the hard-coded password "foobar" and assigning the resulting salt and hash to the user `tj`. The authentication flow uses these values to validate logins. The server starts on port 3000 when the module is run directly, exposing a `/login` route that explicitly instructs use of "tj"/"foobar". There is no environment gating, first-run password change, or disabling mechanism, making this a network-exploitable default account wherever this app is deployed.Why it's exploitable:
Why it's not exploitable:
Attack vector: network - The Express server starts and exposes CVSS v3.1 vector: AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N - Network-accessible default credentials; post-auth access appears limited to a restricted page, reducing impact. Evidence:
44 | var users = {
45 | tj: { name: "tj" },
46 | };
...
51 | hash({ password: "foobar" }, function (err, pass, salt, hash) {
52 | if (err) throw err;
53 | // store the salt & hash in the "db"
54 | users.tj.salt = salt;
55 | users.tj.hash = hash;
56 | });
60 | function authenticate(name, pass, fn) {
62 | var user = users[name];
64 | if (!user) return fn(null, null);
68 | hash({ password: pass, salt: user.salt }, function (err, pass, salt, hash) {
70 | if (hash === user.hash) return fn(null, user);
71 | fn(null, null);
72 | });
73 | }
104 | app.post("/login", function (req, res, next) {
106 | authenticate(req.body.username, req.body.password, function (err, user) {
127 | ' (use "tj" and "foobar")';
128 | res.redirect("/login");
130 | });
131 | });
134 | if (!module.parent) {
135 | app.listen(3000);
136 | console.log("Express started on port 3000");
137 | }Debug{
"id": "019b12b3-8018-73f9-a755-473081a6c4f4",
"codebaseId": "019ac6c3-c4db-70b0-aed6-bb82698030de",
"path": "auth/index.js",
"rangeStart": 51,
"rangeEnd": 56,
"line": 51,
"signature": "019b12b3-47f1-74a9-abc0-536eee2e061c"
}
|
||
| }); | ||
|
|
||
| // Authenticate using our plain-object database of doom! | ||
|
|
||
| function authenticate(name, pass, fn) { | ||
| if (!module.parent) console.log("authenticating %s:%s", name, pass); | ||
|
Comment on lines
+60
to
+62
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Severity: Medium The code logs both the username and the plaintext password during authentication. Logging credentials can leak sensitive data to log files, monitoring systems, or third-party services, leading to account compromise. DetailsThe authentication routine logs plaintext credentials when the module is executed directly, causing username and password to be written to stdout on every login attempt. The same file also starts the server when run without a parent module, making the logging active during real authentication traffic. While the logging is gated by `module.parent`, this application is designed to run standalone, so the guard evaluates true in that mode and credentials are exposed to logs that are typically collected by process managers or centralized logging systems.Why it's exploitable:
Why it's not exploitable:
Attack vector: local - sensitive data exposure requires access to application logs/stdout, though any remote login request triggers the logging. CVSS v3.1 vector: AV:L/AC:L/PR:H/UI:N/S:U/C:H/I:N/A:N - Reading the exposed credentials requires local or privileged access to logs; impact is high for confidentiality only. Base score: 1.4. Evidence:
60 | function authenticate(name, pass, fn) {
61 | if (!module.parent) console.log("authenticating %s:%s", name, pass);
62 | var user = users[name];
63 | // query the db for the given username
64 | if (!user) return fn(null, null);
65 | // apply the same algorithm to the POSTed password, applying
104 | app.post("/login", function (req, res, next) {
105 | if (!req.body) return res.sendStatus(400);
106 | authenticate(req.body.username, req.body.password, function (err, user) {
107 | if (err) return next(err);
108 | if (user) {
133 | /* istanbul ignore next */
134 | if (!module.parent) {
135 | app.listen(3000);
136 | console.log("Express started on port 3000");
137 | }Debug{
"id": "019b12b3-801b-755a-abbe-4ea57ae7e7a5",
"codebaseId": "019ac6c3-c4db-70b0-aed6-bb82698030de",
"path": "auth/index.js",
"rangeStart": 60,
"rangeEnd": 62,
"line": 61,
"signature": "019b12b3-47f1-74a9-abc0-586489c98e82"
}
|
||
| var user = users[name]; | ||
| // query the db for the given username | ||
| if (!user) return fn(null, null); | ||
| // apply the same algorithm to the POSTed password, applying | ||
| // the hash against the pass / salt, if there is a match we | ||
| // found the user | ||
| hash({ password: pass, salt: user.salt }, function (err, pass, salt, hash) { | ||
| if (err) return fn(err); | ||
| if (hash === user.hash) return fn(null, user); | ||
| fn(null, null); | ||
| }); | ||
| } | ||
|
|
||
| function restrict(req, res, next) { | ||
| if (req.session.user) { | ||
| next(); | ||
| } else { | ||
| req.session.error = "Access denied!"; | ||
| res.redirect("/login"); | ||
| } | ||
| } | ||
|
|
||
| app.get("/", function (req, res) { | ||
| res.redirect("/login"); | ||
| }); | ||
|
|
||
| app.get("/restricted", restrict, function (req, res) { | ||
| res.send('Wahoo! restricted area, click to <a href="/logout">logout</a>'); | ||
| }); | ||
|
|
||
| app.get("/logout", function (req, res) { | ||
| // destroy the user's session to log them out | ||
| // will be re-created next request | ||
| req.session.destroy(function () { | ||
| res.redirect("/"); | ||
| }); | ||
| }); | ||
|
|
||
| app.get("/login", function (req, res) { | ||
| res.render("login"); | ||
| }); | ||
|
|
||
| app.post("/login", function (req, res, next) { | ||
| if (!req.body) return res.sendStatus(400); | ||
| authenticate(req.body.username, req.body.password, function (err, user) { | ||
| if (err) return next(err); | ||
| if (user) { | ||
| // Regenerate session when signing in | ||
| // to prevent fixation | ||
| req.session.regenerate(function () { | ||
| // Store the user's primary key | ||
| // in the session store to be retrieved, | ||
| // or in this case the entire user object | ||
| req.session.user = user; | ||
| req.session.success = | ||
| "Authenticated as " + | ||
| user.name + | ||
| ' click to <a href="/logout">logout</a>. ' + | ||
| ' You may now access <a href="/restricted">/restricted</a>.'; | ||
| res.redirect(req.get("Referrer") || "/"); | ||
| }); | ||
| } else { | ||
| req.session.error = | ||
| "Authentication failed, please check your " + | ||
| " username and password." + | ||
| ' (use "tj" and "foobar")'; | ||
| res.redirect("/login"); | ||
| } | ||
| }); | ||
| }); | ||
|
|
||
| /* istanbul ignore next */ | ||
| if (!module.parent) { | ||
| app.listen(3000); | ||
| console.log("Express started on port 3000"); | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Severity: Medium
The session secret is hard-coded to a weak, guessable value. An attacker who knows or can guess this secret can forge or tamper with session data, potentially leading to authentication bypass and session hijacking.
Details
The Express application configures `express-session` with a single, hard-coded secret value (“shhhh, very secret”) and no environment-based override. This secret is used at runtime to sign session cookies. Knowledge of the secret enables forging validly signed session cookies, facilitating session fixation and hijacking when combined with obtaining or influencing a victim’s session ID. No alternative configuration, rotation, or production-only override is present; the same hard-coded secret governs verification.Why it's exploitable:
express-sessionis used withsecret: "shhhh, very secret"and no override logic.connect.sidcookies, enabling session fixation or hijacking if an attacker can set or learn a session ID.Why it's not exploitable:
Attack vector: network - An attacker can interact with the REST API over the network and supply forged cookies once the secret is known.
CVSS v3.1 vector: AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:H/A:N - Exploitation generally requires either user interaction (session fixation) or knowledge of an existing session ID; impacts include confidentiality and integrity via account takeover.
Evidence:
Debug
{ "id": "019b12b3-8015-74b8-8860-49dd0f1a65a6", "codebaseId": "019ac6c3-c4db-70b0-aed6-bb82698030de", "path": "auth/index.js", "rangeStart": 21, "rangeEnd": 26, "line": 25, "signature": "019b12b3-47f1-74a9-abc0-4b11f4ac2577" }