Debian 12 上用 TPM 2.0 安全登陆 SSH

需求

之前在《macOS 上用触控 ID 安全登录 SSH》,最近比较常用 Linux 桌面,所以还得在 Linux 上也搞一套安全的登陆方式。

分析

目前,MBA13 M1 的 Touch ID 在 Asahi Linux 下无法使用,其它机器也都没有指纹识别器,显然只有 TPM 2.0 模块是唯一适合的安全手段。

参考

实现

1. 检查 TPM

1
sudo dmesg | grep -i tpm

如果没有输出,那可能是内核不支持或者没有 TPM 芯片;但也可能只是内核比较老,没有输出而已,比如华为擎云 W515 就没有输出,但它能用。

类似以下输出,是没有芯片:

1
2
[    0.800622] ima: No TPM chip found, activating TPM-bypass!
[ 2.030844] systemd[1]: systemd 252.22-1~deb12u1 running in system mode (+PAM +AUDIT +SELINUX +APPARMOR +IMA +SMACK +SECCOMP +GCRYPT -GNUTLS +OPENSSL +ACL +BLKID +CURL +ELFUTILS +FIDO2 +IDN2 -IDN +IPTC +KMOD +LIBCRYPTSETUP +LIBFDISK +PCRE2 -PWQUALITY +P11KIT +QRENCODE +TPM2 +BZIP2 +LZ4 +XZ +ZLIB +ZSTD -BPF_FRAMEWORK -XKBCOMMON +UTMP +SYSVINIT default-hierarchy=unified)

内核识别出 TPM 芯片的输出:

1
2
3
4
[    0.000000] efi: ACPI=0x75620000 ACPI 2.0=0x75620014 TPMFinalLog=0x755ef000 SMBIOS=0x75cac000 SMBIOS 3.0=0x75cab000 MEMATTR=0x6bf5d018 ESRT=0x6e822718 MOKvar=0x75ce8000
[ 0.014309] ACPI: TPM2 0x00000000754DF000 00004C (v04 ALASKA A M I 00000001 AMI 00000000)
[ 0.014336] ACPI: Reserving TPM2 table memory at [mem 0x754df000-0x754df04b]
[ 12.590389] systemd[1]: systemd 252.22-1~deb12u1 running in system mode (+PAM +AUDIT +SELINUX +APPARMOR +IMA +SMACK +SECCOMP +GCRYPT -GNUTLS +OPENSSL +ACL +BLKID +CURL +ELFUTILS +FIDO2 +IDN2 -IDN +IPTC +KMOD +LIBCRYPTSETUP +LIBFDISK +PCRE2 -PWQUALITY +P11KIT +QRENCODE +TP2 +BZIP2 +LZ4 +XZ +ZLIB +ZSTD -BPF_FRAMEWORK -XKBCOMMON +UTMP +SYSVINIT default-hierarchy=unified)

2. 安装必要软件

1
sudo apt install tpm2-tools tpm2-abrmd libtpm2-pkcs11-tools libtpm2-pkcs11-1

其中:

  • tpm2-tools 是一套工具。获得 tpm2tss2 两个命令,可以用 sudo tpm2 getrandom --hex 8 测试 TPM2 是否正常工作。

  • tpm2-abrmd 是一个服务,使得非 root 用户能访问 TPM2 映射文件,只需把用户加到 tss 组即可。

  • libtpm2-pkcs11-tools 是 PKCS#11 backend,用于访问加密服务。它提供的 tpm2_ptool 是一个 Python 脚本,可用于管理令牌、密钥。

  • libtpm2-pkcs11-1 是 SSH 用的模块,即提供一个符合 PKCS#11 规范的 so 动态库。对于 x64 机器,固定链接位于 /lib/x86_64-linux-gnu/pkcs11/libtpm2_pkcs11.so。如果您安装了 gcc,则可用 TPM2_PKCS11_SO=/usr/lib/$(gcc -dumpmachine)/pkcs11/libtpm2_pkcs11.so 来保存它到变量 TPM2_PKCS11_SO,以方便使用。

3. 配置用户

1
sudo usermod -a -G tss $USER

如果在桌面或 SSH 会话,可以注销,再登录,使以上配置生效。也可以用 su - $USER 登录一个新会话,这时新会话是生效的,但 exit 后,回到的旧会话依然不生效。

4. 检验

1
tpm2 getrandom --hex 8

