☰
CTF Web爆破入门:原理拆解、Burp Suite实操与字典制作全解析
2026/10/9 3:13:17 网站建设 项目流程

“爆破”这个词,在CTF的Web方向里,绝对是入门选手绕不开的第一道坎。很多新手第一次接触ctfshow的web入门题,看到“爆破”这个标签,以为是拿工具对着登录框一顿猛点,结果点半天毫无反应,反而被封了IP或者卡在奇怪的验证码上。其实,CTF里的爆破和现实中的“撞库”有本质区别,它更像是一场精心设计的逻辑游戏,考验的是你对HTTP协议、响应差异和业务逻辑的理解,而不是单纯考验工具的运行速度。

这篇文章,我就以ctfshow的web入门爆破专题为线索,从原理拆解到工具实操,再到字典制作和常见坑点,把这一整套东西讲透。不管你是刚入门的小白,还是想系统梳理思路的选手,这篇内容应该都能给你一些启发。

1. 爆破的本质与CTF题的出题思路

1.1 爆破到底在爆什么

所谓的爆破,全称是暴力破解,英文叫Brute Force。它的核心逻辑听起来相当简单粗暴:一个一个试。你把所有可能的用户名和密码组合排列出来,或者把所有可能的验证码、Token、ID值枚举出来,逐一提交给服务器,直到拿到正确的那个。

但在CTF的Web题里,爆破往往不是“唯一解”,而是“通道”。也就是说,出题人并不会真的让你把几十亿种组合全部跑完,那在比赛环境下不现实,对服务器也是灾难。通常情况下,服务器会存在某种逻辑缺陷或校验漏洞,你需要利用爆破这个手段,去触碰那个隐藏的、不合理的、或者被刻意弱化了的校验逻辑,从而获得关键信息,比如管理员密码、隐藏的备份文件、某个Otp验证码、或者一个完整的Flag。

理解这一点非常重要:你是去“发现”答案,而不是去“硬算”答案。这和现实中用Hydra或Medusa跑弱口令的行为有实质区别,CTF的靶场环境是比赛专用,合法合规,但思路是通用的。如果一个思路在靶场里行得通,在真实的授权渗透测试中,往往也能帮助你理解目标系统的防御薄弱点。

1.2 ctfshow的爆破章节为什么值得刷

ctfshow的Web入门模块,尤其是爆破这个专题,非常适合新手的原因有三点:

  • 题目梯度设计合理,从最简单的“字典直接爆破”到“基于响应差异判断”,再到“自定义脚本绕过”,层层递进。
  • 环境稳定,平台本身就是国内CTF圈子里常用的练手平台,靶场环境不需要自己搭建,登录即用。
  • 考察点集中,不像其他综合题会东拉西扯很多知识点,爆破专题的每一题都有一个非常明确的“爆破点”,你做完之后就能快速知道自己卡在哪、哪儿没想通。

1.3 从出题人视角看爆破题套路

你可以试着站在出题人的角度想一想:如果我想出一道爆破题,我得让选手有得“爆”,但又不能太简单。太简单的话,大家直接手填几个密码就出来了,没意思;太难的话,选手跑了几天都跑不出来,比赛没法进行。

所以出题人一定会引入“变量”,也就是增大爆破难度的因素,常见的就那么几个:

  • 字典范围:用户名可枚举,密码是弱口令或常见组合。
  • 验证码机制:图片验证码是否真的校验了?校验后是否失效?校验是否绑定在会话上?
  • 请求限制:是否限制了IP、是否限制了尝试次数、是否有封禁机制。
  • 响应差异:登录成功和登录失败返回的内容完全不同,或者状态码不同,或者跳转的URL不同。这也是你判断是否爆破成功的关键。

想通这一点,你再看任何一道爆破题,思路就会清晰很多:先搞清楚服务器要什么,再搞清楚它的校验逻辑哪儿不严谨,最后决定用什么工具、什么字典、什么脚本去“精准击中”那个错误。

2. 工具选型与Burp Suite核心配置

2.1 为什么首选Burp Suite

做Web爆破,工具选择不少:有命令行神器Hydra,有基于Python的脚本,甚至你可以用Python的requests库自己写多线程爆破。但如果你在入门阶段,我强烈建议你先用Burp Suite,尤其是它的Intruder模块。

