从零开始学howtoheap:理解fastbins的double-free攻击

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

1.fastbins的double-free攻击

下面的程序展示了fastbins的double-free攻击,可以泄露出一块已经被分配的内存指针。fastbins 可以看成一个后进先出的栈,使用单链表来实现,通过fastbin->fd来遍历。由于free的过程会对free list做检查,我们不能连续两次free同一个chunk,所以这里在两次free 之间,增加了一次对其他chunk的free 过程,从而绕过了检查顺利执行,然后再malloc三次,就在同一个地址malloc了两次,也就有了两个指向同一块内存区域的指针。

2.fastbin_dup程序

这个程序更具体地展示了通过欺骗 malloc 来返回一个我们可控的区域的指针(在这个例子中,我们可以返回一个栈指针)。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>int main()
{fprintf(stderr, "这个例子演示了 fastbin 的 double free\n");fprintf(stderr, "首先申请了 3 个 chunk\n");char* a = malloc(8);strcpy(a, "AAAAAAAA");char* b = malloc(8);strcpy(b, "BBBBBBBB");char* c = malloc(8);strcpy(c, "CCCCCCCC");fprintf(stderr, "第一个 malloc(8): %p\n", a);fprintf(stderr, "第二个 malloc(8): %p\n", b);fprintf(stderr, "第三个 malloc(8): %p\n", c);fprintf(stderr, "free 掉第一个\n");free(a);fprintf(stderr, "当我们再次 free %p 的时候, 程序将会崩溃因为 %p 在 free 链表的第一个位置上\n", a, a);// free(a);fprintf(stderr, "我们先 free %p.\n", b);free(b);fprintf(stderr, "现在我们就可以再次 free %p 了, 因为他现在不在 free 链表的第一个位置上\n", a);free(a);fprintf(stderr, "现在空闲链表是这样的 [ %p, %p, %p ]. 如果我们 malloc 三次, 我们会得到两次 %p \n", a, b, a, a);char* d = malloc(8);char* e = malloc(8);char* f = malloc(8);strcpy(d, "DDDDDDDD");strcpy(e, "EEEEEEEE");strcpy(f, "FFFFFFFF");fprintf(stderr, "第一次 malloc(8): %p\n", d);fprintf(stderr, "第二次 malloc(8): %p\n", e);fprintf(stderr, "第三次 malloc(8): %p\n", f);
}

3.调试fastbin_dup

3.1 获得可执行程序 

gcc -g fastbin_dup.c -o fastbin_dup

3.2 第一次调试程序

调试环境搭建可参考环境从零开始配置pwn环境:优化pwn虚拟机配置支持libc等指令-CSDN博客

root@pwn_test1604:/ctf/work/how2heap# gdb ./fastbin_dup
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 ./fastbin_dup...done.
pwndbg> r
Starting program: /ctf/work/how2heap/fastbin_dup 
这个例子演示了 fastbin 的 double free
首先申请了 3 个 chunk
第一个 malloc(8): 0x602010
第二个 malloc(8): 0x602030
第三个 malloc(8): 0x602050
free 掉第一个
当我们再次 free 0x602010 的时候, 程序将会崩溃因为 0x602010 在 free 链表的第一个位置上
我们先 free 0x602030.
现在我们就可以再次 free 0x602010 了, 因为他现在不在 free 链表的第一个位置上
现在空闲链表是这样的 [ 0x602010, 0x602030, 0x602010 ]. 如果我们 malloc 三次, 我们会得到两次 0x602010 
第一次 malloc(8): 0x602010
第二次 malloc(8): 0x602030
第三次 malloc(8): 0x602010
[Inferior 1 (process 130) exited normally]
pwndbg> 

3.3 第二次调试程序

3.3.1 下相应的断点并走起

可以看到首先分配三块内存,当free掉第一块内存之后,再free一次该内存块是不行的,因为这时候这块内存刚好在对应的free-list的顶部,再次free这块内存就会被检查到,这里就free第二块内存。现在我们再次free第一块内存,因为它已经不在链表顶部了。

这时候的 free-list 有这三块内存 [0x2502010, 0x2502030, 0x2502010],如果我们malloc三次的话,就会得到0x2502010两次。

使用pwndbg逐步调试,首先malloc 3个chunk。

