21 Mar, 2019

The Case of the Missing API Docs

by Kevin Cody

Have you ever purchased an IoT device, signed up for an application/service, or simply wanted to know how something worked, but were surprised when you found out that there was no documented API? First and foremost, I am taking a step back here from my traditional security practitioner position. Meaning, I am not talking about looking for admin-level or super secret root services; instead, I am merely talking about trying to figure out how an application or device works so that you can interface with it. You may have heard of IFTTT or Apple’s Shortcuts App; this post is about how you can start the process of creating your own integrations, even if the API isn’t officially supported. Another word of caution though, any time you integrate with an undocumented, unsupported API, you are opening yourself up to the possibility that the services/endpoints may change drastically with zero notice. This means your work may need to be tweaked, or may even be for naught. This is the risk you take when trying to hack your way into uncharted territory.

Let’s pretend you just bought a fancy new $insertnameofreallycoolIoTwidgethere, and you’re looking to log how many times it $insertnameofancyfunctionhere. You run out to the vendor’s website… but find out that there is no API documentation, no SDK, no public GitHub repo, or anything to give you a jumpstart in your quest. Are you stuck?

TL;DR: You are most likely not stuck.

Step 1: Figure out how to view the widget’s traffic.

Is there a mobile application? Web application? Desktop OS app? Some sort of interface that you can send packets to an application or device? If so, you’ve just identified your primary information source. Even if you don’t have clear documentation of how to interface with the said application, your goal is to merely get in the middle of the traffic between the widget and server/service. If your spidey senses are tingling with inclinations of proxies… you’re 100% correct!

My GoTos for proxying:

  • Burp Suite - The de facto web application tester’s numero uno.
  • OWASP’s Zed Attack Proxy (ZAP) - A wonderfully maintained, open-source application proxy that absolutely gives numero uno a run for its money. Oh, and it’s free!
  • mitmproxy - A remarkable, open-source command line (and web interface) proxy, that offers incredible extensibility with the power to proxy even the most stubborn of traffic. It’s written in python, has a wonderful group of maintainers, and has gotten me out of a few jams.
  • NoPE Proxy - OK, this one is cheating a little bit, as it’s a Burp Suite extension… but, with the power to proxy non-HTTP traffic via DNS binding and listening for arbitrary TCP streams, NoPE is another wonderful asset in your toolkit.

Lastly, I would be remiss if I didn’t at least give a shoutout to Mallet and Fiddler.

Step 2… er, 1-B: You think that you’ve picked your tooling, now what?

Picking a proxy is just the first minor step; next, you need to get your traffic pointed to the proxy listener. This can be an extensive process combining pcaps and Wireshark, modifying /etc/host files, utilizing radio frequency analysis, or much, much more. In summary, sometimes it’s best to pick a tool for step 1 and then be ready to pivot to another tool or chain of tools.

Furthermore, if the traffic itself is encrypted, you’re only halfway there. You now have to decrypt the traffic for analysis. There are many, many, many tutorials on how to add a Root CA to *OS in effort to middle HTTPS traffic, so I will let you refer to those. However, there is also a good trick of exporting SSL Key Logging material as an environmental variable in an effort to view the entire TLS handshake in Wireshark, and then decrypt TLS from there. I won’t go into extreme detail, but Jim Shaver’s blog post does an excellent job of introducing the topic.

Step 2: You can see the traffic, now what?

OK, if you’re lucky (and likely persistent), you’re now looking at traffic. Huzzah! However, there is still a bit further to go.

Your next step is to attempt to identify all of the endpoints, or at least all of the endpoints you need to achieve your goal. So the next best thing to do is to exercise the application or widget, in an effort to make it do all of the things/calls. Whether it’s pushing all of the buttons, old school application spidering, utilizing a JavaScript parsing tool like my favorite, GerbenJavado’s LinkFinder, the goal here is to identify endpoints, methods, and required parameters.

Using LinkFinder to parse API endpoints from JavaScript bundles.

Using LinkFinder to parse API endpoints from JavaScript bundles.

Whether you take that data and merely log it, or go the whole way and document it as an OpenAPI formatted file (of which you can then feed into Swagger or Postman), you’re almost to the point of being able to see the crest of that rollercoaster hill.

Step 3: What about authentication?

It may be pretty obvious, but hopefully, everything you’ve been able to capture thus far as some time of authentication required. If this is indeed the case, it’s crucial to capture the methods in achieving the identifiers, tokens, headers, cookies, keys, etc.

Whether it’s a hardcoded API key that you can simply extract (I sincerely hope this isn’t the case), or a more traditional authentication process wherein a secret or value is traded for a token, it is critical to ensure the entire process is documented. In my experience, I’ve seen small things cause major hiccups in my quest to exercise functions outside of their originally intended use case.

Some examples include:

  • Super-specific User-Agent headers
  • Checksums, hashes, or GUIDs generated within the application/widget
  • Other innocuous looking headers or encoding that is easy to miss

In summary, make sure that you are entirely able to exercise the authentication process outside of the passively sniffed traffic.

Step 4: Still missing some endpoints or data?

Alrighty, at this point you’ve hopefully identified everything you need to take the next step and create your method to invoke your application/widget’s interface outside of the walled garden. However, if you’re still looking to find those elusive endpoints or methods, my goto is decompiling they companion or thick-client application.

Whether it be an Android app (hint apktool and dex2jar are your friends), iOS app (:cough: start with clutch2, :cough:), or desktop OS app (I’m a big Hopper and dotpeek) disassembler/decompiler, the goal here is to attempt to extract additional data from packages, executables, or binaries.

dex2jar and JD-GUI are helpful in hunting down API endpoints in Android apps.

dex2jar and JD-GUI are helpful in hunting down API endpoints in Android apps.

Step 5: OK, now what?

At this point, you should hopefully be at a place where you can repeatedly exercise the functions necessary to obtain the data needed, all the while doing so outside of the original application/widget. If so, you’re at the top of that first rollercoaster hill. Next steps are to choose the methods of which you can invoke those functions within the ecosystem of which you’re trying to integrate.

Next Steps

In a future blog installment, I’ll take that thought and show some various examples of AWS, Apple Shortcuts, IFTTT, and more.