注意,上面这条没有 sudo,必须保证没有 sudo 也能获得随机数,才说明 tpm2-abrmd 正常工作,并且用户加入 tss 组,并且重新登录会话!

5. 新建私钥

1
2
3
4
5
6
7
8
# 在默认位置 ~/.tpm2_pkcs11 初始化一个数据库
tpm2_ptool init

tpm2_ptool addtoken --pid 1 --label SSHToken --sopin [SUPERVISOR-PIN] \
--userpin [USER-PIN]

tpm2_ptool addkey --algorithm [rsa2048/ecc256/ecc384] --label SSHToken \
--key-label [KEY-LABEL] --userpin [USER-PIN]

稣一般使用 ecc384,即 NIST P-384,但有些机器会报错,这时可以尝试 ecc256,即 NIST P-256。注意:据说 NIST 系列安全性存疑?

6. 导入私钥

这第 6 步与第 5 步只需二选一。

第 5 步中新建私钥是无法导出的,万一自己不小心删了,或者升级 BIOS,也可能无法解开,导致私钥丢失。所以,如果这私钥是不能丢的,那最好的方式是从离线保存的私钥文件里导入。

这步可能有风险,因为需要把离线保存的私钥文件复制到目标机器,而且要将私钥的密码清零。为了提高安全性,建议离线操作,并尽可能快速完成全部流程。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 在内存文件系统操作,防止私钥落盘
umask 077 && mkdir /tmp/crypto && cd /tmp/crypto

# 这里断网,再复制你的私钥到 /tmp/crypto/tpm_pri
# 假设是从 U 盘复制,那命令可能是:
sudo mount -o ro /dev/sdb1 /mnt
cp /mnt/key.pem tpm_pri

# 解密私钥,即删除私钥的密码(这很危险!平时绝不能这样做!)
ssh-keygen -f tpm_pri -mPEM -ep

# 导入私钥
tpm2_ptool import --label SSHToken --key-label TPM-SSH --userpin [USER-PIN] \
--privkey /tmp/crypto/tpm_pri --algorithm ecc384

# 清理机密数据
shred -zu tpm_pri
rm -rf /tmp/crypto

7. 查看公钥

1
2
3
TPM2_PKCS11_SO=/usr/lib/$(gcc -dumpmachine)/pkcs11/libtpm2_pkcs11.so

ssh-keygen -D $TPM2_PKCS11_SO

可以导到文件里:

1
ssh-keygen -D $TPM2_PKCS11_SO > ~/.ssh/tpm.pub

8. 设置 SSH 服务端

这里在本地测试:

1
cat ~/.ssh/tpm.pub >> ~/.ssh/authorized_keys2

测试连接:

1
ssh -I $TPM2_PKCS11_SO $USER@localhost

9. 【可选】使用 ssh-agent

1
2
pgrep -u $UID ssh-agent || eval `ssh-agent`
ssh-add -s $TPM2_PKCS11_SO

10. 【可选】对指定主机自动使用 TPM 密钥

添加以下文本:

1
2
3
Host umu618.com
PKCS11Provider /lib/x86_64-linux-gnu/pkcs11/libtpm2_pkcs11.so
IdentityAgent none

或者对全部主机使用:

1
2
cat <(echo "PKCS11Provider $TPM2_PKCS11_SO") ~/.ssh/config \
| tee ~/.ssh/config

家用 WiFi 方案二【MESH 版】

需求

写于 2020-03-23 21:57:52 的《家用 WiFi 方案》已经是 4 年前的方案了,现在流行 Mesh 方案。正好手头上有两台 2023-11-24 产的 CMCC RAX3000M NAND 版,那就和红米 AX6S 一起 Mesh 吧!

思考

  • 为何不用 AC+AP 方案?因为贵。如果新买成品 AC,就得买配套的 AP,不仅要一笔支出,还导致现有的 10 几个路由器都吃灰。而如果使用 OpenWRT 来实现 AC,开发成本更高,目前没发现 OpenWRT 上特别靠谱的 AC 实现。这里有一个十年前的项目。

  • 为何不用现成的 MESH 路由器?因为穷。稣的主路由是 R4S,安装的是自己编译的 OpenWRT。如果改为现成的 MESH 路由器,势必需要替换这个主路由,那不是还得买一个性能和 R4S 差不多,而且还得能刷 OpenWRT 的?买不起啊。

  • 有线回程?还是无线回程?能有线肯定有线,网络质量更好。还好家里布线还行,有线回程没问题。