root@pwn_test1604:/ctf/work/how2heap# gdb ./fastbin_dup
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 ./fastbin_dup...done.
pwndbg> r
Starting program: /ctf/work/how2heap/fastbin_dup 
这个例子演示了 fastbin 的 double free
首先申请了 3 个 chunk
第一个 malloc(8): 0x602010
第二个 malloc(8): 0x602030
第三个 malloc(8): 0x602050
free 掉第一个
当我们再次 free 0x602010 的时候, 程序将会崩溃因为 0x602010 在 free 链表的第一个位置上
我们先 free 0x602030.
现在我们就可以再次 free 0x602010 了, 因为他现在不在 free 链表的第一个位置上
现在空闲链表是这样的 [ 0x602010, 0x602030, 0x602010 ]. 如果我们 malloc 三次, 我们会得到两次 0x602010 
第一次 malloc(8): 0x602010
第二次 malloc(8): 0x602030
第三次 malloc(8): 0x602010
[Inferior 1 (process 130) exited normally]
pwndbg> list
1       #include <stdio.h>
2       #include <stdlib.h>
3       #include <string.h>
4
5       int main()
6       {
7           fprintf(stderr, "这个例子演示了 fastbin 的 double free\n");
8
9           fprintf(stderr, "首先申请了 3 个 chunk\n");
10          char* a = malloc(8);
pwndbg> n
The program is not being run.
pwndbg> b 19
Breakpoint 1 at 0x40072d: file fastbin_dup.c, line 19.
pwndbg> b 24
Breakpoint 2 at 0x400774: file fastbin_dup.c, line 24.
pwndbg> b 29 
Breakpoint 3 at 0x4007be: file fastbin_dup.c, line 29.
pwndbg> b 31
Breakpoint 4 at 0x4007e7: file fastbin_dup.c, line 31.
pwndbg> b 36
Breakpoint 5 at 0x400840: file fastbin_dup.c, line 36.
pwndbg> r
Starting program: /ctf/work/how2heap/fastbin_dup 
这个例子演示了 fastbin 的 double free
首先申请了 3 个 chunk
第一个 malloc(8): 0x602010
第二个 malloc(8): 0x602030Breakpoint 1, main () at fastbin_dup.c:19
19          fprintf(stderr, "第三个 malloc(8): %p\n", c);
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
───────────────────────────────────────────────────────────────────────────────────────────────────[ REGISTERS ]───────────────────────────────────────────────────────────────────────────────────────────────────RAX  0x1eRBX  0x0RCX  0x7ffff7b042c0 (__write_nocancel+7) ◂— cmp    rax, -0xfffRDX  0x7ffff7dd3770 (_IO_stdfile_2_lock) ◂— 0x0RDI  0x2RSI  0x7fffffffbf00 ◂— 0xb8e48cbae4acace7R8   0x7ffff7feb700 ◂— 0x7ffff7feb700R9   0x1eR10  0x0R11  0x246R12  0x400550 (_start) ◂— xor    ebp, ebpR13  0x7fffffffe6a0 ◂— 0x1R14  0x0R15  0x0RBP  0x7fffffffe5c0 —▸ 0x4008e0 (__libc_csu_init) ◂— push   r15RSP  0x7fffffffe590 —▸ 0x602010 ◂— 'AAAAAAAA'RIP  0x40072d (main+231) ◂— mov    rax, qword ptr [rip + 0x20092c]
────────────────────────────────────────────────────────────────────────────────────────────────────[ DISASM ]─────────────────────────────────────────────────────────────────────────────────────────────────────► 0x40072d <main+231>    mov    rax, qword ptr [rip + 0x20092c] <0x601060>0x400734 <main+238>    mov    rdx, qword ptr [rbp - 0x20]0x400738 <main+242>    mov    esi, 0x4009e60x40073d <main+247>    mov    rdi, rax0x400740 <main+250>    mov    eax, 00x400745 <main+255>    call   fprintf@plt <0x400510>0x40074a <main+260>    mov    rax, qword ptr [rip + 0x20090f] <0x601060>0x400751 <main+267>    mov    rcx, rax0x400754 <main+270>    mov    edx, 0x120x400759 <main+275>    mov    esi, 10x40075e <main+280>    mov    edi, 0x4009ff
─────────────────────────────────────────────────────────────────────────────────────────────────[ SOURCE (CODE) ]─────────────────────────────────────────────────────────────────────────────────────────────────
In file: /ctf/work/how2heap/fastbin_dup.c14     char* c = malloc(8);15     strcpy(c, "CCCCCCCC");16 17     fprintf(stderr, "第一个 malloc(8): %p\n", a);18     fprintf(stderr, "第二个 malloc(8): %p\n", b);► 19     fprintf(stderr, "第三个 malloc(8): %p\n", c);20 21     fprintf(stderr, "free 掉第一个\n");22     free(a);23 24     fprintf(stderr, "当我们再次 free %p 的时候, 程序将会崩溃因为 %p 在 free 链表的第一个位置上\n", a, a);
─────────────────────────────────────────────────────────────────────────────────────────────────────[ STACK ]─────────────────────────────────────────────────────────────────────────────────────────────────────
00:0000│ rsp  0x7fffffffe590 —▸ 0x602010 ◂— 'AAAAAAAA'
01:0008│      0x7fffffffe598 —▸ 0x602030 ◂— 'BBBBBBBB'
02:0010│      0x7fffffffe5a0 —▸ 0x602050 ◂— 'CCCCCCCC'
03:0018│      0x7fffffffe5a8 —▸ 0x400550 (_start) ◂— xor    ebp, ebp
04:0020│      0x7fffffffe5b0 —▸ 0x7fffffffe6a0 ◂— 0x1
05:0028│      0x7fffffffe5b8 ◂— 0x0
06:0030│ rbp  0x7fffffffe5c0 —▸ 0x4008e0 (__libc_csu_init) ◂— push   r15
07:0038│      0x7fffffffe5c8 —▸ 0x7ffff7a2d830 (__libc_start_main+240) ◂— mov    edi, eax
───────────────────────────────────────────────────────────────────────────────────────────────────[ BACKTRACE ]───────────────────────────────────────────────────────────────────────────────────────────────────► f 0           40072d main+231f 1     7ffff7a2d830 __libc_start_main+240
Breakpoint /ctf/work/how2heap/fastbin_dup.c:19
pwndbg> heap
heapbase : 0x602000
pwndbg> parseheap                                                                                                                                                                                                  
addr                prev                size                 status              fd                bk                
0x602000            0x0                 0x20                 Used                None              None
0x602020            0x0                 0x20                 Used                None              None
0x602040            0x0                 0x20                 Used                None              None
pwndbg> x/20gx 0x602000
0x602000:       0x0000000000000000      0x0000000000000021
0x602010:       0x4141414141414141      0x0000000000000000
0x602020:       0x0000000000000000      0x0000000000000021
0x602030:       0x4242424242424242      0x0000000000000000
0x602040:       0x0000000000000000      0x0000000000000021
0x602050:       0x4343434343434343      0x0000000000000000
0x602060:       0x0000000000000000      0x0000000000020fa1
0x602070:       0x0000000000000000      0x0000000000000000
0x602080:       0x0000000000000000      0x0000000000000000
0x602090:       0x0000000000000000      0x0000000000000000

 3.3.2 第一个free之后

chunk a被添加到fastbins中。

pwndbg> c
Continuing.
第三个 malloc(8): 0x602050
free 掉第一个Breakpoint 2, main () at fastbin_dup.c:24
24          fprintf(stderr, "当我们再次 free %p 的时候, 程序将会崩溃因为 %p 在 free 链表的第一个位置上\n", a, a);
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
───────────────────────────────────────────────────────────────────────────────────────────────────[ REGISTERS ]───────────────────────────────────────────────────────────────────────────────────────────────────RAX  0x0RBX  0x0RCX  0x7ffff7b04200 (__openat_2+16) ◂— cmp    eax, 0x410000 /* '=' */RDX  0x0RDI  0xffffffffRSI  0x7ffff7dd1b28 (main_arena+8) —▸ 0x602000 ◂— 0x0R8   0x602010 ◂— 0x0R9   0x7ffff7dd2500 (_nl_global_locale+224) —▸ 0x7ffff7b9b997 (_nl_C_name) ◂— add    byte ptr [r15 + 0x5f], bl /* 'C' */R10  0x8b8R11  0x7ffff7a914f0 (free) ◂— push   r13R12  0x400550 (_start) ◂— xor    ebp, ebpR13  0x7fffffffe6a0 ◂— 0x1R14  0x0R15  0x0RBP  0x7fffffffe5c0 —▸ 0x4008e0 (__libc_csu_init) ◂— push   r15RSP  0x7fffffffe590 —▸ 0x602010 ◂— 0x0RIP  0x400774 (main+302) ◂— mov    rax, qword ptr [rip + 0x2008e5]
────────────────────────────────────────────────────────────────────────────────────────────────────[ DISASM ]─────────────────────────────────────────────────────────────────────────────────────────────────────► 0x400774 <main+302>    mov    rax, qword ptr [rip + 0x2008e5] <0x601060>0x40077b <main+309>    mov    rcx, qword ptr [rbp - 0x30]0x40077f <main+313>    mov    rdx, qword ptr [rbp - 0x30]0x400783 <main+317>    mov    esi, 0x400a180x400788 <main+322>    mov    rdi, rax0x40078b <main+325>    mov    eax, 00x400790 <main+330>    call   fprintf@plt <0x400510>0x400795 <main+335>    mov    rax, qword ptr [rip + 0x2008c4] <0x601060>0x40079c <main+342>    mov    rdx, qword ptr [rbp - 0x28]0x4007a0 <main+346>    mov    esi, 0x400a7d0x4007a5 <main+351>    mov    rdi, rax
─────────────────────────────────────────────────────────────────────────────────────────────────[ SOURCE (CODE) ]─────────────────────────────────────────────────────────────────────────────────────────────────
In file: /ctf/work/how2heap/fastbin_dup.c19     fprintf(stderr, "第三个 malloc(8): %p\n", c);20 21     fprintf(stderr, "free 掉第一个\n");22     free(a);23 ► 24     fprintf(stderr, "当我们再次 free %p 的时候, 程序将会崩溃因为 %p 在 free 链表的第一个位置上\n", a, a);25     // free(a);26     fprintf(stderr, "我们先 free %p.\n", b);27     free(b);28 29     fprintf(stderr, "现在我们就可以再次 free %p 了, 因为他现在不在 free 链表的第一个位置上\n", a);
─────────────────────────────────────────────────────────────────────────────────────────────────────[ STACK ]─────────────────────────────────────────────────────────────────────────────────────────────────────
00:0000│ rsp  0x7fffffffe590 —▸ 0x602010 ◂— 0x0
01:0008│      0x7fffffffe598 —▸ 0x602030 ◂— 'BBBBBBBB'
02:0010│      0x7fffffffe5a0 —▸ 0x602050 ◂— 'CCCCCCCC'
03:0018│      0x7fffffffe5a8 —▸ 0x400550 (_start) ◂— xor    ebp, ebp
04:0020│      0x7fffffffe5b0 —▸ 0x7fffffffe6a0 ◂— 0x1
05:0028│      0x7fffffffe5b8 ◂— 0x0
06:0030│ rbp  0x7fffffffe5c0 —▸ 0x4008e0 (__libc_csu_init) ◂— push   r15
07:0038│      0x7fffffffe5c8 —▸ 0x7ffff7a2d830 (__libc_start_main+240) ◂— mov    edi, eax
───────────────────────────────────────────────────────────────────────────────────────────────────[ BACKTRACE ]───────────────────────────────────────────────────────────────────────────────────────────────────► f 0           400774 main+302f 1     7ffff7a2d830 __libc_start_main+240
Breakpoint /ctf/work/how2heap/fastbin_dup.c:24
pwndbg> x/20gx 0x602000
0x602000:       0x0000000000000000      0x0000000000000021
0x602010:       0x0000000000000000      0x0000000000000000
0x602020:       0x0000000000000000      0x0000000000000021
0x602030:       0x4242424242424242      0x0000000000000000
0x602040:       0x0000000000000000      0x0000000000000021
0x602050:       0x4343434343434343      0x0000000000000000
0x602060:       0x0000000000000000      0x0000000000020fa1
0x602070:       0x0000000000000000      0x0000000000000000
0x602080:       0x0000000000000000      0x0000000000000000
0x602090:       0x0000000000000000      0x0000000000000000
pwndbg> heap
heapbase : 0x602000
pwndbg> parseheap                                                                                                                                                                                                  
addr                prev                size                 status              fd                bk                
0x602000            0x0                 0x20                 Freed                0x0              None
0x602020            0x0                 0x20                 Used                None              None
0x602040            0x0                 0x20                 Used                None              None
pwndbg> 

3.3.3第二个 free 之后

chunk b 被添加到fastbins中,可以看到在b的fd指针那里已经改成了chunk a的地址了。 

pwndbg> c
Continuing.
当我们再次 free 0x602010 的时候, 程序将会崩溃因为 0x602010 在 free 链表的第一个位置上
我们先 free 0x602030.Breakpoint 3, main () at fastbin_dup.c:29
29          fprintf(stderr, "现在我们就可以再次 free %p 了, 因为他现在不在 free 链表的第一个位置上\n", a);
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
───────────────────────────────────────────────────────────────────────────────────────────────────[ REGISTERS ]───────────────────────────────────────────────────────────────────────────────────────────────────RAX  0x602000 ◂— 0x0RBX  0x0RCX  0x7ffff7b04200 (__openat_2+16) ◂— cmp    eax, 0x410000 /* '=' */RDX  0x602000 ◂— 0x0RDI  0xffffffffRSI  0x7ffff7dd1b28 (main_arena+8) —▸ 0x602020 ◂— 0x0R8   0x602030 —▸ 0x602000 ◂— 0x0R9   0x0R10  0x0R11  0x246R12  0x400550 (_start) ◂— xor    ebp, ebpR13  0x7fffffffe6a0 ◂— 0x1R14  0x0R15  0x0RBP  0x7fffffffe5c0 —▸ 0x4008e0 (__libc_csu_init) ◂— push   r15RSP  0x7fffffffe590 —▸ 0x602010 ◂— 0x0RIP  0x4007be (main+376) ◂— mov    rax, qword ptr [rip + 0x20089b]
────────────────────────────────────────────────────────────────────────────────────────────────────[ DISASM ]─────────────────────────────────────────────────────────────────────────────────────────────────────► 0x4007be <main+376>    mov    rax, qword ptr [rip + 0x20089b] <0x601060>0x4007c5 <main+383>    mov    rdx, qword ptr [rbp - 0x30]0x4007c9 <main+387>    mov    esi, 0x400a980x4007ce <main+392>    mov    rdi, rax0x4007d1 <main+395>    mov    eax, 00x4007d6 <main+400>    call   fprintf@plt <0x400510>0x4007db <main+405>    mov    rax, qword ptr [rbp - 0x30]0x4007df <main+409>    mov    rdi, rax0x4007e2 <main+412>    call   free@plt <0x4004f0>0x4007e7 <main+417>    mov    rax, qword ptr [rip + 0x200872] <0x601060>0x4007ee <main+424>    mov    rdi, qword ptr [rbp - 0x30]
─────────────────────────────────────────────────────────────────────────────────────────────────[ SOURCE (CODE) ]─────────────────────────────────────────────────────────────────────────────────────────────────
In file: /ctf/work/how2heap/fastbin_dup.c24     fprintf(stderr, "当我们再次 free %p 的时候, 程序将会崩溃因为 %p 在 free 链表的第一个位置上\n", a, a);25     // free(a);26     fprintf(stderr, "我们先 free %p.\n", b);27     free(b);28 ► 29     fprintf(stderr, "现在我们就可以再次 free %p 了, 因为他现在不在 free 链表的第一个位置上\n", a);30     free(a);31     fprintf(stderr, "现在空闲链表是这样的 [ %p, %p, %p ]. 如果我们 malloc 三次, 我们会得到两次 %p \n", a, b, a, a);32     33     char* d = malloc(8);34     char* e = malloc(8);
─────────────────────────────────────────────────────────────────────────────────────────────────────[ STACK ]─────────────────────────────────────────────────────────────────────────────────────────────────────
00:0000│ rsp  0x7fffffffe590 —▸ 0x602010 ◂— 0x0
01:0008│      0x7fffffffe598 —▸ 0x602030 —▸ 0x602000 ◂— 0x0
02:0010│      0x7fffffffe5a0 —▸ 0x602050 ◂— 'CCCCCCCC'
03:0018│      0x7fffffffe5a8 —▸ 0x400550 (_start) ◂— xor    ebp, ebp
04:0020│      0x7fffffffe5b0 —▸ 0x7fffffffe6a0 ◂— 0x1
05:0028│      0x7fffffffe5b8 ◂— 0x0
06:0030│ rbp  0x7fffffffe5c0 —▸ 0x4008e0 (__libc_csu_init) ◂— push   r15
07:0038│      0x7fffffffe5c8 —▸ 0x7ffff7a2d830 (__libc_start_main+240) ◂— mov    edi, eax
───────────────────────────────────────────────────────────────────────────────────────────────────[ BACKTRACE ]───────────────────────────────────────────────────────────────────────────────────────────────────► f 0           4007be main+376f 1     7ffff7a2d830 __libc_start_main+240
Breakpoint /ctf/work/how2heap/fastbin_dup.c:29
pwndbg> parseheap
addr                prev                size                 status              fd                bk                
0x602000            0x0                 0x20                 Freed                0x0              None
0x602020            0x0                 0x20                 Freed           0x602000              None
0x602040            0x0                 0x20                 Used                None              None
pwndbg> x/20gx 0x602000
0x602000:       0x0000000000000000      0x0000000000000021
0x602010:       0x0000000000000000      0x0000000000000000
0x602020:       0x0000000000000000      0x0000000000000021
0x602030:       0x0000000000602000      0x0000000000000000
0x602040:       0x0000000000000000      0x0000000000000021
0x602050:       0x4343434343434343      0x0000000000000000
0x602060:       0x0000000000000000      0x0000000000020fa1
0x602070:       0x0000000000000000      0x0000000000000000
0x602080:       0x0000000000000000      0x0000000000000000
0x602090:       0x0000000000000000      0x0000000000000000
pwndbg> 

3.3.4 第三个free之后

此时,由于chunk a处于bin中第2块的位置,不会被double-free的检查机制检查出来,所以第三个free之后,chunk a再次被添加到fastbins 中。chunk a和chunk b形成了一个环

pwndbg> c
Continuing.
现在我们就可以再次 free 0x602010 了, 因为他现在不在 free 链表的第一个位置上Breakpoint 4, main () at fastbin_dup.c:31
31          fprintf(stderr, "现在空闲链表是这样的 [ %p, %p, %p ]. 如果我们 malloc 三次, 我们会得到两次 %p \n", a, b, a, a);
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
───────────────────────────────────────────────────────────────────────────────────────────────────[ REGISTERS ]───────────────────────────────────────────────────────────────────────────────────────────────────RAX  0x602020 ◂— 0x0RBX  0x0RCX  0x7ffff7b04200 (__openat_2+16) ◂— cmp    eax, 0x410000 /* '=' */RDX  0x602020 ◂— 0x0RDI  0xffffffffRSI  0x7ffff7dd1b28 (main_arena+8) —▸ 0x602000 ◂— 0x0R8   0x602010 —▸ 0x602020 ◂— 0x0R9   0x0R10  0xe8be93e920656572R11  0x246R12  0x400550 (_start) ◂— xor    ebp, ebpR13  0x7fffffffe6a0 ◂— 0x1R14  0x0R15  0x0RBP  0x7fffffffe5c0 —▸ 0x4008e0 (__libc_csu_init) ◂— push   r15RSP  0x7fffffffe590 —▸ 0x602010 —▸ 0x602020 ◂— 0x0RIP  0x4007e7 (main+417) ◂— mov    rax, qword ptr [rip + 0x200872]
────────────────────────────────────────────────────────────────────────────────────────────────────[ DISASM ]─────────────────────────────────────────────────────────────────────────────────────────────────────0x4007d1 <main+395>    mov    eax, 00x4007d6 <main+400>    call   fprintf@plt <0x400510>0x4007db <main+405>    mov    rax, qword ptr [rbp - 0x30]0x4007df <main+409>    mov    rdi, rax0x4007e2 <main+412>    call   free@plt <0x4004f0>► 0x4007e7 <main+417>    mov    rax, qword ptr [rip + 0x200872] <0x601060>0x4007ee <main+424>    mov    rdi, qword ptr [rbp - 0x30]0x4007f2 <main+428>    mov    rsi, qword ptr [rbp - 0x30]0x4007f6 <main+432>    mov    rcx, qword ptr [rbp - 0x28]0x4007fa <main+436>    mov    rdx, qword ptr [rbp - 0x30]0x4007fe <main+440>    mov    r9, rdi
─────────────────────────────────────────────────────────────────────────────────────────────────[ SOURCE (CODE) ]─────────────────────────────────────────────────────────────────────────────────────────────────
In file: /ctf/work/how2heap/fastbin_dup.c26     fprintf(stderr, "我们先 free %p.\n", b);27     free(b);28 29     fprintf(stderr, "现在我们就可以再次 free %p 了, 因为他现在不在 free 链表的第一个位置上\n", a);30     free(a);► 31     fprintf(stderr, "现在空闲链表是这样的 [ %p, %p, %p ]. 如果我们 malloc 三次, 我们会得到两次 %p \n", a, b, a, a);32     33     char* d = malloc(8);34     char* e = malloc(8);35     char* f = malloc(8);36     strcpy(d, "DDDDDDDD");
─────────────────────────────────────────────────────────────────────────────────────────────────────[ STACK ]─────────────────────────────────────────────────────────────────────────────────────────────────────
00:0000│ rsp  0x7fffffffe590 —▸ 0x602010 —▸ 0x602020 ◂— 0x0
01:0008│      0x7fffffffe598 —▸ 0x602030 —▸ 0x602000 ◂— 0x0
02:0010│      0x7fffffffe5a0 —▸ 0x602050 ◂— 'CCCCCCCC'
03:0018│      0x7fffffffe5a8 —▸ 0x400550 (_start) ◂— xor    ebp, ebp
04:0020│      0x7fffffffe5b0 —▸ 0x7fffffffe6a0 ◂— 0x1
05:0028│      0x7fffffffe5b8 ◂— 0x0
06:0030│ rbp  0x7fffffffe5c0 —▸ 0x4008e0 (__libc_csu_init) ◂— push   r15
07:0038│      0x7fffffffe5c8 —▸ 0x7ffff7a2d830 (__libc_start_main+240) ◂— mov    edi, eax
───────────────────────────────────────────────────────────────────────────────────────────────────[ BACKTRACE ]───────────────────────────────────────────────────────────────────────────────────────────────────► f 0           4007e7 main+417f 1     7ffff7a2d830 __libc_start_main+240
Breakpoint /ctf/work/how2heap/fastbin_dup.c:31
pwndbg> parseheap
addr                prev                size                 status              fd                bk                
0x602000            0x0                 0x20                 Freed           0x602020              None
0x602020            0x0                 0x20                 Freed           0x602000              None
0x602040            0x0                 0x20                 Used                None              None
pwndbg> x/20gx 0x602000
0x602000:       0x0000000000000000      0x0000000000000021
0x602010:       0x0000000000602020      0x0000000000000000
0x602020:       0x0000000000000000      0x0000000000000021
0x602030:       0x0000000000602000      0x0000000000000000
0x602040:       0x0000000000000000      0x0000000000000021
0x602050:       0x4343434343434343      0x0000000000000000
0x602060:       0x0000000000000000      0x0000000000020fa1
0x602070:       0x0000000000000000      0x0000000000000000
0x602080:       0x0000000000000000      0x0000000000000000
0x602090:       0x0000000000000000      0x0000000000000000
pwndbg> bin
fastbins
0x20: 0x602000 —▸ 0x602020 ◂— 0x602000
0x30: 0x0
0x40: 0x0
0x50: 0x0
0x60: 0x0
0x70: 0x0
0x80: 0x0
unsortedbin
all: 0x0
smallbins
empty
largebins
empty
pwndbg> 

 3.3.5 最后再malloc三块内存d、e、f

可以看到0x4444444444444444被改成了 0x4646464646464646,是因为后来申请的 f 跟 d 指向同一块内存区域。

pwndbg> n
37          strcpy(e, "EEEEEEEE");
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
───────────────────────────────────────────────────────────────────────────────────────────────────[ REGISTERS ]───────────────────────────────────────────────────────────────────────────────────────────────────RAX  0x602010 ◂— 'DDDDDDDD'RBX  0x0RCX  0x4444444444444444 ('DDDDDDDD')RDX  0x602010 ◂— 'DDDDDDDD'RDI  0x0RSI  0x7ffff7dd1b20 (main_arena) ◂— 0x0R8   0x602020 ◂— 0x0R9   0x7dR10  0x0R11  0x246R12  0x400550 (_start) ◂— xor    ebp, ebpR13  0x7fffffffe6a0 ◂— 0x1R14  0x0R15  0x0RBP  0x7fffffffe5c0 —▸ 0x4008e0 (__libc_csu_init) ◂— push   r15RSP  0x7fffffffe590 —▸ 0x602010 ◂— 'DDDDDDDD'RIP  0x400855 (main+527) ◂— mov    rax, qword ptr [rbp - 0x10]
────────────────────────────────────────────────────────────────────────────────────────────────────[ DISASM ]─────────────────────────────────────────────────────────────────────────────────────────────────────0x40083c <main+502>    mov    qword ptr [rbp - 8], rax0x400840 <main+506>    mov    rax, qword ptr [rbp - 0x18]0x400844 <main+510>    movabs rcx, 0x44444444444444440x40084e <main+520>    mov    qword ptr [rax], rcx0x400851 <main+523>    mov    byte ptr [rax + 8], 0► 0x400855 <main+527>    mov    rax, qword ptr [rbp - 0x10]0x400859 <main+531>    movabs rsi, 0x45454545454545450x400863 <main+541>    mov    qword ptr [rax], rsi0x400866 <main+544>    mov    byte ptr [rax + 8], 00x40086a <main+548>    mov    rax, qword ptr [rbp - 8]0x40086e <main+552>    movabs rcx, 0x4646464646464646
─────────────────────────────────────────────────────────────────────────────────────────────────[ SOURCE (CODE) ]─────────────────────────────────────────────────────────────────────────────────────────────────
In file: /ctf/work/how2heap/fastbin_dup.c32     33     char* d = malloc(8);34     char* e = malloc(8);35     char* f = malloc(8);36     strcpy(d, "DDDDDDDD");► 37     strcpy(e, "EEEEEEEE");38     strcpy(f, "FFFFFFFF");39     fprintf(stderr, "第一次 malloc(8): %p\n", d);40     fprintf(stderr, "第二次 malloc(8): %p\n", e);41     fprintf(stderr, "第三次 malloc(8): %p\n", f);42 }
─────────────────────────────────────────────────────────────────────────────────────────────────────[ STACK ]─────────────────────────────────────────────────────────────────────────────────────────────────────
00:0000│ rsp  0x7fffffffe590 —▸ 0x602010 ◂— 'DDDDDDDD'
01:0008│      0x7fffffffe598 —▸ 0x602030 —▸ 0x602000 ◂— 0x0
02:0010│      0x7fffffffe5a0 —▸ 0x602050 ◂— 'CCCCCCCC'
03:0018│      0x7fffffffe5a8 —▸ 0x602010 ◂— 'DDDDDDDD'
04:0020│      0x7fffffffe5b0 —▸ 0x602030 —▸ 0x602000 ◂— 0x0
05:0028│      0x7fffffffe5b8 —▸ 0x602010 ◂— 'DDDDDDDD'
06:0030│ rbp  0x7fffffffe5c0 —▸ 0x4008e0 (__libc_csu_init) ◂— push   r15
07:0038│      0x7fffffffe5c8 —▸ 0x7ffff7a2d830 (__libc_start_main+240) ◂— mov    edi, eax
───────────────────────────────────────────────────────────────────────────────────────────────────[ BACKTRACE ]───────────────────────────────────────────────────────────────────────────────────────────────────► f 0           400855 main+527f 1     7ffff7a2d830 __libc_start_main+240
pwndbg> bin
fastbins
0x20: 0x602020 —▸ 0x602000 ◂— 'DDDDDDDD'
0x30: 0x0
0x40: 0x0
0x50: 0x0
0x60: 0x0
0x70: 0x0
0x80: 0x0
unsortedbin
all: 0x0
smallbins
empty
largebins
empty
pwndbg> x/20gx 0x602000
0x602000:       0x0000000000000000      0x0000000000000021
0x602010:       0x4444444444444444      0x0000000000000000
0x602020:       0x0000000000000000      0x0000000000000021
0x602030:       0x0000000000602000      0x0000000000000000
0x602040:       0x0000000000000000      0x0000000000000021
0x602050:       0x4343434343434343      0x0000000000000000
0x602060:       0x0000000000000000      0x0000000000020fa1
0x602070:       0x0000000000000000      0x0000000000000000
0x602080:       0x0000000000000000      0x0000000000000000
0x602090:       0x0000000000000000      0x0000000000000000
pwndbg> 
pwndbg> n
38          strcpy(f, "FFFFFFFF");
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
───────────────────────────────────────────────────────────────────────────────────────────────────[ REGISTERS ]───────────────────────────────────────────────────────────────────────────────────────────────────RAX  0x602030 ◂— 'EEEEEEEE'RBX  0x0RCX  0x4444444444444444 ('DDDDDDDD')RDX  0x602010 ◂— 'DDDDDDDD'RDI  0x0RSI  0x4545454545454545 ('EEEEEEEE')R8   0x602020 ◂— 0x0R9   0x7dR10  0x0R11  0x246R12  0x400550 (_start) ◂— xor    ebp, ebpR13  0x7fffffffe6a0 ◂— 0x1R14  0x0R15  0x0RBP  0x7fffffffe5c0 —▸ 0x4008e0 (__libc_csu_init) ◂— push   r15RSP  0x7fffffffe590 —▸ 0x602010 ◂— 'DDDDDDDD'RIP  0x40086a (main+548) ◂— mov    rax, qword ptr [rbp - 8]
────────────────────────────────────────────────────────────────────────────────────────────────────[ DISASM ]─────────────────────────────────────────────────────────────────────────────────────────────────────0x400851 <main+523>    mov    byte ptr [rax + 8], 00x400855 <main+527>    mov    rax, qword ptr [rbp - 0x10]0x400859 <main+531>    movabs rsi, 0x45454545454545450x400863 <main+541>    mov    qword ptr [rax], rsi0x400866 <main+544>    mov    byte ptr [rax + 8], 0► 0x40086a <main+548>    mov    rax, qword ptr [rbp - 8]0x40086e <main+552>    movabs rcx, 0x46464646464646460x400878 <main+562>    mov    qword ptr [rax], rcx0x40087b <main+565>    mov    byte ptr [rax + 8], 00x40087f <main+569>    mov    rax, qword ptr [rip + 0x2007da] <0x601060>0x400886 <main+576>    mov    rdx, qword ptr [rbp - 0x18]
─────────────────────────────────────────────────────────────────────────────────────────────────[ SOURCE (CODE) ]─────────────────────────────────────────────────────────────────────────────────────────────────
In file: /ctf/work/how2heap/fastbin_dup.c33     char* d = malloc(8);34     char* e = malloc(8);35     char* f = malloc(8);36     strcpy(d, "DDDDDDDD");37     strcpy(e, "EEEEEEEE");► 38     strcpy(f, "FFFFFFFF");39     fprintf(stderr, "第一次 malloc(8): %p\n", d);40     fprintf(stderr, "第二次 malloc(8): %p\n", e);41     fprintf(stderr, "第三次 malloc(8): %p\n", f);42 }
─────────────────────────────────────────────────────────────────────────────────────────────────────[ STACK ]─────────────────────────────────────────────────────────────────────────────────────────────────────
00:0000│ rsp  0x7fffffffe590 —▸ 0x602010 ◂— 'DDDDDDDD'
01:0008│      0x7fffffffe598 —▸ 0x602030 ◂— 'EEEEEEEE'
02:0010│      0x7fffffffe5a0 —▸ 0x602050 ◂— 'CCCCCCCC'
03:0018│      0x7fffffffe5a8 —▸ 0x602010 ◂— 'DDDDDDDD'
04:0020│      0x7fffffffe5b0 —▸ 0x602030 ◂— 'EEEEEEEE'
05:0028│      0x7fffffffe5b8 —▸ 0x602010 ◂— 'DDDDDDDD'
06:0030│ rbp  0x7fffffffe5c0 —▸ 0x4008e0 (__libc_csu_init) ◂— push   r15
07:0038│      0x7fffffffe5c8 —▸ 0x7ffff7a2d830 (__libc_start_main+240) ◂— mov    edi, eax
───────────────────────────────────────────────────────────────────────────────────────────────────[ BACKTRACE ]───────────────────────────────────────────────────────────────────────────────────────────────────► f 0           40086a main+548f 1     7ffff7a2d830 __libc_start_main+240
pwndbg> bin
fastbins
0x20: 0x602020 ◂— 'EEEEEEEE'
0x30: 0x0
0x40: 0x0
0x50: 0x0
0x60: 0x0
0x70: 0x0
0x80: 0x0
unsortedbin
all: 0x0
smallbins
empty
largebins
empty
pwndbg> x/20gx 0x602000
0x602000:       0x0000000000000000      0x0000000000000021
0x602010:       0x4444444444444444      0x0000000000000000
0x602020:       0x0000000000000000      0x0000000000000021
0x602030:       0x4545454545454545      0x0000000000000000
0x602040:       0x0000000000000000      0x0000000000000021
0x602050:       0x4343434343434343      0x0000000000000000
0x602060:       0x0000000000000000      0x0000000000020fa1
0x602070:       0x0000000000000000      0x0000000000000000
0x602080:       0x0000000000000000      0x0000000000000000
0x602090:       0x0000000000000000      0x0000000000000000
pwndbg> n
39          fprintf(stderr, "第一次 malloc(8): %p\n", d);
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
───────────────────────────────────────────────────────────────────────────────────────────────────[ REGISTERS ]───────────────────────────────────────────────────────────────────────────────────────────────────RAX  0x602010 ◂— 'FFFFFFFF'RBX  0x0RCX  0x4646464646464646 ('FFFFFFFF')RDX  0x602010 ◂— 'FFFFFFFF'RDI  0x0RSI  0x4545454545454545 ('EEEEEEEE')R8   0x602020 ◂— 0x0R9   0x7dR10  0x0R11  0x246R12  0x400550 (_start) ◂— xor    ebp, ebpR13  0x7fffffffe6a0 ◂— 0x1R14  0x0R15  0x0RBP  0x7fffffffe5c0 —▸ 0x4008e0 (__libc_csu_init) ◂— push   r15RSP  0x7fffffffe590 —▸ 0x602010 ◂— 'FFFFFFFF'RIP  0x40087f (main+569) ◂— mov    rax, qword ptr [rip + 0x2007da]
────────────────────────────────────────────────────────────────────────────────────────────────────[ DISASM ]─────────────────────────────────────────────────────────────────────────────────────────────────────0x400866 <main+544>    mov    byte ptr [rax + 8], 00x40086a <main+548>    mov    rax, qword ptr [rbp - 8]0x40086e <main+552>    movabs rcx, 0x46464646464646460x400878 <main+562>    mov    qword ptr [rax], rcx0x40087b <main+565>    mov    byte ptr [rax + 8], 0► 0x40087f <main+569>    mov    rax, qword ptr [rip + 0x2007da] <0x601060>0x400886 <main+576>    mov    rdx, qword ptr [rbp - 0x18]0x40088a <main+580>    mov    esi, 0x400b660x40088f <main+585>    mov    rdi, rax0x400892 <main+588>    mov    eax, 00x400897 <main+593>    call   fprintf@plt <0x400510>
─────────────────────────────────────────────────────────────────────────────────────────────────[ SOURCE (CODE) ]─────────────────────────────────────────────────────────────────────────────────────────────────
In file: /ctf/work/how2heap/fastbin_dup.c34     char* e = malloc(8);35     char* f = malloc(8);36     strcpy(d, "DDDDDDDD");37     strcpy(e, "EEEEEEEE");38     strcpy(f, "FFFFFFFF");► 39     fprintf(stderr, "第一次 malloc(8): %p\n", d);40     fprintf(stderr, "第二次 malloc(8): %p\n", e);41     fprintf(stderr, "第三次 malloc(8): %p\n", f);42 }
─────────────────────────────────────────────────────────────────────────────────────────────────────[ STACK ]─────────────────────────────────────────────────────────────────────────────────────────────────────
00:0000│ rsp  0x7fffffffe590 —▸ 0x602010 ◂— 'FFFFFFFF'
01:0008│      0x7fffffffe598 —▸ 0x602030 ◂— 'EEEEEEEE'
02:0010│      0x7fffffffe5a0 —▸ 0x602050 ◂— 'CCCCCCCC'
03:0018│      0x7fffffffe5a8 —▸ 0x602010 ◂— 'FFFFFFFF'
04:0020│      0x7fffffffe5b0 —▸ 0x602030 ◂— 'EEEEEEEE'
05:0028│      0x7fffffffe5b8 —▸ 0x602010 ◂— 'FFFFFFFF'
06:0030│ rbp  0x7fffffffe5c0 —▸ 0x4008e0 (__libc_csu_init) ◂— push   r15
07:0038│      0x7fffffffe5c8 —▸ 0x7ffff7a2d830 (__libc_start_main+240) ◂— mov    edi, eax
───────────────────────────────────────────────────────────────────────────────────────────────────[ BACKTRACE ]───────────────────────────────────────────────────────────────────────────────────────────────────► f 0           40087f main+569f 1     7ffff7a2d830 __libc_start_main+240
pwndbg> x/20gx 0x602000
0x602000:       0x0000000000000000      0x0000000000000021
0x602010:       0x4646464646464646      0x0000000000000000
0x602020:       0x0000000000000000      0x0000000000000021
0x602030:       0x4545454545454545      0x0000000000000000
0x602040:       0x0000000000000000      0x0000000000000021
0x602050:       0x4343434343434343      0x0000000000000000
0x602060:       0x0000000000000000      0x0000000000020fa1
0x602070:       0x0000000000000000      0x0000000000000000
0x602080:       0x0000000000000000      0x0000000000000000
0x602090:       0x0000000000000000      0x0000000000000000
pwndbg> bin
fastbins
0x20: 0x602020 ◂— 'EEEEEEEE'
0x30: 0x0
0x40: 0x0
0x50: 0x0
0x60: 0x0
0x70: 0x0
0x80: 0x0
unsortedbin
all: 0x0
smallbins
empty
largebins
empty
pwndbg> 

