打印机之Internet Printing Protocol(IPP)协议分析

您所在的位置:网站首页 基友头像ins 打印机之Internet Printing Protocol(IPP)协议分析

打印机之Internet Printing Protocol(IPP)协议分析

2024-05-08 08:42| 来源: 网络整理| 查看: 265

打印机之Internet Printing Protocol(IPP)协议分析

概述

网络打印协议(IPP)是一种专门的应用层协议,用于客户端设备(计算机,移动电话,平板电脑等)和打印机(或之间的通信的打印服务器)。它允许客户端向打印机或打印服务器提交一个或多个打印作业,并执行诸如查询打印机状态、获取打印作业状态或取消单个打印作业等任务,目前98% 以上的打印机都支持IPP。

​ from wiki Internet_Printing_Protocol

​ 在研究打印机漏洞过程中,发现目前绝大部分的打印机都支持IPP协议,且绝大部分的打印机针对该协议未设置授权访问,这意味着任何人都可以通过IPP协议匿名连接到这些设备(打印机)。攻击者可以滥用这些设备以用于信息披露,包括潜在访问和操纵打印作业。远程代码执行漏洞也已在过去的各种打印机模型上被发现,并且可能会被利用。本文主旨在通过分析IPP协议,让读者对IPP协议有一个更清楚的认识。

​ IPP 是使用超文本传输协议(HTTP) 实现的,并继承了所有 HTTP 流的安全功能,IPP 使用传统的C-S模型,客户端在 HTTP POST 请求中向 IPP 打印机发送带有MIME媒体类型“application/ipp”的IPP 请求消息。IPP 请求消息由使用自定义的二进制编码的键值对组成,后跟“end-of-attributes-tag”属性结束标签和请求所需的任何文档数据(例如要打印的文档)。IPP 响应在 HTTP POST 响应中发送回客户端,再次使用“application/ipp”MIME 媒体类型,如图1所示。

​ 图1 基于HTTP协议的IPP协议

IPP主要有IPP/1.1,IPP/2.0, IPP/2.1, IPP/2.2四个版本。其中1.1版本主要关注用户功能的实现,其他三个版本单独定义了许多新的操作。

本文目录结构组织如下:

IPP简易模型 相关专业术语解释 IPP协议中的核心操作-同步 IPP 传输过程中数据的编码 公网上的暴漏情况 检测工具 IPP简易模型

​ 图2 IPP模型

术语解释:

End User: 终端用户

IPP Client: IPP客户端,实现了IPP的客户端协议,终端用户通过使用IPP客户端去查询打印机以及管理打印任务。

IPP Server:实现了服务端打印机对象的协议。

Print Service: 具体的执行打印任务的服务

Out Device(s): 输出设备

该图节选自RFC8011,从图2可以看出,终端用户通过连接IPP客户端,将要打印的数据传送到IPP服务端,IPP服务端接着将数据交给打印服务,来打印客户提交的打印作业,最后通过输出设备输出。

相关术语解释 Job

一次打印任务被称为一次作业

Attributes

属性是一个信息项,它与一个IPP对象(打印机、作业等)的实例相关联。IPP对象(打印机、作业等)的实例相关联的信息。 一个属性由一个属性名称(name)和一个或多个属性值(value)组成。 每个属性都有一个特定的属性语法,主要分为操作属性,打印属性以及作业属性

操作属性标签

打印属性标签

作业属性标签

Attribute Group Name

相关的属性被分组为命名的组,组的名称组是一个关键字。 组的名称可以用来代替命名组中的所有属性。

Attribute Name

属性名是一个关键字,用来描述一个属性代表的含义

end-of-attributes-tag

属性结束标签,标记着属性的结束。

DATA:

具体的被打印的数据

操作层

因为IPP协议是在http协议之上封装的协议,这里的操作层其实指的就是HTTP请求或响应的消息主体部分(发送post请求的时候的data的值)。IPP传输层协议用的是HTTP,支持HTTP1.1和HTTP1.2。

IPP协议中的核心操作-同步

IPP协议中的核心操作同步主要通过operation-id和request-id来保证服务器与客户端交互的同步性,如下图所示

operation-id

​ 每个IPP操作请求都包括一个可识别的"operation-id" 值,客户端通过"operation-id"指定每次IPP请求发送什么操作。支持的操作列表以及对应的operation-id如下表所示

operation-idOperation Name0x0000reserved, not used0x0001reserved, not used0x0002Print-Job0x0003Print-URI0x0004Validate-Job0x0005Create-Job0x0006Send-Document0x0007Send-URI0x0008Cancel-Job0x0009Get-Job-Attributes0x000aGet-Jobs0x000bGet-Printer-Attributes0x000cHold-Job0x000dRelease-Job0x000eRestart-Job0x000freserved for a future operation0x0010Pause-Printer0x0011Resume-Printer0x0012Purge-Jobs0x4000-0x7fffreserved for vendor extensions request-id