具体步骤

  1. 配置成 AP

lan 口协议改为 DHCP client,关掉 lan 口的 DHCP(即打勾 Ignore interface),再把 dnsmasq 禁用。

可选,如果有 IPv6,再创建一个 lan6 口,协议为 DHCPv6 client。

  1. 查看各 AP 的 MAC 地址

注意:查看的是 WiFi 网卡的 MAC,即 Wireless Overview 页面展示的 BSSID。

以下为假设的值:

  1. 配置 WiFi

SSID 和 Encryption 设置全一样,信道错开。

  1. 开启 AP 的 802.11r 支持

位于 Interface Configuration - WLAN Roaming - 802.11r Fast Transition,打勾即可。

  1. 配置 802.11r

每个 AP 的 NAS ID 设为自己的 MAC 地址去掉冒号,比如 红米 AX6S 的 MAC 为 33:33:33:33:33:33,NAS ID 就设为 333333333333。

Mobility Domain 都设置成一样的 16 位数字的 Hex 格式,比如:abcd。

FT protocol 都设为 FT over DS,即有线回程。如果网口不够用,可以选择 FT over the Air。

R1 Key Holder 设为和 NAS ID 一样即可。

External R0 Key Holder List 添加 3 个,分别为:

  • 11:11:11:11:11:11,111111111111,1234567890abcdef1234567890abcdef
  • 22:22:22:22:22:22,222222222222,1234567890abcdef1234567890abcdef
  • 33:33:33:33:33:33,333333333333,1234567890abcdef1234567890abcdef

其中的 1234567890abcdef1234567890abcdef,您可以改为其它 128 位数值(16 字节)。

External R1 Key Holder List 添加 3 个,分别为:

  • 11:11:11:11:11:11,11:11:11:11:11:11,1234567890abcdef1234567890abcdef
  • 22:22:22:22:22:22,22:22:22:22:22:22,1234567890abcdef1234567890abcdef
  • 33:33:33:33:33:33,33:33:33:33:33:33,1234567890abcdef1234567890abcdef

快速杀死 Linux

问题