3.3.6 总结

程序展示了fastbins的double-free攻击,可以泄露出一块已经被分配的内存指针。fastbins 可以看成一个后进先出的栈,使用单链表来实现,通过fastbin->fd来遍历。由于free的过程会对free list做检查,我们不能连续两次free同一个chunk,所以这里在两次free 之间,增加了一次对其他chunk的free 过程,从而绕过了检查顺利执行,然后再malloc三次,就在同一个地址malloc了两次,也就有了两个指向同一块内存区域的指针。

4.参考资料

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

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

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

相关文章

JavaScript基础第六天

JavaScript 基础第六天 今天我们学习数组的遍历&#xff0c;以及数组的其他用法。 1. 数组遍历 1.1. 古老方法 可以使用 for 循环进行遍历。 let arr ["a", "b", "d", "g"]; for (let i 0; i < arr.length; i) {console.log…

形态学算法应用之连通分量提取的python实现——图像处理

原理 连通分量提取是图像处理和计算机视觉中的一项基本任务&#xff0c;旨在识别图像中所有连通区域&#xff0c;并将它们作为独立对象处理。在二值图像中&#xff0c;连通分量通常指的是所有连接在一起的前景像素集合。这里的“连接”可以根据四连通或八连通的邻接关系来定义…

C语言中的多级指针、指针数组与数组指针

