Category: Uncategorized

  • WSL Docker 迁移 Volume 到 Linux

    看了一堆 Volume 迁移的教程,麻烦死。其实操作逻辑很简单,找到源主机的 docker volume 目录(一般在 /var/docker/volumes/ ),在目标端建立同名的volume,停掉两端的docker,从源把目录 rsync 到目标。

    Windows 11 + WSL2 + Docker。

    操作步骤如下

    1 找到 Docker 的数据盘 VHDX。

    我自己的磁盘被迁移到了 D盘,如果不知道在哪儿,一般在用户目录,例如 C:\Users\sskaje\AppData\Local\Docker,这个目录下 distro 是程序的镜像,data是数据的镜像。

    如果还不在这里,Windows 11 可以使用任务管理器 -> 性能 右上角… -> 资源监视器 -> CPU,在关联的句柄里搜索 vhdx,然后操作docker,例如 系统托盘退出docker 再打开,或者打开docker-desktop 的界面,乱点点。

    2 退出 Docker Desktop。

    3 在 WSL 里 手动加载 Docker Desktop 的数据盘。

    wsl.exe -d Debian --mount --vhd D:/WSL/Docker/data/ext4.vhdx --bare --name docker-data-1

    参考 https://www.sskaje.me/2023/08/13/wsl-mount-external-vhdx-disk/,找到 docker 数据盘可能的磁盘,我这里是 sdd,直接挂载。

    mkdir docker-data
    mount /dev/sdd docker-data/

    于是,在 docker-data/data/docker/volumes 里能找到正常 docker volumes 目录里的所有文件。

    cd docker-data/data/docker/volumes

    4 (新terminal窗口)在目标主机上建立对应的volumes,然后关掉 docker。

    以 gogs-data 为例,在目标主机上执行

    docker volume create gogs-data
    /etc/init.d/docker stop

    5 从源 WSL 里,rsync 目录

    rsync -av gogs-data root@192.168.11.11:/var/lib/docker/volumes/

    执行完成后,在目标主机上启动 docker

    /etc/init.d/docker start

    如果有多个volume要迁移,迁移完所有的volume之后再start。

    6 目标 Linux 启动对应的docker。

    例如我的 gogs

    docker run --detach --name=gogs -p 10022:22 -p 10880:3000 -v gogs-data:/data gogs/gogs

    再用浏览器访问 192.168.11.11:10880,用之前的凭据登录,一切正常。

    7 收拾残局。

    很遗憾,WSL 2 我不知道怎么正确地 unmount Disk ,我尝试 linux 里 umount 再从外边 wsl --unmount DISK,失败,只能用 wsl --unmount 卸载全部。

  • OpenWRT Auto Bind USB Device to USBIP

    OpenWRT 加载设备自动执行脚本使用的是 hotplug,官方文档在

    https://openwrt.org/docs/guide-user/base-system/hotplug

    一般 Linux 可能要使用 udev。

    此方案的设计目标是,使支持 OpenWRT 的随身路由,通过 USB/IP,改造成车载CAN采集终端,并可以支持远程实时采集、刷写。

    简单的脚本如下。(此处只使用了 ETAS 的产品的 USB VID,其他诸如 Vector,IntrepidCS,Peak 等的,修改 if 的条件即可。)

    /etc/hotplug/usb/99-usbcan

    #!/bin/sh
    
    # ETAS 58x
    #    108c/168/*) # es582.1
    #    108c/169/*) # es584.1
    #    108c/15a/*) # es583.1
    #    108c/159/*) # es581.4
    #    108c/15b/*) # es581.4
    
    if [ "${ACTION}" = "bind" ]; then
        if [[ "${PRODUCT}" =~ "108c/.*" ]]; then
          usbip bind -b ${DEVICENAME}
        fi
    fi
    
    if [ "${ACTION}" = "remove" ]; then
        if [[ "${PRODUCT}" =~ "108c/.*" ]]; then
          usbip unbind -b ${DEVICENAME}
        fi
    fi

    附上记录的日志,内容格式

    "$PRODUCT detected, Action=${ACTION}, DEVICENAME=${DEVICENAME}, DEVICE_TTY=${DEVICE_TTY}, DEVPATH=${DEVPATH}"

    插拔 ES582.1 的日志

    
    108c/168/100 detected, Action=add, DEVICENAME=3-1, DEVICE_TTY=, DEVPATH=/devices/platform/usbdrd3_0/fc000000.usb/xhci-hcd.6.auto/usb3/3-1
    108c/168/100 detected, Action=add, DEVICENAME=3-1:1.0, DEVICE_TTY=, DEVPATH=/devices/platform/usbdrd3_0/fc000000.usb/xhci-hcd.6.auto/usb3/3-1/3-1:1.0
    108c/168/100 detected, Action=add, DEVICENAME=3-1:1.1, DEVICE_TTY=, DEVPATH=/devices/platform/usbdrd3_0/fc000000.usb/xhci-hcd.6.auto/usb3/3-1/3-1:1.1
    108c/168/100 detected, Action=bind, DEVICENAME=3-1, DEVICE_TTY=, DEVPATH=/devices/platform/usbdrd3_0/fc000000.usb/xhci-hcd.6.auto/usb3/3-1
    
    108c/168/100 detected, Action=remove, DEVICENAME=3-1:1.0, DEVICE_TTY=, DEVPATH=/devices/platform/usbdrd3_0/fc000000.usb/xhci-hcd.6.auto/usb3/3-1/3-1:1.0
    108c/168/100 detected, Action=remove, DEVICENAME=3-1:1.1, DEVICE_TTY=, DEVPATH=/devices/platform/usbdrd3_0/fc000000.usb/xhci-hcd.6.auto/usb3/3-1/3-1:1.1
    108c/168/100 detected, Action=unbind, DEVICENAME=3-1, DEVICE_TTY=, DEVPATH=/devices/platform/usbdrd3_0/fc000000.usb/xhci-hcd.6.auto/usb3/3-1
    108c/168/100 detected, Action=remove, DEVICENAME=3-1, DEVICE_TTY=, DEVPATH=/devices/platform/usbdrd3_0/fc000000.usb/xhci-hcd.6.auto/usb3/3-1

    其他已知的 USB VIDs:

    Vector: 0x1248
    Peak System: 0x0C72
    Kvaser: 0x0BFD

    也可以从Linux 内核源码里找 https://github.com/torvalds/linux/tree/master/drivers/net/can/usb

  • USBIP + Windows

    测试环境:Linux(PVE) + Windows 10

    软件 https://github.com/vadimgrn/usbip-win2

    使用设备 ETAS ES582.1

    服务端安装

    # 安装
    apt update
    apt install usbip
    # 加载
    modprobe usbip-host
    modprobe usbip-core
    modprobe vhci-hcd
    # 查看列表,查找到 bus id
    usbip list -l
    # bind 设备
    usbip bind -b 1-3
    # 启动服务端
    usbipd -D

    启动后,服务端会打开 TCP 3240 端口。

    客户端,Windows,安装二进制,按要求重启。

    管理员模式 CMD 允许自定义驱动,执行完再重启

    bcdedit.exe /set testsigning on

    usbip.exe 被加到了 %PATH% 里,我是用的 0.9.5.5 版,命令行需要使用 usbip.exe ,如果使用 usbip 会无响应。

    >usbip.exe list -r 192.168.8.254
    Exportable USB devices
    ======================
        1-3    : Robert Bosch GmbH : unknown product (108c:0168)
               : /sys/devices/pci0000:00/0000:00:14.0/usb1/1-3
               : (Defined at Interface level) (00/00/00)
               :  0 - Communications/Multi-Channel/? (02/04/01)
               :  1 - (Defined at Interface level) (00/00/00)
    >usbip.exe attach -r 192.168.8.254 -b 1-3
    succesfully attached to port 1

    使用 ETAS HSP,设备能正常识别。

    Linux 端,tcpdump 抓包,数据能抓到,但是 WireShark 自带的 dissector 暂时有问题,解析不完整。

    理论上到了 tcp/ip 的这条路,做个 mitm 应该就好搞了。

  • 使用 Proxmox VE 抓 USB 数据包

    试过 Windows + USBPcap,Windows + VirtualBox,Mac + VirtualBox,都各种问题。

    本来目标是监测一个设备的 usb 刷写过程,用笔记本电脑的方案里最靠近成功的是 Mac + VirtualBox,需要使用 root 启动 VirtualBox,相关命令如下

    /Applications/VirtualBox.app/Contents/MacOS/VBoxManage list usbhost
    sudo /Applications/VirtualBox.app/Contents/MacOS/VBoxManage controlvm "Win10-USB" usbattach "p=0xXXXX;v=0xXXXX;s=0x0006a003ecaab3f0;l=0x14200000" --capturefile /tmp/esXXXX.pcap

    其中Address 里的s=,或者 UUID 每次都不一样,导致刷写过程的 USB 断开之后,下一次就没法自动发现了。

    因为按VirtualBox 文档要求,需要手动 usbattach,所以还没办法用 USB filter 来自动操作。

    而,文档里介绍的抓 Root Hub 的方法,在我的 mac 上无效,而我试图 Windows + VirtualBox,崩。所以转过来看qemu 的方案。

    搜到了 qemu 的官方文档。

    https://qemu-project.gitlab.io/qemu/system/devices/usb.html

    All usb devices have support for recording the usb traffic. This can be enabled using the pcap=<file> property, for example:
    
    -device usb-mouse,pcap=mouse.pcap

    于是赶紧去看 Proxmox VE 的 USB 选项,配置之后,可以正常发现设备,虚拟机里的软件也能正常识别。

    ssh 到 pve 宿主机上,我的虚拟机 ID 102

    qm showcmd 102

    去掉 USB 再来一次,对比了一下命令参数,和 pve 的文档一致 https://pve.proxmox.com/wiki/USB_Devices_in_Virtual_Machines

    操作方式是 qm monitor,web ui里去掉usb设备,手动添加,把showcmd 里拿到的设备参数处理一下,命令如下

    root@pve:~# qm monitor 102 
    Entering QEMU Monitor for VM 102 - type 'help' for help
    qm> device_add qemu-xhci,p2=15,p3=15,id=xhci,bus=pci.1,addr=0x1b
    qm> device_add usb-host,bus=xhci.0,port=1,vendorid=0xXXXX,productid=0xXXXX,id=usb0,pcap=/tmp/esXXXX.pcap
    qm> quit
    

    其中,VID 和 PID 我替换成 XXXX了,根据自己实际情况来。

    然后,把 pcap 拿回来,Wireshark 打开,分析。

    但是,数据包没抓全。

    Frame 114: 8267 bytes on wire (66136 bits), 320 bytes captured (2560 bits)

    调查了一下,

    https://github.com/qemu/qemu/blob/master/hw/usb/pcap.c#L73

    https://github.com/qemu/qemu/blob/master/hw/usb/pcap.c#L185

    源码这两处定义了最大数据长度 256,正好和拿下里的pcap文件里的一致。

    就这样吧,等有需求的时候,再build一个qemu自己抓完整包,就是不知道性能风险有多大。

    另外一个可能的方案:https://fedoraproject.org/wiki/Usbmon

    结束。

  • Gl-inet AXT1800 修改国家代码

    root@GL-AXT1800:~# cat /proc/mtd 
    dev:    size   erasesize  name
    mtd0: 00180000 00020000 "0:SBL1"
    mtd1: 00100000 00020000 "0:MIBIB"
    mtd2: 00380000 00020000 "0:QSEE"
    mtd3: 00080000 00020000 "0:DEVCFG"
    mtd4: 00080000 00020000 "0:RPM"
    mtd5: 00080000 00020000 "0:CDT"
    mtd6: 00080000 00020000 "0:APPSBLENV"
    mtd7: 00180000 00020000 "0:APPSBL"
    mtd8: 00080000 00020000 "0:ART"
    mtd9: 07280000 00020000 "rootfs"
    mtd10: 00080000 00020000 "log"
    mtd11: 00080000 00020000 "0:ETHPHYFW"
    mtd12: 0041e000 0001f000 "kernel"
    mtd13: 034ad000 0001f000 "ubi_rootfs"
    mtd14: 03339000 0001f000 "rootfs_data"

    暴力搜索,查到在 mtd8

    root@GL-AXT1800:/dev# hexdump -C /dev/mtdblock8 
    *
    00000090  43 4f 55 4e 54 52 59 3a  43 4e ff ff ff ff ff ff  |COUNTRY:CN......|

    导出

    dd if=/dev/mtdblock8 of=mtdblock8
    cp mtdblock8 mtdblock.orig

    修改,opkg里没有 hexedit,但是有个 jupp

    opkg update
    opkg install jupp
    jupp mtdblock8

    比较难用,ctrl + o + g 进入16进制模式,把 COUNTRY:CN 改成 COUNTRY:US ,再使用 ctrl + k + x 保存。可以看 ctrl + j 的帮助。

    回写,重启

    dd if=mtdblock8 of=/dev/mtdblock8
    reboot
  • iOS DNS Tunnel

    一直想留个 dns tunnel 的实例给手机用,以便不时之需。最近发现有个特殊场景,需要用到 dns tunnel。

    很多年前调研的时候,选定了 iodine,但是客户端是个问题,windows的程序古早,而且需要 openvpn 古早版本的 tuntap 驱动,iOS之前一直没有找到合适的客户端,拿电脑开热点有点过于傻(虽然我还是买了个 Connectify并用过几次),带个 OpenWRT 的路由(gl-inet)配充电宝好像是可以但是也挺麻烦。

    其他方案也看过,dns2tcp 算是接受度很高的方案,但是没找到 iOS 的客户端。

    Github 上有个 iOS 版的开源项目,不想折腾。

    最近又发现一个上架了的开源项目,Purple Haze,使用的方案是基于 iodine 的,省事了。

    服务器,iodined

    iodined -f -c -P password -DD -l 1.2.3.4 -m 1120 172.16.55.1 24 dns.sskaje.me

    MTU是个大问题,如果不指定,客户端每次建立连接都要去试。大概观察了一下客户端的日志,选了个小的 1120,客户端也得同步设置。

    NAT是需要开启的。eth0是公网的出口设备。

    iptables -t nat -A POSTROUTING -s 172.16.55.0/24 -o eth0 -j MASQUERADE

    实测,速度大概比 56k 猫的速度快一点,图片什么的基本看不到了,而且丢包率可观。

    再,如果iodined的服务器有其他网络,需要指定出口,例如:

    流量按本机的路由表转给其他二层设备,直接添加路由,并根据需求在出口设备上加 NAT。

    流量转给一个 point-to-point 设备,例如 wireguard、sit tunnel,OpenVPN TUN等,或者 OpenVPN TAP 类似的 二层设备

    例如,全部流量转给 wireguard wg0,table 33

    ip route add 172.16.55.0/24 dev dns0 table 33 
    ip rule add from 172.16.55.0/24 table 33
    ip route add default dev wg0 table 33 
    iptables -t nat -A POSTROUTING -s 172.16.55.0/24 -o wg0 -j MASQUERADE

  • Protected: 某 License Server 的逆向思路

    This content is password protected. To view it please enter your password below:

  • EE_KEY_TOO_SMALL

    Windows 11 + Python 3.10, ssl 加载了 1024-bit 的 证书和私钥。然后遇到了错误 EE_KEY_TOO_SMALL 。

    > python3.10 proxy.py
    Traceback (most recent call last):
      File "\proxy\proxy.py", line 11, in <module>
        server_context.load_cert_chain('../../docs/cert.pem', '../../docs/cert.key')
    ssl.SSLError: [SSL: EE_KEY_TOO_SMALL] ee key too small (_ssl.c:3874)

    尝试手动修改并加载 openssl.cnf ,无效。

    由于是临时服务,只对内,所以简单粗暴

    server_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
    server_context.set_ciphers('ALL:@SECLEVEL=0')
    server_context.load_cert_chain('../../docs/cert.pem', '../../docs/cert.key')

    Python 3.10 的 OpenSSL 版本

    >>> import ssl
    >>> ssl.OPENSSL_VERSION
    'OpenSSL 1.1.1s  1 Nov 2022'
  • Windows 使用 mitmproxy 劫持 TLS 连接

    本来是一个直连 127.0.0.1:xxx 的连接,发现服务器可以手动指定端口,就xxx + 1 手动起服务器连接,不改端口的方案先不管,只做技术验证。

    环境:Windows 11 + mitmproxy 9.0.1

    原有软件的连接,使用 openssl s_client -connect 127.0.0.1:xxx 看到是 TLS 1.2,经过某些手段提取了私钥,配合证书,如果还能还原协议就可以自建server或者篡改请求了。

    私钥的环节其他另文。

    假设已经拿到了 PEM 格式的私钥,加上 openssl s_client 看到的证书 PEM,在验证之后,可以编辑一个满足 mitmproxy 要求的证书文件。格式说明在 https://docs.mitmproxy.org/stable/concepts-certificates/,结构如下

    -----BEGIN PRIVATE KEY-----
    <private key>
    -----END PRIVATE KEY-----
    -----BEGIN CERTIFICATE-----
    <cert>
    -----END CERTIFICATE-----
    -----BEGIN CERTIFICATE-----
    <intermediary cert (optional)>
    -----END CERTIFICATE-----

    这个场景下只是针对明确目标的 MITM 攻击,所以选用 mitmproxy 的反向代理模式 “reverse”,文档在 https://docs.mitmproxy.org/stable/concepts-modes/。

    基本结构是

    Client ---> [port xxx] mitmproxy(reverse mode) [port xxx+1] ---> [port xxx+1] Server

    假设xxx = 12300,则对应的命令是

    mitmproxy --mode reverse:tls://127.0.0.1:12301@12300 

    由于上游证书是自签的,经验证服务端也没有要求客户端使用证书,所以需要使用 -k 关闭证书校验 。

    然后,还需要让下游客户端继续维持上游的证书,防止内部有额外的校验,引入之前的证书文件假设为 mitm.pem 则完整命令为

    mitmproxy --mode reverse:tls://127.0.0.1:12301@12300 -k --certs *=mitm.pem

    脚本看文档 https://docs.mitmproxy.org/