불변 속성 세트가있는 파일을 검색하는 방법은 무엇입니까?


17

구성 감사의 이유로 변경 불가능한 속성이 설정된 파일을 통해 ext3 파일 시스템을 검색 할 수 있기를 원합니다 (via chattr +i). find이 작업을 수행 하는 데 필요한 옵션 이나 유사한 옵션을 찾을 수 없습니다 . 이 시점에서 lsattr각 디렉토리의 출력 을 구문 분석 하기 위해 자체 스크립트를 작성해야합니다 . 더 나은 방법을 제공하는 표준 유틸리티가 있습니까?


필자의 경우 침입 탐지가 아닌 구성 관리에 대해서만 감사하고 있으므로 작업중 인 파일 이름이 알지 못하므로 줄 바꿈에 대해 너무 걱정할 필요가 없음을 분명히해야합니다. 그들. 그럼에도 불구하고 줄 바꿈 문제는 명심할 가치가 있으므로 질문을 그대로 두겠습니다.
depquid

답변:


9

grep명령을 lsattr명령 으로 파이핑하여 부분적으로 수행 할 수 있습니다 .

lsattr -R | grep +i

그러나, 나는 당신이 전체 말할 때 믿는 ext3검색을 포함 할 수 파일 시스템 /proc, /dev및보고하면 그냥 원하는 몇 가지 오류가 무시하는 다른 디렉토리를. 다음과 같이 명령을 실행할 수 있습니다.

lsattr -R 2>/dev/null | grep -- "-i-"

의 PCRE 기능을 grep사용 grep하여 "-i-"와보다 명확하게 일치시켜 조금 더 엄격하게 만들 수 있습니다 .

lsattr -R 2>/dev/null | grep -P "(?<=-)i(?=-)"

그러면 다음과 같은 상황에서 작동합니다.

$ lsattr -R 2>/dev/null afile | grep -P "(?<=-)i(?=-)"
----i--------e-- afile

그러나 불완전하다. 불변 플래그 주위에 추가 속성이 활성화되어 있으면 일치하지 않으며, 위와 같은 패턴과 이름이 일치하는 파일에 속합니다.

$ lsattr -R 2>/dev/null afile* | grep -P "(?<=-)i(?=-)"
----i--------e-- afile
-------------e-- afile-i-am

다음과 같이 패턴을 조금 더 강화할 수 있습니다.

$ lsattr -a -R 2>/dev/null afile* | grep -P "(?<=-)i(?=-).* "
----i--------e-- afile

그러나 여전히 약간 깨지기 쉽고 파일 시스템 내의 파일에 따라 추가 조정이 필요합니다. 하지 언급에 관해서는 @StephaneChazeles은 이 위의 패턴을 우회하는 파일 이름으로 줄 바꿈을 포함하여 비교적 쉽게 gamed 될 수 있다는 의견에 언급했다 grep.

참고 문헌

https://groups.google.com/forum/#!topic/alt.os.linux/LkatROg2SlM


1
나는 같은 스레드를 읽고 게시하려고했습니다. 대신 여분의 것을 추가하겠습니다.
slm

@ slm, 당신은 변경을 가장 환영합니다 :)
Ramesh

2
파일 이름에 줄 바꿈 문자가 있으면 변경 불가능한 파일을 위조하거나 숨길 수 있으므로 감사에 적합하지 않을 수 있습니다. 또한 파일 이름에 이름이있는 경우는 드물지 않습니다 -i-(현재 로그온 한 시스템에 34 개가 있음). 당신은 아마 -a옵션도 원할 것입니다
Stéphane Chazelas

1
호기심 +i때문에 첫 번째 예에서 무엇을해야합니까? 그것은 나를 위해 작동하지 않습니다. 또한 grepping은 (와 같은 ) -i-옆에 나타나는 속성 이 설정되지 않은 것으로 가정합니다 . ia
depquid

1
왜 단순히 grep하지 ^....i않습니까? 또는 같은 적어도 뭔가 ^[^ ]*i(가) 경우 i다섯 번째가 아닌 다른 위치에있을 수 있습니다.
Ruslan

