柏喵Sakura

  • Welcome to bs’ realm.
  • CTFer @Vidar-Team & @El3ctronic, Golang Developer
  • 真不太敢说自己二次元, 但不提又感觉缺了什么。
  • bs 是 “BaiMeow Sakura” 的缩写, 尽管这个词最初并不是其缩写。

我所经历的,我所追寻的

以下内容被密码保护

June 4, 2025 · BaiMeow

从 MCP 聊 AI WEB 应用安全

本文内容原发于 20250413 Vidar-Team Web 安全分享会 近几年 AI 红得发紫,紫得发黑,这不最近又有人搞了一点基建上来,这就是我们的 MCP。 sequenceDiagram Server->>Client: mcp 工具描述 Client->>LLM: mcp 工具描述+用户输入 loop LLM->>Client: mcp 调用请求 Client->>Server: 调用请求 Server->>Client: 调用结果 Client->>LLM: 调用结果 end LLM->>Client: LLM 生成最终回复 上图展示的就是我们 MCP 的全调用链路,可以尝试思考,对于这串调用中的所有角色,可能出现什么安全问题? 我们可以看到,整个流程也就两个接口,LLM 对 MCP Client,MCP Client 对 MCP Server。 LLM - MCP Client 这个接口一般通过一个 Token 完成鉴权,由 MCP Clinet 方向主动连接到 LLM。 从 Web 安全的角度来看,这个问题很简单,就是最基本的无鉴权和 token 泄露等传统 Web 问题。在大模型比较早期的时候,基本都是通过 OpenAI API Token 完成这部分的鉴权问题的,那会就出现了在各种地方,主要是一些代码库,搞个正则就可以搜索到他人的 API Token 的事情,典型网络安全意识缺失。这件事被捅出来了之后呢,搞应用安全这伙人开始做针对性的主动扫描了,知道这个问题的人也多了,暂时好了一点。 但随着各种大模型如雨后春笋般地冒出,外加一些蒸馏技术的出现,大模型的私有化部署逐渐成为可能,但其实一直不温不火,但到 deepseek 开源国产大模型走红之后,整个互联网给人一种是个人都要部署一个 deepseek 的感觉,各种高校企事业单位个人都在搞。这一拥而上啊就容易丢三落四,从结果上看呢,就是互联网上冒出了非常多的 llama API。 ...

April 20, 2025 · BaiMeow

从 HGAME2025 运维,聊聊学校战队 CTF 独立办赛

