工具介绍
项目地址:
https://github.com/DhavalKapil/icmptunnel
说明
icmptunnel的工作原理是将你的内容封装在ICMP echo数据包中,一般在ICMP数据包的 "data "字段中发送,并将其发送到你自己的代理服务器。代理服务器解压缩数据包并转发。传入的以客户为目的地的IP数据包再次被封装在ICMP回复数据包中,并发回给客户。
特点
- 绕过防火墙
- 绕过协议限制
- 通信加密
流量&逻辑分析
环境&测试准备
环境配置
Server Kali 192.168.2.139
Client Ubantu 192.168.2.129
看相关的文件发现引入了部分至于Linux才有的头文件,正常一般只能在Linux环境中运行,同时需要注意针对客户端需要修改部分内容,详情可参考README.md。
测试方式
- Kali上运行
./icmptunnel -s 192.168.2.139
- Ubantu运行命令
./icmptunnel -c 192.168.2.139
- kali通过tun0通道进行ssh连接
检测特征
+--------------+ +------------+
| | ICMP traffic | | IP traffic
| Client | -------------------> | Proxy | ------------------>
| | <------------------- | Server | <------------------
| | through restricted | | proper internet
+--------------+ internet +------------+
整体入口逻辑都在icmptunnel.c#20#main函数中。
不管Server还是Client都会进入run_tunnel流程,详细跟踪一下相关流程,如下:
/**
* Function to run the tunnel
*/
void run_tunnel(char *dest, int server)
{
struct icmp_packet packet;
int tun_fd, sock_fd;
fd_set fs;
//新建tun0虚拟网卡
tun_fd = tun_alloc("tun0", IFF_TUN | IFF_NO_PI);
//ICMP Socket
sock_fd = open_icmp_socket();
//绑定ICMP Socket
if (server) {
bind_icmp_socket(sock_fd);
}
//依据不同类型执行server.sh或者client.sh来进行网络配置
configure_network(server);
while (1) {
FD_ZERO(&fs);
FD_SET(tun_fd, &fs);
FD_SET(sock_fd, &fs);
//监控所有的文件句柄变化
select(tun_fd>sock_fd?tun_fd+1:sock_fd+1, &fs, NULL, NULL, NULL);
//Reading data from tun device and sending ICMP packet
if (FD_ISSET(tun_fd, &fs)) {
// Preparing ICMP packet to be sent
memset(&packet, 0, sizeof(struct icmp_packet));
//DEFAULT_ROUTE为0.0.0.0
if (sizeof(DEFAULT_ROUTE) > sizeof(packet.src_addr)){
close(tun_fd);
close(sock_fd);
exit(EXIT_FAILURE);
}
strncpy(packet.src_addr, DEFAULT_ROUTE, strlen(DEFAULT_ROUTE) + 1);
if ((strlen(dest) + 1) > sizeof(packet.dest_addr)){
...
}
strncpy(packet.dest_addr, dest, strlen(dest) + 1);
//设置type
if(server) {
set_reply_type(&packet);
}
else {
set_echo_type(&packet);
}
//依照MTU分配空间,默认为1472
packet.payload = calloc(MTU, sizeof(uint8_t));
if (packet.payload == NULL){
exit(EXIT_FAILURE);
}
//tun_read用于从搭建的Tun中读取数据
packet.payload_size = tun_read(tun_fd, packet.payload, MTU);
if(packet.payload_size == -1) {
exit(EXIT_FAILURE);
}
// Sending ICMP packet
send_icmp_packet(sock_fd, &packet);
free(packet.payload);
}
if (FD_ISSET(sock_fd, &fs)) {
// Reading data from remote socket and sending to tun device
// Getting ICMP packet
memset(&packet, 0, sizeof(struct icmp_packet));
//用于从socket信道接受packet
receive_icmp_packet(sock_fd, &packet);
// Writing out to tun device
tun_write(tun_fd, packet.payload, packet.payload_size);
strncpy(dest, packet.src_addr, strlen(packet.src_addr) + 1);
free(packet.payload);
}
}
}
Server逻辑分析
icmptunnel的Server逻辑和client基本一致,逻辑基本是相同的,只是一些细微地方存在差异。
Server逻辑分析
Server端逻辑也很简单,也主要是监听、发送功能,没啥特殊的。