AndyYan's Blog - DN42
type: channel
link: https://www.andy-y.cn/index.php/category/DN42/
items: 通过Asterisk自建PBX以接入Telephony42
items: 一次 Looking Glass 参数注入事件的复盘：从 /etc/shadow 泄露到全集群加固
items: 搭建Grafana监测Bird运行状态

通过Asterisk自建PBX以接入Telephony42
type: item
date: 2026-07-12T08:42:00+00:00
description: 提示：本人对于电话网络的了解停留在初步阶段，本博客仅仅是我初步的学习总结，不仅十分不完善，还可能出现部分知识性错误，如遇错误与意见可联系070127andy@gmail.com，感谢您的理解和指正！另：本文默认您已经加入了DN42并至少和一位peer进行了对等连接。本文部分基础概念和图示基于 Yukari Chiba 的《telephony42 完全指南》整理和改写，原文采用 CC BY-SA 4.0，本文相应部分亦按 CC BY-SA 4.0 发布。前言本人在DN42网络中扮演 AS4242422921 并拥有一个四节点的小集群，集群间建立了 FullMesh 的 IBGP 组网，通过 OSPF 作为 IGP 协议建立内部动态路由，并申请了 andy.dn42 作为我的域名，搭建了 1主+1从 的权威服务器（由knot驱动）。最近在DN42的群里看到了 Yukari 大佬提到的telephony42，即一套实验性质的去中心化电话网络。我觉得自建一个电话网络很酷，于是打算跟着Yukari的 这篇博客 搓一个 PBX(Private Branch Exchange - 私有交换机) ，接入telephony42， 打电话骚扰群友 。前期准备{x} 一个DN42域名 {x} 一台 已接入DN42 的，配置不低于1C1G的服务器 {x} 自建的DN42内部权威DNS（这里以knot演示）概念须知PS：本篇博客仅是“最小加入指南”，后面譬如SRTP的进阶操作本人也在学习，还请自行了解，本部分参考了0x7f的博客内容。组件简要解释PBX (Private Branch Exchange - 私有交换机)视作 VoIP 网络中的路由器，负责处理信令和路由，有时也处理语音数据。B2BUA (Back-to-Back User Agent - 背靠背用户代理)Asterisk 之类的 PBX 就是一个典型的 B2BUA。与仅转发信令的 SIP 代理不同，当 A 通过 PBX 呼叫 B 时，PBX 实际上是先以被叫的身份接听了 A 的电话，然后再以主叫的身份向 B 发起一通全新的电话，最后在内部把这两个独立的通道桥接起来。这使得 PBX 能随时介入通话过程，进行录音、转码、甚至强制掐线。Endpoint (终端设备)任何可以发起或接收呼叫的设备。它可以是电脑上的软件电话应用、桌面的实体 IP 电话机、ATA、网页上的 WebRTC 电话，甚至是另一个网络的 PBX。协议简要解释会话发起协议 (SIP - RFC 3261)作为控制平面。采用纯文本格式，长得有点像 HTTP，包含 URI、头字段和正文。主要负责信令传输，例如传递呼叫的来源和目标、接通、挂断或拒接等，不负责传输具体的语音流。SIP 默认监听于 UDP/TCP 5060 端口（在报文较大时通常优先使用 TCP），TLS 加密状态下监听 TCP 5061 端口。实时传输协议 (RTP - RFC 3550)作为数据平面。当 SIP 握手与 SDP 协商完成后，双方会在协商好的高位动态端口（通常在 UDP 10000 至 20000 之间）互相传递 RTP 数据包。这些包对延迟和抖动极其敏感。如果防火墙只放行了 SIP (5060) 但没放行 RTP，就会遇到 VoIP 史上最著名的故障： 单通（接通了但听不到声音）。路由简要解释ENUM (E.164 Number Mapping)是一种自动发现路由的机制。当拨打目标是未知目的地的电话时，PBX 会根据号码查询 DNS 的 NAPTR 记录，查找到该号码对应的 SIP 目标地址，在DN42通过一个特殊的DNS查询实现Context (上下文)是 Asterisk 拨号计划的关键组件。可以把它理解为 VoIP 系统中的 VRF。它可以把不信任的外部呼叫丢进一个没有外拨权限的隔离上下文中，并且能够通过 Goto 等语句实现在不同上下文间链式跳转，在后面的拦截伪造来电等功能上很有用对于跨网的SIP呼叫，可以分为 三个阶段 ：第一部分：SIP 呼叫建立PBX将充当一个类似“ 中转站 ”的角色，先接听主叫设备的 INVITE ，使用 ENUM DNS 查询（ 后面会展开解释 ）与信令路由，查询到对方的PBX之后向其转发INVITE，由对方的PBX再呼叫被叫设备，接听后层层转发回200 OKsequenceDiagram participant Caller as 主叫设备 (A) participant PBXA as 本地 PBX participant PBXB as 对端 PBX participant Callee as 被叫设备 (B) Note over Callee, Caller: 控制平面交互 (SIP) Caller->>PB…