理由很简单:Burp Suite能让看见每一步的请求和响应。CTF里的Web爆破,不是把字典扔进去就行,很多时候你需要边看响应边调整策略。Burp的Intruder模式,能直观地以表格形式列出每次请求的状态码、响应长度、响应内容,你可以一眼扫过去发现“这个包长度为666,别人都是600左右,有点东西”,从而快速定位正确答案。

如果你连Burp都还没学会抓包,那我建议你先花半小时熟悉一下Proxy模块,把浏览器的流量代理到Burp上,搞明白请求是怎么发出去的。学会看原始HTTP请求包,比会用任何工具都重要。

2.2 Intruder模块的四种攻击模式

Burp的Intruder支持四种攻击模式,在CTF里最常用的有两种:

  • Sniper(狙击手):只有一个或几个Payload位置,一次只爆破一个变量,循环尝试。这是最常用的爆破模式,比如固定用户名为admin,爆破密码。
  • Battering Ram(攻城锤):多个位置使用同一组Payload,所有位置用同一个值替换。
  • Pitchfork(草叉):多个位置使用不同的字典,同步对应替换,比如第一个位置从A字典取第一个值,第二个位置从B字典取第一个值。
  • Cluster Bomb(集束炸弹):多个位置使用不同的字典,做笛卡尔积组合,也就是全排列遍历。这在爆破用户名和密码组合时很常见。

你在做题之前,先判断这道题需要爆破几个变量。如果只有一个变量(比如四位数PIN码),那就用Sniper。如果用户名和密码都未知,那你可能需要先枚举用户名,再爆破密码,或者用Cluster Bomb直接跑组合。但注意,Cluster Bomb的组合数量是爆炸式增长的,假设用户名有10个,密码有100个,那一共就是1000次请求,本地跑没问题,但也要注意平台对并发请求的限制。

2.3 Payload配置与线程数调优

很多人爆破不出来,不是方法错了,而是Payload没配置对。

Intruder的Payload Options里有几种常见类型:

  • Simple list:直接粘贴字典,最简单。
  • Numbers:生成的数字序列,比如爆破四位数字验证码,就是从0000到9999,设置好范围就行。
  • Custom iterator:自定义迭代器,可以把几个字典里的元素拼接组合,比如拼接前缀、用户名和密码。
  • Brute forcer:纯暴力字符集枚举,CTF里基本不用,效率太低。

线程数方面,我个人的习惯是从小到大试。遇到不限速、不限并发平台,设置10到20个线程就够了,太快了反而容易被靶场风控拦,而且服务器响应也会变慢。真正影响速度的通常是网络延迟和服务器处理能力,本地工具很强大,刷得快不代表服务器扛得住。

提示:如果你跑着跑着发现返回的包全是429、502或者Connection closed,多半是被限速或封禁了,赶紧调低线程,或者加延时,别硬冲。

3. 字典的哲学:从响应差异中寻找突破口

3.1 为什么说“字典要精,不要泛”

CTF爆破题的字典,往往不是网上几G那种大字典,两三行就能跑完的反而是关键。

我见过很多新手一上来就去下载那种所谓的“10亿密码库”,然后往Burp里一扔,跑半天,结果发现正确答案是一个四位数字,比如PIN码。这时候你用密码字典,当然跑不出来的。关键还是先判断这个位置可能是什么类型的数据。

如果是四位数字验证码,那你就生成0000到9999一列10000个数字;如果是电话号码,那就全排组合;如果是用户名,大概率是admin、root、test这类;如果是备份文件名,那就可能是web.zip、www.zip、index.php.bak这类。所以字典不是用来“砸”的,是用来“试对”的。

3.2 手工制作精准字典

我来分享几个实际在ctfshow里经常能用到的字典思路:

  • 拓扑结构弱口令:admin/123456、admin/admin888、root/root、test/test,再补上admin/123456789、admin/000000、admin/admin@123这种常见组合。
  • 靶场专属口令:很多CTF题目会参考真实漏洞环境中的默认口令,比如某些CMS后台的默认账号密码,或者某些设备的初始口令。
  • 单词变形:不要只准备全小写,也准备首字母大写、全大写、末尾加数字、加特殊符号,比如password、Password、PASSWORD、password123、passwd123。
  • 日期型口令:拿最近的年份、月份做组合,比如20240101、20240520、20230606这种,爆破某些生日类验证码时很好使。

制作字典的过程,其实是你对题目场景做评估的过程。你越了解目标,字典就越短,速度就越快。CTF里真正的高手,往往不是跑字典,而是“猜”字典。

