
استغلال لـ CVE-2022-29464، وهو رفع ملف تعسفي بدون مصادقة في خوادم WSO2 يتيح تنفيذ التعليمات البرمجية عن بُعد عبر رفع ملفات JSP خبيثة.
استغلال ثغرة WSO2 RCE (CVE-2022-29464) وشرحها.
CVE-2022-29464 هي ثغرة خطيرة في WSO2. الثغرة هي رفع ملفات غير مصرح به وغير مقيد، مما يمكّن المستخدمين غير المصرح لهم من رفع ملفات JSP ضارة إلى خوادم WSO2 والحصول على تنفيذ تعليمات برمجية عن بُعد (RCE).
مسار الرفع الثغري هو /fileupload الذي تتم معالجته بواسطة servlet FileUploadServlet. وهو مسار غير محمي بواسطة IAM كما نرى في ملف التكوين indentity.xml:```xml
الوظيفة 'handleSecurity()' مسؤولة عن حماية المسارات المختلفة التي يوفرها WSO2 وتقدم آلية لإجراء فحوصات أمنية على طلبات HTTP المستلمة. ستستدعي 'handleSecurity()' الدالة 'CarbonUILoginUtil.handleLoginPageRequest()'، وبناءً على قيمتها المُرجعة، سيتم تحديد ما إذا كان سيتم منح أو رفض الوصول إلى URI المطلوب:```java
public boolean handleSecurity(HttpServletRequest request, HttpServletResponse response)
throws IOException {
[snipped]
if ((val = CarbonUILoginUtil.handleLoginPageRequest(requestedURI, request, response,
authenticated, context, indexPageURL)) != CarbonUILoginUtil.CONTINUE) {
if (val == CarbonUILoginUtil.RETURN_TRUE) {
return true;
} else {
return false;
}
}
[snipped]
}
CarbonUILoginUtil.handleLoginPageRequest() تُرجع CarbonUILoginUtil.RETURN_TRUE عندما يكون المسار هو /fileupload:```java
protected static int handleLoginPageRequest(String requestedURI, HttpServletRequest request,
HttpServletResponse response, boolean authenticated, String context, String indexPageURL)
throws IOException {
boolean isTryIt = requestedURI.indexOf("admin/jsp/WSRequestXSSproxy_ajaxprocessor.jsp") > -1;
boolean isFileDownload = requestedURI.endsWith("/filedownload");
if ((requestedURI.indexOf("login.jsp") > -1
|| requestedURI.indexOf("login_ajaxprocessor.jsp") > -1
|| requestedURI.indexOf("admin/layout/template.jsp") > -1
|| isFileDownload
|| requestedURI.endsWith("/fileupload")
|| requestedURI.indexOf("/fileupload/") > -1
|| requestedURI.indexOf("login_action.jsp") > -1
|| isTryIt
|| requestedURI.indexOf("tryit/JAXRSRequestXSSproxy_ajaxprocessor.jsp") > -1)
&& !requestedURI.contains(";")) {
if ((requestedURI.indexOf("login.jsp") > -1
|| requestedURI.indexOf("login_ajaxprocessor.jsp") > -1 || requestedURI
.indexOf("login_action.jsp") > -1) && authenticated) {
[snipped]
} else if ((isTryIt || isFileDownload) && !authenticated) {
[snipped]
} else if (requestedURI.indexOf("login_action.jsp") > -1 && !authenticated) {
[snipped]
} else {
if (log.isDebugEnabled()) {
log.debug("Skipping security checks for " + requestedURI);
}
return RETURN_TRUE;
}
}
return CONTINUE;
}
مع `CarbonUILoginUtil.handleLoginPageRequest()` التي تُرجع `CarbonUILoginUtil.RETURN_TRUE`، ستُرجع `handleSecurity()` القيمة `true`، ومن ثم سيتم منح الوصول إلى `/fileupload` دون مصادقة.
أما servlet `FileUploadServlet`، فعند [`init()`](https://github.com/wso2/carbon-kernel/blob/d47232dfb2b26c0ef18a74e2ef4aa503caa59697/core/org.wso2.carbon.ui/src/main/java/org/wso2/carbon/ui/transports/FileUploadServlet.java#L71) وعبر سلسلة من استدعاءات الطرق، يقوم في النهاية بتحميل من ملف الإعداد `carbon.xml` تنسيقات/إجراءات متعددة لرفع الملفات، بالإضافة إلى الكائن الذي يعالج كل تنسيق.```java
public void init(ServletConfig servletConfig) throws ServletException {
this.servletConfig = servletConfig;
try {
fileUploadExecutorManager = new FileUploadExecutorManager(bundleContext, configContext, webContext);
//Registering FileUploadExecutor Manager as an OSGi service
bundleContext.registerService(FileUploadExecutorManager.class.getName(), fileUploadExecutorManager, null);
} catch (CarbonException e) {
log.error("Exception occurred while trying to initialize FileUploadServlet", e);
throw new ServletException(e);
}
}
مُنشئ الفئة FileUploadExecutorManager هو كالتالي:```java
public FileUploadExecutorManager(BundleContext bundleContext,
ConfigurationContext configCtx,
String webContext) throws CarbonException {
this.bundleContext = bundleContext;
this.configContext = configCtx;
this.webContext = webContext;
this.loadExecutorMap();
}
يستدعي المُنشئ الطريقة الخاصة [`loadExecutorMap()`](https://github.com/wso2/carbon-kernel/blob/d47232dfb2b26c0ef18a74e2ef4aa503caa59697/core/org.wso2.carbon.ui/src/main/java/org/wso2/carbon/ui/transports/fileupload/FileUploadExecutorManager.java#L131) والتي يتم فيها تحميل الإعدادات:```java
private void loadExecutorMap() throws CarbonException {
[snipped]
try {
documentElement = XMLUtils.toOM(serverConfiguration.getDocumentElement());
} catch (Exception e) {
String msg = "Unable to read Server Configuration.";
log.error(msg);
throw new CarbonException(msg, e);
}
[snipped]
OMElement fileUploadConfigElement =
documentElement.getFirstChildWithName(
new QName(ServerConstants.CARBON_SERVER_XML_NAMESPACE, "FileUploadConfig"));
for (Iterator iterator = fileUploadConfigElement.getChildElements(); iterator.hasNext();) {
OMElement mapppingElement = (OMElement) iterator.next();
if (mapppingElement.getLocalName().equalsIgnoreCase("Mapping")) {
OMElement actionsElement =
mapppingElement.getFirstChildWithName(
new QName(ServerConstants.CARBON_SERVER_XML_NAMESPACE, "Actions"));
String confPath = System.getProperty(CarbonBaseConstants.CARBON_CONFIG_DIR_PATH);
[snipped]
توجد تكوينات تنسيقات رفع الملفات ضمن مساحة الاسم FileUploadConfig في ملف تهيئة XML، وهذا هو التهيئة الافتراضية:```xml
100
<Mapping>
<Actions>
<Action>keystore</Action>
<Action>certificate</Action>
<Action>*</Action>
</Actions>
<Class>org.wso2.carbon.ui.transports.fileupload.AnyFileUploadExecutor</Class>
</Mapping>