
简介这是一份面向Web安全测试人员的Burp Suite自定义插件名为burpFakeIP主要解决渗透测试过程中需要模拟不同源IP地址、隐藏测试者真实身份或模拟多用户访问的问题。压缩包共12个文件体积1.09MB包含一个Python插件脚本、说明文档、测试文本以及9张界面与效果截图便于快速了解插件用法和运行效果。已有412人学习下载。配套的README与截图能帮助使用者掌握在Burp Suite中加载自定义插件、配置伪造IP的基本流程并理解其实现原理脚本本身结构清晰适合作为二次开发或学习Burp扩展API的参考。该插件可应用于地理限制测试、基于IP的访问控制策略验证、多用户场景模拟等合规渗透测试场景同时资源也强调了实际使用中须遵守法律法规与授权边界。对于希望增强Burp Suite功能、开展合法安全评估的研究者和进阶学习者这份资源兼具实用性与学习价值。1. BurpFakeIP 是什么一个把客户端 IP 变成可控变量的 Burp 扩展做授权测试或前后端联调时最让人心烦的莫过于接口都通了后端却咬定访问来自内网出口或 CDN凡是按来源地址做的白名单、审计和限流规则全都对不上号。burpFakeIP-master.zip 这个压缩包就是为解决这个问题出现的——它是一枚 Burp 扩展插件能在请求发出前把 X-Forwarded-For、X-Real-IP、Client-IP 这些客户端地址头改写为我们指定的值让“来源 IP”从黑匣子变成可配置的变量。适合三类人有授权范围的安全测试人员、在排查 IP 判断逻辑的安服工程师以及需要模拟多来源地址的前后端开发。下文从原理、安装、参数配置到避坑把它当作一次普通扩展工程落地来写保证照着能做通。2. 原理先立住X-Forwarded-For 链路与 Burp 扩展的挂载点2.1 客户端 IP 为什么是最不可信的依赖所有这类扩展能起作用前提是同一个事实TCP 层的源 IP 很难伪造但 HTTP 层这些地址相关头字段只是文本。只要链路里任何一段能改写请求X-Forwarded-For 就能被改成任何内容。正常链路下客户端请求会经过一层或多层接入网关、负载均衡器。第一层入口往往会把原始 TCP 来源记录进去写成X-Forwarded-For: 203.0.113.9如果后面还有一层就变成X-Forwarded-For: 203.0.113.9, 10.0.0.2逗号分隔。问题在于后端到底取哪一段完全没有统一标准——有的框架取最左边第一个值有的取最右边最后一个值还有的干脆把整段字符串拿去匹配。这带来两个坑第一如果转发入口自己不带校验地信任现有头那客户端传什么后端就收到什么第二即使入口强制追加自己的记录多个值同时存在时后端取值策略不同处理结果就完全不同。这也是为什么 burpFakeIP 这类工具的配置里几乎都有“追加还是替换”选项不是简单加一个头就能通用必须按目标后端的读取逻辑来对。2.2 Burp 扩展接口请求在哪个环节被改写Burp 的扩展机制对这类需求支持得很直接。Java 扩展通过IBurpExtender注册再用IHttpListener监听每一笔经过 Burp 的 HTTP 请求。介入发生时processHttpMessage被调用扩展在此时拿到原始请求对象改完头部后再写回去。常见做法的核心代码大致是下面这种骨架package burp; import java.util.List; public class BurpExtender implements IBurpExtender, IHttpListener { private IExtensionHelpers helpers; Override public void registerExtenderCallbacks(ICallbacks callbacks) { this.helpers callbacks.getHelpers(); callbacks.setExtensionName(burpFakeIP); callbacks.registerHttpListener(this); } Override public void processHttpMessage(int toolFlag, boolean messageIsRequest, IHttpRequestResponse messageInfo) { if (!messageIsRequest) { return; } IHttpRequest request messageInfo.getRequest(); ListString headers helpers.analyzeRequest(request).getHeaders(); // 核心动作在原始请求头里追加伪造的客户端地址头 headers.add(X-Forwarded-For: 203.0.113.8); headers.add(X-Real-IP: 203.0.113.8); byte[] body helpers.analyzeRequest(request).getBody(); messageInfo.setRequest(helpers.buildHttpMessage(headers, body)); } }这段示意代码和仓库里的完整实现不一定完全一致但接口骨架是共通的。它做了三件事拿到头部列表、追加指定头、用构造后的新请求覆盖原请求。注意这里只是“追加”如果原请求本身已带有 X-Forwarded-For就需要先删除再插入否则后端可能读到旧值。从这个骨架还能看出一件事processHttpMessage会覆盖 Repeater、Intruder、Scanner 等各个工具面板发出的请求所以扩展一旦挂上就不需要逐个工具去配置。真正需要区分的是值来源——一个固定值对所有请求生效还要“随请求动态生成”那逻辑就要落在每次processHttpMessage调用里而不是只初始化一次。这个细节是后面排查批量请求翻车的关键。3. 把 master.zip 跑起来解压、构建、加载到 Burp 的完整流程3.1 先看包内结构它带的是 jar 还是纯源码拿到 burpFakeIP-master.zip 以后别急着往 Burp 拖。先用三条命令看清包内结构unzip burpFakeIP-master.zip -d burpFakeIP ls -la burpFakeIP find burpFakeIP -maxdepth 3 -type f | head -30第一条命令把压缩包解压到当前目录下的 burpFakeIP 文件夹第二条看顶层内容一般在 master 分支仓库里会看到src、README、pom.xml或build.gradle这类文件第三条按深度列出全部文件前 30 个重点确认有没有编译好的 jar 包注意 jar 可能直接放在目录根下也可能放在target、lib、dist子目录里。如果 find 结果里已经出现burpFakeIP.jar那可以跳过构建直接看 3.2如果只看到src和构建脚本那就需要先构建。常见做法是在解压目录执行 Maven 构建cd burpFakeIP mvn clean package -DskipTests ls -la target/*.jar参数-DskipTests意思是跳过单元测试只做编译打包。构建完成后用ls确认 jar 是否产出。如果机器上没有装 Maven 也不要紧包内带了gradlew就用./gradlew build或者直接按 README 里作者写的命令来。这是最值得先看的一步毕竟各家打包方式五花八门。提示如果压缩包本身就只含源码没有 jar常见原因是作者预期你用 IDE 打开后手动编译。不要为了省事跳过构建否则第 5 章场景四的报错会找上门。3.2 在 Burp Extensions 面板加载并验证jar 在手加载流程就固定了。打开 Burp在顶层菜单栏进入 Extensions 面板按这四步操作在 Extensions 页签里点 Add弹出加载对话框Extension Type 选 Java不要选 Python 或 Ruby在 Extension Details 区域选择刚才的 jar 文件点 Next观察下方 Output 与 Errors 信息。加载成功后Extensions 列表里会出现一行状态为 loaded 的记录同时 Output 区域通常会打印一段初始化日志。如果这个扩展实现了自己的 UIBurp 最上方会多出一个标签页有些扩展不展示界面只在日志输出里写一行配置信息这属于正常现象。验证加载是否真正生效最直接的办法是往 Repeater 发一个原始请求先看返回结果再打开扩展开关重发一次对比头部是否变化。我习惯把这当作“加载成功”的判据比依赖界面更可靠。日志里的 loaded 只能表示类被加载了不能代表监听接口真的挂上常见的 NoClassDefFoundError也往往是在这个步骤才彻底暴露。4. 配置与实战三个必调参数和一次伪造 IP 的完整请求4.1 参数一注入的头列表与伪造值来源装上后第一件事是配置三个参数。第一个是“注入给哪些头”默认常见值有三个X-Forwarded-For、X-Real-IP、Client-IP。实际测试时不要三个全开先判断目标到底读哪个头。判断方法很粗但有效先在本地验证桩上看被接收的头名第 6 章会给出验证桩或者看目标业务日志里记录的是哪个字段。例如一台单独用 Nginx 静态托管的站点日志通常只认 X-Forwarded-For某些 Java 框架内置的客户端地址解析器号称自动识别实际多数看的还是 X-Forwarded-For 的约定。第二个参数是伪造值来源常见四类固定值所有请求都同一个 IP只适合验证单条白名单随机值每次请求或每个批次随机生成适合观察行为差异文件轮询从列表文件里逐个取适合模拟一组来源自增偏移从一个种子 IP 按计数递增适合批量造数据。包里如果自带配置文件常见格式是一份 JSON内容大致长这样{ headers: [X-Forwarded-For, X-Real-IP], ipMode: random, randomCidr: 203.0.113.0/24, replace: true }headers指定要注入的头部ipMode指定来源模式randomCidr限定随机生成的范围前缀避免满网段乱跳replace决定是替换原有头还是追加。注意不同版本字段名会有出入以包内 README 里的配置项为准包没有界面时就是用这种方式在启动时读取的。最重要的建议是replace一开始就设为 true。否则原请求如果已带有 X-Forwarded-For后端解析时可能把新旧两个值混在一起造成“伪造失败”的假象。4.2 参数二生效范围与目标过滤第二个必调参数是“作用范围”。一个挂在 Burp 上的监听器理论上会处理所有走 Burp 的请求——包括你去查公开文档、顺手打开别的网站时带出的流量。如果扩展没有自己的白名单机制非目标域很容易也带上伪造头这在授权测试里是事故。避免这一点的常见方案有三种第一种是扩展自带的 scope 字段配合域名或通配符第二种是依赖 Burp 自带的 Target Scope第三种是直接在代码里硬编码域名名单。无论哪种默认建议手动把目标域名和测试内网网段加进去再打开开关。# 先看目标在携带伪造头时返回什么再到 Burp 里把范围过滤收窄 curl -s http://test.example.cn/api/ip -H X-Forwarded-For: 203.0.113.8这条命令的作用是让目标返回它解析到的来源地址确认目标接口本身通了再回到 Burp 配置里把.example.cn加入白名单这样只有目标域的流量会被改写。提示如果包里找不到 scope 配置项就改到 Burp 的 Target → Scope把测试域名放入 Include 列表。这是最不容易翻车的后备方案。4.3 实战用 Repeater 与 Intruder 完成一次完整验证配置好上面两项后在 Repeater 里做一次最小验证。把请求发到目标接口头部看到X-Forwarded-For: 203.0.113.8点发送后从响应或后端日志确认后端接收到的确实是这个值。要模拟连续多个来源时用 Intruder 更直观。把 payload 位置放在源 IP 字段传入下面这种命令生成的清单seq 1 20 | awk {printf 203.0.113.%d\n, $1}生成从 203.0.113.1 到 203.0.113.20 的 20 个地址。Intruder 选 Sniper把清单里的每项付给 X-Forwarded-For一次跑完。这验证的不只是头部有没有注入字段而是后端限流或白名单会不会随这些值发生变化。整个实战只有三步观察单体请求 → 批量请求 → 对比后端日志。三步都通扩展配置才算可靠。最容易漏的是第二步很多人只验证了一个请求就结束等到次日批量任务出错再回来查时间就浪费了。5. FakeIP 常见问题排查四个翻车场景与解决记录5.1 场景一头已经填了后端日志仍然是接入层地址现象Repeater 里能看到 X-Forwarded-For 带上了伪造值但后端 access.log 记录的来源 IP 没变。原因分三类一是目标系统的接入层强制重写该头比如自建网关配置了头改写逻辑二是后端框架出于安全考虑只对可信来源段内的连接信任 XFF三是扩展在请求链路上的位置太靠后请求还没到应用层就被前置鉴权挡掉了。解决先看请求是否真正到达应用层。方法是临时在本地验证桩上保持同一个目标 Host再把 Burp 的请求指到本地验证桩确认头部能自己发出去随后去目标网关日志看它有没有覆盖。如果是强制覆盖伪造点就要从请求头改成“绕过该网关的测试环境直连后端”这一步不在扩展配置里而在于测试环境的可访问性。5.2 场景二测试目标没翻车别的域名却带着伪造头出去了现象扩展开着时访问一个无关域名也出现伪造的 XFF后端可能因此记录错误甚至拒绝。原因作用范围没有收紧监听器对经过 Burp 的所有请求一视同仁。常见误操作是把 scope 关掉、图省事用通配符.*结果把非目标流量也污染了。解决把范围过滤配置成白名单模式只放行目标域名如果扩展自身没有白名单设定就用 Burp 自带 Scope。我在实际项目里的血泪经验是开 fakeip 之前先保存一份“关闭状态”的配置文件排查可疑流量时能一键恢复原样不靠记忆去猜改过哪里。5.3 场景三Intruder 批量跑的时候伪造 IP 始终不变现象单条请求正常但 Intruder 跑了 100 条后端只看到同一个来源 IP。原因值来源被设置为“固定值”或生成器在扩展加载时只初始化一次。很多伪造扩展的随机 IP 是注册扩展时生成一个副本之后每个请求都复用看起来像随机实际是静态。解决检查并切换为“每次请求生成”模式配置项通常叫 random-per-request、per-request 或 dynamic。如果包内无此模式只能改代码——在processHttpMessage里每次都调用新的随机生成函数注意不能放在构造函数或registerExtenderCallbacks里那是扩展加载时只跑一次的地方。5.4 场景四加载 jar 直接报 NoClassDefFoundError现象Extensions 面板点完 NextOutput 区域显示 NoClassDefFoundError 或 ClassNotFoundException列表状态是 error。原因jar 编译时用的 JDK 版本高于 Burp 自带 JVM或者扩展引用了未打包进 jar 的第三方类库。后者常见于 README 写着“把 xxx.jar 也放进同目录”但用户只加载了主 jar。解决先看报错信息里缺的类名缺第三方库就把它加进 jar或借助 Burp 的 Libraries 字段一并加载版本冲突则用低版本 JDK一般用 8 或 11重新编译。也有少数情况是 Burp 版本太老接口对不上这种直接换新版反而最快。这里没有玄学纯是工程链版本匹配问题。6. 进阶验证两分钟搭一个本地桩看清请求头真实变化6.1 验证桩代码让头变成可见输出与其拿真实目标反复试错我更建议先在本地起一个打印请求头的小服务把 Burp 的 Repeater 目标指到127.0.0.1:8080就能立刻确认 fakeip 到底改了哪些字段。一段最短实现from http.server import BaseHTTPRequestHandler, HTTPServer class Handler(BaseHTTPRequestHandler): def do_GET(self): body str(self.headers).encode(utf-8) self.send_response(200) self.send_header(Content-Type, text/plain; charsetutf-8) self.end_headers() self.wfile.write(body) def log_message(self, fmt, *args): pass HTTPServer((127.0.0.1, 8080), Handler).serve_forever()这个脚本把收到的完整请求头原样返回。运行后在 Repeater 里把请求行改成http://127.0.0.1:8080/发送请求响应体里哪几行带了伪造头一目了然。它还能用来调试 4.1 里的 replace 参数是不是真的替换原有头部不需要开分析工具去猜。6.2 把验证桩接入批量流程从本地点到在线本地桩只验证“扩展有没有改头”在线目标才能验证“后端认不认”。所以我的习惯是把验证桩和批量测试串到一起先用 curl 批量打本地桩确认每组值都符合预期再切回真实测试域名重放一遍。for i in $(seq 1 5); do curl -s http://127.0.0.1:8080/ -H X-Forwarded-For: 203.0.113.$i echo done这个循环会把每次伪造值对应的请求头发回显出来。注意真实目标测试时不要直接在命令行里堆大量不同来源 IP而是交给 Intruder 并固定并发数避免对目标造成无谓压力。一步一步来先本地后线上是我这些年在测试里最稳的顺序把验证桩代码存成一个常用脚本新项目直接掏出来用能省掉大多数“改了半天不知改没改对”的返工。希望这个流程能帮你少走一点弯路。本文还有配套的精品资源点击获取