Saturday, July 28, 2018

Displaying API Keys Client Side

... is a bad idea.

I was pen testing for a friend, and found that most of the application logic was done client-side, which included a REST call to an API. I generally expect sensitive things like keys, app secrets, etc. to be only called server side in non publicly visible code, or at least reference a configuration file with the proper permissions. It is too easy to hijack someone else's API and either run up the bill, or the API limit, or else misuse it in a destructive way (for example, for the Google custom site image search API, one could use the admin console to limit the custom sites to only not-so-nice images, or an image from a server that lies about the MIME type and returns files with malicious code embedded, etc.)

This will probably happen more and more with the widespread use of APIs, specifically for services directly displayed to the user, such as maps or images, since it is tempting and convenient to just call the API directly client-side.

Ollydebug and Email Verification Bypass

Ollydebug combined with Pywin32 are great for finding hidden buttons on desktop applications that are invisible but still active. That Python library makes it easy to access and use them. (I haven't done that much research with desktop applications, and I'm almost positive a tool already exists to do these things in a more automated way, but this is one pretty heinous way, mclovin.py...)

import time
import win32con
import win32gui
import win32api
import win32process
import winxpgui
import struct
import pywintypes

mclovin, cmd = win32.api.CreateProcess(
None, #name
cmd,
None, #process attributes 
None, #thread attributes
0, #inheritance flag
0, #creation flag SW_NORMAL  #invisible, but I can still write to it: 1
win32con.SHOW_MINIMIZED
None, #new environment
None, #current directory
win32process.STARTUPINFO()
)
 
#brunningonline.net
def getEditText(hwnd):
    result = []
    bufferlength = struct.pack('i',255)
    linecount = win32gui.SendMessage(hwnd, win32con.EM_GETLINECOUNT, 0,0)
    linetext = linetext+"".ljust(253)
    linelength = win32gui.SendMessage(hwnd, win32con.EM_GETLINECOUNT, line, linetext)
    result.append(linetext[:linelength])
    return result

def wcallb(hwnd, handle):
    if (win32gui.GetClassName(hwnd) == 'Edit'):
         handle[win32gui.GetClassName(hwnd)+str(hwnd)] = hwnd
    else:
        handle[win32gui.GetClassName(hwnd)] = hwnd
 
    try:
        win32gui.EnumChildWindows(hwnd, wcallb, handle)
    except:
        print ('?no hijos?')
     return True
 
handle = {}
 
while not handle: #loop until we find the window
    time.sleep(0.1)
    win32gui.EnumThreadWindows(tid, wcallb, handle) #select fro future list of handles, not the top window
    print(handle) 
 
#if tabbing worked, I wouldn't need to find instances of components
#mclovin is a valid handle, but keys aren't sent to the window?
#handle['Button'] <-- Output 'Edit' <-- three 'Static' <-- window
'#32770' <-- dialog
 
#don't trust ordering of the fields, read the label text to determine
#text a:\***.csv
onlyEdits = []
for thehandle in handle.keys():
    if "Edit" in thehandle:
        onlyEdits.append(handle[thehandle])
 
try: 
     for k in onlyEdits:
        testPath = getEditText(k)
        if 'a:\***.csv' in testPath:
            editPath = k
except:
    print('couldn't find it)
 
#delete the current text which is at most 20 chars, replace with my own keystrokes
 
for c in range(20):
    win32api.PostMessage(
         editPath,
         win32con.WM_KEYDOWN,
         win32con.VK_DELETE,
        
         )

    win32api.PostMessage (
         editPath,
         win32con.WM_KEYUP,
         win32con.VK_DELETE,
        
         )

for escritarme in "*****\mclovinUSA.txt": 
    win32api.SendMessage(
         editPath
         win32con.WM_CHAR,
         ord(escritarme),
         0
)

Whew that's an ugly script. Anyway, unrelated, but a major social media network implies a lot of verification steps to the user, but if the user clicks the help link to exit the process early and get to the main site, it's clear that the account has already been created and can be used without further verification.

Sunday, July 15, 2018

Customer Support Forum & Trial Workaround

This exploit will leverage the power of a customer support discussion forum. Support teams can give so much advice on how application logic works when troubleshooting user issues, they can unintentionally help out if your exploit is not working. Reading old archives of these discussions can be a great resource, both for application logic and helpful links.

In this case, I was wondering if I had other options for the trial versions of a service. Yes, there's a premium service for 1 week, and a standard service for 1 year... but can I hack it to get a trial they don't offer? The premium for 1 year? Yes.

At first, I signed up for the standard tier trial for 1 week. After some googling, I came across a support forum with an old link to a page they no longer supported. (Since the company was bought by another, the users are now encouraged to go through the parent company's site to be able to get the special 1 year offer... but the user registration process is much harder, requiring a service plan, account number, etc.) So, instead, I used the defunct page to get a link to the premium 1 year service, while still logged in with the other trial. It didn't seem to work at first. Then I found the customer service thread describing how the service must be inactivated before the new one could start. So I did that, and watched the subscription end date of my trial reset. Success!

Keep in mind, this hack doesn't seem to be active anymore. After all, a year is PLENTY of time for development to patch a fix!

UPDATE: It actually is still active... sign up for the short trial, then reuse a URL parameter from the first trial's URL in the longer trial, which references the partner company.