在C语言中&#xff0c;指针是一个非常重要的概念&#xff0c;它为我们提供了直接操作内存地址的能力。通过指针&#xff0c;我们可以访问和修改内存中的数据&#xff0c;实现各种灵活的操作。本文将通过示例代码和详细解释&#xff0c;深入探讨C语言中的多级指针、指针数组和数…

话题:IT行业有哪些证书含金量高?

IT行业有哪些证书含金量高? 1. 以下是一些在IT行业中我认为具有高含金量的证书&#xff1a; 思科认证&#xff08;Cisco Certifications&#xff09;&#xff1a;思科认证是由网络领域的著名厂商——Cisco公司推出的&#xff0c;是互联网领域的国际权威认证。这个认证体系包含…

ICLR 2024 | Harvard FairSeg:第一个研究分割算法公平性的大型医疗分割数据集

近年来&#xff0c;人工智能模型的公平性问题受到了越来越多的关注&#xff0c;尤其是在医学领域&#xff0c;因为医学模型的公平性对人们的健康和生命至关重要。高质量的医学公平性数据集对促进公平学习研究非常必要。现有的医学公平性数据集都是针对分类任务的&#xff0c;而…

openssl3.2 - exp - buffer to BIO

文章目录 openssl3.2 - exp - buffer to BIO概述笔记END openssl3.2 - exp - buffer to BIO 概述 openssl的资料看的差不多了, 准备将工程中用到的知识点整理一下. openssl中很多API是以操作文件作为输入的, 也有很多API是以BIO作为输入的. 不管文件是不是受保护的, 如果有可…