6

스크립트의 목적이 감사라는 점을 고려하면 임의의 파일 이름 (예 : 줄 바꾸기 포함 이름)을 올바르게 처리하는 것이 특히 중요합니다. 이 lsattr경우 출력 lsattr이 모호 할 수 있으므로 여러 파일에서 동시에 사용할 수 없습니다.

한 번에 하나의 파일로 반복해서 find호출 할 수 있습니다 lsattr. 그래도 꽤 느릴 것입니다.

find / -xdev -exec sh -c '
  for i do
     attrs=$(lsattr -d "$i"); attrs=${attrs%% *}
     case $attrs in
       *i*) printf "%s\0" "$i";;
     esac
  done' sh {} +

Perl, Python 또는 Ruby와 같이 덜 까다로운 언어를 사용하고 lsattr직접 작업하는 것이 좋습니다 . ioctl syscall lsattr을 발행 FS_IOC_GETFLAGS하고 파일의 inode 플래그를 검색하여 작동합니다 . 다음은 Python 개념 증명입니다.

#!/usr/bin/env python2
import array, fcntl, os, sys
FS_IOC_GETFLAGS = 0x80086601
EXT3_IMMUTABLE_FL = 0x00000010
count = 0
def check(filename):
    fd = os.open(filename, os.O_RDONLY)
    a = array.array('L', [0])
    fcntl.ioctl(fd, FS_IOC_GETFLAGS, a, True)
    if a[0] & EXT3_IMMUTABLE_FL: 
        sys.stdout.write(filename + '\0')
        global count
        count += 1
    os.close(fd)
for x in sys.argv[1:]:
    for (dirpath, dirnames, filenames) in os.walk(x):
        for name in dirnames + filenames:
            check(os.path.join(dirpath, name))
if count != 0: exit(1)

1
내 시스템의 참고 자료 FS_IOC_GETFLAGS0x80046601입니다.
antonone

1
의 값은에 FS_IOC_GETFLAGS따라 다릅니다 sizeof(long). C에서 매크로가 확장되는 것을 찾으려면 예를 들어 다음 bash 명령을 참조하십시오 gcc -E - <<< $'#include <linux/fs.h>\nFS_IOC_GETFLAGS' | tail -n1. : 나는 그것에서 다음 식을 가지고 (((2U) << (((0 +8)+8)+14)) | ((('f')) << (0 +8)) | (((1)) << 0) | ((((sizeof(long)))) << ((0 +8)+8)))로 단순화 (2U << 30) | ('f' << 8) | 1 | (sizeof(long) << 16).
Ruslan

3

임의의 파일 이름 (줄 바꾸기 문자가 포함 된 파일 이름 포함)을 처리하기 위해 일반적인 속임수 는에서 .//.대신 파일을 찾는 것입니다 .. 때문에 //디렉토리 트리를 통과하는 동안 일반적으로 발생할 수 없습니다, 당신이 확신하는 //것을 알리는에서 새 파일 이름의 시작 find(또는 여기 lsattr -R) 출력.

lsattr -R .//. | awk '
  function process() {
    i = index(record, " ")
    if (i && index(substr(record,1,i), "i"))
      print substr(record, i+4)
  }
  {
    if (/\/\//) {
      process()
      record=$0
    } else {
      record = record "\n" $0
    }
  }
  END{process()}'

출력은 여전히 ​​줄 바꿈으로 구분됩니다. 사후 처리가 필요한 경우이를 조정해야합니다. 예를 들어, -v ORS='\0'GNU를에 공급할 수 있도록를 추가 할 수 있습니다 xargs -r0.

또한 lsattr -R(적어도 1.42.13) 경로가 PATH_MAX (보통 4096) 보다 큰 파일의 플래그를보고 할 수 없으므로 누군가 부모 디렉토리 (또는 경로 구성 요소로 이동하는 경로 구성 요소)를 이동하여 변경 불가능한 파일을 숨길 수 있습니다 그것은 매우 깊은 디렉토리에 있습니다.

해결 방법은 다음 find과 함께 사용하는 것 입니다 -execdir.

