[*] Written in C and compiled it as assembly [*] Strip away a few bits (e.g. set up for the stack frame) which are pointless: exec is a no-return. [*] Workarounds to remove two \x00 bytes that are dissiminated in the current result. [ ] Direct syscall to exec instead of jumping to libc Compilation as by the makefile (also below). The target is 32-bit linux (matching the CTF system), which needs some extra packages for the build to work under 64-bit systems. On OpenSUSE: glibc-32bit + gcc13-32bit Since I'm acquiring expertise with radare2: dumping it can be an interesting exercise: > Assuming that `ret` was added to the code (or else r2 will be somewhat confused on how to determine the end of the frame): @@ -27,5 +27,6 @@ foo: leal -16(%ebp), %eax pushl %eax call execl + ret .size foo, .-foo .section .note.GNU-stack,"",@progbits > Check disassembly of result: $ r2 -Aqc 'pdf @ sym.foo' ./shellcode.o > Dump disassembly to a file: $ r2 -Aqc 'pdf @ sym.foo' ./shellcode.o | xxd -p -r - shellcode.bin > Dump string representation $ r2 -Aqc 'psx $FS - 1 @ sym.foo' > Dump/disassemble in radare2 $ r2 -Aqc 'pdf sym.foo' ./shellcode.o > Execution in radare2 via rarun2: $ more rarun.rr2 stdio=/dev/pts/5 setenv=EGG=\x83\xec\x18\... # etc $ r2 -r /tmp/.../rarun.rr2 ./narnia1 > https://lwn.net/Articles/604287/ The standard ABI for how x86_64 user programs invoke a system call is to the system call number (0 for read) into the RAX register, and the other parameters into specific registers (RDI, RSI, RDX for the first 3 paramet then issue the SYSCALL instruction. > sys_execve -> 59 RDI -> filename RSI -> argv[] RDX -> envp[] > Some useful info gathered about assembly, on ##asm (Libera.chat) Instructions such as "push %edx" is only available in 32 bit mode (gcc -m This is because the 0x52 opcode that means "push edx" in 32 bit mode mean "push rdx" in 64 bit mode. Regardless of 32-bit or 64-bit mode, it is always possible to push a 16 b value or register: opcode 32 bit mode 64 bit mode 50 push eax push rax 6650 push ax push ax > vDSO Dynamically linked to executable. Use ldd(1) on the binary to appreciate it. The kernel links an ELF file. The name of it depends on the architecture. Common names are listed on vdso(7). (HTM) Narnia 1 CTF (overthewire.org) (DIR) .. (TXT) GNUmakefile 2024-Mar-12 23:16 0.1 KB (TXT) main.c 2024-Apr-01 19:17 0.1 KB (TXT) shellcode.S 2024-Apr-24 19:41 0.7 KB __________________________________________________________________________ Gophered by Gophernicus/3.0.1 on FreeBSD/amd64 14.0