unix find command

2009. 12. 8. 19:5499. 정리전 - IT/13. Unix 얇팍지식

find는 단순히 파일을 찾는 명령입니다. 이런 명령이 보안에 중요한 이유는 문제되는 파일을 찾는데 이만큼 중요한 명령이 없기 때문입니다. 특히 백도어를 찾아내는데유용합니다.
find 명령의 메뉴얼 페이지는 UNIX의 모든 메뉴얼 페이지들 중에서 가장 불분명한 페이지의 하나이다. [ 시스템 관리의 핵심 2판 한빛미디어 p100] 이러한 메뉴얼 페이지이긴 하지만 ^^ 메뉴얼 페이지를 잘 본 다면 많은 도움을 받을 수 있습니다. 그럼 가장 기본적인 find의 형태에서 시작해 볼까요!

find를 실행해보자.?

그냥 생각없이 find에 관해서 누르면 ls 저리가라 할 정도로 많은 파일을 뿌려댑니다. find 가 복잡하긴 하지만 기본적인 틀이 있습니다.
find [패스] [표현식]
나 중에 복잡해지는 형식도 이런 간단한 틀에서 시작 합니다. 먼저 [패스]에 대해서 이건 간단합니다. 패스의 디렉토리를 첫머리로 해서 그 아래 파일들을 검색합니다. 시작점을 지정한다고 할까요. 이걸 잘 못지정하면 (특히 / 로 설정하면) 엄청나게 많은 파일에 뿌려대는 걸 봐야 합니다. 또 시간도 오래 걸리지요.^^
다음으로 [표현식]에 대해서 얘기를 해보지요.

기본 표현식

이름

-name 요건 정말 중요하지요. 찾는 파일에 대한 이름을 적으면 됩니다. 예를 들어 han이란 이름이 들어간 파일을 찾고 싶다면 -name "*han*" 이렇게 하면 됩니다. *는 와일드 카드입니다.(이거 모르면 도스에서 공부하세요.-_-+) 실행해 볼까요.

$ find /etc -name "*han*"
/etc/profile.d/hangul-init.csh
/etc/profile.d/hangul-init.sh
/etc/X11/wmconfig/hanterm
find: /etc/X11/xdm/authdir: access denied
find: /etc/X11/fs/.xauth: access denied
find: /etc/skel/Mail: access denied
/etc/charsets/jis-c6229-1984-hand
/etc/charsets/jis-c6229-1984-hand-add

중간에 검색할 수 없는 디렉토리가 있어서 에러 메시지가 났지만 그외의 결과를보면 han이란 글자가 들어간 파일을 찾아냈습니다. 앞의 명령을 find형식의 틀에적용해 보면

find /etc -name "*han*"
-(1)- -----(2)-----

(1)은 패스부분 (2)는 표현식 부분입니다. 이 명령은 /etc라는 디렉토리의 하위 파일중에서 han이라는 이름이 들어가는 파일을 찾으라는 명령이죠. 그리고 -name 뒤의 " "부분에는 정규표현식이 들어갈 수 있다.(글쓴이 왈:정규 표현식은 나중에 설명합니다.)

날짜로 찾아보기

-amin n (액세스 된 시각)
-atime n (액세스 된 날짜)
-cmin n (생성된 시각)
-ctime n (생성 날짜)
-mmin n (변경된 시각)
-mtime n (변경 날짜)을 찾을 때 사용합니다.
n은 원하는 날짜나 분이겠지요.

여러 옵션이 있는 듯 하지만 사용법은 비슷합니다. 생성된 날짜로 찾는 예를 해볼까요. 옵션 중에 -cmin 과 -ctime 이 있는데 -cmin은 단위가 분이고 -ctime 은 단위가 하루 단위 입니다. 이 옵션 다음에 숫자를 넣어야 하는데 5일 전에 만들어진 거면 -ctime 5라고 하면 되겠지요. 그치만 이렇게 사용한 경우는 잘 없겠지요. 5일 전부터 지금까지 만들어진 걸 찾을 경우는 -5를 하면 되겠지요. 그 반대는 +5를 사용하면 됩니다.(그럼 13일 전에서 5일 전 까지 만들어진 파일을 찾으려면 어떻게 해요 하겠지만 그건 나중에 설명하죠.)