3.3 响应差异的判断技巧

在Intruder跑完结果之后,看哪些信息?

  • 状态码:成功的请求可能是200,失败的是302跳转回登录页。
  • 响应长度:很重要。如果用户名或密码错误,服务器返回“用户名或密码错误”,那这个包的长度是固定的。一旦有一个包的长度和其他明显不同,它大概率就是你要的正确答案。
  • 响应内容:包含flag字样,或者包含“登录成功”“welcome”等关键词,都是成功标志。
  • Set-Cookie或者Location:有些登录成功后,服务器的跳转地址会有区别,这也是线索。

我建议你把Intruder的结果列表按“Length”排序,一眼扫过去,异常长度的包会特别显眼。如果所有包的长度都一样,那就要考虑是不是每次请求都有随机因素,比如验证码、Token干扰,此时需要回到抓包阶段重新思考。

4. 实战拆解:从登录框到获取Flag

4.1 拿到题目后的第一件事

不要急着爆破,先把页面看完整。

以ctfshow的爆破题为例,页面通常是这样一个登录框:需要输入用户名和密码,有的会带一个验证码。你首先要做的是:随便输入点什么,比如admin和123456,点击提交,然后用Burp抓包,看看请求发送给了哪个接口、参数名叫什么、有没有额外的隐藏字段。

这一步能告诉你很多信息:

  • 接口是form表单提交还是Ajax请求,返回的数据是JSON还是HTML。
  • 验证码参数存在不存在,如果存在,它的值是怎么生成的。
  • 有没有Token字段,Token是不是动态的。

在Burp里,你抓到的是一个原始HTTP请求,结构大概是这样的:

POST /login HTTP/1.1 Host: xxx.ctf.show Content-Type: application/x-www-form-urlencoded Content-Length: 33 username=admin&password=123456

如果你看到请求头里带着一个token参数,那说明这道题可能不是单纯的爆破,而是需要先获取Token再进行爆破的进阶题。先判断,再动手,能省掉大量无用功。

4.2 常规爆破流程演示

假设这是一道最简单的爆破题,只有用户名和密码两个参数,没有验证码、没有Token。那流程是这样的:

第一步,把请求包发送到Intruder。

第二步,选Attack Type,这里我们固定用户名,只爆破密码,所以选Sniper,密码位置用§符号标记。

POST /login HTTP/1.1 Host: xxx.ctf.show Content-Type: application/x-www-form-urlencoded username=admin&password=§123456§

第三步,配置Payload,在Payload Options里把字典粘贴进去,这里我用一个包含弱口令和常见组合的小字典。

第四步,设置线程数为10,然后点击Start attack。

跑完之后,你还是可以按Length排序,如果有一个返回值长度明显与其他包不同,点一下就能看到详细的响应内容。比如这个包里返回了“flag{y0u_are_g00d_at_brute_f0rce}”,那这道题就完成了。

整个过程不会超过一分钟。

4.3 动态验证码的暴力破解思路

再往上一层,题目可能会加入“验证码”这个变量。注意,这里有两种情况:

第一种,验证码是固定的,或者压根没用了,比如验证码在响应包的Cookie里,但刷新后不更新,那你就直接无视它,继续爆破。怎么判断?多抓几次包,看看验证码字段是不是一直一样。

第二种,验证码虽然在变化,但你可以通过访问某个接口获取它的值,比如把验证码图片的地址请求一下,用脚本识别,或者验证码图片的答案就藏在某个JavaScript变量里、某个接口的返回值里。这种情况下,Burp本身处理不了动态逻辑,你需要考虑用Python脚本。

我遇到过一个很典型的题:验证码是四位数,存在Session里,但服务器校验时是先验证验证码再验证用户名密码。而验证码的校验异常宽松,一旦请求中的验证码匹配,后续的爆破就不再管了。于是解法是把验证码的获取和爆破写在一个循环里:每次爆破的时候先请求验证码接口,把验证码解析出来,再带着正确验证码去试密码。

这种题用Python自带的requests库自己写一下就行,不需要特别的框架。

4.4 Token导致的爆破失败与对策

Token这个东西,本质上是防CSRF的,但它也会顺便把爆破给防了。因为如果每次请求的Token都不同,你的字典还没跑完,Token就过期了,服务器会因为Token校验失败直接拒绝,导致你每次请求都返回错误。

面对这种题,思路很简单:先写脚本获取Token,把它作为请求参数的一部分放在下一个爆破请求中。

用Python做这一步大概是这个流程:

import requests s = requests.Session() url = 'http://xxx.ctf.show/login.php' # 1. 先GET登录页面,把页面里的Token提取出来 r = s.get(url) token = r.text.split('name="token" value="')[1].split('"')[0] # 2.带Token去爆破 for pwd in ['123456', 'admin888', 'password']: data = { 'username': 'admin', 'password': pwd, 'token': token, 'submit': 'login' } r = s.post(url, data=data) if 'flag' in r.text or 'success' in r.text: print('found:', pwd) print(r.text) break

在实际题目里,可能Token藏在响应头里,可能藏在Cookie里,也可能藏在某个JS变量里,你需要结合抓包去看。但核心思想是不变的:会话复用,Token更新,脚本循环。

这就是为什么我强烈建议你做爆破题的时候,至少具备一小点简单的Python脚本能力。很多看似很麻烦的题,其实用几十行脚本就能解决。

5. ctfshow爆破计入门题的几种经典变种

5.1 验证码不变但提示明确的“傻瓜题”

这类题在ctfshow爆破模块早期比较常见。页面上有验证码,但验证码图片在每次刷新页面时都一样,或者验证码的值就藏在图片的src属性里,甚至有的直接把验证码答案作为隐藏字段放在form里。

这时候你根本不需要识别图片,直接抓包看看那个隐藏字段就行。如果验证码字段根本不影响登录结果,你甚至可以把它删了或乱填一通,照样能爆破。

我见过有些朋友在这些题上花费大量时间研究图片验证码识别,其实大可不必。先抓包观察规律,再决定要不要动用OCR或者打码平台,这是性价比最高的策略。

5.2 返回包中隐藏有效信息

有些题目不会让你直接爆破登录成功,而是刁钻一点:登录接口返回的提示信息包含一个字段或者一个跳转地址,而这个字段是可变的,比如可能是“当前IP被封禁,请等待XX秒”,也可能是“密码错误,你还剩N次机会”。

如果你爆破时发现响应里带着计数或封禁逻辑,那就别头铁用Burp硬冲了,赶紧停手,看看有没有其他绕过方式。比如,是不是换一个IP就能绕过封禁?是不是把failed次数改成0就能通过?是不是后端只校验了前几次错误,之后就没再校验了?

遇到这种情况,你就要从“爆破”切换到“协议篡改”的思路上了,尝试修改请求包里的字段,或者直接把响应包里的提示翻译成解题线索。

5.3 字典里夹带“备用口令”

有些题目会在源码注释、HTML代码块或者响应头里塞提示信息,比如“Hint: password is a 4-digit number with no 0”,这就等于告诉你,密码是四位数字,但不包含数字0。

这种提示一出来,你的字典范围就大大缩小了:只能用1到9,四位数全排列,那就是9的4次方,也就是6561个组合。只要你不偷懒,手动生成一下跑一遍,马上就能出答案。

生成这种数字字典,可以用脚本,也可以直接用Burp的Numbers类型Payload,设置范围从1111到9999,然后过滤掉包含0的。如果你不嫌麻烦,手工写几个规律组合也够了。

5.4 逻辑漏洞与爆破结合

还有一类题,看似是爆破,其实是逻辑漏洞,比如登录接口支持“密码参数数组绕过”。什么意思呢?就是你把password参数改成数组,例如password[]=a和password[]=b同时发送,如果后端代码只做了类型的松散比较,就可能导致校验被绕过。

这种题虽然标着“爆破”,但实际解法并不是爆破,而是参数污染或类型混淆。你需要回到抓包阶段,尝试修改请求参数的形态。不过这类题在纯爆破专题里不是主流,先了解有这回事,等以后系统学PHP弱类型比较的时候,你就会更清楚。

6. 踩坑实录与爆破提速的几条小经验

6.1 请求被限速和封禁的应对

前面也提到了,平台为了防止恶意爆破,可能会对单IP的访问频率做限制。最常见的就是同一个IP在一段时间内访问次数超过某个阈值,直接封禁五分钟到半小时。

遇到这种情况,我一般的处理步骤是这样的:

  • 立刻停止爆破,别继续硬跑。
  • 检查Burp的Proxy历史,看看封禁前的最后一次正常请求和触发封禁的请求之间差了多少时间、多少次请求。
  • 判断是单线程连续请求触发,还是多线程并发触发。
  • 如果是多线程导致的,改成单线程,加上固定的延时(比如200ms到500ms)。
  • 如果是平台的硬性频率限制,那只能缩字典范围,提高精准度,用更少的请求来解决问题。

