4
votes

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
3
huh? you pass the input_buffer_length in, you make sure it don't excess your buffer size.J-16 SDiZ
@J-16SDiZ input_buffer_length limits only the number of bytes to be read into my program. The rest of the input goes to Linux shell eg. bash and gets executed, and that is what I'm trying to avoid. In DOS most matters with keyboard could be handled with hooking the keyboard interrupt and using a custom keyboard interrupt, but it seems to me that that's not a correct way to do it in Linux (or is it even possible for non-root programs?).nrz
Oh, you are asking how to clear the rest of steam before returning. Not how to limit the read.J-16 SDiZ

3 Answers

3
votes

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/

3
votes

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.

0
votes

You could read the input until newline character is found.