+n (n일 전 부터 오늘까지)
n (n일 전 것만)
-n (n일 이 전 것만)

한번 3일 사이에 변경된 파일을 찾아 볼까요.
( 2>/dev/null 부분은 에러 처러 부분이므로 무시해도 됩니다. 자세한 건 리다이엑션에 대해 배워 보세요.)

$ find /etc -mtime -3 2>/dev/null
/etc
/etc/mail/virtusertable.db
/etc/mail/access.db
/etc/mail/domaintable.db
/etc/mail/mailertable.db
/etc/aliases.db
/etc/mtab
/etc/ioctl.save
/etc/issue
/etc/issue.net
/etc/resolv.conf

-mtime 옵션 대신 -atime 이나 -ctime도 넣어 보세요. 그리고 -3대신 -5나 여러 숫자를 넣어 보세요. +5나 +3은 아주 많은 결과가 나올겁니다.

퍼미션 찾기

-perm mode
원하는 퍼미션을 찾을 수 있습니다. 특히 SGID나 SUID가 설정된 걸 찾을 때 유용합니다. mode는 숫자로 된 퍼미션 값입니다. (rwxr-xr-x는 755로 표시되지요.) -perm 755이면 퍼미션이 755인 파일만 찾습니다. 정확한 값지정도 가능하지만 어느특정 퍼미션 비트가 설정되어 있는지 확인하는 방법도 있습니다. 앞의 예 처럼 +-를 이용하는 점이죠.자 주의해서 들어보세요.
-mode의 경우는 mode가 같아야 다 적용됩니다. +mode는 mode가 다 같을 필욘 없고 어느 부분만 같아도 적용됩니다. 예를 들어볼까요. 먼저 간단한 예부터

$ find /etc -perm 444 2>/dev/null
/etc/X11/twm/system.twmrc
/etc/X11/xdm/Xaccess
/etc/X11/xdm/Xresources
/etc/X11/xdm/Xservers
/etc/X11/xdm/xdm-config
/etc/X11/xsm/system.xsm
/etc/gtk/gtkrc
/etc/pcmcia/cdrom.opts
/etc/pcmcia/config
/etc/pcmcia/config.opts
/etc/pcmcia/ftl.opts
/etc/pcmcia/ide.opts
/etc/pcmcia/memory.opts
/etc/pcmcia/scsi.opts
/etc/pcmcia/serial.opts
/etc/pcmcia/shared

읽기 속성만 가진 파일을 찾을 수 있습니다. -mode, +mode의 차이를 봐 보세요.

$ ls -l
drwxrwxr-t 2 oprix staff 1024 Nov 26 02:54 I_am_a_directory/
-rwsr-x--x 1 oprix staff 13 Nov 23 20:32 I_am_a_file*
-r-xr-xr-- 1 oprix staff 5 Nov 26 03:07 temp*
$ find -perm +4000
./I_am_a_file
$ find -perm -4000
./I_am_a_file

이럴 경우 같게 나오지만

$ ls -l
drwxrwxr-t 2 oprix staff 1024 Nov 26 02:54 I_am_a_directory/
-rwsr-x--x 1 oprix staff 13 Nov 23 20:32 I_am_a_file*
-r-xr-xr-- 1 oprix staff 5 Nov 26 03:07 temp*
$ find -perm +4111
.
./I_am_a_directory
./I_am_a_file
./temp
$ find -perm -4111
./I_am_a_file

이런 결과를 얻습니다. 간단하게 말해서 보안 상의 문제인 SGID와 SUID를 찾으려면 -mode를 사용하면 됩니다.

$ find -perm -4000
$ find -perm -2000

앞의 명령은 SUID를 찾고 뒤의 명령은 SGID를 찾아냅니다. 특히 퍼미션을 찾는 법은 많은 실행을 해보시고 꼭 차이점을 파악하세요.

소유자, 소유그룹의 파일 찾기

-user name
-uid n
-group name
-gid n
-nouser
-nogroup

이건 쉽게 아실 겁니다. oprix란 사용자가 소유자인 파일을 찾고 싶다면 -user oprix 하면 될거고 staff가 소유 그룹인 파일을 찾고 싶으면 -group staff를 하면 되겠지요. -uid 와 -gid 도 사용자의 사용자 번호와 그룹 번호만 적어서 찾는 방법임을 알 수 있겠지요. 예만 적어보지요.