写这篇文章的时候,HGAME2025 马上就要结束了,还是比较有自信它能够平稳结束吧,就开始提前开香槟写总结文章了,你们看到这篇文章的时候估计已经结束了。 我所在的 Vidar-Team 算是办赛非常非常勤的一支队伍了,几乎覆盖了全年。我们一届运维,一路会从小规模长时间的 HGAME-Mini 开始办赛,到中上规模,较长时间的 HGAME 正式赛,再到线下赛 HGAME Final,最后还要办一个国际范围大强度标准时长的 D^3 CTF。 我先吹一句,高校战队中 No Body Has CTF Hosting Experience More Than Vidar-Team. 🙌 这届 HGAME 对我来说意义不同寻常,往年主要运维工作其实都由凌武科技承担,老学长连着干了不知道多少届运维,我们就混混经验看看操作。但是今年是完全由现役 Vidar-Team 成员去做的所有支撑工作,所以很多东西包括预算,选方案,开机子这些细节是完全从头来过的,也可以说这是我们这一届头一次独立办赛。 这篇文章我们主要还是谈一些运维上的方案,包括备选的技术方案,如果您是某个校队的队长或者运维,希望这些方案以及数据能够给你们提供一些小小的帮助。 关于平台与集群化 平台选择非常重要,下面的讨论是完全基于“回归终端”这一平台进行,你可以在 https://ctf.xidian.edu.cn/ 找到部署好的平台以及找到开发者联系方式。 这个平台目前并不开源,如果要办赛,要做私有化部署,需要事先获取作者rx授权,当然你可以有其他的选择,比如 GZCTF,也是一个非常现代化 CTF 平台,包括所有必须的功能。 HGAME 选取回归终端一部分原因是其还承担着一些关于回归终端的规模技术验证的任务,您自然可以做出你自己的选择。 但是一些旧平台可能会存在一些能力的缺失,导致无法实现下面我们提到的的一些方案。 打个比方说CTFd,他的原版是没有动态靶机能力的,虽然可以通过插件实现 Docker 容器分发,但实际上靶机调度能力比较受限,比如你想做多个节点的容器调度,他就是做不了。 不过我们也不是非要动态靶机不可,下面的丐版方案会提到,最低成本办赛。 一些假设 要出运维方案我们肯定得先确定一下规模和办赛方案,我们做了一些假设: 报名参赛的人数计作 1000 开赛当天有 30% 的人会蹲点开靶机,合计 300-400 靶机 假设平均一个靶机需要 512MB,CPU内存配比按 1:2 给 流量费用与计算资源费用 1:1 峰值过后靶机数量维持在 100 左右 有了这些个假设,我们就可以开始做预算了 HGAME 赛程相当长,平台开放时间从注册两周,到比赛两周,再到复现一周,合计会有5周时间,相同规模下预算会显著高于那些只办 48h 的赛事。 这里所有的预算仅为事先试算,数据均不可靠 多个方案 最优方案: ALL IN 阿里云 ACK 具体计算细节不提了,如果采用这个方案,预算会来到 2000-3000 这一个位置,最大的好处是他确实稳,同时也能省下很多很多的精力,往上面托管就好了。 ...

February 17, 2025 · BaiMeow

fscan 幻境梦游记

fscan 可能是国内最早最知名的内网端口扫描器之一了,最早知道这个扫描器是因为他的速度,比起 nmap 来说是真的快了不少。 听说 fscan2 快要出了,想到自己还没学习过鼎鼎有名的 fscan 的源码,略感惭愧。于是心血来潮决定来对比学习一下第一代 fscan 和即将发布的 fscan2 之间。 略有困意 我们先看看经典的老版本 fscan 吧,看看多年实战历练的代码是什么样子的。 这个项目结构很简洁啊,一眼望去可以看到 Plugins WebScan common main.go 没了,就这 4 个,大小写略有混乱无伤大雅,一眼望过去 common 就是我们的核心了,Plugins 明显是各种协议,设计成 Plugins 单独提出来,非常阳间,WebScan 是针对于 http 的一些专用探测和 poc,太简洁了,牛逼。 对的对的,那我们这就打开 common 看看吧,整体主逻辑肯定就在里面了跑不掉,非常符合我们的幻想啊,太棒了。 Parse.go ParseIP.goo ParsePort.go config.go flag.go log.go proxy.go 这对吗,我的 Scanner 呢? (沉默片刻) 或许我应该看看 main.go … func main() { start := time.Now() var Info common.HostInfo common.Flag(&Info) common.Parse(&Info) Plugins.Scan(Info) fmt.Printf("[*] 扫描结束,耗时: %s\n", time.Since(start)) } 原来 Scanner 的主逻辑也是一个 Plugins,super 插件化,狠狠插拔,一切皆为插件,我的我的,太兴奋了没有先看该看的东西。 其实我们如果再看到 Plugins 包,会发现里面有一堆 xxx.go 丢在那。这也包括扫描器的核心逻辑在内,所以其实是一种大平层的结构,感觉和 plugins 关系不是很大。 ...

January 8, 2025 · BaiMeow

ORM 框架 SQL 注入点分析 (以Golang为例)