VUE学习——事件处理

事件分为内联事件和方法事件。 我们可以使用【v-on】&#xff08;简写&#xff1a;&#xff09;来处理。 内联 <button v-on:click"count">按钮</button><button click"count">按钮</button><p>{{ count }}</p>方法

新年新展望

去年其实是收获颇丰的一年&#xff0c;除了工作中各项工作都得到了很大的推进&#xff0c;个人生活中也有很多变化&#xff0c;其中还拿到了功能安全工程师的证书&#xff0c;以及功能安全经理的证书。 展望一下2024年准备输出的内容&#xff0c;一个是对ISO26262的解读&#x…

【力扣】回文数,反转一半数字 + 字符串

回文数原题地址 方法一&#xff1a;反转一半数字 考虑特殊情况&#xff1a; 负数不是回文数&#xff0c;如 -123 &#xff0c;反过来为 321- 。个位数为零的非零数不是回文数&#xff0c;比如 120 &#xff0c;反过来为 021 。 对于一般情况&#xff0c;我们只需要取出后半…

容器基础:Docker 镜像如何保证部署的一致性?

Docker 镜像如何通过固化基础环境、固化依赖性和固化软件启动流程保证部署的一致性 Docker 镜像通过以下三个方面保证部署的一致性&#xff1a; 1. 固化基础环境: 镜像包含构建应用程序所需的所有环境依赖项&#xff0c;例如操作系统、库和工具。构建镜像时&#xff0c;所有…