$ find /tmp -user oprix
$ find /tmp -group staff


이렇게 하면 되지요. 여기서 중요한 건 소유자와 소유 그룹이 없는 파일의 경우입니다. ftp나 몇 몇 프로그램으로 받은 파일은 그 시스템의 소유그룹과 소유자의 정보를 가지고 있을 경우가 있습니다. 따라서 시스템에 없는 소유자를 가리킬 경우가 있습니다. 이럴 경우 보안 문제가 되는데 이런 문제의 파일을 찾는 게 -nouser와 -nogroup입니다.

$ find / -nouser 2> /dev/null
$ find / -nogroup 2> /dev/null

이렇게 해서 간혹 파일 이름이 나올 경우 삭제하거나 소유자를 정해주어야 합니다.

파일의 종류

파일의 종류는 여러가지가 있지만 일반 파일과 디렉토리나 링크파일이 생각나지요.이런 파일의 종류대로 검색할 수 있습니다.
-type c
여기서 c는 디렉토리일 경우 d가 되고 일반 파일은 f 심볼릭 링크는 l로 나타낼 수있습니다. 이 옵션은 혼자 쓰이기 보다 다른 옵션과 함께 쓰일 경우가 많습니다. 그럼 /etc의 디렉토리를 나열해 볼까요.

$ find /etc -type d

이렇게 하면 되겠지요.

모아서 섬세하게

앞에서 배운 것들을 모아서 사용할 수 있습니다. 전체 디렉토리에서 이름에 gtk가 들어가고 모두가 실행할수 있는 파일이면서 만들어진지 30일 이상 되고 소유자가 root인 파일을 찾아볼까요.

$ find / -name "*gtk*" -perm -111 -ctime +30 -user root -type f 2> /dev/null
/etc/profile.d/hgtk-init.csh
/etc/profile.d/hgtk-init.sh
/usr/lib/libgnorbagtk.so.0.0.0
/usr/lib/libgtkxmhtml.so.1.0.1
/usr/lib/libgtk-1.2.so.0.2.1
/usr/lib/libgtk.so.1.0.6
$ cd /etc/profile.d
$ ls -l hgtk-init.sh
-rwxr-xr-x 1 root root 306 Jun 21 02:27 hgtk-init.sh*

우리가 원하는 조건에 맞지요.

파일 크기

-size n 로 파일 크기를 검사할 수 있습니다. 예를 들어

$ find -size 20000c

이렇게 입력하면 파일크기가 정확히 20000 byte가 되는 파일만 나옵니다. 이러면별 쓸모가 없겠죠. 앞의 퍼미션 처럼 +와 -를 이용할 수 있습니다. +는 그 크기 이상만 -는 그 크기 이하만 찾지요. 그리고 더 한 가지 20000뒤에 c가 붙어있는데 그것은 바이트 크기라는 겁니다. 숫자다음에 붙을 수 있는 단위는 기본적으로 생략가능한 블럭단위 b (1 block = 512byte), 바이트 단위 c, 킬로바이트 단위 k, 2바이트 워드 단위 w를 쓸수 있지요. 입맛에 맞게 쓰세요. 전바이트 단위가 편하더군요.
그럼 실습을 해볼까요.

$ find / -size +10000000c 2> /dev/null
/proc/kcore
/usr/X11R6/lib/X11/fonts/truetype/gulim.ttc
/usr/lib/libc.a
/usr/lib/netscape/netscape-communicator

컴퓨터에 깔려있는 거대 파일들을 찾아보았는데 이렇게 나오는 군요.(앞서 말했지만 2>/dev/null은 에러처리를 위한 리다이렉션입니다.) 다시한번 파일 크기가 정확히 10인 파일을 찾아보지요.

$ find / -size 10c -type f 2>/dev/null
/etc/adjtime
/home/oprix/temp/level13/character
/usr/lib/linuxconf/lang_intro.sk

자 찾았네요. 그렇지만 이걸로도 부족한 부분이 있다고 느끼신 분이 있을 겁니다. 이름에 gtk가 들어가거나 han이 들어갈 경우는 어떻게 하지요. 다 방법이 있지요.

조건 강화