​ 每个IPP操作请求都包括一个可识别的 "request-id"值,每个操作(operation-id指定)的调用都是由一个 "request-id "值来识别。 对于每个请求,客户端选择"request-id",它必须是一个唯一的整数(范围为1到2**31-1(包括),这个 "request-id "允许客户管理多个未处理的请求。

​ 接收的IPP对象(打印机、作业等)会复制所有的32位的客户提供的 "request-id "属性复制到响应中,以便客户能与之匹配响应,以便客户可以将响应与正确的未处理请求相匹配。 如果请求在收到完整的 "request-id "之前就被终止了,那么IPP对象就会拒绝这个请求并返回一个 "request-id "为0的响应。

IPP 传输过程中数据的编码

​ 操作层是HTTP请求或响应的消息主体部分,它必须包含一个IPP操作请求或IPP操作响应。 每个请求或响应是由一连串的值和属性组成的序列。 属性组指的是一个属性的序列,每个属性包含一个名称和值,本章节介绍了传输过程中IPP数据的编码请求和响应消息的编码。

Request and Response ----------------------------------------------- | version-number | 2 bytes - required ----------------------------------------------- | operation-id (request) | | or | 2 bytes - required | status-code (response) | ----------------------------------------------- | request-id | 4 bytes - required ----------------------------------------------- | attribute-group | n bytes - 0 or more ----------------------------------------------- | end-of-attributes-tag | 1 byte - required ----------------------------------------------- | data | q bytes - optional -----------------------------------------------

​ IPP 报文格式

每次IPP操作请求都必须包含以下参数(注意顺序):

"version-number" "operation-id" "request-id"

每次的IPP操作响应都必须包含以下参数(注意顺序):

"version-number" "status-code" "request-id":对应的请求中的request-id

​ 第四个字段是 "attribute-group "字段,它出现0次或更多次。 每个 "attribute-group "字段代表一个单一的属性组,例如文中上面提到的操作属性组或工作属性组,但要注意顺序,是有序的。"end-of-attributes-tag "字段总是存在的,即使"data "字段不存在,"data"字段代表打印的数据。

Attribute Group --------------------------------------------------------- | begin-attribute-group-tag | 1 byte ---------------------------------------------------------- | attribute | p bytes |- 0 or more ----------------------------------------------------------

​ 一个 "attribute-group "字段包含零个或多个 "attribute"字段。请注意,"begin-attribute-group-tag "字段的值和"end-of-attributes-tag"字段的值被称为 "分隔符"(delimiter-tags)。

Attribute --------------------------------------------------------- | attribute-with-one-value | q bytes ---------------------------------------------------------- | additional-value | r bytes |- 0 or more

​ 当一个属性只有一个单一的指(例如,"copies "的值为10和"side-supported "仅具有值"one-sided";代表单面打印10页),则传输的数据根据"attribute-with-one-value"的数据结构来进行编码。当一个属性是有n个值的多值时 (例如,"sides-supported "有 " one-sided"和 "two-sided-long-edge "两个值),它就被编码为一个 "attribute-with-one-value "字段,后面有n-1个 "additional-value "字段。

Attribute-with-one-value ----------------------------------------------- | value-tag | 1 byte ----------------------------------------------- | name-length (value is u) | 2 bytes ----------------------------------------------- | name | u bytes ----------------------------------------------- | value-length (value is v) | 2 bytes ----------------------------------------------- | value | v bytes

一个 "Attribute-with-one-value "字段被编码为五个子字段。

"value-tag "字段指定了属性的语法,例如,0x44代表 "keyword"。 "name-length "字段指定了 "name "字段的长度,以字节为单位,例如上图中的u或 "side-supported "名称的长度15。 "name "字段包含属性的文本名称,例如"side-supported"。 "value-length "字段指定了 "value "字段的长度,单位为字节,例如,图中的v或者值 "one-sided"的长度是9(上面side-supported对应的值)。 "value "字段包含了属性的值,例如,文本值 "one-sided"。 Additional-value ----------------------------------------------- | value-tag | 1 byte ----------------------------------------------- | name-length (value is 0x0000) | 2 bytes ----------------------------------------------- | value-length (value is w) | 2 bytes ----------------------------------------------- | value | w bytes

一个 "附加值 "是由四个子字段编码的。

"value-tag "字段指定了对应的属性,例如,0x44表示 "keyword"。 "name-length "字段的值为0,表明它是一个 "additional-value"。 "value-length"字段的值,例如上面提到的"two-sided-long-edge"的长度是19 "value":字段表明文本值 "two-sided-long-edge"。 部分代码实现 DEFAULT_PROTO_VERSION = (2, 0) # GET_PRINTER_ATTRIBUTES operation= 0x000B DEFAULT_CHARSET = "utf-8" DEFAULT_CHARSET_LANGUAGE = "en-US" # 注意这里需要进行一个ipp或者IPPS 到http 或者https的转化 # 如果是检测ipp,则scheme是http,如果检测ipps,则scheme是https self.printer_url=self.scheme + "://" + host + ":" + port + "/ipp/print" def message(self, operation): # 数据包的构造必须是有序的 payload = OrderedDict() payload["version"] = DEFAULT_PROTO_VERSION payload["operation"] = operation payload["request-id"] = random.choice(range(10000, 99999)) attributes = OrderedDict() attributes["attributes-charset"] = DEFAULT_CHARSET attributes["attributes-natural-language"] = DEFAULT_CHARSET_LANGUAGE attributes["printer-uri"] = self.printer_url payload["operation-attributes-tag"] = attributes return payload 公网上的暴漏情况

shodan 搜索关键字 device:printer port:"631",可以发现公网上设备还是挺多的

检测工具

https://github.com/ctalkington/python-ipp

安装 pip install pyipp 用法 import asyncio from pyipp import IPP, Printer async def main(): """Show example of connecting to your IPP print server.""" async with IPP("ipps://EPSON123456.local:631/ipp/print") as ipp: printer: Printer = await ipp.printer() print(printer) if __name__ == "__main__": loop = asyncio.get_event_loop() loop.run_until_complete(main()) 参考

https://datatracker.ietf.org/doc/html/rfc2910

https://datatracker.ietf.org/doc/html/rfc8011

https://datatracker.ietf.org/doc/html/rfc8010



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3