SNMP报文抓取与分析(二)
SNMP报文抓取与分析(二)
- SNMP报文抓取与分析(二)
- 1、SNMP报文表示简介
- 基本编码规则BER
- 标识域Tag表示
- 长度域length表示
- 基本编码规则BER
- 2、SNMP报文详细分析(以一个get-response报文为例)
- 2.1、数据包分析结果(以get-response为例)
- get-response报文示例分析(b.hex)
- 2.1、SNMP首部
- 2.3、SNMP版本表示
- 2.4、Community共同体表示
- 2.1、数据包分析结果(以get-response为例)
- 3、PUD表示
- PDU类型表示
- get/set的表示
- 请求标识符Request ID
- 错误状态error-state
- 错误索引error-index
- 变量绑定
- trap(notification)
- 一些数据类型的编码表示
- Integer整型编码表示
- OID对象标识符编码表示
- sequence组合类型
netcat
来抓取数据包了。也给出了对数据包分析的结果。本篇文章将介绍具体的分析过程。本文由乌合之众 lym瞎编,欢迎转载
blog.cnblogs.net/oloroso
本文由乌合之众 lym瞎编,欢迎转载
my.oschina.net/oloroso
1、SNMP报文表示简介 SNMP(简单网络管理协议)是目前在计算机网络中用得最广泛的网络管理协议,它使用
ASN.1
(Abstract Syntax Notation One抽象语法表示法.1)来定义SNMP报文格式和MIB(Management Information Base管理信息库)变量的名称。ASN.1是一种
描述数据和数据特征
的正式语言,它和数据的存储及编码无关。根据ASN.1标准定义,数据类型分为:
简单数据类型:
boolean
布尔值、null
空、integer
整型、real
实数、octerstring
八进制字符串、object identifier
对象标识、ipaddress
IP地址、time ticks
时刻值等。构造数据类型:
sequence
序列、sequence of set
、set ofchoice
等。构造数据类型提供一种或多种简单数据类型进行复合的方法。基本编码规则BER
在具体系统中,我们需要用具体的编码规则将
ASN.1
语法表示的抽象数据转换成具体的比特流
。SNMP使用的编码方法是
BER(Basic Encoding Rule)
。BER的数据都由三个域构成:标识域(tag
)+长度域(length
)+值域(value
)。标识域Tag表示
数据类型 | 编码十六进制表示 |
---|---|
BOOL | 0x01 |
INT | 0x02 |
OCTSTR | 0x04 |
NULL | 0x05 |
OBJID | 0x06 |
ENUM | 0x0A |
SEQ | 0x30 |
SETOF | 0x31 |
IPADDR | 0x40 |
COUNTER | 0x41 |
GAUGE | 0x42 |
TIMETICKS | 0x43 |
OPAQUE | 0x44 |
GET | 0xA0 |
GETNEXT | 0xA1 |
GETResp | 0xA2 |
SET | 0xA3 |
TRAP | 0xA4 |
值域value
的字节数。但是这个长度域自身多长怎么确定呢?SNMP使用的是变长表示法,这有点类似与UTF8
的编码方式。具体表示方法如下:1、如果值域的长度在
0
到127
字节之间,那么就是一个字节来表示,即第一个最高位为0
的时候,其值就代表了值域的长度。2、如果值域的长度在
127
字节以上,那么第一个字节的第一个bit位
(为1)就用于指示值域的长度在127
字节以上,后7个bit位
(实际值)以及后续用于表示值域长度的字节数。例如:
值域长度(十进制) | 编码表示(十六进制) | 解释 |
---|---|---|
16 | 0x10 | 在0 到127 之间,直接表示 |
160 | 0x81 0xA0 | 0x81 的二进制为1000 0001 第一位表示其超过127 ,低7位表示后续还有一个字节来表示值域字节数。0xA0 表示值域的长度为160个字节。 |
1500 | 0x82 0x05 0xDC | 第一个字节0x82 表示后续还有两个字节表示值域长度,0x05DC 的十进制值为1500 |
【0,127】
区间内,所有这种表示方法最节约。2、SNMP报文详细分析(以一个
get-response
报文为例) 【SNMP报文抓取与分析(二)】先来看看报文数据2.1、数据包分析结果(以get-response为例)
先使用
hexdump
来查看一下获取到的报文内容。(hexdump是一个很好用的十六进制分析工具)o@o-pc:~/snmpPUD$ hexdump -C b.hex
0000000030 30 02 01 01 04 06 7075 62 6c 69 63 a2 23 02|00.....public.#.|
0000001004 22 70 8b d4 02 01 0002 01 00 30 15 30 13 06|."p........0.0..|
000000200e 2b 06 01 04 01 8c a65e 01 01 01 01 01 00 02|.+......^.......|
0000003001 2b|.+|
00000032
get-response
报文示例分析(b.hex)
十六进制数据 | 解释 |
---|---|
30 | 表示SNMP协议报文(整个报文是一个SEQUENCE) |
30 | 消息长度48字节(表示后面还有44个字节的内容) |
02 01 01 | 协议版本(2c)(前两个字节02 01 表示INTEGER类型) |
04 | 参数类型(OCTSTR) |
06 | 群体(community)名长度 |
70 75 62 6c 69 63 | 群体名public的assic码值 |
a2 | PUD类型get-response |
23 | snmp pdu的长度为35个OctStr(后面的内容31字节) |
02 04 22 70 8b d4 | 请求标识符Request ID |
02 01 00 | 表示error-state为0 |
02 01 00 | 表示error-index为0 |
30 11 | 表示后面变量绑定是SEQUENCE类型17个字节长度 |
30 0f | 表示(变量名1变量值1)是SEQUENCE类型15个字节长度 |
06 | 表示该字段是OID类型 |
0b | OID长度11字节 |
2b 06 01 04 01 | 1.3.6.1.4.1(标识1.3被合并为2B) |
8c a6 5e | 201566 (这也是根据规则转换得到的) |
01 01 01 | 1.1.1 |
00 | 表示.0 即第一个实例\ |
(下面的值实际是节点1.3.6.1.4.1.201566.1.1.1.0的) | |
02 01 2b | 02 01 表示INTEGER类型,2b表示值(43) |
SNMP报文的首部指明了这个报文是SNMP协议报文,以及报文的字节数。
SNMP报文的第一个字节用于表示这是一个SNMP报文,就是
0x30
。在第一个字节之后是一个长度域,用于告知后面的SNMP报文的总字节数(不包括前面的
0x30
和这个长度域所占的字节数)。如下所示0x30 | length | 后面的内容,字节数为length.... |
---|---|---|
标识域 | 长度域 | 值域 |
这就是BER编码规则出来的
Byte
流数据。2.3、SNMP版本表示 上述值域部分,前三个字节是SNMP版本的内容。
0x02,0x01,0x01
0x02
是标识域,表示的是值域类型为Integer
0x01
是长度域,表示后续值域的长度为1个字节0x01
是值域,表示版本为SNMP v2c
。SNMP版本 | 编码(十六进制) |
---|---|
V1 | 0x00 |
V2C | 0x01 |
V3 | 0x02 |
0x04,0x06,0x70,0x75,0x62,0x6c,0x69,0x63
0x04
是标识域,表示值域类型为(OCTSTR)0x06
是长度域,表示值域的长度为6个字节 70 75 62 6c 69 63
是值域的内容,是群体名public
的assic码值3、PUD表示 这个部分内容比较多,但都是基于BER形式编码出来的。就不详细分析了。
先把这一部分的内容贴出来
a2 23 02 04 22 70 8b d4 02 01 00 02 01 00 30 15 30 13 06 0e 2b 06 01 04 01 8c a6 5e 01 01 01 01 01 00 02 01 2b
PDU类型表示
上面的第一个字节
0xa2
就是表示这个PDU的类型。见下表PDU类型编码 | 名称 |
---|---|
0xA0 | get-request |
0xA1 | get-next-request |
0xA2 | get-response |
0xA3 | set-request |
0xA4 | trap(notification) |
0xA5 | GetBulk(SNMPv2增加) |
0xA6 | Inform(SNMPv2增加) |
0xa2
后一个字节是这个PUD的长度域,0x23
表示后面的值域是35
个字节。get/set的表示
SNMP应该说是有三种操作,
get/set/trap
,又可细分为上面表格中的5中PDU
类型。其中get
和set
有共同之处,这里先以get
的来做说明。请求标识符Request ID 这是由
管理进程
设置的一个整数值。代理进程在发送get-respons
e报文时也要返回此请求标识符。管理进程可同时
向许多代理发出get
报文,这些报文都使用UDP
传送,先发送的有可能后到达。设置了请求标识符可使管理进程
能够识别
返回的响应报文对于哪一个请求报文先贴数据
02 04 22 70 8b d4
0x02
是标识域,表示值域为整型数据0x04
是长度域,表示值域长度为4个字节0x22 70 8b d4
是值域,就是一个整数而已。(577801172)错误状态error-state 错误状态是用于告知管理进程,代理进程对其发出的请求的处理结果的状态的。
还是贴数据
02 01 00
0x02
是标识域,表示值域为整型数据0x01
是长度域,表示值域长度为1个字节0x00
是值域,表示没有出错错误状态的编码如下表所示
编码 | 名字 | 说明 |
---|---|---|
0 | noError | 一切正常 |
1 | tooBig | 代理无法将回答装入到一个SNMP报文之中 |
2 | noSuchName | 操作指明了一个不存在的变量 |
3 | badValue | 一个set操作指明了一个无效值或无效语法 |
4 | readOnly | 管理进程试图修改一个只读变量 |
5 | genErr | 某些其他的差错 |
noSuchName
、badValue
或readOnly
的差错时(见上表),由代理进程在回答时设置的一个整数
,它指明有差错的变量在变量列表
中的偏移。贴数据
02 01 00
0x02
是标识域,表示值域为整型数据0x01
是长度域,表示值域长度为1个字节0x00
是值域,因为没有出错,所以这里为0变量绑定 变量绑定就是跟在错误索引后面的一系列变量。这些变量同样也采取
BER
形式的编码规则。在get或get-next报文中,变量的值应忽略。
trap(notification)
PUD的类型如果不是上面的所述的
get/set
那就应该是trap(notification)
类型了。这里没有抓取相关的数据包,只是简单的介绍一下。trap部分的编码字节流大致如下分布形式
-
- 1、第一个部分是指trap报文对应的网络设备的对象标识符。此对象标识符肯定是在enterprise结点{1.3.6.1.4.1}下面的一棵子树上。
- 2、trap类型
此字段正式的名称是generic-trap,共分为下表中的7种。
trap类型 名字 说明 0 coldStart 代理进行了初始化 1 warmStart 代理进行了重新初始化 2 linkDown 一个接口从工作状态变为故障状态 3 linkUp 一个接口从故障状态变为工作状态 4 authenticationFailure 从SNMP管理进程接收到具有一个无效共同体的报文 5 egpNeighborLoss 一个EGP相邻路由器变为故障状态 6 enterpriseSpecific 代理自定义的事件,需要用后面的“特定代码”来指明 - 3、当使用上述类型2、3、5时,在报文后面变量绑定部分的
第一个变量
应标识响应
的接口。
- 4、特定代码(specific-code)
指明代理自定义的时间(若trap类型为6),否则为0。 - 5、时间戳(timestamp)
指明自代理进程初始化
到产生trap报告
的事件发生所经历的时间,例如时间戳为1230表明在代理初始化后1230ms发生了该时间。 - 5、变量绑定(variable-bindings)
指明一个或多个变量的名和对应的值。也是采用的BER
编码规则。
Integer整型编码表示
整型数据的标识域编码是
0x02
,长度域不定,一般是1/2/4
字节等。整型数据的值域是带符号类型,最高位是符号位,采取补码的表示形式。要注意的是,其是
大端表示法
(高地址存低位)。OID对象标识符编码表示
SNMP服务器维护的所有管理信息库(MIB)对象采用ObjectID表示,如,1.3.6.1.2.1.1.1表示MIB库中的设备描述
SysDesc
变量,其编码规则如下:标识域编码为
0x06
,长度域根据情况而定,值域的编码比较复杂,如下所示。- 1、首两个ID被合并为一个字节
X * 40+Y
。
例如:1.3
合并为1x40+3 =43
=0x2B
- 2、后续的ID,如果在区间
[1,127]
内,直接编码表示,如果大于127
,那么按照下面(3)所述方法编码 - 3、如果ID大于127,那么使用多个字节来表示。
- a.这多个字节中
除最后一个字节
外,前面的字节最高位为1
- b.这多个字节的
最后一个字节
的最高位为0
- c.这里每个字节剩下的7个比特位用来表示实际的数值
例如这里的201566
这个数,用十六进制表示是0x03 13 5e
那么用二进制表示是000 1100
010 0110
101 1110
注意上面是以7个比特位为单位进行分划的,现在我们来填充最高位
将前面的最高位填1
,最后一个最高位填0
即可得到1000 1100
1010 0110
0101 1110
用十六进制表示为0x8c a6 5e
- a.这多个字节中
sequence表示其由多个数据组合而成,每一个数据也都还是采用的
BER
编码方法。例如我们这里分析的数据包中就要一个
sequence
类型的数据,其值域又是有一个OID
类型的数据和一个Integer
类型的数据组合而成的。推荐阅读
- AnyProxy抓取http/https请求
- python|python 爬虫抓取图片
- Scrapy1.4.0之抓取58同城房源详解(一)
- 如何将EDI报文转换为CSV格式文件()
- 网络爬虫抓取图片并上传到fastdfs图片不完整问题解决
- 抓包工具|抓包工具 charles
- Java|Java 解析xml报文放入Map,并判断所有xml标签是否为空
- 有关报文、分组、帧、比特流的问题
- XML|XML报文转Map
- tcpip协议栈 协议报文合集