How to avoid stdin input that does not fit in buffer be sent to the shell in Linux 64-bit Intel (x86-64) assembly

StackOverflow https://stackoverflow.com/questions/12459729

Question

Edit: Title changed, as @Gunner pointed out that this is not a buffer overflow.

In reading user input from stdin with NR_read in Linux 64-bit Intel assembly, I wonder how can I avoid that the input that does not fit in the input buffer being sent to Linux shell eg. bash? For example in this example program I have defined an input buffer of 255 bytes (the size of the buffer can be whatever >= 1). The rest of an input longer than 255 bytes is sent to bash (if running from bash) and and this is obviously a serious vulnerability. How should input be read in Linux 64-bit assembly to avoid this vulnerability?

Here's my code:

[bits 64]

section .text
global _start

; can be compiled eg. with nasm or yasm.
; nasm:
; nasm -f elf64 read_stdin_64.asm; ld read_stdin_64.o -o read_stdin_64
; yasm:
; yasm -f elf64 -m amd64 read_stdin_64.asm -o read_stdin_64.o; ld read_stdin_64.o -o read_stdin_64

NR_read     equ 0
NR_exit     equ 60

STDIN       equ 1

; input:
; rax   number of syscall
; rdi   parameter 1
; rsi   parameter 2
; rdx   parameter 3
; r10   parameter 4
; r8    parameter 5
; r9    parameter 6
;
; output:
; rax   syscall's output
@do_syscall:
    push    rcx
    push    r11
    syscall      ; 64-bit syscall, overwrites rcx and r11
    pop     r11  ; syscall's return value in rax
    pop     rcx
    ret

@read_stdin:
    push    rdi
    push    rsi
    push    rdx
    mov     rdi,STDIN                ; file handle to read. STDIN = 1.
    lea     rsi,[input_buffer]
    mov     rdx,input_buffer_length  ; length of string
    mov     rax,NR_read              ; number of syscall (0)
    call    @do_syscall
    sub     rax,1                    ; get the number of writable characters.
    pop     rdx
    pop     rsi
    pop     rdi
    ret

_start:     ; linker entry point
    call    @read_stdin

@end_program:
    xor     rdi,rdi
    mov     rax,NR_exit  ; number of syscall (60)
    syscall

section .data

input_buffer         times 255 db 0
input_buffer_length  equ $-input_buffer
Was it helpful?

Solution

It is not a buffer overflow as others have stated. I wrote a tutorial on reading from the terminal in Linux which also shows how to deal with this issue. It uses 32-bit Int 0x80, but you can easily change it to fit your needs.

http://www.dreamincode.net/forums/topic/286248-nasm-linux-terminal-inputoutput-wint-80h/

OTHER TIPS

The read syscall already has that protection built in. One other thing though: You shouldn't be explicitly using syscall. What if your code is taken to an x86-64 machine (which uses sysenter)? You should be using Linux's VDSO (virtual dynamic shared object), which contains code to do syscalls on all architectures, regardless as to wheather they support syscall, sysenter, or only int.

You could read the input until newline character is found.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top