• We just launched and are currently in beta. Join us as we build and grow the community.

[Reversing] Create your own Twitch Tools! [PRIME,VIEWBOT,BITS,FRIENDS,WHISPER,RAINBOW,AUTH,FOLLOWERS,CHANNEL VIEWS]

Jamesmykil

Privilege Escalation Specialist
J Rep
0
0
0
Rep
0
J Vouches
0
0
0
Vouches
0
Posts
103
Likes
116
Bits
2 MONTHS
2 2 MONTHS OF SERVICE
LEVEL 1 300 XP
This will be a detailed explanation of reversing Twitch.TV which will help you create your own tools and functionalities so you learn and won't have to pay anymore for tools or download infected tools and can actually learn something regarding services like the one's twitch uses work. This tutorial includes C# code and guides on services such as Rainbow Spam, Twitch Auth, Twitch Prime, Twitch Bits and more.

This guide is handwritten by me (LeFrenchFrog) from experience and memory.



If this reaches 100 likes I'll write a part two with more reversing and showing how to create your own tools for Twitch.


What is Twitch?
Twitch (stylized as twitch) is a live streaming video platform owned by Twitch Interactive, a subsidiary of Amazon. Introduced in June 2011 as a spin-off of the general-interest streaming platform, Justin.tv, the site primarily focuses on video game live streaming, including broadcasts of eSports competitions, in addition to music broadcasts, creative content, and more recently, "in real life" streams. Content on the site can be viewed either live or via video on demand.

What will I be teaching you today?
In this thread I'll be explaining in detail how Twitch works and how you can reverse services like theirs on your own and create your own tools.
I expect you to know the basics of a simple framework language such as C# and experience with JSON.



Let's start!
For transferring data between their React App and backend, Twitch uses GraphQL.
When logged in, Twitch authenticates requests using an Authorization header.
Twitch uses OAuth ( Open Authorization ). Read more about it here: https://en.wikipedia.org/wiki/OAuth
Read more about it in the link but it's basicly a session token.



CREATED BY LeFrenchFrog (HandMade from experience)



Part 1: Authentication
Twitch uses a POST request to authenticate using JSON. The request looks as follows:



Login Request


Code:
Request URL: https://passport.twitch.tv/login
Request Payload: {"username":"MyUserName","password":"MyPassword","client_id":"kimne78kx3ncx6brgo4mv6wki5h1ko","undelete_user":false}


Response Success (Status Code 200):


Code:
{"access_token":"f0brj9srkzg6bt4ni3ze9kysznAZS","redirect_path":"https://www.twitch.tv/"}


Response Failed (Status Code 400):


Code:
{"error":"Incorrect username or password.","error_code":3001,"error_description":"user credentials incorrect"}


Response Failed Captcha:


Code:
{"error":"Please complete the CAPTCHA correctly.","error_code":1000,"error_description":"captcha incorrect"}


This is pretty basic. Its an authentication POST request to the twitch login servers which results back in the access_token , the access_token is your OAuth token. A lot of people dont realize this.



So for example in C# you could make a simple POST to the server for example:


Code:
request.Post("https://passport.twitch.tv/login",
"{\"username\":\"" + user + "\",\"password\":\"" + pass +
"\",\"client_id\":\"kimne78kx3ncx6brgo4mv6wki5h1ko\"}",
"text/plain;charset=UTF-8");


NOTE: This is done with

You must upgrade your account or reply in the thread to view hidden text.


I suggest you use C# and this library if your new.



The authentication token will expire in a really long time or it will be invalid when a user logs in again.
Make sure to save the OAuth token as you wont have to re-login again to use certain services!



Part 2: Twitch Prime
So now that the basics of twitch have been explained I will be going in depth with sending Twitch Prime.
What you will need:
- Target ID (ID of the person you want to gift primes to)
- User ID (ID of your own account)
- OAuth Token (Token of the account with prime)

An example of how to get the User ID with a C# request would be:


Code:
request.AddHeader("Client-Id", "kimne78kx3ncx6brgo4mv6wki5h1ko");
request.AddHeader("Authorization", "OAuth " + token);
string response = request.Post("https://gql.twitch.tv/gql", "[{\"operationName\":\"Core_Services_Spade_CurrentUser\",\"variables\":{},\"extensions\":{\"persistedQuery\":{\"version\":1,\"sha256Hash\":\"482be6fdcd0ff8e6a55192210e2ec6db8a67392f206021e81abe0347fc727ebe\"}}}]", "application/json").ToString();


So lets review the request. We notice in the request we're identifying the operation Core_Services_Spade_CurrentUser. You contact this service to get information regarding the account associated with your Oauth token. You must specify the Client ID as it's required. The Authorization header is the part we learned in part 1 which sends Twitch confirmation which account your using.

In the response there will be an ID. It's at ['data']['currentUser']['id'] , Save this into a variable which will be User ID.

An example of how to get the Target ID with a C# request would be:


Code:
request.AddHeader("Client-Id", "kimne78kx3ncx6brgo4mv6wki5h1ko");
string response = request.Post("https://gql.twitch.tv/gql", "[{\"operationName\":\"ChannelPage_SubscribeButton_User\",\"variables\":{\"login\":\""+ channel + "\"},\"extensions\":{\"persistedQuery\":{\"version\":1,\"sha256Hash\":\"c43e0ea49ccd19bae4473dc426480d4c95ea9cc590d7101ff60f45b24c2a308d\"}}}]", "application/json").ToString();


If we review this request we can see that we've added the client-id but not the OAuth ID as it's not required with this request. We send a POST request to GQL with operationName Channel_Page_SubscribeButton_user in order to receive back information regarding the channel. The channel variable in this request would be the channel that you're targeting.



If you parse the JSON response the Target ID will be under ['data']['user']['id'].
Save this value in a variable which will be the Target ID.

Now we're all set to send a prime subscription to the channel.

What were going to do is create a POST request to the service which handles the prime requests.


Code:
request.AddHeader("Client-Id", "kimne78kx3ncx6brgo4mv6wki5h1ko");
request.AddHeader("Authorization", "OAuth " + token);
var html = request.Post("https://gql.twitch.tv/gql",
"[{\"operationName\":\"PrimeSubscribe_SpendPrimeSubscriptionCredit\",\"variables\":{\"input\":{\"broadcasterID\":\"" +
targetid + "\",\"userID\":\"" + userID +
"\"}},\"extensions\":{\"persistedQuery\":{\"version\":1,\"sha256Hash\":\"639d5286f985631f9ff66c5bd622d839f73113bae9ed44ec371aa9110563254c\"}}}]",
"application/json").ToString();


If you review the request here above you can see we add the client ID (static) and the Authorization Token of the account that has a prime subscription available.
the VAR targetid is the target ID we got earlier and the user ID is the user ID we got earlier.

Once you've send the request the prime subscription should arrive. An example of a response you could receive back is:
- UNABLE_TO_SPEND



This means it doesn't have Prime available.



ldwd.png




gfkm.png


Part 3: Twitch Bits



What you will need:



- Random Generated Value



- Amount of bits



