Larnaka Salt Lake in Cyprus

Hacking Tinder

Have you ever wanted to query your Tinder matches and send a batch of messages to them?

You might find this creepy, but to the point where we are now, I believe that swiping tens (hundreds?) of people a minute based on their appearance is already disturbing.

But this is with this ruby script that I met my fiancee!

Whatever your intent is, you should be respectful and honest. This little hack is just a way to save your time and meet great people.

Why?

  1. Learning
  2. Laziness
  3. Send messages from my laptop

It may be a bit tricky to get responses on Tinder; I think my matches were ignoring my messages because:

  • They have many people talking to them already
  • They found love and don’t use the app anymore (but I had no way to know that from the app itself)
  • Tinder servers were down
  • They noticed that I skip both torso and leg days

So I felt like wasting my time, trying to be nice to a girl and just simply being ignored. Complete radio silence can be painful, to quote Elie Wiesel :

The opposite of love is not hate, it’s indifference. The opposite of art is not ugliness, it’s indifference. The opposite of faith is not heresy, it’s indifference. And the opposite of life is not death, it’s indifference.

Though sometimes they would just take their time because this is the way it works now.

How?

Tinder doesn’t provide an open API, but by intercepting the traffic between our phone and the Tinder API, we can mimic the phone behaviour and send out similar HTTP requests from a computer, namely a Man-in-the-middle attack. Then, we can download the list of matches and send the messages.

Many different tools can help us achieve this. In this post, I will explain how I did it. Here is my setup:

  • a Macbook
  • an iPhone 6s

Your phone needs to be connected to the same network as your computer because your phone network traffic will pass through your computer.

In terms of software, I have used :

Setup

On your computer

I use Homebrew as a package manager which allows me to install mitmproxy by running the following command in a terminal:

brew install mitmproxy

If you plan to do more Ruby, I recommend using rbenv that you can install with Homebrew as well. Otherwise, and if you don’t already have Ruby :

brew install ruby

And once you have Ruby installed:

gem install http

Now, let’s start mitmproxy

mitmproxy

A blank screen will appear, everything is fine. mitmproxy is now running and listening for incoming requests on the port 8080 (by default). You will see activity once your phone is configured.

On your phone

Uninstall the Tinder app and remove its local data. This will force the app to redownload the list of your matches. You will not lose all your matches as they are stored on the Tinder servers. Then reinstall the app but don’t open it yetIf you know a better way to do it without reinstalling the app, please leave a comment, and I will update the post. I haven’t dug too much into that, to be honest.

This is important that you reinstall the app before setting up the proxy because the AppStore use certificate pinning which make it unaccessible when going through mitmproxy.

Go in your network settings, and set up the http proxy to use our mitmproxy server. It looks like this on my iPhone:

iphone proxy settings
Iphone proxy settings

In the field “server” set your computer local IP address (you can get it with ifconfig) and the port to 8080.

Now, from your phone visit mitm.it, and install the certificate.

Once the certificate is installed, try launching your web browser on your phone and you should see the HTTP/HTTPS traffic being monitored on the mitmproxy screen. If it doesn’t work, visit the mitmproxy documentation to get further assistance.

Hack

Open the Tinder app, and log in. Now your mitmproxy console might go crazy because the app is about to redownload everything that it needs, including the pictures. We want to find our list of matches. Tinder poll their API every second to get the updated content, this is done via a POST request to https://api.gotinder.com/updates. We can filter the mitmproxy view by pressing L and then entering a regular expression, here is a reference of the expressions you can use. Here I want to filter by URL so I use ~ufollowed by the regexp.

~u /.*(tinder).*(update).*/

Here is what it looks like on my computer :

mitm

Now try to spot the biggest request (or the one that took the longest to load), it should be the first one. You can navigate in mitmproxy using the arrow keys. Press enter to view the request details. The first tab is already interesting since it contains the request header.

mitm request header

Copy and save the authorization token (the part that I have blanked out from the picture). We will send our requests using almost the same header (but don’t bother copying it just yet).

Then hit TAB to go in the response, then B to save the output to a file in the current directory. You will be prompted for a file name; you can save it to matches.json for example.

Have a quick glance at the file, and it should contain all your matches and the full history of your messages and activity.

Now, using the same technique of intercepting requests, I found that sending a message to a match is done via a POST request to https://api.gotinder.com/user/matches/:match_id with the request body being { message: 'Hello.' }

To send a batch of messages to the matches I had no messages with yet, I wrote a short ruby script:

#!/usr/bin/env ruby

gem 'http'
require 'http'
require 'json'

# Your token goes here
TOKEN = ''

HEADERS = { 'host' => 'api.gotinder.com',
            'Authorization' => "Token token='#{TOKEN}'",
            'x-client-version' => '47217',
            'app-version' => '467',
            'Proxy-Connection' => 'keep-alive',
            'Accept-Encoding' => 'gzip, deflate',
            'Accept-Language' => 'en-GB;q=1, fr-FR;q=0.9',
            'platform' => 'ios',
            'Content-Type' => 'application/json',
            'User-Agent' => 'Tinder/4.7.2 (iPhone; iOS 9.2.1; Scale/2.00)',
            'Connection' => 'keep-alive',
            'X-Auth-Token' => TOKEN,
            'os_version' => '90000200001' }

# Here you should specify the path of your matches.json file
def matches
  JSON.parse(File.read('matches.json'))['matches']
end

def new_matches
  matches.select { |m| !m['pending'] && m['messages'].size == 0 }
end

new_matches.each_with_index do |m, n|
  puts "sending message ##{n} to #{m['person']['name']} id (#{m['person']['_id']})"
  res = HTTP.headers(HEADERS)
        .post("https://api.gotinder.com/user/matches/#{m['_id']}",
              json: { message: "Hello #{m['person']['name']}. If I had a flower for every time I thought of you... I could walk through my garden forever." })

  puts res.body
  puts res.status == 200 ? 'OK' : 'FAILED'
  sleep(1)
end

This is quite straightforward ruby code. I use the http gem because I never remember how to use the native Net::HTTP library. I let the thread sleep for a second between each request just in case they have some request rate/throttling protection.

Save this code to a file, i.e. tinder.rb. Don’t forget to set your token at the top of the script and to customise your message.

Execute the ruby script to send out the messages:

ruby tinder.rb

Voilà !

Conclusion

This is a simple demonstration on how we can leverage reverse engineering to unlock features that are not accessible through a mobile app. The data we get from the API calls also give us more information than the app, for example, we can see the last ping date of the match or its birthday date… That could unlock more potential for further hacking, but use it wisely :-)