Twitter’s Web Intents allow visitors of a website to interact with content on Twitter without having to leave the website. This is done by means of a twitter.com popup for desktop users, and native app handlers for iOS and Android users. This is the same platform powering the tweet and follow buttons you may see on webpages across the Internet.
I identified a parameter tampering vulnerability that in total affected all four web intent types. These vulnerabilities allowed an attacker to stage a Web Intent dialog with tampered parameters, which could lead to a visitor following a Twitter user they didn’t intend to follow.
All four intent types were vulnerable: Following a user, liking a tweet, retweeting, and tweeting or replying to a tweet.
Note: I wish I had screenshots to show for these examples. Unfortunately, I didn’t take any and the vulnerability has since been patched. For an idea of what Web Intents look like, please see Twitter’s API documentation, which I’ve linked to in the beginning of the article.
The first one I found was in the “follow a user” intent. By crafting a URL like the following, the page would render a form with the action set to “/intent/follow?screen_name=ericrtest3”.https://twitter.com/intent/follow?screen_name=twitter&screen_name=ericrtest3:
<form class="follow " id="follow_btn_form" action="/intent/follow?screen_name=ericrtest3" method="post"> <input type="hidden" name="authenticity_token" value="..."> <input type="hidden" name="screen_name" value="twitter"> <input type="hidden" name="profile_id" value="783214"> <button class="button" type="submit" > <b></b><strong>Follow</strong> </button> </form>
The page would display the profile of the user referenced by the first
screen_name parameter. However, upon submitting the form (clicking “follow”), the screen name referenced by the second
screen_name parameter (which would be in the form action) seemed to take precedence over the first. The result was that upon clicking the follow button, the user followed the user EricRtest3 instead of Twitter.
This exploit is a bit different than the original, but relied on the same mechanics of parameter tampering.
I could inject a
screen_name field into the like form on an intent page, even though a
screen_name parameter has no relevance in liking a tweet, like so:
The screen_name would be carried over with the form submission when the victim finished liking the tweet. The victim would end up redirected to a URL like this:
The correct profile would be displayed with a “follow” button. However, the
screen_name parameter was injected into the form as a hidden input field. The result was that after liking a tweet and seeing the US Department of Interior’s profile, clicking “follow” would then actually follow the user EricRtest3.
Note that I chose the US Department of Interior because that is an example user used in Twitter’s Web Intent documentation. I have nothing against this organization or their Twitter account.
Tweet/Reply and Retweet Intents
Both the tweet/reply intent and retweet intent were susceptible to exploitation in a way very similar to the like intent. I will save the reader time and simply say that by including a
screen_name parameter in any of these web intents, form submission would redirect to a page in which the screen_name parameter was staged to override the correct one.
Why This Worked
Duplicate parameters are typically ignored by most web servers and web application frameworks. So why did this vulnerability even exist in the first place? Well, I can’t say for sure since I don’t have Twitter’s source code in front of me. However, we can observe the following:
The web application handling the initial GET request reads the query string and shows one of the users referenced. It seems to delete it from the query string, so that when the URL is rendered in the form, only the second one is left. This can be seen in the HTML snippet above. Both parameters should be removed from the URL after it has been read. Because the second one isn’t, and because of the fact that when the form gets submitted the query string takes precedence over the body of the request, the application is tricked into using different usernames in different steps of the web intent flow.
I thought that this was a very interesting web parameter tampering attack. Twitter has since patched all of the vulnerabilities. The follow form no longer accepts two
screen_name parameters, and other intents no longer accept a
screen_name parameter on their success pages. Twitter was quick to address my bug submission and did a great job of deploying a patch. Kudos to them.