众所周知,Linux 上的脚本可以通过 Shebang 符号(#!)来指定它的解释器(interpreter)。那么,ELF 格式的程序又是谁来执行的呢?

研究

Linux 系统必然存在一个用于加载 ELF 程序的程序,它本身是被内核拉起的。然而,虽然有这么一个叫做 init 的进程,但对应的 init 程序文件是位于 /sbin 下,它不应该是直接用来运行其它程序的,不然普通用户的程序岂不是都无法启动?

一次使用 file 时,发现它打印出一个 interpreter:

1
2
$ file $(which bash)
/usr/bin/bash: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=0b6b11360e339f231f17484da2c87d0d78554e31, for GNU/Linux 3.2.0, stripped

这个 /lib64/ld-linux-x86-64.so.2 可以说是相当眼熟的,每次 ldd 一个 ELF 程序都会看到:

1
2
3
4
5
$ ldd $(which bash)
linux-vdso.so.1 (0x00007ffcdbf89000)
libtinfo.so.6 => /lib/x86_64-linux-gnu/libtinfo.so.6 (0x00007fe156917000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fe156736000)
/lib64/ld-linux-x86-64.so.2 (0x00007fe156aa1000)

所以,可以拿它来运行别的 ELF 程序?

1
2
$ /lib64/ld-linux-x86-64.so.2 $(which pwd)
/root

哦吼!还真可以……看看它到底是啥:

1
2
3
4
$ file /lib64/ld-linux-x86-64.so.2
/lib64/ld-linux-x86-64.so.2: symbolic link to /lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
$ file /lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2: ELF 64-bit LSB shared object, x86-64, version 1 (GNU/Linux), dynamically linked, BuildID[sha1]=38e7d4a67acf053c794b3b8094e6900b5163f37d, stripped

所以,在 x64 的 Linux,ELF 的解释器其实是 /lib/x86_64-linux-gnu/ld-linux-x86-64.so.2

结论

最快杀死 Linux 的方法是:

1
> chmod -x /lib/x86_64-linux-gnu/ld-linux-x86-64.so.2

请勿轻易尝试。如果您真的很好奇,记得先备份这个程序,在一定时间内还能救回来。可以这么思考:这个解释器又是谁加载的?您不会已经关闭 shell 了吧?

Debian 12 的 xrdp 开启声音重定向

需求

自从给华为擎云 L420L410W515 都装上 Debian 12 后,稣就把前两者卖了,因为它们是笔记本,稣有太多笔记本了……唯独留下 W515,并宠爱有加,因为它是台式机。

稣还给它装了(华为?)MATE 桌面,获得和 xrdp 不错的兼容性!果然还是华为 MATE 牛逼!

于是乎,在远程桌面下都有图像的前提下,没有声音就显得很奇怪!

分析

很容易发现,远程桌面下,默认是没有声音输出设备的,所以没有声音!我们需要的是一个虚拟声卡。

由于 Debian 12 的声音系统是 pipewire,使用“pipewire xrdp”作为关键词,很容易能找到:

https://github.com/neutrinolabs/pipewire-module-xrdp

编译 pipewire-module-xrdp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
git clone https://github.com/neutrinolabs/pipewire-module-xrdp
cd pipewire-module-xrdp

# Install build environment
sudo apt install git pkg-config autotools-dev libtool make gcc

# Install dependencies
sudo apt install libpipewire-0.3-dev libspa-0.2-dev

# Build
./bootstrap
./configure
make

# Install
sudo make install

使用

连重启都不用,只需要重新进行 RDP 连接即可生效。

诗盗·就洗淋被

《诗盗·就洗淋被》:虚拟世界虚拟币,真实人性真实利。手持千枚比体系,年薪和纸一个亿。

注解

就洗淋被:闽南语,意思是被子拿出去晒,结果被雨淋湿了,又洗了一遍。/狗头
比体系:稣曾经有一千多枚 BTC,后来都变成废纸。
年薪和纸一个亿:密钥写在纸上的,结果纸丢了,但是那张纸确实能做到年薪一个亿,还是美元哦!

Linux 上各种 DE 和 xrdp 的兼容性

需求

稣主要使用 macOS 和 Windows 远程桌面访问 Windows 和 Linux,所以 Linux 下哪个 DE 对 xrdp 支持最好呢?

选手

在过去Linux 桌面玩稣的时代,主要使用以下 DE:

  • GNOME
  • Cinnamon
  • MATE
  • Xfce
  • KDE
  • i3

其中 GNOME 和 KDE 太大了,而且对 xrdp 支持并不好,不想再使用,直接淘汰。加入两个从没使用过的选手:

  • LXDE
  • LXQt

但由于它们太像了,简单看起来仅仅是样式不同,所以算一个吧。

对比

以下为最直观的感受,没有深入去折腾。

DE 名称 GUI 下支持的缩放个数 缩放有效否 明显的坑
Cinnamon 5 个(100、125、150、175、200) 是,立刻生效 第一次设置缩放后,开始菜单高度没变高,是个矮个子的错误状态,注销再登录才正常
MATE 2 个(100、200) 是,立刻生效 没有 Cinnamon 漂亮,界面布局需要适应,容易把左下角的“显示桌面”当成开始菜单
Xfce 5 个(100、125、150、175、200) 否,即使重新登录也无效 永远 100% 的缩放
i3 0 个(自己改配置去!) 否,改配置后无法在一次会话里即时成效 WIN 键有时候失灵,是在不同 RDP 客户端连接下键值可能和服务端本地不同!
LXDE/LXQt 0 个 否,界面上没找到地方改 永远 100% 的缩放,即使 RDP 客户端已经记住密码,每次登录必然再弹出对话框要求输入密码。

结论

似乎就 Cinnamon 和 MATE 是应该一起安装的!一个大哥,一个小妹,能互补,还能偶尔换换口味。

Xfce 和 i3 也许折腾几下也能好用。

不过,以上,在 Windows 面前,都是乐射……不管本地、还是被远程,Windows 都完美缩放。

CMCC RAX3000M 刷 OpenWRT

需求

写于 2020-03-23 21:57:52 的《家用 WiFi 方案》已经是 4 年前的方案了,现在流行 Mesh 方案。正好手头上有两台 2023-11-24 产的 CMCC RAX3000M NAND 版,那就把它们刷成官方版 OpenWRT 再来和红米 AX6S 一起 Mesh 吧!

参考

  1. OpenWRT Techdata: CMCC RAX3000M

  2. mediatek: add CMCC RAX3000M support

  3. Setting up a TFTP server for TFTP

  4. RAX3000M刷OpenWRT官方版本23.05.2

  5. 关于CMCC RAX3000M 刷机防变砖教程

  6. RAX3000M 刷固件时没刷BL2,还需要重新刷入吗?

  7. H3C Magic NX30 Pro 官方 OpenWrt 安装教程

  8. 关于mt7621原厂固件启用nmbm的提醒

  9. mediatek/filogic预编译镜像中带nmbm字样的应该如何安装?

警告

  1. 目前(2024-04-08),OpenWRT 官方还不支持 NMBM,所以刷机有一定风险!万一 NAND 有坏块,有可能无法启动。
1
2
3
4
5
6
7
root@RAX3000M:/tmp# dmesg | grep nmbm
[ 0.685313] nmbm nmbm_spim_nand: Signature found at block 1023 [0x07fe0000]
[ 0.693039] nmbm nmbm_spim_nand: First info table with writecount 0 found in block 960
[ 0.703133] nmbm nmbm_spim_nand: Second info table with writecount 0 found in block 963
[ 0.711141] nmbm nmbm_spim_nand: NMBM has been successfully attached
[ 0.717754] 8 fixed-partitions partitions found on MTD device nmbm_spim_nand
[ 0.724799] Creating 8 MTD partitions on "nmbm_spim_nand":
  1. 这是 1124 版、NAND 版,非 eMMC 版,其它版本不保证可行。

软件工具

  1. 大部分系统都自带的 ssh 命令,可选 scp 命令或 winscp。大部分镜像文件都可以直接在路由器里用 wget 下载,如果您已经在电脑上下载好,也可以用 scp 命令或 winscp 上传到路由器。

  2. Linux 系统,或 Windows 上的 WSL。

  3. tftpd 或其它同类 TFTP 服务端。

具体步骤

1. 开启路由器 ssh 服务端

原理:导出配置,修改配置使能 dropbear,导入配置。

原版固件里导出的配置是一个加密的 tar 包,要编辑它,需要先解包,在 Linux 或 WSL 操作:

1
openssl aes-256-cbc -d -pbkdf2 -k $CmDc#RaX30O0M@\!$ -in cfg_export_config_file.conf -out - | tar -zxvf -

解开后,做两件事:编辑 etc/config/dropbear 允许 dropbear 和编辑 etc/shadow 修改 root 密码。

dropbear 里删除以下行,或把 0 改为 1:

1
option enable '0'

shadow 里的第一行格式为:

1
root:$1$<salt>$<password>:<unconcerned>

即,只关心第一和第二 : 之间的 <salt> 和 <password>,如果您能破解出 <password> 的明文,那可以不用改了;否则就用 <salt> 生成一个新密码,去替换 <password>。

1
openssl passwd -1 -salt <salt> OpenWRT

以上命令产生明文为 OpenWRT 的密码,拿它替换 shadow 里的原始密码。然后把修改后的文件再打包回去:

1
tar -zcvf - etc | openssl aes-256-cbc -pbkdf2 -k $CmDc#RaX30O0M@\!$ -out cfg_export_config_file_ssh.conf

拿 cfg_export_config_file_ssh.conf 去恢复配置,重启后,即可用 root 身份 ssh 到路由器。

2. 备份原始分区

这步可以跳过,对一些人来说,备份意义不大,不可能刷非官方 OpenWRT 的。请自行斟酌。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
root@RAX3000M:~# cat /proc/mtd
dev: size erasesize name
mtd0: 08000000 00020000 "spi0.0"
mtd1: 00100000 00020000 "BL2"
mtd2: 00080000 00020000 "u-boot-env"
mtd3: 00200000 00020000 "Factory"
mtd4: 00200000 00020000 "FIP"
mtd5: 03d00000 00020000 "ubi"
mtd6: 02500000 00020000 "plugins"
mtd7: 00800000 00020000 "fwk"
mtd8: 00800000 00020000 "fwk2"

# 备份 mtd0 - mtd8
dd if=/dev/mtd0 of=/tmp/0.img
dd if=/dev/mtd1 of=/tmp/1.img
dd if=/dev/mtd2 of=/tmp/2.img
dd if=/dev/mtd3 of=/tmp/3.img
dd if=/dev/mtd4 of=/tmp/4.img
dd if=/dev/mtd5 of=/tmp/5.img
dd if=/dev/mtd6 of=/tmp/6.img
dd if=/dev/mtd7 of=/tmp/7.img
dd if=/dev/mtd8 of=/tmp/8.img

# 以上每条 dd 命令运行后,需要立刻在电脑上用 scp 把文件复制到电脑,
# 并删除路由器里的文件,防止 /tmp 被写爆

3. 刷 uboot

1
2
3
4
5
6
7
8
9
wget https://mirrors.ustc.edu.cn/openwrt/releases/23.05.3/targets/mediatek/filogic/openwrt-23.05.3-mediatek-filogic-cmcc_rax3000m-nand-bl31-uboot.fip

# wget https://downloads.openwrt.org/releases/23.05.3/targets/mediatek/filogic/openwrt-23.05.3-mediatek-filogic-cmcc_rax3000m-nand-bl31-uboot.fip
# sha256sum openwrt-23.05.3-mediatek-filogic-cmcc_rax3000m-nand-bl31-uboot.fip
# f60d7aa3dcd854a5a39c2b3e05cdc9985460d4b358d02e96d51c50f476650270

# 3. Erase and write new FIP:
mtd erase FIP
mtd write openwrt-mediatek-filogic-cmcc_rax3000m-nand-bl31-uboot.fip FIP

4. 刷 OpenWRT

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
4. Set static IP on your PC:
IP 192.168.1.254, GW 192.168.1.1

5. Serve OpenWrt initramfs image using TFTP server.
# 文件名需要去掉版本号,即改为:
# openwrt-mediatek-filogic-cmcc_rax3000m-initramfs-recovery.itb

6. Cut off the power and re-engage, wait for TFTP recovery to complete.

7. After OpenWrt has booted, erase UBI volumes:
ubidetach -p /dev/mtd0
ubiformat -y /dev/mtd0
ubiattach -p /dev/mtd0

8. Create new ubootenv volumes:
ubimkvol /dev/ubi0 -n 0 -N ubootenv -s 128KiB
ubimkvol /dev/ubi0 -n 1 -N ubootenv2 -s 128KiB

9. Additionally, if you want to have NAND recovery boot feature:
(Don't worry! You will always have TFTP recovery boot feature.)
ubimkvol /dev/ubi0 -n 2 -N recovery -s 20MiB
ubiupdatevol /dev/ubi0_2 openwrt-mediatek-filogic-cmcc_rax3000m-initramfs-recovery.itb

10. Perform sysupgrade.

5. 刷 bl2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
root@UMUTech:~# cd /tmp

# 查看 mtd 分区信息
root@UMUTech:/tmp# cat /proc/mtd
dev: size erasesize name
mtd0: 07200000 00020000 "ubi"
mtd1: 00200000 00020000 "fip"
mtd2: 00200000 00020000 "factory"
mtd3: 00080000 00020000 "u-boot-env"
mtd4: 00100000 00020000 "bl2"

# 同步仓库源
root@UMUTech:/tmp# opkg update

# 安装 kmod-mtd-rw 内核模块
root@UMUTech:/tmp# opkg install kmod-mtd-rw

# 将分区配置为可读写
root@UMUTech:/tmp# insmod /lib/modules/$(uname -r)/mtd-rw.ko i_want_a_brick=1

# 下载 preloader
root@UMUTech:/tmp# wget https://downloads.openwrt.org/releases/23.05.3/targets/mediatek/filogic/openwrt-23.05.3-mediatek-filogic-cmcc_rax3000m-nand-preloader.bin

# 刷写 BL2 分区
root@UMUTech:/tmp# mtd write /tmp/openwrt-23.05.3-mediatek-filogic-cmcc_rax3000m-nand-preloader.bin bl2
Unlocking bl2 ...

Writing from /tmp/openwrt-23.05.3-mediatek-filogic-cmcc_rax3000m-nand-preloader.bin to bl2 ...

macOS 上用触控 ID 安全登录 SSH

需求

  1. 使用文件存 SSH 私钥,其实安全性挺堪忧的:如果私钥没有密码,任何程序都可以直接读取,被流氓软件偷偷上传怎么办?为了安全,给私钥加密,这就要输入密码,麻烦。而且输入密码时,又可能被偷。

  2. 有没有一种木马专门针对 ssh-agent 呢?您把密钥的密码交给 ssh-agent​,真放心吗?

  3. 稣特地买了一台 MBA 13 M1 乞丐版装 Asahi Linux,结果触控板在 Linux 下表现不如 macOS 下好用,Touch ID 还不能用,又回 macOS 了。既然回 macOS,就需要开发 Touch ID 更多功能,不然怎么对得起吃灰的 Asahi Linux?

总之,稣需要一种更安全的 SSH 登录方式,那就是——用 Touch ID 登录。

原理

安全隔区(Secure Enclave)是集成到 Apple 片上系统 (SoC) 的专用安全子系统。安全隔区独立于主处理器,因此私钥不会被操作系统(OS)读取。验证时,是安全芯片参与运算,全程私钥都不会交给 OS。

简单来说,它更像一台微型服务器,有自主的算力,而不是一个静态文件,不会被不良应用程序偷走。

实现

使用开源软件 sekey,替换默认的 ssh-agent。

它的详细介绍请参考其 GitHub 仓库

1. 安装 sekey

1
brew install sekey

安装后,可用以下命令检查 sekey 是否在运行:

1
ls ~/.sekey/ssh-agent.ssh

2. 创建基于 Secure Enclave 的密钥对

创建一个名为 SSH 的密钥对:

1
sekey -c SSH

sekey -l 查看其 ID,然后用 sekey -e <ID> 查看公钥。这个公钥是 ecdsa-sha2-nistp256 格式的,把公钥配置到 SSH 服务器即可。

3. 配置 ssh 使用 sekey

1
vim ~/.ssh/config

添加以下一行:

1
IdentityAgent ~/.sekey/ssh-agent.ssh

疑难杂症

当服务器为 OpenWRT 系统时,有可能无法正常工作。因为 OpenWRT 默认的 SSH 服务端是 dropbear,它不支持 ecdsa-sha2-nistp256。装个 OpenSSH 即可:

1
2
opkg update
opkg install openssh-server

最后提醒:业界对 ecdsa-sha2-nistp256 有一些质疑的声音,它的安全性应该不如 ed25519。

无银第八哥【3】修改分支走向

需求

从人类的角度看,无非有两种情况:要某功能和不要某功能。在代码层面上则是:

  • 改变程序执行路径。

  • 跳过部分代码。

分析

如果您不要某个功能,那就是找到这功能的调用指令,把它去掉。而想要某个功能,则有两种基本的做法:

  1. 无视原条件,修改后续的条件跳转指令,强行跳到需要的功能代码;

  2. 改变条件本身,达成此功能需要的条件。

下面用 C++ 代码解释,假设原始代码如下:

1
2
3
4
bool flag = Condition();
if (flag) {
Wanted();
}

如果正常情况下 Condition 返回 false,而我们想 Wanted 函数被调用,那么,方法 1 是将代码改为:

1
2
bool flag = Condition();
Wanted();

而方法 2 则是改为:

1
2
3
4
bool flag = true;
if (flag) {
Wanted();
}

当然,还有两种方法一起用,那就是改为:

1
Wanted();

实现

具体实现主要使用 jmpnop,更复杂的场景可能需要配合其它指令,请自行领悟。

1. jz/jnz 改为 jmp

最简单的一种情况是:跳转地址为 1 字节的相对位移,这种直接把跳转指令改为 jmp 即可,例如:

1
X: jz Y

需要改为:jmp Y,只需:eb X eb 即可。

如果跳转地址为 4 字节的相对位移,则 jz/jnz 有 2 字节,而 jmp 只有 1 字节,所以需要先 nop 掉第一字节:eb X 90 e9。这种方法无需调整后面的地址,另外还可以不用 nop,但需要调整地址:

1
X: jmp Y+1

因为指令变短了 1 字节,相对位移就更远 1 字节,这种改法纯属蛋疼,严重不建议采用。

2. nop 掉 call 指令

这种方法的基本操作极其简单,只需要 eb 若干个 90。

1
X: call Y

只要先查看 X 地址的这条指令有几个字节,再 eb X 后面跟几个 90 即可。

但有些情况也比较复杂,比如一个 x86 的 __stdcall,单独把 call 指令 nop 掉,会导致栈失衡(短期看不出任何异常),所以需要把前面的 push 也 nop 掉。__cdecl 和 __fastcall 不用,所以需要先判断一个 call 是不是 __stdcall。em,还是 x64 省事。

最简单的例子

正常情况下,按下 winver 界面上的“确定”按钮可以退出,我们来把它无效掉!

winver

  1. 首先,推测按下“确定”按钮后,是调用 EndDialog 来退出,所以对它下断点:bp USER32!EndDialog

  2. 发现 USER32!EndDialog 确实能断,gu 使它返回到调用处,发现是 SHELL32!AboutDlgProc+0xea。

1
2
3
4
5
6
7
8
9
10
0:000> ub SHELL32!AboutDlgProc+0xea
SHELL32!AboutDlgProc+0xca:
00007fff`6d218f3a 895f18 mov dword ptr [rdi+18h],ebx
00007fff`6d218f3d 488bce mov rcx,rsi
00007fff`6d218f40 89473c mov dword ptr [rdi+3Ch],eax
00007fff`6d218f43 e84c6e0000 call SHELL32!_ApplyLayout (00007fff`6d21fd94)
00007fff`6d218f48 e9d2000000 jmp SHELL32!AboutDlgProc+0x1af (00007fff`6d21901f)
00007fff`6d218f4d 488bd5 mov rdx,rbp
00007fff`6d218f50 488bce mov rcx,rsi
00007fff`6d218f53 48ff15166f3700 call qword ptr [SHELL32!_imp_EndDialog (00007fff`6d58fe70)]

地址 00007fff`6d218f53 处的 call 指令有 7 字节,所以它本身的地址是 SHELL32!AboutDlgProc+0xea-7,即 SHELL32!AboutDlgProc+0xe3。

  1. 重新运行,开始 nop:eb SHELL32!AboutDlgProc+0xe3 90 90 90 90 90 90 90,此时再继续运行后,即可得到一个无法按“确定”关闭的对话框。

注意:这样改后,同时标题栏的“关闭”按钮也无法关闭了,所以 winver 已经无法在界面上退出,需要用任务管理器关闭!

文本文件加不加 BOM?

问题

文本文件加 BOM 有何好处?有何坏处?到底加不加?

说法

  1. UTF-8 不需要 BOM,不含 BOM 的 UTF-8 才是标准形式,尽管 Unicode 标准允许在 UTF-8 中使用 BOM。

  2. 文本文件带 BOM 不是个标准的做法,而且可能会导致某些 reader 或者编辑器解析出错,所以一般不推荐文本文件去携带 BOM。

分析

人们写文本文件肯定有不同目的,所以,加和不加可能分别适用于不同目的,不能一概地认为哪种更好。

更聪明的做法是分类对待,可以根据以下基本原则:

  • 在有结构的文件里,不需要 BOM。

  • 在没有结构的文本文件里,最好有 BOM(见下面“兼容问题”)。

举例 1:.html, .xml 等文件有结构,不需要。

举例 2:.txt 没有结构,如果不加 BOM,软件需要自己判断,很可能判断失误出现乱码,或者为了正确判断付出巨大代价。

举例 3:带 shebang line 的文件,有结构,如果加了 BOM,会使弱鸡 Shell 不认识而出错。

举例 4:.cpp, .hpp,没有结构,里面如果没有中文、法语等 ASCII 码大于 127 的字符,加不加都无所谓,如果带中文,哪怕是注释,建议 UTF-8 with BOM。

毕竟稣有 20 几台电脑,涵盖 Windows、macOS、Linux 系统和 x86、x64、armhf、arm64 架构,没有 BOM 怎么愉快地写 C++?

兼容问题

本节,只针对没有结构的文本文件。

遇到阅读器/编辑器不支持的情况,那就是不加好,但并不是绝对,因为这其实还是个需求问题。

比如说,稣一直用 Windows 的记事本写一些备忘,如果汉字局多,就选择 UTF-16 LE with BOM,代码居多则用 UTF-8 with BOM。这些文件换用其它软件打开也许会乱码,但有何关系呢?他们可以写出不支持 BOM 的擸𢶍软件,稣也可以不用呀!稣在 macOS、Linux 上都可以拿支持 BOM 的软件(比如 VSCode)打开这些文件。

再考虑一种死翘翘的情况:您在用 B 语言写代码,但它的编译器不支持 BOM,那么显然您就不应该加了。

所以,当您的文本文件的主程序不支持 BOM 时,不应该加,支持的情况,还是加的好。