在真实环境中,有的平台还会校验User-Agent,如果你的UA不变但访问频率突变,很容易触发WAF的拦截规则。所以你也可以把UA改成常见的浏览器UA,伪装成普通用户的行为模式。

6.2 不要忽略响应中的“大小写”和“标点”

很多Flag是区分大小写的,响应里有flag字样也不一定代表这道题结束了。你要做的是,把完整的Flag字段复制到题目提交框里,而不是只看个大概就得意洋洋。

另外,如果响应的内容被压缩了(比如gzip),Burp默认会自动解压。但如果响应内容里包含中文字符,且编码是GBK或者GB2312,可能出现乱码。此时你需要检查响应包头的字符集,必要时手动转码。乱码是解不出信息来的,还可能误导你判断成功还是失败。

6.3 爆破时的HTTP方法选择

很多时候登录页面是POST请求,但也有例外:有些题目用的是GET请求,参数在URL里。这种情况下,你需要把爆破位置放在URL参数上。

还有一种特殊情况,服务器可能同时支持POST和GET,但两者的处理逻辑略有不同,比如POST方式限制了尝试次数,但GET方式没有。这种题目就比较坑,得靠你自己多试几个方法。拿到题不要只盯着Burp自动抓的包,也可以在Repeater里手动改一下请求方法,观察响应差异,说不定就找到捷径了。

6.4 如何把Python脚本写得又快又稳

当你决定用Python自己写爆破脚本,有几个实用的小技巧:

  • 尽量使用requests.Session()来维持会话,这样能自动携带Cookie,避免每次请求都手动带上。
  • 如果服务器支持Keep-Alive(默认就是支持的),Session复用TCP连接,速度会比每次新建连接快很多。
  • 并发太高反而容易出错,使用线程池或asyncio时,控制并发数在10以内,加上随机延时。
  • 注意捕捉异常,防止网络抖动导致脚本直接崩溃,用try/except包住请求发送部分,失败重试两次。

下面是一个简化的多线程爆破模板,你可以根据自己的需求改一下:

import requests from concurrent.futures import ThreadPoolExecutor def try_login(password): s = requests.Session() data = { 'username': 'admin', 'password': password } try: r = s.post('http://xxx.ctf.show/login.php', data=data, timeout=5) if 'flag' in r.text or 'success' in r.text: print(f'[+] Found password: {password}') print(r.text) return True except Exception as e: pass return False if __name__ == '__main__': passwords = ['123456', 'admin888', 'password', '666666'] with ThreadPoolExecutor(max_workers=5) as executor: list(executor.map(try_login, passwords))

这种写法比较通用,即使你不会用Scapy或者Burp的扩展插件,也能满足日常85%以上的爆破需求。

6.5 手慢无:关注题目环境过期时间

ctfshow的靶场环境有公网地址访问时限,如果长时间不操作,环境可能会被回收或重置。解决办法是:做题前先热身,把请求的结构和参数搞清楚,然后快速进入爆破阶段。如果环境真的被重置了,那你记录一下当前的会话ID,重开环境后再试,不要慌。

7. 爆破题后的能力拓展与经验沉淀

做完ctfshow的爆破专题,我建议你别急着翻下一篇,回头看一遍你提交过的正确答案和当时的解题记录,总结一下:哪些题是运气跑出来的,哪些题是真的理解了原理。

爆破在CTF里只是一个工具,它不是目的。真正要掌握的是HTTP请求的理解能力、Burp的熟练度、响应分析的敏感度,以及一点点的脚本编写能力。这些能力无论以后你转去做Web渗透还是二进制逆向,都会非常有帮助。

另外说一个我个人的习惯:我会把每一道爆破题的请求包和字典单独保存下来,按题目名归档。以后遇到类似题目,直接翻出来做参考,效率提升明显。CTF的知识点本身就是通过题目积累起来的,不总结等于白刷。

最后再分享一个小技巧:爆破了半天没出结果,不妨停一下手,回头看看页面的HTML源码,看有没有注释掉的提示,看JS文件里有没有接口路径,甚至看响应头里有没有奇怪的字段。爆破题不是说只能靠爆破,很多线索藏在别人容易忽略的细节里。能在爆破前发现那个线索,往往比爆破本身更快。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询