MoreRSS

site iconLala | 荒岛修改

一个应用分享、教程类的博客,主要是那些需要自部署的。
请复制 RSS 到你的阅读器,或快速订阅到 :

Inoreader Feedly Follow Feedbin Local Reader

Lala | 荒岛的 RSS 预览

CrowdSec AppSec WAF误报处理

2026-08-14 14:09:54

CrowdSec常规的白名单不能用于启用了CRS的AppSec WAF,如果是被CRS规则拦截的,则最好使用插件的方式来排除。创建插件目录,例如grafana-exclusions:

mkdir -p /var/lib/crowdsec/data/crs-plugins/grafana-exclusions

创建*-before.conf文件,例如grafana-before.conf:

nano /var/lib/crowdsec/data/crs-plugins/grafana-exclusions/grafana-before.conf

文件名必须以-before.conf结尾,这样包含的规则才会在CRS主规则集执行之前生效(才能提前排除规则或更改参数)写入SecRule规则:

SecRule REQUEST_FILENAME "@beginsWith /apis/dashboard.grafana.app/" \
    "id:9900001,\
    phase:1,\
    pass,\
    nolog,\
    ctl:ruleRemoveById=911100,\
    ctl:ruleRemoveById=932115,\
    ctl:ruleRemoveById=942100"

SecRule REQUEST_FILENAME "@beginsWith /api/ds/query" \
    "id:9900002,\
    phase:1,\
    pass,\
    nolog,\
    ctl:ruleRemoveById=942100"

SecRule REQUEST_FILENAME "@beginsWith /api/datasources" \
    "id:9900003,\
    phase:1,\
    pass,\
    nolog,\
    ctl:ruleRemoveById=911100,\
    ctl:ruleRemoveById=931100"

1.排除规则自身的ID最好从9900001开始,避免与其它的规则ID冲突。

2.排除规则不会写没关系,只要能找到误报的规则ID和详情,后面的事交给AI就行了,AI会帮你写排除规则。

误报的规则ID,可以通过这个命令查询:

cscli alerts list

找到ID后,再用这个命令查看详情:

cscli alerts inspect 24705

会输出类似下面这样的内容:

################################################################################################
 - ID           : 24705
 - Date         : 2026-08-14T04:26:51Z
 - Machine      : 33229323947d41878f3730daae8f8f340mkPL0rvRql9cJd3
 - Simulation   : false
 - Remediation  : false
 - Kind         : waf
 - Reason       : anomaly score block: anomaly: 8, 
 - Events Count : 5
 - Scope:Value  : Ip:130.12.180.77
 - Country      : US
 - AS           : Railnet LLC
 - Begin        : 2026-08-14T04:26:50Z
 - End          : 2026-08-14T04:26:50Z
 - UUID         : edf7d1f7-3d6f-41c1-99e8-b55a64aea6ef
 - Context  :