Rust语言入门(第3篇)

引用与借用 上一篇中&#xff0c;我们介绍了rust的所有权概念&#xff0c;若直接传递变量做函数参数&#xff0c;堆上的变量就会失去所有权&#xff0c;而栈上变量则由于复制&#xff0c;仍有所有权。 fn main(){let b 3;makes_copy(b);println!("after using a variab…

STM32之USART

概述 串口通信&#xff0c;通用异步收发传输器&#xff08;Universal Asynchronous Receiver/Transmitter &#xff09;&#xff0c;简称UART&#xff1b;而USART&#xff08;Universal Synchronous/Asynchronous Receiver/Transmitter&#xff09;通用同步收发传输器。 USAR…

python学习笔记 -- 字符串

目录 一、输出字符串的格式 二、字符串的一些函数 1、len函数&#xff1a;字符串长度 2、查找字符所在位置index 3、某字符在字符串中的个数count 4、字符切片 对字符串进行翻转 -- 利用步长 5、修改大小写字母&#xff1a; 6、判断开头和结尾 7、拆分字符串 一、输出…

Transformer实战-系列教程13:DETR 算法解读

&#x1f6a9;&#x1f6a9;&#x1f6a9;Transformer实战-系列教程总目录 有任何问题欢迎在下面留言 本篇文章的代码运行界面均在Pycharm中进行 本篇文章配套的代码资源已经上传 点我下载源码 1、物体检测 说到目标检测你能想到什么 faster-rcnn系列&#xff0c;开山之作&…

