packet을 감청하는 루트킷을 만들어 보려고 한다.
더 나아가 특정 조건이 맞는 패킷을 전송하게 되면, 특정 포트로 리버스 쉘을 생성하고자 한다.
먼저 사용할 내용은 netfilter라는 프레임 워크를 사용하고자한다.
이를 위해서 netfilter와 관련된 내용을 공부한다.
netfilter 관련 자료는 다음의 자료를 확인하면서 정리하려 한다.
http://www.roman10.net/2011/07/22/how-to-filter-network-packets-using-netfilterpart-1-netfilter-hooks/
http://www.tune2wizard.com/kernel-programming-network-programming/
물론... 인터넷에서 코드를 긁어와서 사용해도 되겠지만... 하나 하나 파악하면서 해보려한다..
Netfilter는 리눅스 커널 내부에 존재하는 훅 집합이다.
Netfilter는 LKM이 네트워크 패킷을 조작하거나 가로채기 위해서 네트워크 스택에 콜백 함수를 등록할 수 있게 해준다.
먼저 네트워크 패킷이 들어오면, 해당 패킷은 NF_INET_PRE_ROUTING 훅으로 향하게 된다.
해당 패킷은 라우팅 코드[훅에 의해서 흐르므이 NT_INET_PRE_ROUTING으로 향함]로 향했기 때문에, 해당 코드를 거친 후,
같은 네트워크의 포트로 향할지, 아니면 다른 인터페이스로 향할지 방향이 결정되게 된다. 물론 마음에 들지 않으면? 드롭 시킬 수도 있다.
NT_INET_PRE_ROUTING 위치는 국가의 문 공항 같은 느낌이다. 가장 먼저 필터링 되는 1차 관문이다.
같은 인터페이스에 있는 다른 포트로 패킷이 전송되어 지면, 다른 훅 [두번 째 훅] NF_INET_LOCAL_IN이 동작하게 된다.
목적지 포트에 패킷이 도달하기 전에 NF_INET_LOCAL_IN 훅이 동작하게 되는 것이다!
다른 네트워크 인터페이스로 패킷이 전송되다면, 다른 훅인 NF_INET_FORWARD가 호출된다. 그리고 뒤어어(followed by) 다른 훅인
NF_INET_POST_ROUTING 이 호출된다. 이러한 행위는 유선(wire)에 도달하기 전에 발생한다.
이제 나머지 훅이 남았는데, NF_INET_LOCAL_OUT이다. 이것은 로컬에서 나가는 패킷(local outgoing packets)을 처리할 때 호출된다.
정확한 타이밍? 시기는 라우팅이 결정되고 난 후이며, IP 주소를 처리하기 전에 호출된다.
--> 좀 더 자세히 알아봐야 함.
NF_INET_PRE_ROUTING
Incoming packets pass this hook in ip_rcv() before routing
NF_INET_LOCAL_IN
All incoming packets addressed to the local host pass this hook in ip_local_deliver()
NF_INET_FORWARD
All incoming packets not addressed to the local host pass this hook in ip_forward()
NF_INET_LOCAL_OUT
All outgoing packets created by this local computer pass this hook in ip_build_and_send_pkt()
NF_INET_POST_ROUTING
All outgoing packets (forwarded or locally created) will pass this hook in ip_finish_output()
How to Register the Hooks [훅을 어떻게 설치하느냐?]
netfilter 훅 관련 소스코드(헤더)는 다음과 같은 위치에 존재한다.
/lib/modules/$(uname -r)/build/include/linux/
훅을 등록하고 제거하는 함수는 netfilter.h 에 존재하는다. 다음과 같은 원형을 지닌다.
1 2 3 | int nf_register_hook(struct nf_hook_ops *reg); void nf_unregister_hook(struct nf_hook_ops *reg); | cs |
직관적으로도 register/unregister_hook 함수인 것을 알 수 있다.
그리고 nf_hook_ops 구조체의 경우도 netfilter.h에 존재하며, 다음과 같은 원형을 지닌다.
1 2 3 4 5 6 7 8 9 10 11 12 13 | struct nf_hook_ops { struct list_head list; /* User fills in from here down. */ nf_hookfn *hook; //function point struct net_device *dev; void *priv; u_int8_t pf; unsigned int hooknum; /* Hooks are ordered in ascending priority. */ int priority; }; | cs |
struct list_head는 훅 끼리 연결 시키기 위해서 사용되는 인자인것 같다. --> 사용해보지 않아서 단언 못하겠다.
nf_hookfn 인자의 경우에는 훅 함수의 포인터를 나타 낸다. 즉 실제 훅이 발생하면 실행되는 함수의 포인터를 넣는 인자이다.
그러면 nf_hookfn 가장 중요한 이 함수의 원형을 살펴 본다.
살펴 보면 커널 버전에 따라서 nf_hookfn 함수 원형이 변형된것을 알 수있다.
2.x 버전?인가 보면 좀 더 많고 인자가 다양하고.. 뭐 그런데 지금 현재 버전은 4.8 xx 여서 다르다 여튼 확인해보면 아래와 같다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | typedef unsigned int nf_hookfn(void *priv, struct sk_buff *skb, const struct nf_hook_state *state); struct nf_hook_state { unsigned int hook; int thresh; u_int8_t pf; struct net_device *in; struct net_device *out; struct sock *sk; struct net *net; struct list_head *hook_list; int (*okfn)(struct net *, struct sock *, struct sk_buff *); }; | cs |
nf_hookfn 함수 원형에서 nf_hook_state 구조체로 좀 더 정확?하게 뭐.. 표현할수 있게 변형된것 같다.
unsigned int hooknum 인자의 경우에는 위에서 설명한 어떠한 훅인지 설정하는 번호이다.
u_int8_t pf 인자의 경우 프로토콜 패밀리(Protocol Family)를 셋팅 하는 인자이다.
그래서 PF_INET4 를 설정하면 IPV4를 사용하고, PF_INET6를 설정하면 IPV6을 사용한다.
int priority 같은 경우는 우선순위이다.
우선순위를 표현하는 데이터는 enum 공용체 형식으로 netfilter_ipv4.h에 존재한다.
/lib/modules/$(uname -r)/build/include/uapi/linux/netfilter_ipv4.h
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 | /* IP Hooks */ /* After promisc drops, checksum checks. */ #define NF_IP_PRE_ROUTING 0 /* If the packet is destined for this box. */ #define NF_IP_LOCAL_IN 1 /* If the packet is destined for another interface. */ #define NF_IP_FORWARD 2 /* Packets coming from a local process. */ #define NF_IP_LOCAL_OUT 3 /* Packets about to hit the wire. */ #define NF_IP_POST_ROUTING 4 #define NF_IP_NUMHOOKS 5 #endif /* ! __KERNEL__ */ enum nf_ip_hook_priorities { NF_IP_PRI_FIRST = INT_MIN, NF_IP_PRI_CONNTRACK_DEFRAG = -400, NF_IP_PRI_RAW = -300, NF_IP_PRI_SELINUX_FIRST = -225, NF_IP_PRI_CONNTRACK = -200, NF_IP_PRI_MANGLE = -150, NF_IP_PRI_NAT_DST = -100, NF_IP_PRI_FILTER = 0, NF_IP_PRI_SECURITY = 50, NF_IP_PRI_NAT_SRC = 100, NF_IP_PRI_SELINUX_LAST = 225, NF_IP_PRI_CONNTRACK_HELPER = 300, NF_IP_PRI_CONNTRACK_CONFIRM = INT_MAX, NF_IP_PRI_LAST = INT_MAX, }; | cs |
위에서 설명한 HOOK에 대한 정의와 함께 우선순위에 대한 정의를 확인할 수 있다.
이때 우선순위는 작으면 작을 수록 우선순위가 높다.
예를들면 NF_IP_PRI_FIRST 가 가장 높은 우선순위를 가진다고 할 수있다.
unsigned int hooknum의 번호도 나와있다.
위의 내용을 가지고 만든.. Template? 이다. 일단 지금은 통신하면 무조건 보내주고 프린트만 해준다.
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 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | #include <linux/init.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/sched.h> #include <linux/mm.h> #include <linux/highmem.h> #include <linux/skbuff.h> #include <linux/in.h> #include <linux/icmp.h> #include <linux/ip.h> #include <linux/netfilter.h> #include <linux/netfilter_ipv4.h> //function define int rootkit_init(void); void rootkit_exit(void); module_init(rootkit_init); module_exit(rootkit_exit); unsigned int sniff(void *priv, struct sk_buff *skb, const struct nf_hook_state *state); //nf_hook_ops struct nf_hook_ops net_hook; int rootkit_init(void) { printk("Network Sniffing\n"); //setting pre_hook; net_hook.hooknum = NF_INET_PRE_ROUTING; net_hook.priority = NF_IP_PRI_FIRST; net_hook.pf = PF_INET; net_hook.hook = &sniff; nf_register_hook(&net_hook); return 1; } unsigned int sniff(void *priv, struct sk_buff *skb, const struct nf_hook_state *state){ printk("sniff fucntion\n"); return NF_ACCEPT; } void rootkit_exit(void) { nf_unregister_hook(&net_hook); } MODULE_DESCRIPTION ("netfilter rootkit"); MODULE_LICENSE("GPL"); | cs |
'reversing > rootkit' 카테고리의 다른 글
rootkit - packet sniff[2] (0) | 2017.07.15 |
---|---|
rootkit - packet sniff[1] (0) | 2017.06.21 |
rootkit - root [2] (0) | 2017.06.13 |
rootkit - root [1] (0) | 2017.06.02 |
rootkit - vfs hooking [readdir,iterate] (0) | 2017.05.25 |