Skip to content

Commit

Permalink
Women's Day Offer Challenge
Browse files Browse the repository at this point in the history
The flow of challenge is as follows:
- The user obtains the coupon code 'WMNSDY2019' either through the
twitter account or by guessing the coupon code(knowing the fact that
the offer was on Women's day of 2019).
- When the user tries to use the coupon code, it is errored saying
'Invalid coupon.'
- The user will then modify their system time to be that of the
Womens Day(08 March 2019), after this using the coupon code will give
the user a discount of 75%.
- The user will then checkout(complete the purchase) to solve the
challenge.

Please let me know of suggestions and improvements. Thank You
  • Loading branch information
agrawalarpit14 committed Mar 13, 2019
1 parent ac7c97c commit 2726fbd
Show file tree
Hide file tree
Showing 8 changed files with 95 additions and 38 deletions.
8 changes: 8 additions & 0 deletions data/static/challenges.yml
Original file line number Diff line number Diff line change
Expand Up @@ -647,5 +647,13 @@
hint: 'The 2FA implementation requires to store a secret for every user. You will need to find a way to access this secret in order to solve this challenge.'
hintUrl: 'https://bkimminich.gitbooks.io/pwning-owasp-juice-shop/content/part2/broken-authentication.html#solve-the-2fa-challenge-for-user-wurstbrot'
key: twoFactorAuthUnsafeSecretStorage
-
name: 'Women''s Day Discount'
category: 'Broken Access Control'
description: 'Avail the occasional discount by using the coupon code.'
difficulty: 1
hint: 'Once coupon code is obtained, manipulating the browser time might prove to be useful.'
hintUrl: ''
key: manipulateClockChallenge


2 changes: 1 addition & 1 deletion frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions frontend/src/app/Services/basket.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ export class BasketService {
return this.http.post(this.host + '/', params).pipe(map((response: any) => response.data), catchError((error) => { throw error }))
}

checkout (id) {
return this.http.post(this.hostServer + '/rest/basket/' + id + '/checkout',{}).pipe(map((response: any) => response.orderConfirmation), catchError((error) => { throw error }))
checkout (id, success: boolean) {
return this.http.post(this.hostServer + '/rest/basket/' + id + '/checkout',{ 'campaignSuccess': success }).pipe(map((response: any) => response.orderConfirmation), catchError((error) => { throw error }))
}

applyCoupon (id, coupon) {
Expand Down
1 change: 1 addition & 0 deletions frontend/src/app/basket/basket.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
<div *ngIf="confirmation && !couponControl.dirty" style="margin-top:5px;">{{ confirmation }}</div>

<div *ngIf="error && !couponControl.dirty" style="margin-top:5px;">{{error?.error}}</div>
<div *ngIf="campaignError && !couponControl.dirty" style="margin-top:5px;">Invalid coupon.</div>

<mat-form-field>
<label><small [innerHtml]="'FOLLOW_FOR_MONTHLY_COUPONS' | translate:{twitter: twitterUrl, facebook: facebookUrl}"></small></label>
Expand Down
49 changes: 36 additions & 13 deletions frontend/src/app/basket/basket.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ export class BasketComponent implements OnInit {
public facebookUrl = null
public applicationName = 'OWASP Juice Shop'
public redirectUrl = null
private campaignSuccess: boolean = false
public campaignError: boolean = false

constructor (private dialog: MatDialog,private basketService: BasketService,private userService: UserService,private windowRefService: WindowRefService,private configurationService: ConfigurationService,private translate: TranslateService) {}

Expand Down Expand Up @@ -114,26 +116,47 @@ export class BasketComponent implements OnInit {
}

checkout () {
this.basketService.checkout(sessionStorage.getItem('bid')).subscribe((orderConfirmationPath) => {
this.basketService.checkout(sessionStorage.getItem('bid'), this.campaignSuccess).subscribe((orderConfirmationPath) => {
this.redirectUrl = this.basketService.hostServer + orderConfirmationPath
this.windowRefService.nativeWindow.location.replace(this.redirectUrl)
}, (err) => console.log(err))
}

applyCoupon () {
this.basketService.applyCoupon(sessionStorage.getItem('bid'), encodeURIComponent(this.couponControl.value)).subscribe((data: any) => {
this.resetForm()
this.error = undefined
this.translate.get('DISCOUNT_APPLIED', { discount: data }).subscribe((discountApplied) => {
this.confirmation = discountApplied
}, (translationId) => {
this.confirmation = translationId
this.error = false
this.campaignError = false
this.campaignSuccess = false
if (this.couponControl.value === 'WMNSDY2019') {
let clientDate: any = new Date()
clientDate.setHours(0,0,0,0)
let couponDate = new Date('Mar 08, 2019')
if (clientDate.getTime() === couponDate.getTime()) {
this.campaignSuccess = true
this.showStatus(75)
} else {
this.confirmation = undefined
this.campaignError = true
this.resetForm()
}
} else {
this.basketService.applyCoupon(sessionStorage.getItem('bid'), encodeURIComponent(this.couponControl.value)).subscribe((data: any) => {
this.showStatus(data)
},(err) => {
console.log(err)
this.confirmation = undefined
this.error = err
this.resetForm()
})
},(err) => {
console.log(err)
this.confirmation = undefined
this.error = err
this.resetForm()
}
}

showStatus (data) {
this.resetForm()
this.error = undefined
this.translate.get('DISCOUNT_APPLIED', { discount: data }).subscribe((discountApplied) => {
this.confirmation = discountApplied
}, (translationId) => {
this.confirmation = translationId
})
}

Expand Down
30 changes: 8 additions & 22 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions routes/order.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,14 @@ module.exports = function placeOrder () {
doc.text(discount + '% discount from coupon: -' + discountAmount)
doc.moveDown()
totalPrice -= discountAmount
} else if(req.body.campaignSuccess){
if (utils.notSolved(challenges.manipulateClockChallenge)) {
utils.solve(challenges.manipulateClockChallenge)
}
const discountAmount = (totalPrice * (75 / 100)).toFixed(2)
doc.text(75 + '% discount from coupon: -' + discountAmount)
doc.moveDown()
totalPrice -= discountAmount
}
doc.text('Total Price: ' + totalPrice)
doc.moveDown()
Expand Down
31 changes: 31 additions & 0 deletions test/e2e/basketSpec.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
const insecurity = require('../../lib/insecurity')
const config = require('config')
const models = require('../../models/index')

describe('/#/basket', () => {
describe('as admin', () => {
Expand Down Expand Up @@ -63,12 +64,42 @@ describe('/#/basket', () => {

describe('as jim', () => {
protractor.beforeEach.login({ email: 'jim@' + config.get('application.domain'), password: 'ncc-1701' })
describe('challenge "Clock Manipulation Challenge"', () => {

it('should be possible to enter WMNSDY2019 coupon', () => {
browser.executeScript('window.localStorage.couponPanelExpanded = false;')

browser.get('/#/basket')
browser.executeScript('event = new Date("March 08, 2019 00:00:00"); Date = function(Date){return function() {date = event; return date; }}(Date);')

element(by.id('collapseCouponButton')).click()
browser.wait(protractor.ExpectedConditions.presenceOf($('#coupon')), 5000, 'Coupon textfield not present.') // eslint-disable-line no-undef

element(by.id('coupon')).sendKeys('WMNSDY2019')
element(by.id('applyCouponButton')).click()
})

it('should be possible to place an order with the coupon', () => {
element(by.id('checkoutButton')).click()
})

protractor.expect.challengeSolved({ challenge: 'Women\'s Day Discount' })
})

describe('challenge "forgedCoupon"', () => {
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')
})

it('should be possible to add a product in the basket', () => {
browser.waitForAngularEnabled(false)
models.sequelize.query('SELECT * FROM PRODUCTS').then(([products]) => {
browser.executeScript('var xhttp = new XMLHttpRequest(); xhttp.onreadystatechange = function () { if (this.status === 201) { console.log("Success") } } ; xhttp.open("POST", "http://localhost:3000/api/BasketItems/", true); xhttp.setRequestHeader("Content-type", "application/json"); xhttp.setRequestHeader("Authorization", `Bearer ${localStorage.getItem("token")}`); xhttp.send(JSON.stringify({"BasketId": `${sessionStorage.getItem("bid")}`, "ProductId":' + 1 + ', "quantity": 1}))') // eslint-disable-line
})
browser.driver.sleep(1000)
browser.waitForAngularEnabled(true)
})

it('should be possible to enter a coupon that gives an 80% discount', () => {
browser.executeScript('window.localStorage.couponPanelExpanded = false;')

Expand Down

0 comments on commit 2726fbd

Please sign in to comment.