> Welcome to reversing! Prove your worth and get the flag from this > neat little program! The program is a bunch of byte-sized integers. I wrote a throw-away program in Ruby to turn it into a binary. bytes = File.open('program.txt').read.split(', ').map(&:to_i) File.open('program', 'wb') { |f| bytes.each { |b| f.write(b.chr) } } Going by the file size my first hunch was that it's raw shell code. `radare2` agrees, showing reasonable x64 code doing multiplications (as suggested by the challenge name): $ r2 -q -cpd program 0x00000000 55 push rbp 0x00000001 4889e5 mov rbp, rsp 0x00000004 4883ec18 sub rsp, 0x18 0x00000008 48c745f84f00. mov qword [rbp - 8], 0x4f ; 'O' ; 79 0x00000010 48b8154fe74b. movabs rax, 0x14be74f15 0x0000001a 488945f0 mov qword [rbp - 0x10], rax 0x0000001e 48c745e80400. mov qword [rbp - 0x18], 4 0x00000026 48c745e00300. mov qword [rbp - 0x20], 3 0x0000002e 48c745d81300. mov qword [rbp - 0x28], 0x13 0x00000036 48c745d01501. mov qword [rbp - 0x30], 0x115 ; 277 0x0000003e 48b8615b644b. movabs rax, 0x77cf4b645b61 0x00000048 488945c8 mov qword [rbp - 0x38], rax 0x0000004c 48c745c00200. mov qword [rbp - 0x40], 2 0x00000054 48c745b81100. mov qword [rbp - 0x48], 0x11 0x0000005c 48c745b0c121. mov qword [rbp - 0x50], 0x21c1 0x00000064 48c745a8e965. mov qword [rbp - 0x58], 0x182265e9 0x0000006c 48c745a03308. mov qword [rbp - 0x60], 0x833 ; 2099 0x00000074 48c74598ab0a. mov qword [rbp - 0x68], 0xaab ; 2731 0x0000007c 48c74590adaa. mov qword [rbp - 0x70], 0x8daaad 0x00000084 488b45f8 mov rax, qword [rbp - 8] 0x00000088 480faf45f0 imul rax, qword [rbp - 0x10] 0x0000008d 48894588 mov qword [rbp - 0x78], rax 0x00000091 488b45e8 mov rax, qword [rbp - 0x18] 0x00000095 480faf45e0 imul rax, qword [rbp - 0x20] 0x0000009a 480faf45d8 imul rax, qword [rbp - 0x28] 0x0000009f 480faf45d0 imul rax, qword [rbp - 0x30] 0x000000a4 480faf45c8 imul rax, qword [rbp - 0x38] 0x000000a9 48894580 mov qword [rbp - 0x80], rax 0x000000ad 488b45c0 mov rax, qword [rbp - 0x40] 0x000000b1 480faf45b8 imul rax, qword [rbp - 0x48] 0x000000b6 480faf45b0 imul rax, qword [rbp - 0x50] 0x000000bb 480faf45a8 imul rax, qword [rbp - 0x58] 0x000000c0 48898578ffff. mov qword [rbp - 0x88], rax 0x000000c7 488b45a0 mov rax, qword [rbp - 0x60] 0x000000cb 480faf4598 imul rax, qword [rbp - 0x68] 0x000000d0 480faf4590 imul rax, qword [rbp - 0x70] 0x000000d5 48898570ffff. mov qword [rbp - 0x90], rax 0x000000dc b800000000 mov eax, 0 0x000000e1 c9 leave There's no way I'm going to reverse-engineer that though. I'd rather execute it in GDB and inspect the stack afterwards. My feeble attempts at writing a C program that executes shell code failed with segfaults, but no worries, I can instead just transplant the shell code into a dummy program doing literally nothing. For that the amount of NOP instructions must naturally match the size of the shell code: int main(){ asm("nop"); // repeat 225 more times } The actual patching is done with `r2 -w program.elf`: s main wx q Finally step through it with the debugger. I like GEF for that purpose: gef➤ start gef➤ ni # repeat with return until leave instruction gef➤ hexdump $rbp-0x90 0x00007fffffffea20 7d 6d 34 72 67 30 00 00 72 70 5f 64 31 6c 00 00 }m4rg0..rp_d1l.. 0x00007fffffffea30 34 76 5f 72 33 70 75 73 7b 67 61 6c 66 00 00 00 4v_r3pus{galf... 0x00007fffffffea40 ad aa 8d 00 00 00 00 00 ab 0a 00 00 00 00 00 00 ................ 0x00007fffffffea50 33 08 00 00 00 00 00 00 e9 65 22 18 00 00 00 00 3........e"..... The flag is encoded in reverse on the stack: $ ruby -e "puts '}m4rg0rp_d1l4v_r3pus{galf'.reverse" flag{sup3r_v4l1d_pr0gr4m}