find . -execdir sh -c '
  a=$(lsattr -d "$1") &&
    case ${a%% *} in
      (*i*) ;;
      (*) false
    esac' sh {} \; -print0

이제와 -print0, 후 처리 가능한, 그러나 당신이 그 경로가 무엇보다 큰 파일 경로에있는 모든 시스템 호출주의 할하려는 경우 PATH_MAX가 여전히 실패 및 디렉토리 구성 요소가 간격으로 이름이 변경 될 수도 있습니다.

다른 사람이 쓸 수있는 디렉토리 트리에 대한 신뢰할 수있는 보고서를 얻으려면 lsattr언급해야 할 명령 자체에 몇 가지 문제가 더 있습니다 .

  • 이 방법 lsattr -R .은 디렉토리 트리를 통과하며 경쟁 조건에 따라 달라질 수 있습니다. .적절한 시점에 일부 디렉토리를 심볼릭 링크로 교체하여 라우팅 된 디렉토리 트리 외부의 디렉토리로 내려갈 수 있습니다 .
  • 심지어 lsattr -d file경쟁 조건이 있습니다. 이러한 속성은 일반 파일 또는 디렉토리에만 적용됩니다. 그래서 lsattr않는 lstat()파일이 올바른 유형이며 다음 않는다는 것을 확인하기 위해 먼저 open()다음 ioctl()속성을 검색 할 수 있습니다. 그러나 (또는 O_NOCTTY) open()없이 호출합니다 O_NOFOLLOW. 예를 들어 및 사이에 file있는 심볼릭 링크로 대체 되어 시스템이 재부팅 될 수 있습니다. 그것은 어떻게해야 그 다음 , 그리고 여기에 경쟁 조건을 피하기 위해./dev/watchdoglstat()open()open(O_PATH|O_NOFOLLOW)fstat()openat()ioctl()

2

Ramesh, slm 및 Stéphane에게 올바른 방향으로 나를 가리켜 주셔서 감사합니다 (에 대한 -R스위치 가 누락되었습니다 lsattr). 불행히도, 지금까지 답변 중 어느 것도 나를 위해 올바르게 작동하지 않았습니다.

나는 다음을 생각해 냈다.

lsattr -aR .//. | sed -rn '/i.+\.\/\/\./s/\.\/\///p'

이렇게하면 파일이 변경되지 않은 경우 파일을 변경할 수없는 것처럼 보이게하는 데 사용되는 줄 바꿈을 방지 할 수 있습니다. 변경 불가능으로 설정되고 파일 이름에 줄 바꿈이있는 파일은 보호 하지 않습니다 . 그러나 그러한 파일은 루트로 그렇게 만들어야하므로, 해당 파일이 내 사용 사례를 위해 파일 시스템에 존재하지 않는다고 확신 할 수 있습니다. (이 방법은 루트 사용자가 손상된 경우 침입 탐지에 적합하지 않지만 lsattr동일한 루트 사용자가 소유 한 동일한 시스템 유틸리티를 사용하지 않습니다 .)


루트 만이 파일에 불변 비트를 추가 할 수 있지만 나중에 다른 사용자가 해당 파일로 이어지는 경로 구성 요소의 이름을 바꿀 수 있으므로 파일 경로에 줄 바꾸기가 포함될 수 있습니다. 또한 사용자는 다른 파일을 변경할 수 없다고 생각하는 스크립트를 속이는 파일 경로 (변경 불가능하지 않음)를 만들 수 있습니다.
Stéphane Chazelas

2

사용 find -exec의 출력을 구문 분석, 너무 느린 것은 lsattr입니다 유사의에 신뢰할 수없는ls 에서 파이썬을 사용하여, 질 의해 답변 에 대한 상수를 선택하는 데 필요한 ioctl파이썬 인터프리터는 32 비트 또는 64 비트인지에 따라 ...

C ++은 스크립팅 언어만큼 나쁘지는 않습니다. 보너스로 C 프리 프로세서의 모든 기능을 갖춘 시스템 C 헤더에 액세스 할 수 있습니다.