- Target ID (Which we've learned in part 2)
- Client-ID (static)
- Authorization Token


Code:
request.AddHeader("Client-ID", "ua66iwix1zjua2n6n0ajn0zs0ij4rg");
request.AddHeader("Authorization", "OAuth " + token);
string response = request.Post("https://gql.twitch.tv/gql", "[{\"operationName\":\"ChatInput_SendCheer\",\"variables\":{\"input\":{\"id\":\"" + generated + "\",\"targetID\":\"" + targetid + "\",\"bits\":"+ bits + ",\"content\":\"Cheer"+ bits +"\",\"isAutoModEnabled\":true,\"shouldCheerAnyway\":false,\"isAnonymous\":false}},\"extensions\":{\"persistedQuery\":{\"version\":1,\"sha256Hash\":\"57b0d6bd979e516ae3767f6586e7f23666d612d3a65af1d5436dba130c9426fd\"}}}]", "application/json").ToString();


Twitch bits is pretty straight forward. You send a post request to Twitch GQL with the operationName ChatInput_Sendcheer, you then specify a generated code which is variable generated.
Replicating Twitch Random Generated code:


Code:
public static string generateID()
{
string v = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx";
string output = "";
Random rand = new Random();
Regex r = new Regex("[xy4-]");
foreach (Match m in r.Matches(v))
{
string val = m.Value;
if (val == "x")
{
val = rand.Next(0, 15).ToString("x");
}
else if (val == "y")
{
int i = rand.Next(0, 15);
i = (3 & i | 8);
val = i.ToString("x");
}
output += val;
}
return output;
}


Twitch requires you to send a random string for some reason, still havn't figured out why. You can simply forge these using the function I made above.
The bits variable in the POST request is just simply the amount you want to send. Make sure the Twitch account that is attached with the AUTH token has enough.

How to check the Bits Balance of an account:


Code:
request.AddHeader("Client-Id", "kimne78kx3ncx6brgo4mv6wki5h1ko");
request.AddHeader("Authorization", "OAuth " + token);
string response = request.Post("https://gql.twitch.tv/gql", "[{\"operationName\":\"BitsCard_Bits\",\"variables\":{},\"extensions\":{\"persistedQuery\":{\"version\":1,\"sha256Hash\":\"fe1052e19ce99f10b5bd9ab63c5de15405ce87a1644527498f0fc1aadeff89f2\"}}},{\"operationName\":\"BitsCard_MainCard\",\"variables\":{\"name\":\"70658111\",\"withCheerBombEventEnabled\":false},\"extensions\":{\"persistedQuery\":{\"version\":1,\"sha256Hash\":\"37be341cf861b1f262f33325070fc166d72b3fddadf1f4e2022c1de8c27efa81\"}}}]", "application/json").ToString();


You can do this multiple ways. This is my way. Send a POST request to Twitch GQL with the operationName BitsCard_bits and at variables -> name put the target ID of a random person or the person you're sending the bits too. for example now it says: 70658111 (which is fake, dont try).



Parse the JSON response and go to ['data']['currentUser']['bitsBalance']
This will show you the bits balance of a user.

So now you're able to check the bits balance of a Twitch account and how to send them!
p4kz.png




fa91.png




Part 4: Whisper Bot



What you will need:



- Your message



- Target ID (Learned in Part 2)
- Authorization Token



Straight forward , this is the POST request you do to the Twitch GQL server.


Code:
request.AddHeader("Client-Id", "kimne78kx3ncx6brgo4mv6wki5h1ko");
request.AddHeader("Authorization", "OAuth " + token);
string html = request.Post("https://gql.twitch.tv/gql", "[{\"operationName\":\"SendWhisper\",\"variables\":{\"input\":{\"message\":\"" + message + "\",\"nonce\":\"cf853ff744536f71191c917050582388\",\"recipientUserID\":\"" + targetid + "\"}},\"extensions\":{\"persistedQuery\":{\"version\":1,\"sha256Hash\":\"3bbd599e7891aaf3ab6a4f5788fd008f21ad0d64f6c47ea6081979f87e406c08\"}}}]", "application/json").ToString();


In the request you can see that for this request you need to send a request to the GQL with operationName SendWhisper.
Variables you'll find back in this request are message which is your message, the recipientUserID which would be the Target ID we've learned in part 2.

This sends out a whisper message and if you loop through Auth Tokens this can be a lot of fun.
ckno.png




Part 5: Rainbow Spam



What you will need:



- Your custom message



- Display Name (streamers channel name)
- Authorization Token



- Username of account



So rainbow spam is a bit more difficult. Twitch chat is based of IRC.
Twitch Chat can be viewed by anyone, but requires a login to send messages. There are the concepts of separate chat rooms, which can be restricted to subscribers. Users can send predefined emotes. These emotes can be available to everyone or they can be limited to people who subscribe.



Underneath, Twitch chat uses websockets and talks to an IRC backend. The usage of IRC is abstracted away from the user, but we can see its traces in the url, irc-ws.chat.twitch.tv, and also with the initial websocket connection.



When we connect without being logged in, we register with a NICK myUsername , and PASS myPassword. These are typically for an IRC server. Then we connect to the IRC channel for the stream, so if we are watching https://twitch.tv/ninja, we will JOIN #ninja.

So lets do this in C#.


Code:
Socks5ProxyClient proxyClient = new Socks5ProxyClient(proxyresult[0], port);
TcpClient Client = proxyClient.CreateConnection("irc.chat.twitch.tv", 6667);
StreamWriter writing = new StreamWriter(Client.GetStream());
writing.AutoFlush = true;
if (Client.Connected)
{
writing.WriteLine($"PASS oauth:{token}");
writing.WriteLine($"NICK {username}");
writing.WriteLine($"JOIN #{displayName}");
writing.WriteLine($"PRIVMSG #{displayName} :/me {message}\r\n");
}


We created at first a proxyClient because we want to use proxies. We then create a TcpClient which we use with our proxyclient to create a connection to irc.chat.twitch.tv on port 6667.
We then want to assign a StreamWriter with AutoFlush on true. When the client is connected we want to put in our PASS which is oauth: + your oauth token.
Then we want to input our nickname into the client from the account and then join the target's chatroom. After that we send out the custom message we like and then close the client.
Verifying if the message is actually sent is not neccesary as this function is ment as a fire-and-forget and move on as fast as possible to have more impact while rotating through OAuth tokens.
So why is it in color? It's because of /me which is an old IRC function to set a status of what your doing.



4oni.png




Part 6: Friend Requests



Are you in need of friends on Twitch? No worry!



What you will need:



- Authorization Token



- Target ID (Learned in Part 1&2)



Friend requests are pretty straight forward.


Code:
request.AddHeader("Authorization", "OAuth " + token);
response = request.Post("https://gql.twitch.tv/gql", "{\"operationName\":\"SearchFriendResult_CreateFriendRequest\",\"variables\":{\"input\":{\"targetID\":\"" + targetid + "\"}},\"extensions\":{\"persistedQuery\":{\"version\":1,\"sha256Hash\":\"d040c85df71756a454cdc098b72a1dcf9323572126d01e25701e7f98b8777725\"}}}", "application/json");


Send a POST request to Twitch GQL with operationName SearchFriendResult_CreateFriendRequest. at targetID make sure to add the targetid variable of who you would like to target.
This will send a friend request on Twitch to that person.

Free exploit because you've made it to the end



If you send a lot of Twitch Whisper messages from a lot of accounts really fast, it will crash the persons browser because the javascript overloads.



I've used this to troll Twitch Streamers like Yassuo



awd4.png




7pw8.png



Edited by Deger, 20 August 2019 - 09:23 PM.
 

439,009

316,008

316,017

Top