여러가지 조건들을 한꺼번에 써 줄수 있습니다. 그래서 검색을 정확하고 빠르게 할
수가 있습니다.그럼 그 방법을 알아 볼까요?

-and ,-a
-or , -o
-not , !

이건 논리 조건들입니다. 이것들을 괄호를 이용해서

\( -name "*gtk*" -or -name "*han*" \)
-----(1)----- (2) ----(3)------

이러한 방법으로 쓸 수가 있습니다. (괄호는 쉘이 해석하지 않고 프로그램에서 해석해야 하므로 \을 붙여 그자체로 쓰이도록 했습니다.) (1)과 (3)은 조건식이고 (2)는 논리 연산자이지요. 괄호와 논리 연산자를 적절히 이용해서 정확하게 검색할 수 있습니다.그럼 예를 들어 볼까요?

$ find /tmp -size +100000c \( -atime +120 -or -mtime +30 \)
/tmp/backup.tgz

이건 해석해 보면 /tmp하위 디렉토리에서 엑세스가 120일 이상 안되었거나 ,수정을 30일 이상 안하고 크기가 100000바이트 이상인 파일을 찾으라는 명령입니다. 제 설명을 잘 보시고 -나, -고가 어디에 쓰였는지 알아보세요. 크기가 항상 100000바이트 이상이어야 하고 액세스가 120일 이상 안되가나 고친게 30일상 된 것중 둘중 하나가 만족해야 한다는 말이죠.(잘 모르시는 분은 수학의 명제부분을 찾아보세요.) 홀로 쓰인 조건은 다른 조건들과 and 조건을 이룹니다. 좀 더 쓸만한 예를 들어볼까요. 좀 길어요.

$ find /home \( -name a.out -or -name core -or -name "*~" -or -name ".*~"
-or -name "#*#" \) -type f -atime +14 2>/dev/null
/home/oprix/.jnewsrc~
/home/oprix/GTKstudy/tmp/core
/home/oprix/GTKstudy/core
/home/oprix/.saves-656-localhost.localdomain~
/home/oprix/usr/local/share/engdic/core
/home/oprix/usr/local/share/engdic/enc.c~
/home/oprix/usr/local/share/engdic/dec.c~

이런 결과가 나왔죠. 잘 모르시겠다는 분들은 앞의 조건들 -name a.out 과 -name core을 -and 나 -or 혹은 -not(-not은 조건 앞에 혼자쓰이지요.) 을 붙여서 직접해보세요.

좀 더 쓸 만하게

파일을 찾으면 뭐하나 그걸 어떻게 사용을 할지를 생각해야지. 그렇지요. 파일을찾는 게 find의 주목적이지만 그 파일을 이용해 어떤일을 하는 점도 중요합니다.
-exec command \;
이걸 쓰면 됩니다. 간단합니다. find로 실행하는 가장 간단한 예가 오래된 파일 삭
제지요. 먼저 예를 들고 설명하지요. 앞의 예를 이용해서

$ find /home \( -name a.out -or -name core -or -name "*~" -or -name ".*~" -or -name "#*#" \) -type f -atime +14 -exec rm -f {} \; 2>/dev/null

앞의 예와 틀린 건 -exec rm -f {} \; 이죠. -exec는 명령을 실행한다는 옵션이고rm은 지우는 명령 -f는 rm의 옵션 {}그럼 이게 뭘까요. {}는 find가 찾은 파일 이름을 말합니다. 따라서 이건 find가 찾은 파일을 묻지말고 삭제하라는 명령입니다.뒤의 \;는 ;가 쉘에서 다른 뜻으로 쓰이므로 \를 붙여서 프로그램에 그 자체를 넘겨 주라는 명령입니다. 혹시라도 모르는 분을 위해서 간단한 예를 ^^

$ find /tmp -name "*file*" -exec ls -l {} \;
-rwsr-x--x 1 oprix staff 13 Nov 23 20:32 /tmp/test/I_am_a_file

-exec를 이용하면 편하게 할 수 있어요.

그 밖의 옵션들

-ls 이건 파일에 대한 자세한 정보를 줍니다.
-exec ls -l {} 과 같음 명령이죠.
-print 기본으로 설정되어 있어서 잘 모를 수 있지만 결과를 출력하라는 명령입니다. 너무 당연한 건데 이 옵션 안 주면 안 나오는 find도 있답니다.

from hackers home page