SNMP報文抓取與分析(二)
在上一篇文章(SNMP報文抓取與分析(一))中已經介紹了怎么使用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 |
長度域length表示
長度域用於指示后續的值域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
報文為例)
先來看看報文數據
2.1、數據包分析結果(以get-response為例)
先使用hexdump
來查看一下獲取到的報文內容。(hexdump是一個很好用的十六進制分析工具)
o@o-pc:~/snmpPUD$ hexdump -C b.hex
00000000 30 30 02 01 01 04 06 70 75 62 6c 69 63 a2 23 02 |00.....public.#.|
00000010 04 22 70 8b d4 02 01 00 02 01 00 30 15 30 13 06 |."p........0.0..|
00000020 0e 2b 06 01 04 01 8c a6 5e 01 01 01 01 01 00 02 |.+......^.......|
00000030 01 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) |
2.1、SNMP首部
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 |
2.4、Community共同體表示
還是以之前的數據包來做分析,共同體部分這里一共占了8個字節。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 | 某些其他的差錯 |
錯誤索引error-index
當出現noSuchName
、badValue
或readOnly
的差錯時(見上表),由代理進程在回答時設置的一個整數
,它指明有差錯的變量在變量列表
中的偏移。
貼數據02 01 00
0x02
是標識域,表示值域為整型數據
0x01
是長度域,表示值域長度為1個字節
0x00
是值域,因為沒有出錯,所以這里為0
變量綁定
變量綁定就是跟在錯誤索引后面的一系列變量。這些變量同樣也采取BER
形式的編碼規則。
在get或get-next報文中,變量的值應忽略。
trap(notification)
PUD的類型如果不是上面的所述的get/set
那就應該是trap(notification)
類型了。這里沒有抓取相關的數據包,只是簡單的介紹一下。
trap部分的編碼字節流大致如下分布形式
OID | 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組合類型
sequence表示其由多個數據組合而成,每一個數據也都還是采用的BER
編碼方法。
例如我們這里分析的數據包中就要一個sequence
類型的數據,其值域又是有一個OID
類型的數據和一個Integer
類型的數據組合而成的。