zoukankan      html  css  js  c++  java
  • C# 自己组装SNMP的Get请求报文

    版本 SNMPv2 ,先添加具体内容,最后添加报文长度及类型。

    执行以下代码前,请先打开SNMP服务。并接收所有IP的SNMP请求

                    string oid = "1.3.6.1.2.1.1.5.0";  //sysName 计算机名
    
                    List<byte> lstOidBytes = new List<byte>();
                    string[] mibvals = oid.Split('.');
    
                    #region 将oid转换成byte 这一部分是从别的地方抄的,含义还不是很明白  1.3.6.1.2.1.1.5.0转换出来变成 2b 06 01 02 01 01 05 00
                    // Convert the string MIB into a byte array of integer values
                    // Unfortunately, values over 128 require multiple bytes
                    // which also increases the MIB length
                    for (int i = 0; i < mibvals.Length; i++)
                    {
                        short temp = Convert.ToInt16(mibvals[i]);
                        if (temp > 127)
                        {
                            lstOidBytes.Add(Convert.ToByte(128 + (temp / 128)));
                            lstOidBytes.Add(Convert.ToByte(temp - ((temp / 128) * 128)));
                        }
                        else
                        {
                            lstOidBytes.Add(Convert.ToByte(temp));
                        }
                    }
                    lstOidBytes.RemoveRange(0, 2);
                    lstOidBytes.Insert(0, 0x2b);
                    #endregion
    
    
                    //添加查询键值对 Pdu中的键值绑定部分(Variable bindings),先添加内容,最后添加长度及类型
                    List<byte> lstVariablebindings = new List<byte>();
                    lstVariablebindings.Add(0x06);  /类型 OBJECT IDENTIFIER  即用于查询的Oid
                    lstVariablebindings.Add(Convert.ToByte(lstOidBytes.Count));//Oid 的长度 
                    lstVariablebindings.AddRange(lstOidBytes); //添加OID,即1.3.6.1.2.1.1.5.0
                    lstVariablebindings.Add(0x05); //NULL值 查询时Value为空
                    lstVariablebindings.Add(0x00); //NULL 空 
    
                    lstVariablebindings.Insert(0, Convert.ToByte(lstVariablebindings.Count)); ////第一对键值对的长度
                    lstVariablebindings.Insert(0, 0x30); //第一对键值对的类型为 SEQUENCE
    
                    lstVariablebindings.Insert(0, Convert.ToByte(lstVariablebindings.Count)); //整个 Variable bindings 的长度
                    lstVariablebindings.Insert(0, 0x30); //整个 Variable bindings的类型为  SEQUENCE
    
                    //PDU报文部分 先添加内容,最后添加长度及类型
                    List<byte> lstPdu = new List<byte>();
                    lstPdu.AddRange(BitConverter.GetBytes(new Random().Next())); //请求编号 RequestID 根据该值对返回的数据进行判断
    
                    lstPdu.Insert(0, Convert.ToByte(lstPdu.Count)); //RequestID的长度
                    lstPdu.Insert(0, 0x02); //RequestID的类型为INTEGER
    
                    //错误状态 Error Status  在请求时,默认置0
                    lstPdu.Add(0x02); //INTEGER
                    lstPdu.Add(0x01); //长度1
                    lstPdu.Add(0x00); //值为0
    
                    //错误索引 Error Index  在请求时,默认置0
                    lstPdu.Add(0x02); //INTEGER
                    lstPdu.Add(0x01); //长度1
                    lstPdu.Add(0x00); //值为0
    
                    lstPdu.AddRange(lstVariablebindings);
    
                    lstPdu.Insert(0, Convert.ToByte(lstVariablebindings.Count)); //PDU报文部分的长度
                    lstPdu.Insert(0, 0xa0); //PDU 类型 get请求 //代码含义:a0 get-request a1 get-next-request a2 get-response a3 set-request a4 trap
    
                    //SNMP报文部分 先添加内容,最后添加长度及类型
                    List<byte> lstSNMP = new List<byte>();
    
                    lstSNMP.Add(0x02); //版本号 INTEGER类型
                    lstSNMP.Add(0x01); //版本号长度1 
                    lstSNMP.Add(0x01); //版本号01,即v2版本
    
                    //Community Name //打开SNMP服务时可以设置,这里使用默认的public
                    byte[] communityBytes = Encoding.ASCII.GetBytes("public");
    
                    lstSNMP.Add(0x04); //团体名(Community)类型 OCTET STRING
                    lstSNMP.Add(Convert.ToByte(communityBytes.Length));
                    lstSNMP.AddRange(communityBytes);
    
                    lstSNMP.AddRange(lstPdu);
    
                    lstSNMP.Insert(0, Convert.ToByte(lstSNMP.Count)); //整个SNMP报文长度
                    lstSNMP.Insert(0, 0x30); //整个SNMP报文类型 SEQUENCE类型
    
                    UdpClient udpsender = new UdpClient();
    
                    IPEndPoint ipe = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 161);
    
                    udpsender.Connect(ipe);
    
                    udpsender.Send(lstSNMP.ToArray(), lstSNMP.Count);
    
                    byte[] response = udpsender.Receive(ref ipe);
    
                    //将返回报文以字符串显示出来
                    List<string> lst = new List<string>();
                    foreach (byte item in response)
                        lst.Add(item.ToString("X").PadLeft(2, '0'));
                    txtContent.Text = string.Join(" ", lst.ToArray());

    在我的机器上,执行上述方法后,返回 30 43 02 01 01 04 06 70 75 62 6C 69 63 A2 36 02 04 7B A8 56 04 02 01 00 02 01 00 30 28 30 26 06 08 2B 06 01 02 01 01 05 00 04 1A 43 44 4F 43 30 31 30 31 34 2E 63 68 69 63 6F 6E 79 73 71 75 61 72 65 2E 63 64

    这里可以简单分析下返回的SNMP报文

    30 43                                           SEQUENCE类型,SNMP报文最开始应该都是固定的30 。 43 为整个报文长度 67个字节

    02 01 01                                      这里是版本号,INTEGER类型 长度1个字节 ,值为1,即v2

    04 06 70 75 62 6C 69 63             团体名(community name), OCTET STRING类型,长度6个字节,值为 public

    A2 36                                           PDU类型 2 即 get-response  对get请求的应答 ,长度54字节

    02 04 7B A8 56 04                       RequestID ,INTEGER类型,长度4个字节,值即为刚才请求时的ID

    02 01 00                                      错误状态,0,表示没有错误,INTEGER类型,1个长度,值为0

    02 01 00                                      错误索引,0,表示没有错误,INTEGER类型,1个长度,值为0

    30 28                                           PDU键值对开始的地方,SEQUENCE类型,长度40个字节

    30 26                                           第一个键值对,SEQUENCE类型,长度38个字节

    06 08 2B 06 01 02 01 01 05 00   键  OBJECT IDENTIFIER 类型,即Oid , 长度8个字节, 1.3.6.1.2.1.1.5.0  

    04 1A 43 44 4F 43 30 31 30 31 34 2E 63 68 69 63 6F 6E 79 73 71 75 61 72 65 2E 63 64  值  OCTET STRING类型,26个字节, 1A后面的内容即是我的计算机名,用ASCII转换出来,为CDOC01014.chiconysquare.cd。说明运行正常。

    虽然现在有SnmpSharpNet这个开源项目可以直接使用,但自己从底层写一遍更有利与加深对该协议格式的理解。

  • 相关阅读:
    解析漏洞总结
    ssh登录日志位置
    xshell ssh连接linux时提示ssh服务器拒绝了密码
    Linux安装ssh
    Apache Shiro (Shiro-550)(cve_2016_4437)远程代码执行
    CVE-2019-1388 UAC提权复现
    CVE-2019-0708复现之旅
    Apache Flink漏洞(CVE-2020-17519)复现
    FourEye(重名免杀实践)过360
    CVE-2020-11651:SaltStack认证绕过复现
  • 原文地址:https://www.cnblogs.com/xyz0835/p/5135666.html
Copyright © 2011-2022 走看看