一次 Looking Glass 参数注入事件的复盘：从 /etc/shadow 泄露到全集群加固
type: item
date: 2026-07-02T06:21:00+00:00
description: 本文隐去了真实主机名、域名与 IP，但保留了完整的攻击 payload 与处置命令，方便复现与自查。TL;DR我的 DN42 集群跑着一个公网可访问的 bird-lg-go Looking Glass，四台节点共用一个前端。其中 bird-lgproxy ≤ v1.4.6 存在参数注入漏洞（CVE-2026-26514，GHSA-3qm5-22pm-wqg9）：攻击者通过 traceroute 功能的 q 参数注入 mtr 的 -F 选项，把任意文件当作“报告文件”读出来，最终读到了每台机器的 /etc/shadow——也就是 root 密码哈希。注意 v1.4.6 的修复不完整、可被绕过，真正修好是在 v1.4.7。处置结论：四台节点全部升级到 v1.4.7、轮换全部 root 密码、审计 SSH 密钥与计划任务、确认无后门与异常登录。 漏洞在公网边缘已验证彻底关闭。漏洞原理Looking Glass 的 traceroute 功能，本质上是把用户输入的目标丢给系统的 mtr / traceroute 去跑。问题出在旧版 bird-lgproxy 直接把用户输入拼进 exec.Command，既没有把它当成单一目标、也没有拒绝以 - 开头的输入。于是用户输入里可以夹带选项。攻击者只要构造：-F /etc/shadow test.invalid它就被当成了 mtr -F /etc/shadow test.invalid。而 mtr 的 -F 选项恰好是“从文件读取主机列表（report file）”——mtr 会尝试打开 /etc/shadow，并在报错信息里带出文件内容；而 proxy 用 CombinedOutput() 把 stdout + stderr 一起回显给前端，于是文件内容就顺着错误输出泄露了出去。test.invalid 只是凑一个“看起来像目标”的占位。于是一条 HTTP GET 就能读任意文件：# 攻击者视角：通过公网 LG 前端读取 /etc/shadow curl 'https://<lg-frontend>/traceroute/<node>/-F%20%2Fetc%2Fshadow%20test.invalid'这类问题的根源是老生常谈的一句话：永远不要把用户输入拆成命令行参数。目标就该当作一个不可拆分的整体字符串，任何以 - 开头的东西都不该被解释成选项。下面这张图把整条注入链路画出来了——注意红色路径是漏洞如何从一个 HTTP 参数一路变成任意文件读取的：flowchart LR A[公网攻击者] -->|"GET /traceroute/node/ -F /etc/shadow test.invalid"| B[LG 前端 bird-lg] B -->|转发请求 源 IP = 前端| C[节点 bird-lgproxy :8000] C -->|"输入直接进 exec.Command 未拒绝 - 开头参数"| D{"mtr -F /etc/shadow test.invalid"} D -->|-F 被解释为 read report file| E"读取 /etc/shadow" E -->|回显文件内容| A style A fill:#ffd5d5,stroke:#c0392b style D fill:#ffe6cc,stroke:#e67e22 style E fill:#ffd5d5,stroke:#c0392b,stroke-width:2px攻击时间线从被攻击节点的 bird-lgproxy 日志里，能看到一段非常“教科书”的探测→提权信息收集过程（时间为东八区，2026 年 7 月 1 日晚）：时间（UTC+8）谁干了什么07-01 21:47攻击者（经前端转发）bird-lgproxy 读 /etc/passwd（枚举用户、确认可读文件）07-01 21:53攻击者读 /root/.bash_history（翻历史命令，找线索/凭据）07-01 21:57攻击者读 /etc/shadow（拿到 root 密码哈希）用时序图看这十分钟的动作更直观，也能看清“攻击者 → 前端 → proxy → 文件系统”这条链路上，日志分别记在了哪一层：sequenceDiagram autonumber actor Atk as 攻击者（公网） participant FE as LG 前端 bird-lg participant PX as 节点 bird-lgproxy participant FS as 节点文件系统 Note over Atk,FS: 2026-07-01 晚（UTC+8） Atk->>FE: 21:47 GET -F /etc/passwd FE->>PX…

