Zombie Mall Attack II: The SQL

In a world where time must be killed and only one man sits in row L…

A few days ago I went to see a movie as the Castro Theatre. I arrived early for the show and sat in an empty theater. The mighty Wurlitzer was off for the night so I turned to my iPod Touch for entertainment until the movie would begin. Since I was in a movie theater it seem appropriate to look for some movie-themed apps. An obvious choice was the IMDb app1.

I installed the app and multi-touched my way through a few screens. I recognized several of IMDb’s list of the Bottom 100 films from MST3K episodes (which were fresh in my mind from seeing Cinematic Titanic live a few weeks earlier).

Another menu took me to US Box Office Results. Stuck between A Single Man and Lovely Bones was a curiosity that had taken $291K for the week and grossed $43.4M. The movie title was (null). Interesting…and possibly related to web security no less!

Now, there are a few options for looking behind the scenes of an app:

  • Jailbreak the device, reverse engineer the IMDb app or hook its network layer, write all of its network communications to a log file
  • Set up a wireless sniffer to capture traffic, hoping that it won’t be using an encrypted channel
  • Set up a sniffer on the access point’s LAN connection (in case KisMAC won’t work), but still be foiled by the potential of encrypted traffic
  • Change the Touch’s HTTP Proxy settings for the Wi-Fi Network to point to Paros running on another system. You realize Paros doesn’t just have to listen on localhost, right?

Ten times out of nine the simplest approach is the best approach. So, I set up Paros, which conveniently solves the problem of HTTPS as well2. If I had wanted to work hard I would have chosen binary exploit development over throwing together a few angle brackets and quotes to pull off XSS and SQL injection attacks against web sites.

With Paros listening I returned my fingers to the IMDb app. A few taps later I had my traffic. The User-Agent was “IMDb/1.1 CFNetwork/459 Darwin/10.0.0d3” which isn’t really relevant, but of interest if you’re into HTTP Headers…*crickets*

Okay, let’s stay relevant. Paros reveals that app makes simple GET requests and receives JSON-formatted data from the server as shown here:

There’s a copyright notice for each response that states, “For use only by clients authorized in writing by IMDb. Authors and users of unauthorized clients accept full legal exposure/liability for their actions.” A likely reason for the notice is to prevent other apps or services from spoofing requests and emulating the IMDb app. HTTP messages are trivial to spoof, but that’s a topic for another time.

This is what the first entry looks like. The title information, thumbnail image, and year of release are in red (I haven’t seen this movie yet, so expect the gross to go up by at least $10 next week):

{"weekend":{"currency":"USD","amount":41062440},"title":{"tconst":"tt1130884","type":"feature","title":"Shutter Island","image":{"width":501,"url":"http://ia.media-imdb.com/images/M/MV5BMTMxMTIyNzMxMV5BMl5BanBnXkFtZTcwOTc4OTI3Mg@@._V1_.jpg","height":755},"year":"2010"},"rank":1,"gross":{"currency":"USD","amount":41062440}}

Now, let’s search for our mysterious Number 25, which is highlighted in the previous screenshot. The title, image, and year are missing — in their place sits a single “vendor_title” field:

{"weekend":{"currency":"USD","amount":291360},"vendor_title":"2010 OSCAR SHORTS","rank":25,"gross":{"currency":"USD","amount":291360}}

So, no obvious SQL errors or malformed JSON syntax lurking here. We’ll have to change plot direction mid-course and find a happy ending. The app is still an inherently web-based application since it uses HTTP for transport and returns data with JSON formatting.

This leaves us with a chance to talk about defensive programming. The data for Number 25 was well-formed, but in the wrong format. The entry didn’t contain invalid characters and its content used correct delimiters to separate fields. Yet it was clearly missing the expected fields for title, image, and year. Since the app didn’t blow up in the face of unexpected results it was either lucky or benefited from some degree of a secure failure state.

In this case, a value was non-existent, NULL. In programming languages like C referencing a NULL value can be disastrous, as in Michael Bay disastrous3:

printf(“%s”, title)

Whereas a slightly more secure technique would ensure the title pointer is valid:

printf(“%s”, title != NULL ? title : “(null)”)

Web applications typically use languages that don’t have the potential pointer problems of a language like C, but the concept is still applicable.

Defensive programming is a proactive countermeasure that helps protect web sites from unexpected errors or situations. In this IMDb example, the JSON was well-formed. It also only contained name/value string pairs as opposed to serialized functions. So, we’ll end with a brief, high-level checklist for implementing secure code.

  • Check return values of functions.
  • Check for errors.
  • Fall back to a default value or action.
  • Don’t try to massage data to correctness. While it probably wouldn’t have been bad in our example if “vendor_title” had been used since it had the word “title” in it. On the other hand, filtering out “<script” from “<sc<scriptript>” in an attempt to massage bad mojo, i.e. an offending <script> tag, into good mojo fails miserably. Fixing data can also cause problems when dealing with character encoding schemes.
  • Write output securely. A simple example is writing custom 404 messages. If the non-existent link is written back into the page, then it’s a good idea to URL encode the link before rendering it into the page. Otherwise, you end up with attackers looking for links like “/<script+src=http://ip.address/j>” to send to their phishing victims — who see a link being served safely, one assumes, since it’s from the original site.

Also, keep in mind that web security pops up in unexpected places. Just because an application doesn’t look like a web browser doesn’t mean it’s immune to the types of injection attacks that plague the more familiar web sites.

1 One of the app’s ratings warns it may contain “Infrequent/Mild Profanity or Crude Humor”. Mild? Not if you dig into reviews for some of the more awful movies. There are times when the English lexicon fails to describe movies like Robot Holocaust.
2 The app will see a certificate from Paros rather than the one used by the web site. If the app enforced strict checks on the SSL certificate’s validity, then intercepting the traffic would be more difficult.
3 In the huge explosion sense, not plot. (They’re just different types of disasters. Watch Transformers 2 if you don’t believe me and you’re really bored. The kind of bored that makes you read parenthetical notes inside endnotes bored.)