最近研究了一些现代 ORM 框架的 SQL 注入情况,做一些笔记吧。 GORM 注入点 gorm 注入点简单可以分为三种情况 检测转义 直接转义 schema 校验 如果 gorm 认为这个参数他不会是一个表达式也不会是`aaa`.`bbb` 的形式,从功能上也只可能是一个单纯的列名,这个时候 gorm 会直接给你套上 ` 同时对内部的内容全部进行转义,这种一般是不存在注入点的,例如 Association 函数。 另外部分多表关联(Associations)查询的字段会存在 schema 校验,如果对不上列名会在 sql 构建阶段报错,例如 Preload 函数,这些也是无法注入的。 那剩下的部分都执行一个检测转义的策略: 先检测`的存在, 如果不存在就套上,并假装存在,直到扫描另一个` 这个转义设计上是为了兼容性,并不出于安全性考虑,所以是比较好注的 根据注入点出现的位置分类,可以分为下面这几个 参数位置 函数 1 Group,Order,Exec,Having,InnerJoins,Joins,Not,Or,Pluck,Raw,Select,Table,Where 1… Distinct 2 Find,First,FirstOrCreate,FirstOrInit,Last,Take 参数位置 为 2 的一类基本是 gorm 新增的一些语法糖 API,不过从上表也可以看出 Gorm 设计的真的不错,API 风格真的非常统一。 案例 DB.Order("id = case when version() rlike '8.*' then ? else 0 end #").First(&a) DB.First(&a, "?=0 union select 1,1,version() #") SELECT * FROM `aaaa` ORDER BY id = case when version() rlike '8.*' then 1 else 0 end #,`aaaa`.`id` LIMIT ? SELECT * FROM `aaaa` WHERE 1=0 union select 1,1,version() # ORDER BY `aaaa`.`id` LIMIT ? 坑点 预编译参数 gorm 有很多方法会附加 limit 1,例如 First Last FirstOrCreate 其中 limit 1 的 “1” 是预编译的,在注入 gorm 的时候需要注意补齐预编译形参 ...

August 8, 2024 · BaiMeow

CTF是怎么出题的?关于今年 D^3CTF 的 OSPF Enhanced

前言 今年给 D^3CTF 出了一道 Web 一道 Misc,非常可惜都TMD有非预期,出的最差的一回了。 Web 那道题暂且不提,那道题在出题角度来说其实没有任何难度,只是把原项目的Docker镜像稍微重打包了一下交给平台。 今给大伙讲讲我们这道 Misc 网络题,这道题前前后后打包容器和平台联调等等,非常有难度,可能耗费了我将近一周的时间。 早期构思 其实一早就定下了出一道网络相关的 Misc 题的基调,问题在于具体整点什么活上去比较有意思。 早先 D^3 CTF 出过一道网络相关的 Misc 赛题,原题叫 O!!!SPF!!!!!! 那道题非常简单,只需连上 OSPF 就可以拿到 flag 了,没有什么难度。 Soha 每年都会出一些网络相关的新年红包,他的题目也是遵循 CTF 的形式的,所以也在我的参考范围之内。 翻阅了很多,决定题目主体就出一个路由劫持,具体劫持的手法来源于一次真实路由劫持,不过那次环境比较复杂没通,但是我觉得这个思路还可以再利用,就只能出成题这样分享一下。 此外,Potat0 还给我提供了一个 rDNS 的小 trick,作为套娃的一部分,这个 trick 也成为了题目的一部分。为了防止选手写了一坨脚本打完卡在这个 trick 上,因此还设计将这个 trick 前置了一下。 开始出题吧 出一道这样的网络题和传统 CTF 题目不一样,他需要去模拟一个网络环境,首先在本地测试的时候,最容易想到的就是 docker compose,可以添加几个 network,然后将他们绑定到容器上构建一些内网出来。 我们大概需要一个这样子的内网环境,简单来说就是三个设备其中一个是路由器,负责两个内网的路由,openvpn 从这里接入并且桥接到 100.64.11.0/24 上。 好吧那就开工吧,把这个网络拓扑写进 docker compose 以下 docker compose 并非最终版本,有意留下了一些错误,后文会纠正 version: '3' name: ospf-enhanced services: router: image: router build: ./router privileged: true ports: - 1194:1194 networks: nw0: ipv4_address: 100.64.11.1 nw1: ipv4_address: 100.64.12.1 client: build: ./client image: client privileged: true environment: - authkey=Jy3aPmrX465PURdZ - gamekey=r5UCJsfs4LDeDFqz cap_add: - NET_ADMIN networks: nw1: ipv4_address: 100.64.12.2 target: build: ./target image: target privileged: true environment: - authkey=Jy3aPmrX465PURdZ - gamekey=r5UCJsfs4LDeDFqz - flag=d3ctf{1_10ve_n4tvv0rk1n9_4nd_R0uting!!!} networks: nw0: ipv4_address: 100.64.11.2 networks: nw0: ipam: config: - subnet: 100.64.11.0/24 gateway: 100.64.11.254 nw1: ipam: config: - subnet: 100.64.12.0/24 gateway: 100.64.12.254 由于容器里要跑 openvpn,要跑 bird 所以需要一点特权,所以早期全部开成特权容器了,这里给他们模拟设计了三个设备两个子网,其中一个设备是路由器,做两个子网之间的路由。 ...

May 7, 2024 · BaiMeow

一种借助PCDN实现隐秘通信的方法

本文仅供安全研究学习使用 前言 早先找实习的时候了解了一下玄武实验室,再读了一遍玄武那篇域前置的文章,这里贴一下链接 https://xlab.tencent.com/cn/2021/05/14/domain-borrowing 这是篇老老老文章了,这篇文章里提出了利用公共 CDN 服务来做 C2 通信的隐藏的一种手法 在防火墙来看,高可信域名+高可信 IP,唯一瑕疵就 DNS 对不上。即使是专门部署 TLS 解密设备来针对这一类的,一看 Host 对的上,也大概率放行。所以走这种 TLS 的 c2 流量是非常难去识别的,因为他伪装得实在是太好了。 但是想要用这个手法做隐蔽通信有个前提,就是需要在 CDN 厂商那边创建这个高可信域名的资源。 大多数的 CDN 供应商,他们的 CDN 往往都会有一个所有权校验,只有你证明你拥有这个域名,你才能创建这个域名的一个 CDN 资源。 在做 DNS 校验的 CDN 厂商创建 CDN 资源比较困难,DNS 污染是运营商层面的东西了。 不过在规模比较大的提供 CDN 服务的云厂商中,AWS 的验证方式是少数不同于其他的,他需要的是一个域名下的TLS证书用作所有权校验,因此利用这个手法做隐蔽通信的一个最低门槛,就是必须要有一个来自高可信域名的证书。 原文提到这点时,建议利用漏洞获取证书,但是这并不容易,越是高可信的域名,他背后的公司组织可能其实做的防御越强,所以域前置就有了这样的一个硬门槛。 那么,有没有办法以较低的代价得到一个来自高可信域名的证书呢? PCDN 与证书 PCDN 中文又称点对点内容分发网络,你可能没实际玩过,但是肯定也听说过运营商封杀 PCDN 的事情。 PCDN 的出现是因为正常的 CDN 和商业宽带的价格比较高昂,尤其国内这种宽带金贵的地方,所以就出现了利用用户闲置的上传带宽做内容分发的应用,他被称之为 PCDN,对企业而言 PCDN 最最显著的特点就是廉价。 既然上面提到,PCDN 是用户在扮演CDN做内容的上传,那么当他跑 HTTPS 流量的时候,他是怎么实现 TLS 加密的呢? 没有什么花活,他就是单纯地把相应的 TLS 证书交给了用户,然后做了一些加密,不让用户能够简单获取到证书。 那么既然证书都给我们了,而且在我们本地做到解密,我们肯定是可以解密出证书的原始内容的 无论有些是有现成的脚本,有些可能需要你做一点点逆向,总归是有办法拿到原证书的,这里就不具体阐述证书是怎么拿到的了。 ...

April 29, 2024 · BaiMeow

GOSTv3 扩展开发 —— SM4 加密隧道

Gost 是什么 Gost 是 Golang 语言编写的网络隧道工具。得益于纯 Go 开发以及 Go 在网络开发以及交叉编译方面的强势,Gost 能够在几乎任何地方近乎零依赖地运行,因此 Gost 最早作为一个方便好用的 socks5 server 启动器在内网渗透等领域开始出名。 Gost 即将正式推出他的 v3 版本,这个版本改变之大,几乎相当于是一个独立的应用。不得不承认,Gost 的作者对于网络和隧道是有一些他的想法的。给大家解读一下在我看来的 Gostv3 设计的核心思想。 Gostv3 核心思想 在介绍 Gost 的配置之前,我们需要先理解一个概念 “传输层与应用层分离” 假设一个socks5隧道,如果我们暂时只考虑tcp代理的情况,那么这个事情其实很简单。先在客户端和服务器之间建立一个tcp连接,随后就按照socks5协议所描述的,协商版本号和认证方式,进行认证,发送代理地址,相应结果,建立隧道,这事情就好了。 隧道应用只是一个应用层的例子,我们可以把上述所做的所有事情分成两部分 建立可靠连接 (传输层) 处理应用层消息 (应用层) 对于大多数基于应用层网络协议,我们可以把他们所做的都抽象为这两件事情。 在常见的网络协议里,传输层与应用层往往是绑定的,但这是没有必要的,我们完全可以为一个应用层协议配置另一个传输层协议,唯一的要求(如果原来是tcp)就是建立可靠流式传输。 这种做法并非是没有先例的,互联网的发展过程中 web 服务逐渐使用 https 替代 http,这就是将 http 协议的应用层部分抽象出来并将其传输层协议替换为 tls 带来的一个结果。 大可放开想象,除了替换成 tls,为什么不能替换成更多的能够实现可靠传输的传输层协议呢?比如说 kcp websocket ssh quic 这些协议可能乍一看怎么可能是一个传输层协议,但是他们确实能够提供可靠传输,相对于我们的应用层而言,他就是传输层。 一个网络协议,他并非属于一个固定的层,这其实也是学术界和工业界的区别,学术界可以理想地对网络协议进行划层,但是工业界只在乎能不能用好不好用。就像很多路由协议,你可能很难给他没有争议地划分到一个层去。 这就是我认为的 Gostv3 最核心的设计,他拆分了隧道协议的网络层和应用层,使他们能够自由组合 Gostv3有四种最基本的概念(listener,handler,dialer,connector) block-beta columns 5 arr1<[" "]>(right) listener1["listener"] space connector2["connector"] arr2<[" "]>(right) space arr3<[" "]>(down) space arr4<[" "]>(up) space space handler1["handler"] space dialer2["dialer"] space space arr5<[" "]>(down) space arr6<[" "]>(up) space space dialer1["dialer"] space handler2["handler"] space space arr7<[" "]>(down) space arr8<[" "]>(up) space space connector1["connector"] arr9<["net"]>(right) listener2["listener"] space space client("client") space server("server") space 其中listner和handler分别是Gost监听服务使用的传输层和应用层,而dialer和connector分别是Gost转发时所使用的传输层和应用层 ...

March 15, 2024 · BaiMeow

在实验网络中使用 step-ca 签发 SSL 证书

DN11 是受 DN42 启发而搭建的一个实验性网络,目前用于杭电范围内,对网络感兴趣的同学学习使用,DN11和DN42非常相似,他们之间的经验都有广泛借鉴意义。 在真实的互联网中,我们常常会通过校验 SSL 证书的方式创建加密 socket 来访问互联网上的资源,这能够有效阻止他人看到通信的内容。而在 DN11 中,由于每个人都相当于是 ISP,流量可能途径每一个人,随时可能被人抓取,因此使用 SSL 证书这件事就更为重要了。 本文将在使用 PDNS 搭建好实验性网络 DNS 的基础上使用 step-ca 搭建 ACME Server 并使用 acme.sh 签发证书。 0. 实验环境介绍 DNS服务器自建已经完成了,通过 anycast IP172.16.255.53可以解析顶级域名dn11。 acme.dn11域名已经解析到172.16.255.2,并且实验机已经宣告了这个 IP。 已经获取到根证书,中间证书,中间证书的签名密钥,而根证书密钥安全起见由他人代管。 GOGOGO! 1. 初始化 step-ca step-ca 提供了很多种安装方式,裸机,docker,k8s等等。由于计划部署 step-ca 的机器上并没有集群环境,裸机又不方便 remake,通过 docker 镜像安装便成为了最佳选择。 https://hub.docker.com/r/smallstep/step-ca docker pull smallstep/step-ca docker run -it --rm -v step:/home/step smallstep/step-ca step ca init --remote-management 上面的命令会拉取 step-ca 的镜像,使用step ca init --remote-management替换原有的启动命令启动容器同时创建一个名为 step 的卷挂载到 /home/step,还使用了-it参数进入交互式。 ...

October 8, 2023 · BaiMeow

IBGP FullMesh 实现多节点自治域

最近不少群友有把自己的其他服务器也接入自己的 AS 的需求,那这篇教程也是时候该出了。 总览 这个事情比较复杂,我们先不急着开始配,先了解一下我们需要一个什么效果。 DN11 作为一个发展了有一段时间的实验性网络,我们目前有很大一批人,他们手上都已经有了一个节点,并且在这个节点上配置了 BGP 从而联通到其他节点。那这个情景下,他们的自治域就是由那一个节点组成的单节点自治域。我们现在需要添加一个新的节点到这个自治域,我们需要解决两个问题。 这两个节点之间需要组网 需要把某一个节点获取到的 BGP 路由与其他节点做一个同步 这两件事情我们分别将通过 OSPF 和 IBGP 实现。OSPF 是 DN11 的老东西,从使用者的角度看,就一个通过获取全局拓扑计算最短路的路由协议。IBGP 是 BGP 的一种,BGP 协议分为两种 EBGP 和 IBGP, 他们分别用于将 BGP 路由发给其他 AS 和将 BGP 路由同步到自己 AS 的其他节点。 IBGP 需要配置 fullmesh,这是由他的设计决定的,IBGP 只会把自己收到的 EBGP 路由转发给自己的邻居,对于自己收到的 IBGP 路由他并不会做一个转发,这主要是为了防止产生环。这其实无所谓,节点多了我们可以用 rr 反射器甚至多级 rr,还可以玩联邦,这个日后再说。下面将以双节点为例,配置一个多节点的 AS。 入口文件 由于这次的配置文件比较长,我们会把他切分到各个文件中,所以先介绍一下入口文件bird.conf的配置 log syslog all; debug protocols all; router id 172.16.4.6; protocol device{ } protocol kernel{ ipv4 { import none; export all; }; } ipv4 table OSPF_table; ipv4 table BGP_table; include "/etc/bird/ospf.conf"; include "/etc/bird/bgp.conf"; include "/etc/bird/ibgp.conf"; protocol pipe pipe_ospf_table{ table master4; peer table OSPF_table; import filter { krt_prefsrc=172.16.4.6; accept; }; export none; } protocol pipe pipe_bgp_table { table master4; peer table BGP_table; import filter { if source != RTS_BGP then reject; krt_prefsrc=172.16.4.6; accept; }; export none; } 我们很容易会发现,入口文件这里使用了三个include关键字,我们在这个入口文件里分别引用了三个文件,后续我们的 OSPF IBGP 和 EBGP 的实际逻辑都会在里面去实现。 ...

September 23, 2023 · BaiMeow