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


68

얼마 전에 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출력에 나타나 거나 출력 되는 것을 막을 수 있습니까 (동일한 것 같습니다) ? (나는 이것에 대한 대답이 "아니오"라고 생각하지만이 여분의 반 질문을 포함시키는 것이 가치가있는 것 같습니다.)



16
답은 아니지만이 방법은 안전하지 않습니다 . 프로그램 시작과 사용자가 암호를 읽을 수있는 인수 문자열 지우기 사이에 경쟁 창이 있습니다. 명령 행에 민감한 비밀번호를 허용하지 마십시오.
R ..

1
느슨하게 관련됨 : 환경 변수는 누구에게 속해 있습니까? 그리고 실제로 사람이 사용합니까 environ환경 변수에 액세스 할 직접? — 결론 : 환경 변수 목록과 같은 인수 목록은 읽기 / 쓰기 사용자 프로세스 메모리에 있으며 사용자 프로세스에 의해 수정 될 수 있습니다.
Scott

1
@ JPhi1618, grep패턴 의 첫 문자를 문자 클래스로 만드십시오 . 예ps -ef | grep '[c]url'
와일드 카드

1
@mpy, t는 그렇게 복잡하지 않습니다. 일부 정규 표현식은 서로 일치하지만 일부 정규 표현식은 일치하지 않습니다. curl일치 curl하지만 일치 [c]url하지 않습니다 [c]url. 더 자세한 정보가 필요하면 새로운 질문을하면 기꺼이 답변 해 드리겠습니다.
와일드 카드

답변:


78

커널은 프로세스를 실행할 때 프로세스에 속하는 읽기 쓰기 메모리 (적어도 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이 기능 에서는 사용자 비밀번호 를 수정하는 등 몇 번 사용됩니다 . 함수는 매개 변수 구문 분석에서 호출되므로 컬 호출 초기에 발생하지만이 전에 명령 행을 덤프하면 여전히 비밀번호가 표시됩니다.

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


큰! 그래서, 사양 스 니펫 것을 관한, 나는 그것이 커널 저장소 프로세스의 원래의 명령 줄 인수를 만들기 위해 POSIX 호환 될 것이라고 의미를 이해하는 외부 프로세스의 읽기 - 쓰기 메모리 (에서 또한 읽기 - 쓰기 메모리의 복사본) ? 그런 다음 ps프로세스의 읽기-쓰기 메모리의 변경 사항을 무시하고 해당 커널 메모리에서 보고서 인수를 사용합니까? 그러나 (올 바르면?) 대부분의 UNIX 변형은 전자를 수행하지 않으므로 ps원래 데이터가 어디에도 보관되지 않기 때문에 커널 수정없이 후자를 수행 할 수 없습니까?
와일드 카드

1
@ 와일드 카드 수정. 원본을 유지하는 Unix 구현이있을 수 있지만 일반적인 구현은 생각하지 않습니다. C 언어는의 내용을 수 있습니다 argv항목 (당신이 설정할 수 없습니다 변경할 수 argv[i]있지만, 당신이 쓸 수 argv[i][0]를 통해 argv[i][strlen(argv[i])]), 그래서 프로세스의 메모리에 복사본이 있어야한다.
Gilles


4
@Wildcard, Solaris가이 작업을 수행합니다. / usr / ucb / ps에 표시된 명령 줄은 프로세스 소유 (변경 가능) 사본입니다. / usr / bin / ps에 표시된 명령 줄은 커널 소유 (불변) 복사본입니다. 커널은 처음 80 자만 유지합니다. 다른 것은 잘립니다.
BowlOfRed

1
@Wildcard 실제로 후미 널은 빈 인수입니다. 에서 ps이 아무것도 없다,하지만 당신은 얼마나 많은 공간을 확인하면 예,이 차이를 만들어 않으며, 당신은 더 직접적으로 관찰 할 수처럼 출력, 빈 인자를 많이 본다 /proc/PID/cmdline.
Gilles

14

다른 답변은 일반적인 방식으로 질문에 잘 대답합니다. " 이 효과는 어떻게 달성됩니까 ? 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 인수의 공백을 공백으로 덮어 쓴 것을 분명히 알 수 있습니다 .


나는 cleanarg질문이 요구하는 것을하고 있다고 명시 적으로 언급 한 것을 좋아합니다 !
Floris

3

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

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

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


좋아, 그러나 예를 들어 실행 bash -c 'awk 1 /proc/$$/cmdline; set -- something; awk 1 /proc/$$/cmdline'하는 것은 적어도 쉘에서 매개 변수를 설정하는 것이 커널이 프로세스 매개 변수로 보는 것을 수정하는 것과는 다르다는 것을 보여줍니다.
와일드 카드

4
@Wildcard 쉘 스크립트의 위치 인수는 초기 에 쉘 프로세스의 명령 행 인수 중 일부사본 입니다 . 대부분의 쉘은 스크립트가 원래 인수를 변경하도록 허용하지 않습니다.
Gilles

@Gilles, 그렇습니다. 제 의견의 핵심이었습니다. :) 프로세스 가 수행 할 수 있는 일반적인 진술 (이 답변의 첫 문장)은 기존 쉘 기능으로 이것이 달성 될 수 있는지 여부에 대해서는 대답하지 않습니다. 이것에 대한 대답은 "아니오"인 것 같습니다. 이것이 제가 질문의 맨 아래에서 추측 한 것입니다.
와일드 카드
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.