点云——噪声(代码)

本人硕士期间研究的方向就是三维目标点云跟踪&#xff0c;对点云和跟踪有着较为深入的理解&#xff0c;但一直忙于实习未进行梳理&#xff0c;今天趁着在家休息对点云的噪声进行梳理&#xff0c;因为预处理对于点云项目是至关重要的&#xff0c;所有代码都是近期重新复现过。 这…

2022年全国青少年信息素养大赛 第8届Python编程挑战赛(小学组)复赛试题解析

2022年全国青少年信息素养大赛 第8届Python编程挑战赛(小学组)复赛试题解析T1. 分草莓 小明邀请了四个同学一起游玩,带了一盒草莓平均分给大家一起吃,任意输入草莓的数量n,输出每个人可以分到几颗草莓,最后剩下了几颗。 注意: input()内不添加任何参数 只有完全正确才可…

shell脚本之无限计时器

无限计时器 a0while : dolet aecho $asleep 1 done新建一个.sh结尾的文件复制粘贴进去即可使用&#xff01;

保育员答案在哪搜?这4款足够解决问题 #媒体#其他#其他

学会运用各类学习辅助工具和资料&#xff0c;是大学生培养自主学习能力和信息获取能力的重要途径之一。 1.石墨文档 石墨文档(Shimo Docs)是一款强大的在线文档协作工具。它提供了多人实时协作、版本控制、评论和批注等功能&#xff0c;方便学生在学习中进行文档编写、合作项…

Qt安装配置教程windows版(包括:Qt5.8.0版本,Qt5.12,Qt5.14版本下载安装教程)(亲测可行)

目录 Qt5.8.0版本安装教程Qt5.8.0版本下载安装 Qt5.12.2版本安装教程下载安装 Qt 5.14.2安装教程下载安装和创建项目 参考视频 QT为嵌入式系统提供了大量的库和可重用组件。 WPS Office&#xff0c;咪咕音乐&#xff0c;Linux桌面环境等都是QT开发的。 Qt5.8.0版本安装教程 Q…

Kotlin手记(一):基础大杂烩

Kotlin简介 2011年7月&#xff0c;JetBrains推出Kotlin项目&#xff0c;这是一个面向JVM的新语言 2012年2月&#xff0c;JetBrains以Apache 2许可证开源此项目。 2016年2月15日&#xff0c;Kotlin v1.0发布&#xff0c;这被认为是第一个官方稳定版本。 在Google I/O 2017中&am…