搭建Grafana监测Bird运行状态
type: item
date: 2026-02-19T14:39:00+00:00
description: 写在前面本人在dn42网络中有4个节点，本来搭建了LookingGlass来监测节点运行状态，但考虑到不够直观 其实是想折腾，所以打算搭建一个可以图形化监控每台节点Bird运行状态的仪表盘，在社区里面发现可以用Grafana搭配Prometheus作为数据源实现拓扑图如下：graph TD subgraph DN42 Network N1[Node 1] --> NE1(Node Exporter) N1 --> BE1(Bird/FRR Exporter) N2[Node 2] --> NE2(Node Exporter) N2 --> BE2(Bird/FRR Exporter) N3[Node 3] --> NE3(Node Exporter) N3 --> BE3(Bird/FRR Exporter) N4[Node 4] --> NE4(Node Exporter) N4 --> BE4(Bird/FRR Exporter) end NE1 --> P(Prometheus Server) NE2 --> P NE3 --> P NE4 --> P BE1 --> P BE2 --> P BE3 --> P BE4 --> P P --> G(Grafana Server) User[用户] --> G搭建部署 Prometheus ServerPrometheus Server 将运行在独立的监控服务器上。创建工作目录mkdir -p /opt/prometheus/config /opt/prometheus/data创建 Prometheus 配置文件 (/opt/prometheus/config/prometheus.yml)global: scrape_interval: 15s # 默认抓取间隔 scrape_configs: - job_name: 'prometheus' static_configs: - targets: ['localhost:9090'] # 监控 Prometheus 自身 - job_name: 'node_exporter' static_configs: - targets: ['<node1_ip>:9100', '<node2_ip>:9100', '<node3_ip>:9100', '<node4_ip>:9100'] # 替换为您的 DN42 节点 IP - job_name: 'bird_exporter' static_configs: - targets: ['<node1_ip>:9324', '<node2_ip>:9324', '<node3_ip>:9324', '<node4_ip>:9324'] # 替换为您的 DN42 节点 IP注意: 请将 <nodeX_ip> 替换为您的 DN42 节点的实际 IP 地址。使用 Docker Compose 部署 Prometheus创建 docker-compose.yml 文件：services: prometheus: image: prom/prometheus container_name: prometheus network_mode: host ports: - "9090:9090" volumes: - /opt/prometheus/config/prometheus.yml:/etc/prometheus/prometheus.yml - /opt/prometheus/data:/prometheus command: - '--config.file=/etc/prometheus/prometheus.yml' - '--storage.tsdb.path=/prometheus' - '--web.enable-lifecycle' restart: unless-stopped将数据目录的权限赋予 Prometheus 用户：chown -R 65534:65534 /opt/prometheus/data启动 Prometheus：docker-compose up -d通过访问 http://<监控服务器IP>:9090 来验证 Prometheus 是否正常运行。部署 Node Exporter (每个 DN42 节点上)创建工作目录mkdir -p /opt/node_exporter方式1：使用 Docker 部署 Node Exporterdocker run -d \ --name node_exporter \ --net="host" \ --pid="host" \ -v "/:/host:ro,rslave" \ quay.io/promethe…