2012-09-17 2 views
4

편집 : @Gunner가 버퍼 오버플로가 아님을 지적하여 바뀜 .버퍼에 맞지 않는 stdin 입력을 피하는 방법 Linux 64 비트 Intel (x86-64) 어셈블리의 쉘로 보내려면

Linux 64 비트 인텔 어셈블리에서 에서 NR_read으로 사용자 입력을 읽는 중 입력 버퍼가 Linux 셸에 전송되는 것과 맞지 않는 입력을 피할 수 있을지 궁금합니다. 세게 때리다? 예를 들어,이 예제 프로그램에서는 255 바이트의 입력 버퍼를 정의했습니다 (버퍼의 크기는 1 이상이 될 수 있습니다). 255 바이트보다 긴 나머지 입력은 bash (bash에서 실행중인 경우)로 전송되며 이것은 심각한 심각한 취약점입니다. 이 취약점을 피하기 위해 Linux 64 비트 어셈블리에서 입력을 어떻게 읽어야합니까? 개행 문자가 발견 될 때까지

[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 
+0

huh? 'input_buffer_length'를 넘겨 주면 버퍼 크기를 초과하지 않도록해야한다. –

+0

@ J-16SDiZ'input_buffer_length'는 내 프로그램에서 읽을 바이트 수만을 제한합니다. 나머지 입력은 Linux 쉘로 이동합니다. 배쉬하고 사형 당해서, 그게 내가 피하려고하는거야. 도스에서 키보드와 관련된 대부분의 문제는 키보드 인터럽트를 연결하고 커스텀 키보드 인터럽트를 사용하여 처리 할 수 ​​있습니다.하지만 그것은 Linux에서 올바른 방법이 아닌 것처럼 보입니다 (또는 루트가 아닌 프로그램에서도 가능합니까?). . – nrz

+0

오, 돌아 오기 전에 나머지 스팀을 제거하는 방법을 묻습니다. 읽기를 제한하는 방법이 아닙니다. –

답변

3

다른 사람이 언급 한 것처럼 버퍼 오버플로가 아닙니다. 나는이 문제를 다루는 방법을 보여주는 리눅스의 터미널에서 읽는 방법에 대한 튜토리얼을 썼다. Int 80을 사용하지만 필요에 맞게 쉽게 변경할 수 있습니다.

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

+0

고마워, 내 문제가 해결되었습니다. 내 자신의 읽기 입력 루틴에서 입력 버퍼 플러시 코드를 구현하고 잘 작동합니다. – nrz

+0

글쎄, 적어도 작동하지만 초과 문자 각각에 대해 시스템 호출을 보내면 합리적이라고 생각하지 않습니다. 더 큰 tmp 버퍼가 향상되지만 여전히 ... 파이프와 같이 어떤 데이터가 사용되는지 알 수 없습니다. – IdiotFromOutOfNowhere

+0

이 하루 종일 감사합니다. – divinci

0

당신은 입력을 읽을 수 :

여기 내 코드입니다.

3

이미 읽은 syscall에는 보호 기능이 내장되어 있습니다.하지만 다른 한 가지 : 명시 적으로 syscall을 사용해서는 안됩니다. 코드를 x86-64 시스템 (코드 : sysenter)으로 가져 가면 어떻게 될까요? syscall, sysenter 또는 int을 지원하는 wheather에 관계없이 모든 아키텍처에서 syscall을 수행하는 코드가 포함 된 Linux의 VDSO (가상 동적 공유 객체)를 사용해야합니다.

+0

''lea rsi, [input_buffer]'(유효 주소를로드하고 레지스터에 실효 주소를 정확하게 저장합니다.)는'mov rsi, input_buffer'와 같습니다. 나는 레지스터에 저장된 값이 메모리 주소라는 것을 표시하기 때문에'lea '를 선호한다. 또한,'lea'는 더 고급 어드레싱 양식에서 사용될 수 있습니다.'lea rax, [rbx + 8 * rcx + 7238]'명령으로'rax = rbx + 8 * rcx + 7238'을 계산할 수 있습니다. , 그리고 [[]'을 사용하는 메모리 어드레싱 구문에도 불구하고 메모리 주소 만 MMU에서 계산되지만 메모리는 지정되지 않는다. x86에서'[]'는 메모리 주소가 아닌 레지스터에만 관계가 있습니다. – nrz

+0

@nrz : 죄송합니다! 완전하게 'lea'를 잊었다. 나는 그걸 없애 버릴거야. – Linuxios

+0

만약'syscall'을 대체한다면 (적어도 NR_read, NR_write, NR_exit 작업은 괜찮지 만 NR_read의 경우 NR_read에서이 문제가 발생합니다)'sysenter'로 즉시'Segmentation fault'를 얻을 수 있습니다. 내 프로그램 안에 입력. 그래서, 어떤 이유로'sysenter'는 전혀 작동하지 않습니다. 내 사용자 정의 커널 버전은 3.5.3이고 내 프로세서는 Intel Core i7-2760QM입니다. 그리고 "당신의 코드가 x86-64 머신 ('sysenter'를 사용하는)으로 옮겨 진다면 어떻게 될까요?" ? 이것은 x86-64 기계입니다. – nrz

관련 문제