0

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

0 Answers0