curl은 ps 출력에 비밀번호가 나타나지 않도록 어떻게 보호합니까? 수 있습니다.) 아래 데모 : [root@localhost ~]# nc -l

얼마 전에 curl커맨드 라인 인수로 지정된 사용자 이름과 비밀번호 가 ps출력에 나타나지 않는다는 것을 알았습니다 (물론 bash 기록에 나타날 수도 있습니다).

마찬가지로에 표시되지 않습니다 /proc/PID/cmdline.

(그러나 결합 된 username / password 인수의 길이는 파생 될 수 있습니다.)

아래 데모 :

[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합니까? 아니면 일종의 커널 기능입니까?)


또한 : 바이너리 실행 파일의 소스 코드 외부 에서이 작업을 수행 할 수 있습니까? 예를 들어 아마도 루트 권한과 결합 된 쉘 명령을 사용합니까?

즉 , 임의의 쉘 명령에 전달 된 인수 /procps출력에 나타나 거나 출력 되는 것을 막을 수 있습니까 (동일한 것 같습니다) ? (나는 이것에 대한 대답이 “아니오”라고 생각하지만이 여분의 반 질문을 포함시키는 것이 가치가있는 것 같습니다.)



답변

커널은 프로세스를 실행할 때 프로세스에 속하는 읽기 쓰기 메모리 (적어도 Linux에서는)에 명령 행 인수를 복사합니다. 프로세스는 다른 메모리와 마찬가지로 해당 메모리에 쓸 수 있습니다. 때 ps인수를 표시, 그것은 프로세스의 메모리의 특정 주소에 저장되어있는 어떤 다시 읽습니다. 대부분의 프로그램은 원래 주장을 유지하지만 변경할 수 있습니다. 상태 의 POSIX 설명은ps

표시된 문자열이 시작될 때 명령에 전달 된 인수 목록의 버전인지 또는 응용 프로그램에 의해 수정되었을 수있는 인수의 버전인지 여부는 지정되지 않습니다. 응용 프로그램은 인수 목록을 수정할 수 있고 ps의 출력에 해당 수정 사항이 반영되도록 할 수 없습니다.

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

이 기능은 프로세스가 임의로 변경할 수 없으므로 제한적으로 사용됩니다. 프로그램 ps이 인수를 가져올 위치를 변경할 수없고 영역을 원래 크기 이상으로 확장 할 수 없기 때문에 최소한 인수의 총 길이를 늘릴 수 없습니다. 인수는 C 스타일의 널 종료 문자열이기 때문에 길이가 널 바이트를 사용함으로써 효과적으로 길이를 줄일 수 있습니다 (이것은 끝에 빈 인수가없는 것과 구별 할 수 없습니다).

정말로 파고 싶다면 오픈 소스 구현의 소스를 볼 수 있습니다. 리눅스의 소스는 ps당신이 보는 것 모두가에서 명령 행 인수 읽는이, 흥미없는 proc 파일 시스템을 에 . 이 파일의 내용을 생성하는 코드는의 커널 있습니다. 프로세스 메모리의 일부 (로 액세스 )는 주소 에서 ; 이 주소는 프로세스가 시작될 때 커널에 기록되며 나중에 변경할 수 없습니다./proc/PID/cmdlineproc_pid_cmdline_readfs/proc/base.caccess_remote_vmmm->arg_startmm->arg_end

어떤 데몬이 자신의 상태를 반영하기 위해이 기능을 사용하여, 예를 들어, 그들은 그들의 변화 argv[1]유사한 문자열로 starting또는 availableexiting. 많은 유닉스 변형은 setproctitle이것을 수행 하는 기능을 가지고 있습니다 . 일부 프로그램은이 기능을 사용하여 기밀 데이터를 숨 깁니다. 프로세스가 시작되는 동안 명령 행 인수가 표시되므로 이는 제한적으로 사용됩니다.

대부분의 고급 언어는 인수를 문자열 객체에 복사하고 원래 저장소를 수정할 수있는 방법을 제공하지 않습니다. 다음은 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

argvcurl 소스 코드에서 수정 된 것을 볼 수 있습니다 . 컬은를 사용하여 인수를 모든 공백으로 변경하는 데 사용되는 함수 cleanargsrc/tool_paramhlp.c 정의합니다 memset. src/tool_getparam.c이 기능 에서는 사용자 비밀번호 를 수정하는 등 몇 번 사용됩니다 . 함수는 매개 변수 구문 분석에서 호출되므로 컬 호출 초기에 발생하지만이 전에 명령 행을 덤프하면 여전히 비밀번호가 표시됩니다.

인수는 프로세스의 자체 메모리에 저장되므로 디버거를 사용하지 않는 한 외부에서 인수를 변경할 수 없습니다.


답변

다른 답변은 일반적인 방식으로 질문에 잘 대답합니다. ” 이 효과는 어떻게 달성됩니까 ? curl의 소스 코드 어딘가에 있습니까?

curl 소스 코드인수 구문 분석 섹션 에서 -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다른 답변에서 설명한 것처럼 username : password 인수의 공백을 공백으로 덮어 쓴 것을 분명히 알 수 있습니다 .


답변

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

나는 개발자가 아니므 로이 물건에 익숙하지 않지만 환경 매개 변수 변경과 비슷한 접근 방식으로 외부에서 가능할 수 있습니다.

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