다음 프로그램은 하나의 파일 시스템 내에있는 불변 파일을 검색합니다. 즉, 마운트 지점을 절대로 넘지 않습니다. 필요에 따라 마운트 포인트를 건너는 겉보기 트리를 검색하려면 호출 FTW_MOUNT에서 플래그를 제거 nftw하십시오. 또한 심볼릭 링크를 따르지 않습니다. 이를 따르려면 FTW_PHYS플래그를 제거하십시오 .

#define _FILE_OFFSET_BITS 64
#include <iostream>
#include <stdio.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/fs.h>
#include <sys/stat.h>
#include <ftw.h>

bool isImmutable(const char* path)
{
    static const int EXT3_IMMUTABLE_FLAG=0x10;

    const int fd=open(path,O_RDONLY|O_NONBLOCK|O_LARGEFILE);
    if(fd<=0)
    {
        perror(("Failed to open file \""+std::string(path)+"\"").c_str());
        return false;
    }
    unsigned long attrs;
    if(ioctl(fd,FS_IOC_GETFLAGS,&attrs)==-1)
    {
        perror(("Failed to get flags for file \""+std::string(path)+"\"").c_str());
        close(fd);
        return false;
    }
    close(fd);
    return attrs & EXT3_IMMUTABLE_FLAG;
}

int processPath(const char* path, const struct stat* info, int type, FTW* ftwbuf)
{
    switch(type)
    {
    case FTW_DNR:
        std::cerr << "Failed to read directory: " << path << "\n";
        return 0;
    case FTW_F:
        if(isImmutable(path))
            std::cout << path << '\n';
        return 0;
    }
    return 0;
}

int main(int argc, char** argv)
{
    if(argc!=2)
    {
        std::cerr << "Usage: " << argv[0] << " dir\n";
        return 1;
    }
    static const int maxOpenFDs=15;
    if(nftw(argv[1],processPath,maxOpenFDs,FTW_PHYS|FTW_MOUNT))
    {
        perror("nftw failed");
        return 1;
    }
}

-1

출력을 grep에 파이핑하는 대신 awk를 사용하여 출력의 첫 번째 필드에서 'i'만 일치시키는 이유는 무엇입니까?

lsattr -Ra 2>/dev/null /|awk '$1 ~ /i/ && $1 !~ /^\// {print}'

실제로 매일 cron을 통해 수백 대의 서버에서 / etc 디렉토리를 스캔하고 출력을 syslog로 보냅니다. 그런 다음 Splunk를 통해 일일 보고서를 생성 할 수 있습니다.

lsattr -Ra 2>/dev/null /etc|awk '$1 ~ /i/ && $1 !~ /^\// {print "Immutable_file="$2}'|logger -p local0.notice -t find_immutable

첫 번째 코드 스 니펫에는 오타가 있으며 두 번째 코드 스 니펫은 시스템에서 변경할 수없는 파일을 찾지 못합니다.
depquid

첫 번째 명령에서 오타가 수정되었습니다. 아마도 두 번째 파일이 없기 때문에 변경 불가능한 파일을 찾지 못하고 있습니까?
Rootdev

나는 두 번째 명령 만보 고 있음을 알지 못했습니다 /etc. 그러나 두 명령은 잘못 만든 비 불변의 파일 찾기touch `"echo -e "bogus\n---------i---e-- changeable"`"
depquid

원래 게시물에서 cron을 통해 / etc 디렉토리를 스캔한다고 말합니다. 게시하기 전에 게시물이나 명령을 읽지 않으면 도움이 될 수 없습니다. 그리고 예, 원하는 경우 검색을 속일 수있는 가장자리 사례를 구성 할 수는 있지만 원래 명령에서 오타를 너무 빨리 지적했기 때문에 (마지막 '누락), 나는 지적 할 것입니다 당신의 명령은 작성된대로 작동하지 않으므로 아무것도 만들지 않습니다! :-)
Rootdev

내 잘못이야. 이것을보십시오 :touch "`echo -e 'bogus\n---------i---e-- changeable'`"
depquid

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.