I am trying to learn about shellcode and system calls by injecting a simple "hello world" shellcode into a program that reads and executes code from an environment variable.
The shellcode is executed but does not print to stdout even though strace
informs me that the correct syscall is performed:
>nasm helloworld1.asm
>export SHELLCODE=$(cat helloworld1.asm)
>strace ./vuln
write(1, "hello, wurld!\n\r", 15) = ? │~
+++ exited with 0 +++
Modifying the shellcode to use the syscall
instruction rather than int 0x80
resolves the issue.
My question is: Why does my shellcode not print to stdout even though the write syscall is called with the correct parameters?
The target program:
#include <stdio.h>
#include <stdlib.h>
int main(void){
void (*funptr)() = NULL;
funptr = getenv("SHELLCODE");
funptr();
}
Compiled with gcc -fno-stack-protector -z execstack -no-pie -o vuln vuln.c.
Shellcode that does not write to stdout
BITS 64
section .data
section .text
global _start
jmp end
trick:
pop rsi ; Put address of msg into source register
; SYSCALL WRITE(1, msg, 15)
xor rax, rax
add rax, 1 ; Put syscall 1 (write) into register a
xor rdi, rdi ; Zero destination register
inc rdi ; put stdin fd (1) into destination register
xor rdx, rdx ; zero register d
add rdx, 15 ; put length of string into register d
int 0x80 ; perform syscall
; SYSCALL EXIT(1)
xor rdi, rdi ; put return code 0 into destination register
xor rax, rax ; zero register a
add rax, 60 ; move syscall (exit=60) into register a
int 0x80 ; perform syscall
end:
call trick ; call to go back to trick which pushes address of msg onto the stack
msg db "hello, wurld!", 0x0a, 0x0d ; The string and newline char + CR
Shellcode that writes to stdout:
BITS 64
section .data
section .text
global _start
jmp end
trick:
pop rsi ; Put address of msg into source register
; SYSCALL WRITE(1, msg, 15)
xor rax, rax
add rax, 1 ; move syscall 1 (write) into register a
xor rdi, rdi ; Zero destination register
inc rdi ; put stdin fd (1) into destination register
xor rdx, rdx ; zero register d
add rdx, 15 ; put length of string into register d
syscall ; perform syscall
; SYSCALL EXIT(1)
xor rdi, rdi ; put return code 0 into destination register
xor rax, rax ; move system call 0 into register a
add rax, 60 ; move syscall (exit=60) into register a
syscall ; perform syscall
end:
call trick ; go back and push the next address (msg) onto the stack
msg db "hello, wurld!", 0x0a, 0x0d