聲明
出品|且聽安全(ID:QCyber)
以下內(nèi)容珊豹,來自且聽安全公眾號的作者原創(chuàng)鸵荠,由于傳播冕茅,利用此文所提供的信息而造成的任何直接或間接的后果和損失,均由使用者本人負責,長白山攻防實驗室以及文章作者不承擔任何責任姨伤。
漏洞信息
2022.06 ZDI發(fā)布多個Advantech iView漏洞信息CVE-2022-2135&2143&2135 等?:
影響版本為 Advantech iView All versions prior to 5_7_04_6469哨坪。重點關注其中評分為 `9.8` 的高危漏洞,發(fā)現(xiàn)問題主要集中在 `NetworkServlet`? 姜挺,整理的部分漏洞信息如下:
?`findCfgDeviceList` :When parsing the COLUMN and VALUE elements of the findCfgDeviceList action, the process does not properly validate a user-supplied string before using it to construct SQL queries. An attacker can leverage this vulnerability to execute code in the context of SYSTEM.
?`getAllActiveTraps` :When parsing the search_date_to and search_date_from elements of the getAllActiveTraps action, the process does not properly validate a user-supplied string before using it to construct SQL queries. An attacker can leverage this vulnerability to execute code in the context of SYSTEM.
?`performZTPConfig` :When parsing any element of the performZTPConfig action, the process does not properly validate a user-supplied string before using it to construct SQL queries. An attacker can leverage this vulnerability to execute code in the context of SYSTEM.
?`setTaskEditorItem` :When parsing the DESCRIPTION element of the setTaskEditorItem action, the process does not properly validate a user-supplied string before using it to construct SQL queries. An attacker can leverage this vulnerability to execute arbitrary code in the context of SYSTEM.
?`exportDeviceList` :When parsing the filename element of the exportDeviceList action, the process does not properly validate a user-supplied path prior to using it in file operations. An attacker can leverage this vulnerability to execute code in the context of SYSTEM.
?`findCfgDeviceListDetailsExport` :When parsing the filename element of the findCfgDeviceListDetailsExport action, the process does not properly validate a user-supplied path prior to using it in file operations. An attacker can leverage this vulnerability to execute code in the context of SYSTEM.
?`backupDatabase` :When parsing the backup_filename element of the backupDatabase action, the process does not properly validate a user-supplied string before using it to execute a system call. An attacker can leverage this vulnerability to execute code in the context of SYSTEM.
?`runProViewUpgrade` :When parsing the fwfilename element of the runProViewUpgrade action, the process does not properly validate a user-supplied string before using it to execute a system call. An attacker can leverage this vulnerability to execute code in the context of SYSTEM.
?`findSummaryUpdateDeviceList` :When parsing the COLUMN and VALUE elements of the findSummaryUpdateDeviceList action, the process does not properly validate a user-supplied string before using it to construct SQL queries. An attacker can leverage this vulnerability to execute code in the context of SYSTEM.
分析發(fā)現(xiàn)這些漏洞實現(xiàn) RCE 的方式主要是以下三種方式:
?SQL 注入漏洞結(jié)合 `outfile` 實現(xiàn) getshell?
? 直接命令拼接 getshell
? 路徑穿越導致 getshell?
查看 `NetworkServlet` 定義:
定位?
`com.imc.iview.network.NetworkServlet#doPost` :
提取參數(shù) `page_action_type` 齿税,根據(jù)取值調(diào)用不同的函數(shù)。下面就選擇三個不同接口來分析三種不同 getshell 的方法炊豪。
方式1:SQL注入+outfile getshell
接口定義:
提取參數(shù)后凌箕,調(diào)用 `findCfgDeviceList` :
進入 `getDistinctDeviceTypes` :
進入 `buildSelectSQL` :
進行一z列參數(shù)賦值與類型轉(zhuǎn)換后進入 `checkForChassisUpdates` ,
傳入的參數(shù) `strSegment` 就是 GET 請求攜帶的參數(shù) `segment` :
private boolean checkForChassisUpdates(String strSegment) {
boolean bReturn = false;
new String();
int nCount = 0;
if (this.initDBServices()) {
String strSQL = "SELECT COUNT(*) UpdateCount FROM device_tree_table as a, device_tree_table as b WHERE b.nDeviceTypeId = 18 AND b.dtBuildDate < '2012-07-09 08:04:00' AND a.nDeviceId = b.nParentId AND a.strDescription = '" + strSegment + "'";
Connection conn = this.getConnection();
try {
Statement stmt = conn.createStatement();
ResultSet resultset;
for(resultset = stmt.executeQuery(strSQL); resultset.next(); nCount = resultset.getInt("UpdateCount")) {
}
...
}
沒有對參數(shù)進行任何檢查词渤,直接拼接進入了 SQL 查詢語句牵舱,導致出現(xiàn) SQL 注入漏洞:
因為 Advantech iView 默認集成的 MySQL 數(shù)據(jù)庫版本較低,支持 `outfile` 缺虐,所以可以利用 SQL 注入直接寫入 webshell:
方式2:mysqldump 命令注入 getshell
接口定義:
提取請求參數(shù) `backup_filename` 芜壁,通過 `checkFileNameIncludePath` 和
`checkSQLInjection` 對進行檢查。
?`checkFileNameIncludePath` 函數(shù)檢查是否存在路徑穿越高氮,并對 `\webapps\` 等進行了過濾慧妄,很顯然 `/webapps/` 就可以繞過。
?`checkSQLInjection` 函數(shù)對插件的 SQL 注入關鍵詞進行了過濾剪芍,也對 `getRuntime().exec` 等命令執(zhí)行常用字符串進行了過濾塞淹,但是沒有過濾 `ProcessBuilder` 等其他可以命令執(zhí)行的函數(shù)。
回到 `backupDatabase` 函數(shù)罪裹,通過過濾檢查后饱普,將調(diào)用 `mysqldump` 進行數(shù)據(jù)庫備份:
if (!errFile && !sqlInj) {
if (tempDBServices.getMySQLLocation()) {
String strMySQLPath = tempDBServices.getMySQLPath();
if (tempDBServices.retrieveDbSettings()) {
String strUser = tempDBServices.getStrLoginUserID();
String strPassword = tempDBServices.getStrLoginPassword();
if (tempSystemTable.findDbBackupFilePath()) {
String strDbBackupFilePath = tempSystemTable.getDbBackupFilePath();
strDbBackupFilePath = strDbBackupFilePath + strFilename;
if (OsUtils.isWindows()) {
strExecuteCmd = "\"" + strMySQLPath;
strExecuteCmd = strExecuteCmd + "bin\\mysqldump\" -hlocalhost -u " + strUser + " -p" + strPassword + " --add-drop-database -B iview -r \"" + strDbBackupFilePath + "\"";
}
try {
runtimeProcess = Runtime.getRuntime().exec(strExecuteCmd);
...
將請求的參數(shù)直接拼接進入了命令執(zhí)行語句:
查看 `mysqldump` 支持的參數(shù)列表:
其中 `-r` 可以指定導出文件的路徑, `-w` 用于設置導出的數(shù)據(jù)條件状共,但其取值也會導出到文件中套耕,所以我們可以用來傳遞 shell 內(nèi)容。最終通過構(gòu)造特殊的 `backup_filename` 參數(shù)實現(xiàn) getshell :
方式3:路徑穿越可導致 getshell
接口定義:
提取參數(shù) `filename` 峡继,傳入 `exportDeviceList` 函數(shù)冯袍,沒有檢查存在路徑穿越風險:
重點關注 `getExportDevices` 和 `createExportFile` 函數(shù):
?`getExportDevices`
StringBuffer strSQL = new StringBuffer("SELECT a.nDeviceId AS \"Device Id\", b.strDescription AS \"Segment\", a.strDeviceTypeId AS \"Device Type\", a.strIPAddress AS \"IP Address\", a.strDNSName AS \"Device Domain Name\", a.strMACAddress AS \"MAC Address\", a.strGetCommunity AS \"Get Community\", a.strSetCommunity AS \"Set Community\", a.strDeviceUser AS \"Device User\", a.strDevicePassword AS \"Device Password\" FROM device_tree_table a, device_tree_table b WHERE a.nParentId = b.nDeviceId");
String strColNames = "Device Id, Segment, Device Type, IP Address, Device Domain Name, MAC Address, Get Community, Set Community, Device User, Device Password";
首先從數(shù)據(jù)表 `device_tree_table` 中查詢符合條件的設備列表 `tempDeviceList` ,然后通過 `setExportList` 賦值給 `m_ExportList` 私有變量碾牌。
`createExportFile`
通過 `getExportList` 提取 `m_ExportList`變量并賦值給
`tempRowOutputList` 颠猴,然后寫入路徑可控文件。
從上面分析可知小染,如果可以將 shell 寫入 `device_tree_table` 翘瓮,那么結(jié)合路徑穿越可以將 shell 寫入任意目錄。比較幸運的是在 `NetworkServlet` 中可以找到添加設備的接口 `addDevices` :
組合 `addDevices` 和 `exportDeviceList` 應該就可以實現(xiàn) getshell 裤翩。
在漏洞復現(xiàn)時發(fā)現(xiàn)资盅, `addDevices` 在多個地方需要通過發(fā)送 udp 廣播包檢查設備的存活性(比如 `Network#updateProViewFunction` 函數(shù)):
偽造數(shù)據(jù)包肯定可以繞過檢查调榄,有興趣的小伙伴可以自行深入分析協(xié)議解析過程完成構(gòu)造!
修復方式
多處增加了SQL注入檢查呵扛,比如`findCfgDeviceList` :
多處增加了路徑穿越檢查每庆,比如 `exportDeviceList` :
縫縫補補修復的地方很多,但是對比分析后仍然感覺程序代碼怎一個亂字了得今穿!