-
Notifications
You must be signed in to change notification settings - Fork 141
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #122 from OWASP/dockerize-second-degree
Dockerize second degree - First four challenges
- Loading branch information
Showing
23 changed files
with
1,054 additions
and
681 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
/* | ||
Copyright 2023 VMware, Inc. | ||
SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
listBucket = (req, res) => { | ||
res.setHeader('Content-type', 'text/xml'); | ||
let responseXML = `<?xml version="1.0" encoding="UTF-8"?> | ||
<ListBucketResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/"> | ||
<Name>scd-c2</Name><Prefix></Prefix><Marker></Marker><MaxKeys>1000</MaxKeys> | ||
<IsTruncated>false</IsTruncated> | ||
<Contents><Key>secret.txt</Key><LastModified>2023-06-07T15:24:36.000Z</LastModified><ETag>"9f00fa953c30966bf2c361b01ab60cab"</ETag><Size>16</Size><Owner><ID>scd</ID><DisplayName>scd</DisplayName></Owner><StorageClass>STANDARD</StorageClass></Contents> | ||
<Contents><Key>messages/</Key><LastModified>2023-06-07T15:24:36.000Z</LastModified><ETag>"9f00fa953c30966bf2c361b01ab60cab"</ETag><Size>16</Size><Owner><ID>scd</ID><DisplayName>scd</DisplayName></Owner><StorageClass>STANDARD</StorageClass></Contents> | ||
<Contents><Key>chat/</Key><LastModified>2023-06-07T15:24:36.000Z</LastModified><ETag>"9f00fa953c30966bf2c361b01ab60cab"</ETag><Size>16</Size><Owner><ID>scd</ID><DisplayName>scd</DisplayName></Owner><StorageClass>STANDARD</StorageClass></Contents> | ||
</ListBucketResult> | ||
` | ||
res.send(responseXML) | ||
} | ||
|
||
listChatFolder = (req, res) => { | ||
res.setHeader('Content-type', 'text/xml'); | ||
let responseXML = `<?xml version="1.0" encoding="UTF-8"?> | ||
<ListBucketResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/"> | ||
<Contents><Key>chatUsers.json</Key><LastModified>2023-06-07T15:24:34.000Z</LastModified><ETag>"b40064d8a0c616639625dd2788b0a4db"</ETag><Size>354</Size><Owner><ID>scd</ID><DisplayName>scd</DisplayName></Owner><StorageClass>STANDARD</StorageClass></Contents> | ||
<Contents><Key>cncChat.css</Key><LastModified>2023-06-07T15:24:35.000Z</LastModified><ETag>"9c3948279137ca3194a3ef103d39a0cd"</ETag><Size>508358</Size><Owner><ID>scd</ID><DisplayName>scd</DisplayName></Owner><StorageClass>STANDARD</StorageClass></Contents> | ||
<Contents><Key>cncChat.html</Key><LastModified>2023-06-07T15:24:35.000Z</LastModified><ETag>"c407c85c2dc8bb901e8cf8041222fbbf"</ETag><Size>10832</Size><Owner><ID>scd</ID><DisplayName>scd</DisplayName></Owner><StorageClass>STANDARD</StorageClass></Contents> | ||
<Contents><Key>messages.json</Key><LastModified>2023-06-07T15:24:34.000Z</LastModified><ETag>"d663f1f40451dd745d91b8faba273e28"</ETag><Size>476</Size><Owner><ID>scd</ID><DisplayName>scd</DisplayName></Owner><StorageClass>STANDARD</StorageClass></Contents> | ||
</ListBucketResult>` | ||
|
||
res.send(responseXML) | ||
|
||
} | ||
|
||
module.exports = { | ||
listBucket, | ||
listChatFolder | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
/* | ||
Copyright 2023 VMware, Inc. | ||
SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
const jwt = require('jsonwebtoken'); | ||
const crypto = require('crypto'); | ||
|
||
|
||
//issue challenge tokens and redirect to challenge code signer | ||
getChallengeUrl = async(challengeId) => { | ||
var token = await jwt.sign({"sub": challengeId}, process.env.HDEN_SIGN_SECRET, {expiresIn:15*60}); | ||
return {"message":"YOU GOT IT!","challengeCodeUrl":"/code/getCode.html#"+token, "challengeId":challengeId}; | ||
} | ||
|
||
validate = async(req,resp) => { | ||
//validate the token | ||
try { | ||
let decoded = await jwt.verify(req.body.token, process.env.HDEN_SIGN_SECRET) | ||
console.log('authorized:', decoded); | ||
var challengeId = decoded.sub; | ||
|
||
if(challengeId===null || typeof challengeId==='undefined'){ | ||
resp.status(400) | ||
return resp.send({"errorMessage":"Invalid challenge id"}); | ||
} | ||
|
||
if(!req.body.codeSalt || req.body.codeSalt.length < 5){ | ||
return resp.send({"errorMessage":"Invalid salt"}); | ||
} | ||
|
||
var masterSalt = ""; | ||
if(process.env.CHALLENGE_MASTER_SALT){ | ||
masterSalt=process.env.CHALLENGE_MASTER_SALT; | ||
} | ||
|
||
var verificationHash = crypto.createHash('sha256').update(challengeId+req.body.codeSalt+masterSalt).digest('base64'); | ||
|
||
return resp.send({ | ||
"verificationCode":verificationHash | ||
}); | ||
|
||
} catch (error) { | ||
console.log('Failed challenge code JWT verify'); | ||
resp.status(400) | ||
return resp.send({"errorMessage":"Invalid or expired token"}); | ||
} | ||
|
||
} | ||
|
||
|
||
|
||
module.exports = { | ||
getChallengeUrl, | ||
validate | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,151 @@ | ||
/* | ||
Copyright 2023 VMware, Inc. | ||
SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
const jwt = require('jsonwebtoken') | ||
const challengeCode = require('./challenge-code') | ||
const chatUsers = require('./chat/chatUsers.json') | ||
const JSEncrypt = require('nodejs-jsencrypt').default | ||
const crypto = require('crypto') | ||
let messages = require('./messages.json') | ||
|
||
authenticate = (req, resp) => { | ||
var user = chatUsers[req.body.userName]; //get the user entry from the db | ||
var userPassHash = user.passHash; | ||
var vfHash = crypto.createHash('sha1').update(req.body.userPass).digest('hex'); | ||
if(userPassHash===vfHash){ | ||
//generate JWT to identify this user | ||
let permissions = ["currentuser"] | ||
|
||
if(req.body.userName == "badspaghetti" || req.body.userName == "stinkyfish"){ | ||
permissions.add("messages") | ||
} | ||
|
||
let tokenInfo = {"sub": req.body.userName,"name": user.name, "permissions":permissions} | ||
|
||
var token = jwt.sign(tokenInfo, process.env.HDEN_AUTH_SECRET); | ||
resp.send({"token": token}); | ||
} | ||
else{ | ||
resp.status(401) | ||
resp.send("Invalid credentials"); | ||
} | ||
|
||
} | ||
|
||
getAuthorizedUser = async(req) => { | ||
var authToken = req.headers.Authorization; | ||
if(typeof authToken === 'undefined'){ | ||
authToken = req.headers.authorization; | ||
} | ||
|
||
if(authToken && authToken.split(' ')[0] === 'Bearer') { | ||
let idToken = authToken.split(' ')[1]; | ||
try { | ||
let decoded = await jwt.verify(idToken, process.env.HDEN_AUTH_SECRET) | ||
|
||
for(let perm of decoded.permissions){ | ||
if(req.path.indexOf(perm) > -1) return decoded | ||
} | ||
} catch (error) { | ||
console.log('failed jwt verify: ', err, 'auth: ', idToken); | ||
return null | ||
} | ||
} | ||
return null | ||
} | ||
|
||
|
||
|
||
getCurrentUser = async(req, resp) => { | ||
//validate the token | ||
|
||
let user = await getAuthorizedUser(req); | ||
|
||
if(user===null){ | ||
resp.status(403) | ||
return resp.send("Unauthorized") | ||
} | ||
|
||
var challengeId = null; | ||
|
||
switch(user.sub){ | ||
case "test": challengeId = "owasp2017sensitive"; break; | ||
case "badspaghetti": challengeId = "owasp2017brokenauth"; break; | ||
case "stinkyfish": challengeId = "owasp2017brokenauth"; break; | ||
} | ||
|
||
|
||
if(challengeId!==null){ | ||
let challengeResponse = await challengeCode.getChallengeUrl(challengeId) | ||
user.challengeCodeUrl = challengeResponse.challengeCodeUrl | ||
resp.send(user) | ||
|
||
} | ||
} | ||
|
||
getMessages = async(req,resp) => { | ||
let user = await getAuthorizedUser(req); | ||
|
||
if(user===null){ | ||
resp.status(403) | ||
return resp.send("Unauthorized") | ||
} | ||
|
||
resp.send(messages) | ||
} | ||
|
||
postMessage = async(req,resp) => { | ||
let user = await getAuthorizedUser(req); | ||
|
||
if(user===null){ | ||
resp.status(403) | ||
return resp.send("Unauthorized") | ||
} | ||
|
||
let message = JSON.parse(JSON.stringify(req.body)) | ||
if(message.type==='encMessage'){ | ||
let challengeResponse = await challengeCode.getChallengeUrl("owasp2017xss") | ||
let challengeCodeUrl = challengeResponse.challengeCodeUrl | ||
message = validateMessage(message, challengeCodeUrl) | ||
} | ||
|
||
messages.push(message) | ||
if(messages.length>1000) messages.pop() | ||
resp.send("Message received.") | ||
} | ||
|
||
validateMessage = (message, challengeCodeUrl) => { | ||
//check integrity | ||
var toHash = "<img src='https://gov.logger.good' width='0px'>"+message.pubKey; | ||
var hash = crypto.createHash('sha256').update(toHash).digest('hex'); | ||
|
||
if(message.integrity===hash){ | ||
var encrypt = new JSEncrypt(); | ||
encrypt.setPublicKey(message.pubKey); | ||
var re = new RegExp('.{1,40}', 'g'); | ||
var challengeCodeUrlParts = challengeCodeUrl.match(re); | ||
var encChallengeCodeUrlParts = []; | ||
challengeCodeUrlParts.forEach(part => { | ||
encChallengeCodeUrlParts.push(encrypt.encrypt(part)); | ||
}); | ||
message.challengeCodeUrl = encChallengeCodeUrlParts; | ||
message.nextChallenge = encrypt.encrypt("/ping"); | ||
} | ||
else{ | ||
message.error = "Integrity check failed for:'"+JSON.stringify(message)+"'"; | ||
} | ||
return message; | ||
} | ||
|
||
|
||
module.exports = { | ||
authenticate, | ||
getAuthorizedUser, | ||
getCurrentUser, | ||
getMessages, | ||
postMessage | ||
} | ||
|
||
|
||
|
File renamed without changes.
File renamed without changes.
Oops, something went wrong.