╭───────────────┬──────────────────────────────────────────────────────────────╮
│      Key      │                             Value                            │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ ja4h          │ ge11nn010000_b8bcd45ac095_000000000000_000000000000          │
│ matched_zones │ REQUEST_HEADERS.Host                                         │
│ matched_zones │ REQUEST_BASENAME                                             │
│ matched_zones │ TX.extension                                                 │
│ method        │ GET                                                          │
│ msg           │ Host header is a numeric IP address                          │
│ msg           │ URL file extension is restricted by policy                   │
│ name          │ native_rule:920350                                           │
│ name          │ native_rule:920440                                           │
│ target_uri    │ /config.php.bak                                              │
│ user_agent    │ Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 │
│               │ (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36           │
╰───────────────┴──────────────────────────────────────────────────────────────╯

触发的规则ID是920350和920440,触发的URI是/config.php.bak,你直接把这些内容全部复制给AI,让AI写排除规则就行了,当然我这里只是演示,这并不是一个真正的误报。

建议每次添加或者修改规则后,先检查一遍有无错误:

crowdsec -t

没问题再重载配置:

systemctl reload crowdsec

龟壳降配及彻底修复引导丢失的问题

2026-08-14 11:35:00

前几天龟壳发邮件说让降配到2C12G,不然就删鸡了。。我登上去找半天才找到降配的页面:

把这里改成2和12:

保存之后小鸡会重新引导,然后不出意外就要出意外了,因为我是私自安装的Debian系统,所以又遇到了之前GRUB引导丢失的问题了:龟壳ARM Debian11 UEFI GRUB启动项丢失修复,如果按照我之前这篇文章的步骤操作,只能暂时修复,如果龟壳哪天又维护,估计引导又丢了。

我这回仔细研究了一下,发现是龟壳维护后以及某些场景下会重置小鸡的NVRAM(UEFI的非易失性存储),Debian在默认情况下又不会将GRUB安装到UEFI的fallback路径,这就导致找不到引导最终进入EFI shell。解决办法其实很简单,重新安装GRUB的时候带上--removable参数即可:

grub-install --target=arm64-efi --efi-directory=/boot/efi --bootloader-id=debian --removable

这会在/boot/efi/EFI/BOOT/目录下生成BOOTAA64.EFI文件:

/EFI/BOOT/BOOTAA64.EFI是UEFI规范中的默认路径,这样即便NVRAM被重置,系统也能自动识别并开机。

还有一个需要注意的地方:Debian自身的系统更新,如果Debian更新了grub-efi软件包,系统可能会重新运行默认的grub-install,从而只更新/EFI/debian而忘记更新/EFI/BOOT,最好运行以下命令重新配置grub-efi:

dpkg-reconfigure grub-efi-arm64

前面弹出配置内核参数的界面都保持默认直接回车就好了,在下面这两个界面选择Yes:

配置完成后,以后无论是龟壳维护,还是你自己运行apt full-upgrade升级系统内核与GRUB,系统都会自动保证/EFI/BOOT里的兜底文件是最新的。

另外现在创建控制台连接也不用那么麻烦了,可以直接用龟壳的Cloud Shell:

如果小鸡引导丢了,此时在Cloud Shell敲一个回车就能看到EFI shell了,然后输入exit还是quit我忘了= =,即可看到小鸡的BIOS界面:

然后按照之前文章里面的步骤从Boot维护管理里面的Boot From File先把机子启动再重新安装GRUB即可。

Docker部署Stalwart Mail + Bulwark Webmail

2026-08-10 17:17:02

其实我一直有在关注Stalwart Mail这个项目,早在2年多以前我就写过一篇部署的文章,当时的Stalwart Mail还没有Web UI,所有操作都只能通过CLI完成。我还有一台服务器一直在使用Stalwart Mail,只不过这台服务器运行的版本比较旧了:

0.14还是升级过的,如果我没记错的话,我应该是从0.11升级上来的。时过境迁,这个项目也从最初的几百个star变成了如今的破万star,我觉得我有资格谈一谈这个程序目前面临的一些问题。

用了这么多年这个邮件服务器,让我觉得最操蛋的地方就是每次大版本更新简直就是灾难,隔个版本就来一大堆破坏性的更改,每次更新都得跟着官方release里面的步骤小心翼翼一步步来,没有哪一次大版本更新是能够轻松完成的。在我的印象里,像这种打包成一个二进制文件或者用一个docker容器就能跑起来的程序,更新不就是pull个新的image然后up就完事了么,但是Stalwart Mail很任性,你要想这么简单的升个级那等着你的绝对是boom,这也就是为什么我之前这台服务器一直运行的是0.14版本,我已经不打算把它升级到0.15然后再从0.15升级到目前最新的0.16了。

现在好就好在作者意识到这个问题了,且之前有说过0.16是个很关键的版本,在0.16后应该不会再引入大规模的破坏性更改,且在今年晚些时候会发布具有里程碑意义的1.0版本:《立即升级到0.16,或者等待1.0版本

然后就是这个项目的定位我觉得有点问题,作者似乎在开发这块有点割裂,想让Stalwart Mail成为一个新手小白都能快速上手的All-in-One邮件服务器,但同时又想兼顾具备专业知识和有能力的人去折腾,这就导致了两个问题:

1.官方文档写的摸棱两可,不清不楚,明明给个示例配置就完事儿的事情,非要在那里车轱辘话说一大堆,到头来新手看了半天文档还是不知道怎么操作,老鸟又没有看的必要。。我认为一篇优秀的文档应该是理论与实践并行,缺一不可,如果只能2选1,那我宁愿选择实践。

2.Web UI对每个功能的可配置性我觉得有点过于细致了,作者似乎想把有关邮件服务器内所有能配置的东西都给你在Web UI上列出来,让你可以看到每一个细节,修改每一个参数。这看上去很美好,但是新手一看到这个Web UI头皮都是麻的,完全看不懂这些设置项有什么用,该怎么配置。别说新手了,就算是具备一定专业知识的人可能都不能完全了解这些设置的作用,再加上文档极其抽象,第一次接触到这个Web UI的人就只会感觉到复杂与繁琐。

当然这些只是我的猜测,作者真实的开发意愿我无从得知,我也无意干预作者对项目开发的路线,我只是想说如果能在这之间找到一个平衡点那当然是最好的,如果找不到平衡点那就专攻一个点去做就行了。

好就好在现在的0.16版本似乎在朝着这个“平衡”的方向发展,在用户首次登录的时候会有一个“配置向导”,只要你按照这个向导去完成配置,那么剩下的那些“让人看不懂”的配置基本就可以不用管了,你的邮件服务器也能正常工作。对于喜欢折腾或者有更多需求的人可以在向导完成后去修改那些更高级的配置。

除了上述我说的这些问题外,还有一个我有点担心的问题是,作者能否保持初心不去恰烂钱,目前来看似乎有点这方面的趋势,小声bb:Masked Emails功能。但愿作者后续不会把关键且核心的功能加到企业版本付费才能使用。

让我们正式开始部署,本文尽量用大白话把一些容易出问题的地方给讲清楚,同时为方便理解,本文不对敏感内容脱敏。准备工作,一个域名(本文示例:ohsb.cc)接入到Cloudflare并做好如下DNS解析:

名称 类型 内容
mail A 152.53.89.75
bulwark A 152.53.89.75

我们不在这里配置MX、SPF、DKIM、DMARC等DNS记录,这些记录稍后统一交给Stalwart自动管理,由Stalwart自行添加。除了这些正向DNS记录外,你的服务器最好支持设置PTR/rDNS,这里我以Netcup的VPS为例,值与正向DNS中的A记录匹配:

验证PTR/rDNS是否生效:

dig -x 152.53.89.75 +short

安装NGINX、CertBot、Docker:

apt update
apt install curl nginx python3-certbot-nginx
curl -fsSL https://get.docker.com -o get-docker.sh
sh get-docker.sh

创建目录和compose文件:

mkdir -p /opt/stalwart-mail && cd /opt/stalwart-mail && nano docker-compose.yml

写入如下内容:

services:
  stalwart:
    image: stalwartlabs/stalwart:v0.16
    container_name: stalwart
    restart: unless-stopped
    ports:
      - "8443:443"
      - "8080:8080"
      - "25:25"
#      - "587:587"
      - "465:465"
#      - "143:143"
      - "993:993"
#      - "110:110"
#      - "995:995"
#      - "4190:4190"
    volumes:
      - ./stalwart-etc:/etc/stalwart
      - ./stalwart-data:/var/lib/stalwart

  bulwark:
    image: ghcr.io/bulwarkmail/webmail:latest
    container_name: bulwark
    restart: unless-stopped
    environment:
      BULWARK_TELEMETRY: off
    ports:
      - "3008:3000"
    depends_on:
      - stalwart
    volumes:
      - bulwark-settings:/app/data/settings
      - bulwark-config:/app/data/admin
      - bulwark-state:/app/data/admin-state
    healthcheck:
      test:
        [
          "CMD",
          "wget",
          "--no-verbose",
          "--tries=1",
          "--spider",
          "http://127.0.0.1:3000/api/health",
        ]
      interval: 30s
      timeout: 5s
      retries: 3
      start_period: 10s

volumes:
  bulwark-settings:
  bulwark-config:
  bulwark-state:

1.由于stalwart容器使用的是bind-mounts,且该镜像以非特权用户(UID2000)身份运行,所以主机目录的所有者必须是UID2000,我们就自行创建目录并修改所有者:

mkdir stalwart-data stalwart-etc && chown 2000:2000 stalwart-data/ stalwart-etc/

2.根据官方的安全实践,禁用了587 / 143 / 110 / 995 / 4190这些非必要且可能有安全问题的端口,如果你有需要可以取消相应的注释。

3.考虑到stalwart后续的大版本更新可能会比较麻烦,官方也不建议将镜像的tag改成latest,所以这里固定使用v0.16,避免导致后续升级时的混乱,例如当前使用的latest指向的是0.16,但这期间官方连发了2个大版本,最新的latest已经指向0.18了,那现在本地的这个0.16去拉最新的0.18升级肯定是要出问题的。

4.官方文档关于NGINX反向代理的示例配置是使用TCP直通,既NGINX不终止TLS,直接将TLS会话原封不动地传递给stalwart。我不打算使用这种方式,我觉得这种方式有点脱裤子放屁的意思,谁没事会在一台服务器上面运行两个甚至多个邮件服务器?完全没有必要通过NGINX去转发25 / 465 / 993的流量嘛,且一旦NGINX使用stream模块监听443端口后,443端口会被stream模块独占,那么http模块就不能再监听443端口了,如果你的服务器上还运行着其它网站,那这些网站都将无法访问。除了这些以外,你还得去配置Proxy Protocol,不然stalwart拿不到客户端真实IP一大堆的功能都会出问题。这简直是一个亏损最大化的反代方式。。。如果要我用这种方式,那我不如单独拿一台服务器出来只跑stalwart得了。。。

考虑再三,我决定使用一个折中的方案,既我们只使用NGINX反向代理stalwart的HTTP端口(8080),其它的邮件服务端口,如25 / 465 / 993这些全部由stalwart自身处理。这种方案唯一的缺点是你需要维护两套TLS证书,既NGINX需要一套证书,stalwart自身也需要一套证书,但好在证书申请和配置都比较简单,NGINX有certbot,stalwart则可以通过ACME DNS 01全自动完成。这种方案也不会导致stalwart的功能有异常或者缺失,因为stalwart 8080端口提供的服务(OAuth、OIDC、JMAP、Autoconfig等)与stalwart 443端口提供的服务完全一致。

启动:

docker compose up -d

查看临时的管理员账号和密码:

docker logs stalwart 2>&1 | grep -A8 'bootstrap mode'

注意这个管理员账号和密码仅用于引导程序运行设置向导,等向导完成后会重新配置一个永久的管理员帐户:

配置NGINX反向代理,先配置stalwart的反代:

nano /etc/nginx/sites-available/stalwart

写入如下内容:

server {
    listen 80;
    server_name mail.ohsb.cc autoconfig.ohsb.cc autodiscover.ohsb.cc ua-auto-config.ohsb.cc mta-sts.ohsb.cc;
    client_max_body_size 0;

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        # 支持 JMAP Push (WebSocket)
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}

1.注意server_name不仅仅要有mail.ohsb.cc,自动配置自动发现以及mta-sts这些功能也需要配置单独的主机名。

2.JMAP依赖WebSocket,务必启用。

启用站点:

ln -s /etc/nginx/sites-available/stalwart /etc/nginx/sites-enabled/stalwart

继续配置bulwark webmail的反代:

nano /etc/nginx/sites-available/bulwark 

写入如下内容:

server {
    listen 80;
    server_name bulwark.ohsb.cc;
    client_max_body_size 0;

    location / {
        proxy_pass http://127.0.0.1:3008;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_cache_bypass $http_upgrade;
    }
}

启用站点:

ln -s /etc/nginx/sites-available/bulwark /etc/nginx/sites-enabled/bulwark

签发证书:

certbot --nginx

访问https://mail.ohsb.cc/admin打开Web UI,如果你发现访问https://mail.ohsb.cc/admin报错502,那么暂时先使用http://152.53.89.75/admin,这大概率是因为stalwart没有获取到客户端的真实IP,将所有传入的请求都识别为Docker桥接网络的网关IP,然后因为有公网扫描器执行的一些探测扫描被stalwart识别到了,stalwart就把Docker桥接网络的网关IP给ban了导致的,这个问题稍后等安装向导完成后再来解决。

使用临时管理员账号登录开始安装向导,配置主机名和邮箱域名:

配置存储,直接用默认的RocksDB就好了,单机部署最佳选择:

账户目录,直接用默认的内部目录即可:

日志目标,这里默认的是文件形式,且保存路径在/var/log/stalwart

由于我们之前没有挂载这个目录,建议将这里的日志输出模式改为console,后续可以通过如下命令来查看日志:

docker compose logs 

如果硬要以文件形式来保存日志,那么应该在compose文件内增加如下内容:

volumes:
  - ./stalwart-etc:/etc/stalwart
  - ./stalwart-data:/var/lib/stalwart
  - ./stalwart-log:/var/log/stalwart

并主动创建目录及修改所有者:

mkdir stalwart-log && chown 2000:2000 stalwart-log

然后就到了非常关键的一步了:自动DNS管理。将Cloudflare的API Token输入到这里,即可让stalwart自动为你创建DNS记录,例如MX、SPF、DKIM、DMARC等。注意MX记录默认是没有为你创建的,需要后续手动配置,我稍后会详细说明:

向导完成后,会重新打印一个管理员账号和密码,这就是永久的管理员账号了,请妥善保管:

重启容器以使新配置生效:

docker compose down
docker compose up -d

再次登录到Web UI,让我们继续完善设置。向导虽然为我们配置了大多数设置,但还有以下步骤缺一不可,请务必全部按照操作完成。

1.找到HTTP Server页面,启用Obtain remote IP from Forwarded header,这将确保stalwart能够获取到客户端的真实IP:

2.找到HTTP Security页面,启用Permissive CORS policy,这将解决bulwark webmail无法正常登录,报错CORS禁止的问题:

3.如果你之前访问https://mail.ohsb.cc/admin报错502,那么请找到Blocked IP addresses页面,不出意外的话,这里会列出你的Docker桥接网络的网关IP:

把这个IP从封禁列表删除,然后找到Actions页面,点击Blocked IPs list按钮重载配置,使其生效:

之前已经启用了Obtain remote IP from Forwarded header,所以stalwart不会再将所有通过NGINX代理的IP都识别为Docker桥接网络的网关IP,这个问题也就解决了,且自动封禁的功能也将正常工作。

4.我们使用stalwart自动管理DNS记录,所以找到Domains页面,点击你的域名进入详情页:

找到DNS Management内的Record Types,可以看到这里默认没有MX记录:

勾选MX记录,保存设置:

找到Actions,重载服务器配置使其生效,请注意,大多数配置修改后都需要这一步才能使新的配置生效:

最后我们还需要找到Tasks页面,创建一个新的任务:

Task type选择Perform DNS management for a domain,Record Types选择MX records,Due设置为你当前时间的后1分钟:

5.在你的个人账户设置页面,创建一个名为Archive的文件夹,以适配bulwark webmail及其它邮件客户端的归档功能:

到这里stalwart就配置好了,接下来配置bulwark webmail,在你首次访问bulwark webmail的时候会让你输入一个安装token:

使用如下命令查看bulwark容器日志以获取安装token:

docker compose logs -f bulwark

bulwark webmail是一个基于JMAP协议的客户端,这里需要配置你的JMAP server URL:

测试一下邮件发送,能发保底10分

能收:

文章篇幅有限,更多高级功能如PGP加密,反垃圾邮件配置,这些内容另外单独用一篇文章说明,未完待续。。。

使用Wordfence CLI / YARA排查PHP网站后门

2026-08-04 10:53:44

Wordfence CLI是一款开源、高性能的安全扫描器,使用Python编写,能够快速扫描文件系统,检测PHP及其他恶意软件和WordPress漏洞。CLI支持并行运行、定时执行,可以通过管道接收输入,也可以将输出通过管道传递给其他命令。

官方提供了多种安装方式,包括pip包、deb包、二进制文件等等,我这里选择二进制文件安装,因为Debian现在不允许直接用pip全局安装pip包了,你要装一个包还得先建个venv,特别麻烦。deb软件包在Debian 13有依赖问题,这坑我已经踩过了:

apt install ./wordfence.deb 
Note, selecting 'wordfence' instead of './wordfence.deb'
Solving dependencies... Error!
Some packages could not be installed. This may mean that you have
requested an impossible situation or if you are using the unstable
distribution that some required packages have not yet been created
or been moved out of Incoming.
The following information may help to resolve the situation:
Unsatisfied dependencies:
 wordfence : Depends: libpcre3 but it is not installable
Error: Unable to correct problems, you have held broken packages.
Error: The following information from --solver 3.0 may provide additional context:
   Unable to satisfy dependencies. Reached two conflicting decisions:
   1. wordfence:amd64=5.0.5rc1 is selected for install
   2. wordfence:amd64 Depends libpcre3
      but none of the choices are installable:
      [no choices]

所以二进制是最舒服的,下载解压就能用了:

wget https://github.com/wordfence/wordfence-cli/releases/download/v5.0.4/wordfence_amd64.tar.gz
tar -xvf wordfence_amd64.tar.gz

试试看能不能运行,首次运行应该会提示让你注册一个免费的许可证,以及生成默认的配置文件:

./wordfence version

同时看一下扫描引擎的支持情况,现在PCRE和Vectorscan应该都显示的是No:

Wordfence CLI 5.0.4
PCRE Supported: No
Vectorscan Supported: No

我找了半天硬是找不到Debian 13的这个PCRE3的依赖包名叫啥,应该和之前安装deb包的那个依赖问题一样,索性我干脆放弃PCRE了,直接使用Vectorscan。

实际上也是Vectorscan更好用,Vectorscan的扫描速度比PCRE快几十倍,所以支不支持PCRE已经不重要了。在Debian 13安装这个包即可:

apt install libvectorscan5

我还有一台Debian 11的机器也需要装,发现Debian 11根本没有这个libvectorscan5,取而代之可以安装libhyperscan5,因为Vectorscan是Hyperscan的一个分支,并保持着兼容的API:

apt install libhyperscan5

Wordfence CLI目前同时支持这两种技术,但如果Vectorscan的API与Hyperscan的API出现差异,这种情况可能会随时间而改变,到时候就看具体情况怎么处理了。再次检查一下扫描引擎的支持情况,如果正常应该显示:

Wordfence CLI 5.0.4
PCRE Supported: No
Vectorscan Supported: Yes - Version: 5.4.2 2024-12-30 (API Version: 5.4.2)

默认情况下,CLI将使用PCRE进行扫描。要将CLI配置为使用Vectorscan,可以使用以下命令行参数:

./wordfence malware-scan --match-engine=vectorscan /var/www/wordpress

但每次都加上--match-engine=vectorscan使用起来不太方便,可以编辑配置文件:

nano ~/.config/wordfence/wordfence-cli.ini

在[MALWARE_SCAN]下面写入:

[MALWARE_SCAN]
match_engine=vectorscan

开始扫描:

./wordfence malware-scan --output-format csv --output-path scan_report.csv /var/www/wordpress

默认情况下Wordfence CLI不会扫描全部文件,例如图片之类的文件会跳过,如果你想扫描全部文件请使用:

./wordfence malware-scan --include-all-files --output-format csv --output-path scan_report.csv /var/www/wordpress

扫描结果会保存至scan_report.csv:

cat scan_report.csv

测试了一下,可以扫到后门:

/tmp/wf_test/test_webshell.php,11121,Backdoor:PHP/short.assert.11121,Short RCE,

如果没有检测到任何恶意程序,则scan_report.csv内容为空,你看到文件内没有内容应该感到高兴而不应该认为是Wordfence CLI没有正常工作。也可能是人家的后门太牛逼,Wordfence CLI扫不出来。

Wordfence CLI虽然是专为WordPress打造的,但请注意Wordfence CLI也可以扫描其它网站程序的PHP后门和恶意程序,并不是说你的网站程序不是WordPress就不能用Wordfence CLI。只是Wordfence CLI针对WordPress有更多的功能,比如扫描CVE漏洞,自动修复被篡改的文件等。

Wordfence CLI其实是一款收费软件,只是官方同时提供了免费版本,免费版本与收费版本的区别在于免费版本的数据库比收费版本慢了30天。如果你使用Wordfence CLI扫描后还不太放心,可以再试试YARA。

YARA是一款旨在(但不限于)帮助恶意软件研究人员识别和分类恶意软件样本的工具。YARA被誉为“恶意软件研究人员的瑞士军刀”,由VirusTotal的安全团队开发和维护。这么说吧,在网络安全行业里,几乎所有主流的杀毒软件和安全大厂(如卡巴斯基、赛门铁克等等)都在广泛使用YARA。

安装YARA:

apt install yara

YARA只是一个检测引擎,规则还需要自己写或者用别人现成的,Github上有很多,这里我使用signature-base。我们把规则下载放到目录内:

mkdir yara-rule && cd yara-rule/
wget https://raw.githubusercontent.com/Neo23x0/signature-base/master/yara/gen_webshells.yar

然后就可以使用这个规则来扫描了:

yara -r yara-rule/gen_webshells.yar /tmp/wf_test/

如果目录内有多个规则,可以用通配符:

yara -r yara-rule/*.yar /tmp/wf_test/

测试了一下,也可以检测到:

EXT_WEBSHELL_PHP_Generic /tmp/wf_test//test_webshell.php
WEBSHELL_PHP_Base64_Encoded_Payloads /tmp/wf_test//test_webshell.php
WEBSHELL_PHP_Gzinflated /tmp/wf_test//test_webshell.php
WEBSHELL_PHP_OBFUSC_3 /tmp/wf_test//test_webshell.php
WEBSHELL_PHP_Dynamic_Big /tmp/wf_test//test_webshell.php

补充点内容,如果你的站点使用WordPress,可以使用WP-CLI校验Core文件的官方哈希值:

sudo -u www-data wp core verify-checksums --path=/var/www/wordpress

一旦发现某个文件的指纹对不上就说明:文件被黑客修改、注入了恶意代码。请注意WP-CLI默认只拿英文版本做比对,如果你的WordPress是简中版本,可能会有个别文件误报,为了让它精准比对简中版本,请加上locale参数:

sudo -u www-data wp core verify-checksums --path=/var/www/wordpress --locale=zh_CN

WP-CLI还可以校验主题、插件的哈希值,但是仅支持WordPress官方市场安装的主题、插件。考虑到大部分站点都会从其它地方安装主题和插件,所以校验的价值就不太高了。

南无阿弥陀佛,佛祖保佑,希望自己永远也不会用到这些工具!!

利用vsd下载并解密MGSTAGE / DMMTV视频

2026-08-03 21:55:09

我之前写过一篇文章《记一次流媒体MPEG-DASH DRM解密过程(Widevine)》后来有很多人跟我说WVGuesserExtension这个浏览器扩展获取不到MGSTAGE和DMMTV的Key了,但是我实际测试下来都是没问题的啊,至少MGSTAGE我能肯定目前是没问题的。

另外我在DMM购买的视频也能获取到Key,而且DMM的那些素人视频根本都没有用Widevine,用的是ClearKey,这个扩展能自动算出来ClearKey的KID:KEY,但是由于我只买这些素人视频,DMM还有其它的服务,比如包月的流媒体服务,这个我就没测试。反正我也不知道他们是怎么操作的,按道理来说都是能用的。

但是u1s1这个扩展确实很久没更新了,而且已经不兼容现在的新版Chrome浏览器了,现在安装的话直接就提示不支持了:

这是由于很多老的扩展都基于Manifest V2,谷歌为了限制扩展对浏览器底层权限的滥用采用了新标准:Manifest V3。但如果你硬要用的话也不是不行,换个火狐或者其它套壳旧版本的浏览器还是能用的,而且这个扩展确实很方便。。

然后还有就是总有人想要我分享WVD(L3 CDM)文件,讲道理这个我是肯定不可能分享的,这是我自己手机提取出来的,如果分享出去给其他人用,到时候很可能被谷歌拉黑,一旦被谷歌拉黑,就属于全球性、永久性封杀,这个WVD文件在所有使用Widevine技术的平台都将彻底作废,到时候我自己都没法用了。所以这个我肯定不会分享,但是我在这里可以给一点建议或者说提示,如果你的安卓手机确实没办法ROOT,可以尝试这几种方法(最近爆出了很多高危漏洞,ROOT应该比之前容易一些了吧):

1.使用Android Studio导出你自己的L3 CDM

2.总有好心人会分享一些L3 CDM,比如VideoHelp论坛的这个帖子:Ready to use CDMs available here!

3.有一些专门提供CDM的网站可用,这些网站一般会有免费试用,但最终目的是为了恰米。我这里不会说具体的名字,免得有人说我给他们打广告,我也不想给他们打广告,如果你需要请善用Google搜索。

我这篇文章主要想介绍一款工具:vsd,全称:Video Stream Downloader,这是一个用Rust写的CLI工具,支持DRM解密。可以从Widevine或者PlayReady的License服务器获取Key解密受保护的内容。这也就意味着你可以用它代替WVGuesserExtension扩展以及N_m3u8DL-RE。

这篇文章实战演示一下如何使用vsd下载并解密MGSTAGE的视频,请注意WVD(L3 CDM)文件是必须要的,如果你没有就没有必要往下看了。

安装vsd,你可以使用PowerShell执行如下命令将vsd一键安装至当前目录:

irm https://github.com/clitic/vsd/releases/download/vsd-0.5.0/vsd-0.5.0-x86_64-pc-windows-msvc.zip -OutFile vsd.zip; Expand-Archive vsd.zip -DestinationPath . -Force; rm vsd.zip

也可以使用Scoop包管理器安装:

scoop install vsd

其它平台的安装见:https://clitic.github.io/vsd/installation/

除了vsd以外,在开始前还应该准备好其它依赖:

1.MGSTAGE的视频文件是分离的,你需要安装FFMPEG以将分离的音频流、视频流合并成一个单一视频文件,vsd会自动完成这些操作,但需要你将FFMPEG的二进制文件放在与vsd相同的目录内。

2.将device.wvd(L3 CDM)文件放在vsd同级的目录内,方便后续vsd命令的执行与调用。

3.浏览器安装猫抓扩展,用于嗅探MGSTAGE的MPD媒体链接地址

让我们正式开始:

1.打开MGSTAGE播放一个视频,同时打开猫抓,获取MPD的URL:

2.按F12打开浏览器控制台,找到License服务器的目标URL:

3.在PowerShell执行如下命令获取KID:KEY:

.\vsd.exe license "https://dash-streaming.mgstage.com/streaming/bibid/522dht/1338/522dht-1338_20260701T143002.mpd..." `
--widevine-url "https://cenc.webstream.ne.jp/drmapi/wv/mgstage?custom_data=..." `
--widevine-device device.wvd `
--skip-playready `
-H "Origin: https://www.mgstage.com" `
-H "Referer: https://www.mgstage.com" `
-H "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36"

请务必使用-H带上必要的标头(header),否则License服务器会返回400报错。

如果正常,会回显类似下图的内容,其中DrmKey就是我们需要的KID:KEY:

4.使用上一步获取到的KID:KEY下载并解密视频:

.\vsd.exe save "https://dash-streaming.mgstage.com/streaming/bibid/522dht/1338/522dht-1338_20260701T143002.mpd?..." `
--keys "62bd99e8c11047809157e0a8058a6444:21639f31dcac3d8555919f055ba0cd77" `
-f best `
-o 522DHT-1338.mp4

测试视频能播放,声音也正常:

补充一点vsd的其它用法,其实vsd也可以代替猫抓,但是我说实话不如直接用猫抓方便。vsd有一个capture功能,当你执行capture后,vsd会自己启一个Chrome浏览器,然后vsd会把抓到的媒体地址以curl可调用的形式回显到终端。

具体用法:

.\vsd.exe capture "https://www.mgstage.com/mgsplayer/?PID=...&PVFID=...&TPID=...&MgsvrURL=http://www.mgstage.com/mgsvr/Mgsvr.php&html5=1"

然后你在vsd启动的Chrome浏览器登录MGSTAGE账号,播放这个视频,稍等片刻MPD媒体URL就嗅探出来了:

CrowdSec Web UI:调查警报、管理决策、监控运行时指标

2026-07-29 17:09:34

这篇文章记录下将本地部署的CrowdSec接入到CrowdSec Web UI以获取更多实用的功能:

  • 仪表板:警报和决策总数、攻击地图、快速筛选器等
  • 警报:查看历史记录、CrowdSec告警上下文、IP/AS/位置详情、事件元数据等
  • 决策:查看生效和失效的决策、重复项隐藏、添加手动封禁决策、自定义持续时间、删除决策操作等
  • 多实例:多个CrowdSec LAPI、每个实例的视图以及仪表板
  • 指标:可选的Prometheus视图,查看CrowdSec运行时的各项指标数据
  • 通知:通过电子邮件、Gotify、MQTT、ntfy或Web hooks发送警报、决策、CVE、可用性等
  • 多语言:阿拉伯语、中文、英语、法语、德语、印地语、日语、葡萄牙语、俄语和西班牙语

由于CrowdSec LAPI的限制,此Web UI能做的事情(实现的功能)其实不多,更多的是一个数据可视化的作用,除此之外,还可以管理一下决策和警报,就不用每次都去使用cscli这个CLI工具了,但其它的操作还是得用cscli,所以并不是装上这个Web UI就完全不用了解CrowdSec了,至少得入个门,入门看看我这篇文章就可以了。

安装NGINX、CertBot、Docker:

apt update
apt install curl nginx python3-certbot-nginx
curl -fsSL https://get.docker.com -o get-docker.sh
sh get-docker.sh

生成一个足够复杂的密码:

openssl rand -hex 32

使用刚生成的密码创建LAPI的登录凭据:

cscli machines add crowdsec-web-ui --password 'replace-with-generated-password' -f /dev/null

请注意一定要加上-f /dev/null,否则它将替换掉/etc/crowdsec/local_api_credentials.yaml文件内的默认凭据。

新建compose文件:

mkdir /opt/crowdsec-web-ui && cd /opt/crowdsec-web-ui && nano docker-compose.yml

由于我的CrowdSec是部署在服务器本地的(没有使用Docker),所以与CrowdSec Web UI对接的方案有多种,这里我会全部写下来,至于你选择用哪一种那就不是我能决定的事情了。

1.直接让crowdsec-web-ui容器使用主机网络(Host Network)这种是最简单的,因为不需要修改CrowdSec的配置:

services:
  crowdsec-web-ui:
    image: ghcr.io/theduffman85/crowdsec-web-ui:latest
    container_name: crowdsec_web_ui
    network_mode: "host"
    environment:
      CONFIG_SERVER_PORT: 3002
      CONFIG_INSTANCE_METRICS_URL: http://127.0.0.1:6060/metrics
      CONFIG_INSTANCE_LAPI_URL: http://127.0.0.1:8088
      CONFIG_INSTANCE_LAPI_AUTH_USERNAME: crowdsec-web-ui
      CONFIG_INSTANCE_LAPI_AUTH_PASSWORD: 
    volumes:
      - ./data:/app/data
    restart: unless-stopped

1.crowdsec-web-ui默认使用3000端口,但3000端口是一个常用端口,已经被我服务器上的其它程序占用了,所以这里我改成了3002端口。因使用的是主机网络,所以不存在端口映射,只能修改程序自身运行的端口,依靠程序自带的环境变量CONFIG_SERVER_PORT实现。

2.之所以说这种配置是最简单的原因是,CrowdSec的LAPI默认就是监听在127.0.0.1的,且两者都在同一个网络中了,所以无论是CONFIG_INSTANCE_LAPI_URL还是CONFIG_INSTANCE_METRICS_URL都直接配置成127.0.0.1就行了。还有CrowdSec的信任IP配置默认就是信任127.0.0.1的。

启动:

docker compose up -d

2.使用host.docker.internal:host-gateway

services:
  crowdsec-web-ui:
    image: ghcr.io/theduffman85/crowdsec-web-ui:latest
    container_name: crowdsec_web_ui
    ports:
      - "3002:3002"
    extra_hosts:
      - "host.docker.internal:host-gateway"
    environment:
      CONFIG_SERVER_PORT: 3002
      CONFIG_INSTANCE_METRICS_URL: http://host.docker.internal:6060/metrics
      CONFIG_INSTANCE_LAPI_URL: http://host.docker.internal:8088
      CONFIG_INSTANCE_LAPI_AUTH_USERNAME: crowdsec-web-ui
      CONFIG_INSTANCE_LAPI_AUTH_PASSWORD: 
    volumes:
      - ./data:/app/data
    restart: unless-stopped

这种方案必须修改CrowdSec的主配置文件:

nano /etc/crowdsec/config.yaml

将LAPI监听改为0.0.0.0并配置信任IP:

api:
  server:
    log_level: info
    listen_uri: 0.0.0.0:8088
    trusted_ips: # IP ranges, or IPs which can have admin API access
      - 127.0.0.1
      - ::1
      - 172.16.0.0/12 # 信任Docker默认的桥接网络

1.host.docker.internal:host-gateway本质是往容器的操作系统里面写了一个Hosts,指向的是宿主机Docker默认的桥接网络的网关IP,CrowdSec如果只监听127.0.0.1,host.docker.internal也无法访问。

2.必须将crowdsec-web-ui容器的源IP地址(最好是其Docker网络的CIDR)添加到CrowdSec的信任IP配置中。这不是你浏览器的IP地址或Docker主机的公网IP地址。如果没有此配置,决策操作仍可正常工作,但警报删除操作会失败并报错:403 Forbidden。

3.这方案有一点好处就是,在你配置反向代理后,可以将端口映射改为:

ports:
  - "127.0.0.1:3002:3002"

这可以保证crowdsec-web-ui只能通过NGINX反向代理访问,且在你部署了crowdsec-nginx-bouncer时能够为crowdsec-web-ui提供保护。如果不这样配置,你的crowdsec-web-ui相当于裸奔在公网,既没有TLS也没有受到crowdsec-nginx-bouncer保护。这方案也有缺点,那就是将CrowdSec LAPI暴露在公网了,虽然LAPI是必须要鉴权的,但原本只监听在127.0.0.1肯定是最安全的,假设哪一天CrowdSec自身曝了个洞这些也说不准。

重启CrowdSec使新的配置生效:

systemctl restart crowdsec

启动:

docker compose up -d

新建NGINX站点配置文件:

nano /etc/nginx/sites-available/crowdsec-webui

写入如下内容:

server {
    listen 80;
    server_name crowdsec-webui.example.com;
    client_max_body_size 0;

    location / {
        proxy_pass http://127.0.0.1:3002/;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-Host $http_host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}

启用站点:

ln -s /etc/nginx/sites-available/crowdsec-webui /etc/nginx/sites-enabled/crowdsec-webui

访问crowdsec-webui.example.com创建一个管理员账户就可以登录了,看下效果。

仪表板:

告警:

决策:

指标: