$ k=v p &
[1] 3028
언급되지 않은 p
내용을 변경할 수 있는 방법이 있나요?/proc/3028/environ
k=v
하지만 p
아직 실행 중인가요?
답변1
Linux에서는 스택의 환경 문자열 값을 재정의할 수 있습니다.
따라서 이 항목을 0이나 다른 항목으로 덮어써서 숨길 수 있습니다.
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char* argv[], char* envp[]) {
char cmd[100];
while (*envp) {
if (strncmp(*envp, "k=", 2) == 0)
memset(*envp, 0, strlen(*envp));
envp++;
}
sprintf(cmd, "cat /proc/%u/environ", getpid());
system(cmd);
return 0;
}
다음으로 실행:
$ env -i a=foo k=v b=bar ./wipe-env | hd
00000000 61 3d 66 6f 6f 00 00 00 00 00 62 3d 62 61 72 00 |a=foo.....b=bar.|
00000010
k=v
덮어 썼습니다 \0\0\0
.
이 경우 새 문자열이 할당되므로 값을 재정의 setenv("k", "", 1)
해도 아무런 효과가 없습니다 ."k="
환경 변수를 사용/수정하지 않는 경우 k
다음과 같은 작업을 수행하여 스택의 문자열 주소를 가져올 수도 있습니다(그 중 하나).setenv()
putenv()
k=v
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char* argv[]) {
char cmd[100];
char *e = getenv("k");
if (e) {
e -= strlen("k=");
memset(e, 0, strlen(e));
}
sprintf(cmd, "cat /proc/%u/environ", getpid());
system(cmd);
return 0;
}
하지만 제거만 가능하다는 점에 유의하세요.하나k=v
환경에서 수신된 항목 수입니다. 일반적으로 하나만 있지만 전달된 환경 목록에서 누구든지 k=v1
및 (또는 두 번) 을 모두 전달하는 것을 막을 수는 없습니다 . k=v2
이것이 과거에 보안 위반이 발생한 이유입니다.k=v
execve()
CVE-2016-2381. bash
실제로 쉘쇼크 이전에 변수와 함수를 동일한 이름으로 내보냈을 때 이런 일이 발생할 수 있었습니다.
그럼에도 불구하고 env var 문자열을 덮어쓰지 않은 작은 창이 항상 있으므로 이를 전달하는 다른 방법을 찾아야 할 수도 있습니다.비밀/proc/pid/environ
필요한 경우 노출된 명령(예: 파이프)을 통해 정보를 고려하세요.
또한 반대로 동일한 euid 또는 루트(또는 프로세스의 euid와 ruid가 다른 것으로 나타나는 경우에만 루트)를 가진 프로세스에서만 액세스할 수 있습니다 /proc/pid/cmdline
./proc/pid/environment
에서 값을 숨길 수 있지만 /proc/pid/environ
디버거를 연결하는 등 메모리에 있는 문자열의 다른 복사본을 얻을 수는 있습니다.
바라보다https://www.kernel.org/doc/Documentation/security/Yama.txt최소한 루트가 아닌 사용자가 이 작업을 수행하지 못하도록 방지하는 방법을 알아보세요.
답변2
위의 문자열을 덮어쓸 필요는 없습니다(실제로는 그렇지 않습니다).존재하다) 2010년 이후 Linux의 메인 스레드 스택.
/proc/self/cmdline
둘 다 런타임 시 + 또는 +를 사용하여 함수를 호출 /proc/self/environ
하여 프로세스 자체에서 수정할 수 있습니다 . 메모리 포인터를 프로세스의 애플리케이션 메모리 공간에 직접 설정합니다. 이 메모리 공간은 각 프로세스에 대해 커널에 의해 저장되고 의 내용 과 명령줄 및 명령에 의해 보고되는 환경을 검색하는 데 사용됩니다 .prctl()
PR_SET_MM_ARG_START
PR_SET_MM_ARG_END
PR_SET_MM_ENV_START
PR_SET_MM_ENV_END
/proc/${PID}/cmdline
/proc/${PID}/environ
ps
따라서 새로운 매개변수나 환경 문자열(벡터가 아니라 가리키는 메모리가 연결되고 ␀
구분된 실제 문자열 데이터여야 함)을 구성하고 커널에 위치를 알려줍니다.
이는 Linux 함수 매뉴얼 페이지 prctl(2)
와 매뉴얼 페이지에 문서화되어 있습니다. environ(7)
무엇인가요아니요기록을 위해 커널은 시작 주소를 끝 주소보다 높게 설정하거나 끝 주소를 시작 주소보다 낮게 설정하거나 두 주소 중 하나를 (재)0으로 설정하려는 시도를 거부합니다. 게다가 이는 2009년 Bryan Donlan이 제안한 원래 메커니즘이 아니며, 단일 작업에서 시작과 끝을 원자적으로 설정할 수 있었습니다. 게다가 커널은 어떠한 메소드도 제공하지 않습니다.얻다이 포인터의 현재 값.
이로 인해 까다로워진다조정환경 및 명령줄 영역 prctl()
. 이 prctl()
함수는 최대 4번 호출해야 합니다. 왜냐하면 첫 번째 시도에서는 이전 데이터와 새 데이터가 메모리에 있는 위치에 따라 시작 포인터를 끝 포인터보다 높게 설정하려는 시도가 발생할 수 있기 때문입니다. 꼭 그렇게 불러야 해더 멀리이로 인해 시스템의 다른 프로세스가 새로운 시작/끝을 설정하지만 새 끝은 설정하지 않는 동안 프로세스 메모리 공간의 임의 범위를 확인할 수 있는 기회를 갖지 않도록 하려면 /start를 네 번 실행하면 안 됩니다. 일했다.
애플리케이션이 전체 범위를 한 번에 안전하게 설정하는 단일 원자 시스템 호출을 사용하는 것이 더 쉬울 것입니다.
더 큰 문제는 실제로 타당한 이유가 없다는 것입니다(원본 데이터 영역의 재기록 가능성에 대해 커널에서 검사한 경우).그래도, 실제로 동등한 작업은 Linux에서 수퍼유저 권한이 필요한 BSD에서의 권한 있는 작업이 아닙니다.
나는 이것을 사용하는 도구 세트에 대해 매우 간단한 setprocargv()
함수를 작성했습니다 setprocenvv()
. 체인로더는 setenv
및 와 같은 내장 도구 세트에서 체인로드되므로 foreground
Linux에서 명령 인수 및 환경에 연결할 수 있는 기능이 반영됩니다.
# /package/admin/nosh/command/clearenv setenv WIBBLE 스윙 포그라운드 일시 중지\;true& [1]1057 # hexdump -C /proc/1057/cmdline 00000000 66 6f 72 65 67 72 6f 75 6e 64 00 70 61 75 73 65 |foreground.pause| 00000010 00 3b 00 74 72 75 65 00 |.;.true.| 00000018 # hexdump -C /proc/1057/environ 00000000 57 49 42 42 4c 45 3d 77 6f 62 62 6c 65 00 |위블=흔들기. | 0000000e # hexdump -C /proc/1058/cmdline 00000000 70 61 75 73 65 00 | | 00000006 # hexdump -C /proc/1058/environ 00000000 57 49 42 42 4c 45 3d 77 6f 62 62 6c 65 00 |위블=흔들기. | 0000000e #
이는 프로세스가 추적되고 이 두 가상 파일을 통하지 않는 다른 방법으로 해당 메모리에 직접 액세스하는 것을 막지 못하며 물론 문자열을 덮어쓰기하는 것과 마찬가지로 문자열을 수정하기 전에 이 정보를 볼 수 있는 창을 남깁니다. 메인 스레드 스택 위의 데이터. 데이터 덮어쓰기의 경우와 마찬가지로 이는 각 경우에 환경(힙에)을 복사하는 언어 런타임 라이브러리를 고려하지 않습니다. 일반적으로 이것을 이름 없는 파이프의 읽기 끝 부분에 열린 파일 설명자를 상속하거나 전적으로 사용자가 제어할 수 있는 입력을 읽는 것과 같이 프로그램에 "비밀"을 전달하기 위한 좋은 메커니즘으로 생각하지 마십시오. 버퍼로 사용한 다음 닦아냅니다.
추가 읽기
- 티모 시라닌(2009-10-02).prctl()에 PR_SET_PROCTITLE_AREA 옵션이 추가되었습니다.. 리눅스 커널 메일링 리스트.
- https://unix.stackexchange.com/a/432681/5132
- 다니엘 J. 번스타인. 비밀번호 인터페이스 확인. cr.yp.to.
- https://github.com/jdebp/nosh/blob/master/source/setprocargv.cpp
- https://github.com/jdebp/nosh/blob/master/source/setprocenvv.cpp