컬은 비밀번호가 ps 출력에 나타나지 않도록 어떻게 보호합니까?

컬은 비밀번호가 ps 출력에 나타나지 않도록 어떻게 보호합니까?

나는 얼마 전에 curl명령줄 인수로 제공된 사용자 이름과 비밀번호가 출력에 나타나지 않는다는 것을 발견했습니다 ps(물론 bash 기록에는 나타날 수 있지만).

에도 나타나지 않습니다 /proc/PID/cmdline.

(단, 결합된 사용자 이름/비밀번호 매개변수의 길이는 내보낼 수 있습니다.)

데모는 다음과 같습니다.

[root@localhost ~]# nc -l 80 &
[1] 3342
[root@localhost ~]# curl -u iamsam:samiam localhost &
[2] 3343
[root@localhost ~]# GET / HTTP/1.1
Authorization: Basic aWFtc2FtOnNhbWlhbQ==
User-Agent: curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.15.3 zlib/1.2.3 libidn/1.18 libssh2/1.4.2
Host: localhost
Accept: */*



[1]+  Stopped                 nc -l 80
[root@localhost ~]# jobs
[1]+  Stopped                 nc -l 80
[2]-  Running                 curl -u iamsam:samiam localhost &
[root@localhost ~]# ps -ef | grep curl
root      3343  3258  0 22:37 pts/1    00:00:00 curl -u               localhost
root      3347  3258  0 22:38 pts/1    00:00:00 grep curl
[root@localhost ~]# od -xa /proc/3343/cmdline 
0000000    7563    6c72    2d00    0075    2020    2020    2020    2020
          c   u   r   l nul   -   u nul  sp  sp  sp  sp  sp  sp  sp  sp
0000020    2020    2020    0020    6f6c    6163    686c    736f    0074
         sp  sp  sp  sp  sp nul   l   o   c   a   l   h   o   s   t nul
0000040
[root@localhost ~]# 

이 효과는 어떻게 달성됩니까? 소스 코드 어딘가에 있습니까 curl? ( curl기능이 아닌 기능인 줄 알았는데 ps? 아니면 일종의 커널 기능인 걸까요?)


반품:이진 실행 파일의 소스 코드 외부에서 이를 달성할 수 있습니까? 예를 들어 쉘 명령을 사용하여 루트 권한과 결합할 수 있습니까?

즉, 특정 사람들에게 전달한 매개변수가 출력에 나타나 /proc거나 출력되지 않도록 어떻게든 가릴 수 있습니까 ps?(동일한 것이라고 생각합니다)평상복쉘 명령? (나는 이 질문에 대한 대답이 "아니요"라고 추측하지만, 추가 질문을 포함할 가치가 있는 것 같았습니다.)

답변1

커널이 프로세스를 실행할 때 프로세스에 속한 읽기-쓰기 메모리(적어도 Linux의 경우 스택)에 명령줄 인수를 복사합니다. 프로세스는 다른 메모리와 마찬가지로 이 메모리에 쓸 수 있습니다. 매개변수가 표시 되면 ps프로세스 메모리의 특정 주소에 저장된 모든 내용을 다시 읽습니다. 대부분의 프로그램은 원래 매개변수를 유지하지만 변경할 수 있습니다. 이것POSIX 설명ps지적

표시된 문자열이 매개변수 목록의 버전(시작 시 명령에 전달됨)인지 또는 매개변수 버전(애플리케이션에 의해 수정되었을 수 있음)인지는 지정되지 않습니다. 애플리케이션은 인수 목록을 수정하고 해당 수정 사항을 ps의 출력에 반영할 수 있다고 믿을 수 없습니다.

대부분의 UNIX 변형은 이러한 변경 사항을 반영하지만 다른 유형의 운영 체제에서의 POSIX 구현은 그렇지 않을 수 있기 때문에 이것을 언급합니다.

프로세스가 임의로 변경할 수 없기 때문에 이 기능은 사용이 제한되어 있습니다. 적어도 매개변수의 총 길이는 늘릴 수 없습니다. 왜냐하면 프로그램은 ps매개변수를 얻은 위치를 변경할 수 없고 영역을 원래 크기 이상으로 확장할 수도 없기 때문입니다. 인수는 C 스타일의 null로 끝나는 문자열(끝에 여러 개의 null 인수를 갖는 것과 다르지 않음)이기 때문에 끝에 null 바이트를 넣으면 길이가 효과적으로 줄어듭니다.

정말로 자세히 알아보고 싶다면 오픈 소스 구현의 소스 코드를 확인해 보세요. Linux에서 의 출처는 ps흥미롭지 않습니다. 여러분이 볼 수 있는 것은 그것이프로세스 파일 시스템, 존재하다. 이 파일의 내용을 생성하는 코드는 커널에 있습니다./proc/PID/cmdlineproc_pid_cmdline_read존재하다fs/proc/base.c. access_remote_vm주소에서 mm->arg_start까지 액세스되는(액세스하여) 프로세스의 메모리 부분은 mm->arg_end프로세스가 시작될 때 커널에 기록되며 나중에 변경할 수 없습니다.

argv[1]일부 데몬은 이 기능을 사용하여 상태를 반영합니다. 예를 들어 또는 또는 같은 문자열 로 변경합니다 . 많은 UNIX 변종에는startingavailableexitingsetproctitle이 작업을 수행하는 함수입니다. 일부 프로그램은 이 기능을 사용하여 기밀 데이터를 숨깁니다. 프로세스가 시작될 때 명령줄 인수가 표시되므로 이는 사용이 제한되어 있습니다.

대부분의 고급 언어는 인수를 문자열 객체에 복사하고 원래 저장소를 수정할 수 있는 방법을 제공하지 않습니다. 다음은 argv요소를 직접 변경하여 이 기능을 보여주는 C 프로그램입니다 .

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[])
{
    int i;
    system("ps -p $PPID -o args=");
    for (i = 0; i < argc; i++)
    {
        memset(argv[i], '0' + (i % 10), strlen(argv[i]));
    }
    system("ps -p $PPID -o args=");
    return 0;
}

예제 출력:

./a.out hello world
0000000 11111 22222

argv컬 소스 코드에서 수정 사항을 볼 수 있습니다 . 컬은기능 cleanarg하다src/tool_paramhlp.c모든 공백을 변경하는 매개변수를 사용할 때 사용됩니다 memset. 예를 들어 편집 등을 src/tool_getparam.c통해 이 기능에서 여러 번 사용되었습니다.사용자 암호. 함수는 매개변수 구문 분석에서 호출되므로 컬 호출 초기에 발생하지만 이 일이 발생하기 전에 명령줄을 덤프하면 여전히 비밀번호가 노출됩니다.

매개변수는 프로세스 자체 메모리에 저장되므로 디버거를 사용하는 경우를 제외하고는 외부에서 변경할 수 없습니다.

답변2

다른 답변은 이 질문에 매우 잘 대답합니다. 구체적인 답변"이 효과는 어떻게 달성됩니까?컬 소스 코드 어딘가에 있나요?":

내부에컬 소스코드의 매개변수 파싱 부분, 이 -u옵션은 다음과 같이 처리됩니다.

    case 'u':
      /* user:password  */
      GetStr(&config->userpwd, nextarg);
      cleanarg(nextarg);
      break;

게다가cleanarg()기능이 정의되었습니다다음과 같이:

void cleanarg(char *str)
{
#ifdef HAVE_WRITABLE_ARGV
  /* now that GetStr has copied the contents of nextarg, wipe the next
   * argument out so that the username:password isn't displayed in the
   * system process list */
  if(str) {
    size_t len = strlen(str);
    memset(str, ' ', len);
  }
#else
  (void)str;
#endif
}

argv따라서 다른 답변에서 언급한 것처럼 사용자 이름:비밀번호 매개변수가 공백으로 덮여 있음 을 분명히 알 수 있습니다 .

답변3

프로세스는 매개변수를 읽을 수 있을 뿐만 아니라 쓸 수도 있습니다.

저는 개발자가 아니기 때문에 이 내용에 익숙하지 않지만 외부에서는 환경 매개변수 변경과 같은 작업을 수행할 수 있습니다.

https://stackoverflow.com/questions/205064/is-there-a-way-to-change-another-processs-environment-variables

관련 정보