- Get link
- X
- Other Apps
As Freebsd is an active and maintained operating system. It's offer some debugger software for programmer working on it. There is a user space and kernel space debugger. We'll mostly working on the later one.
But before let's resume in one image the final goal we want to achieve.
To do a source level, step by step debugging. We need to setup a remote debugging environment consisting mainly of two Freebsd operating system.
I'm using Oracle virtualbox as it allow us to setup things easily than using real physical machine which need a serial cable. And you know, modern laptop at least don't support this at all apart from using some usb converter.
And in virtualbox we can create a virtual serial connexion between the 2 Freebsd VM.
Naming convention:
- Target VM: The VM which will be the target of the attack and need to be
debugged from another remote VM.
- DEBUG VM: The VM used to perform a source level debugging against
the target VM.
Without further words let's get straight to the actual step needed for this.
- First download an AMD64 Freebsd iso image from the official site.
- Of course you need to install virtualbox.
- Install the Freebsd iso with source codes options enabled.
- Now an important step, we need to rebuild the freebsd kernel with debugging symbol so we can enable source level debugging later on.
- cd into /usr/src/sys/amd64/conf
- create a copy of the original config file : cp GENERIC GENERIC_DBG
- Edit the newly copied GENERIC_DBG file by adding some new options
options DDB and options GDB.
- cd /usr/src
- make buildkernel KERNCONF=GENERIC_DBG
- make installkernel KERNCONF=GENERIC_DBG
- Once this step is done and you confirmed that new kernel has been installed by
running the uname command, clone this VM and name the cloned VM
differently.
- Another important step, we need to setup a virtual serial connection between
the two VM. But first power off the two VM.
- Target VM:
- Click on the VM setting->Serial Ports->Port1
- Enable Serial Port option.
- Choose COM1 as port number.
- Port mode: Host Pipe
- Leave the option connect to existing pipe/socket unchecked.
- Choose a path for the pipe. (Mine: /home/michael/Exploit/pipe)
This will create a pipe socket when VM is powered on.
- DEBUG VM:
- Click on the VM setting->Serial Ports->Port1
- Enable Serial Port option.
- Choose COM1 as port number.
- Port mode: Host Pipe
- Enable the option connect to existing pipe/socket
- Choose the same path like the Target VM.
- Now, we need to enable some uart flag on the Target VM. Power on the VM
and edit or add hint.uart.0.flags="0xC0" in /boot/device.hints
reboot it.
- After rebooting the Target VM, start the DEBUG VM.
- On Target VM, enter ddb mode: sysctl debug.kdb.enter=1
and type gdb it will now wait the DEBUG VM for command.
- On the DEBUG VM side, type:
kgdb -r /dev/cuau0 /usr/obj/usr/src/sys/GENERIC_DBG/kernel.debug
It will enter a gdb mode, and we can begin to do a source level debugging from now. Type continue to let the TARGET VM continue it's execution.
We'll begin to debug a ICMP hook modules as use case.
- nethook.c: The actual icmp kernel hook modules in C.
- Makefile: Makefile for nethook.c
We'll use this C modules through this series, It's an example of a reachable
vulnerable networking code from a remote a remote attacker.
There is a stack based overflow vulnerability in the process_icmp function.
What this code does is just replacing the original icmp_input function inside freebsd kernel networking code which used to process an icmp packet from the IP layer. So all ICMP packet will be intercepted by our function instead of the original.
Now, copying these two file nethook.c and Makefile into each VM.
I've been using ssh and scp that connect into these VM doing this.
On Target VM:
- make DEBUG_FLAGS='-g -O0'
- kldload ./nethook.ko
- sysctl debug.kdb.enter=1
- Type gdb in ddb.
On DEBUG VM:
- make DEBUG_FLAGS='-g -O0'
- cd /usr/obj/usr/src/sys/GENERIC_DBG/
- kgdb -r /dev/cuau0 ./kernel.debug
(kgdb) add-kld pathto_nethook.ko
(kgdb) break process_icmp
(kgdb) c
You can ping the Target VM from your HOST(ex:Linux) and you we'll see that the DEBUG VM cathed the breakpoint against process_icmp function.
This is because ping tools use ICMP protocol.
Figure 1: DEBUG VM: Setting breakpoint
Figure 2: DEBUG VM: Breakpoint catched.
We can inspect all variable, structure, registers, like normal user space
debugging
Figure 3: DEBUG VM: Back trace
Figure 4: DEBUG VM: Info reg
We've done the debugging environment now. In the next part we'll use all of these for exploring deep and deep into the FreeBSD kernel.
Thanks for reading.
http://freebsd.org/
https://www.freebsd.org/doc/en/books/handbook/kernelconfig-building.html
https://www.freebsd.org/doc/en_US.ISO8859-1/books/developers-handbook/kerneldebug-online-gdb.html
But before let's resume in one image the final goal we want to achieve.
To do a source level, step by step debugging. We need to setup a remote debugging environment consisting mainly of two Freebsd operating system.
I'm using Oracle virtualbox as it allow us to setup things easily than using real physical machine which need a serial cable. And you know, modern laptop at least don't support this at all apart from using some usb converter.
And in virtualbox we can create a virtual serial connexion between the 2 Freebsd VM.
Naming convention:
- Target VM: The VM which will be the target of the attack and need to be
debugged from another remote VM.
- DEBUG VM: The VM used to perform a source level debugging against
the target VM.
Without further words let's get straight to the actual step needed for this.
- First download an AMD64 Freebsd iso image from the official site.
- Of course you need to install virtualbox.
- Install the Freebsd iso with source codes options enabled.
- Now an important step, we need to rebuild the freebsd kernel with debugging symbol so we can enable source level debugging later on.
- cd into /usr/src/sys/amd64/conf
- create a copy of the original config file : cp GENERIC GENERIC_DBG
- Edit the newly copied GENERIC_DBG file by adding some new options
options DDB and options GDB.
- cd /usr/src
- make buildkernel KERNCONF=GENERIC_DBG
- make installkernel KERNCONF=GENERIC_DBG
- Once this step is done and you confirmed that new kernel has been installed by
running the uname command, clone this VM and name the cloned VM
differently.
- Another important step, we need to setup a virtual serial connection between
the two VM. But first power off the two VM.
- Target VM:
- Click on the VM setting->Serial Ports->Port1
- Enable Serial Port option.
- Choose COM1 as port number.
- Port mode: Host Pipe
- Leave the option connect to existing pipe/socket unchecked.
- Choose a path for the pipe. (Mine: /home/michael/Exploit/pipe)
This will create a pipe socket when VM is powered on.
- DEBUG VM:
- Click on the VM setting->Serial Ports->Port1
- Enable Serial Port option.
- Choose COM1 as port number.
- Port mode: Host Pipe
- Enable the option connect to existing pipe/socket
- Choose the same path like the Target VM.
- Now, we need to enable some uart flag on the Target VM. Power on the VM
and edit or add hint.uart.0.flags="0xC0" in /boot/device.hints
reboot it.
- After rebooting the Target VM, start the DEBUG VM.
- On Target VM, enter ddb mode: sysctl debug.kdb.enter=1
and type gdb it will now wait the DEBUG VM for command.
- On the DEBUG VM side, type:
kgdb -r /dev/cuau0 /usr/obj/usr/src/sys/GENERIC_DBG/kernel.debug
It will enter a gdb mode, and we can begin to do a source level debugging from now. Type continue to let the TARGET VM continue it's execution.
We'll begin to debug a ICMP hook modules as use case.
- nethook.c: The actual icmp kernel hook modules in C.
- Makefile: Makefile for nethook.c
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* FreeBSD net stack hooking | |
* Used as demo for debugging and RCE in kernel space | |
*/ | |
#include <sys/types.h> | |
#include <sys/systm.h> | |
#include <sys/module.h> | |
#include <sys/errno.h> | |
#include <sys/param.h> | |
#include <sys/kernel.h> | |
#include <sys/proc.h> | |
#include <sys/sysent.h> | |
#include <sys/sysproto.h> | |
#include <sys/syscall.h> | |
#include <sys/libkern.h> | |
#include <vm/vm.h> | |
#include <vm/pmap.h> | |
#include <vm/vm_page.h> | |
#include <sys/mbuf.h> | |
#include <sys/protosw.h> | |
#include <netinet/in.h> | |
#include <netinet/ip.h> | |
#include <netinet/ip_var.h> | |
#include <netinet/ip_icmp.h> | |
extern struct protosw inetsw[]; | |
#define MOD_NAME "nethook" | |
#define OK (1) | |
#define ERROR (-1) | |
#define DATA_SIZE 80 | |
#define ICMP_HEADER 8 | |
#define OFFSETOF_CURTHREAD 0 | |
static void hooking_main(void); | |
static int tcp_input_hook(struct mbuf **mp, int *offp,int proto); | |
static int icmp_input_hook(struct mbuf **mp, int *offp, int proto); | |
static void forwad_icmp(struct mbuf **mp, int *offp, int proto); | |
static void process_icmp(struct mbuf **mp, int *offp, int proto); | |
pr_input_t *_saved_tcp_input; | |
/* icmp_input hook. */ | |
static void | |
process_icmp(struct mbuf **mp, int *offp, int proto) | |
{ | |
struct icmp *icmpp; | |
struct mbuf *mb; | |
struct ip *ipp; | |
char datap[DATA_SIZE]; | |
char *icmpdata; | |
int iphlen; | |
int icmplen; | |
iphlen = *offp; | |
mb = *mp; | |
ipp = mtod(mb, struct ip *); | |
icmplen = ntohs(ipp->ip_len) - iphlen; | |
mb->m_len -= iphlen; | |
mb->m_data += iphlen; | |
icmpp = mtod(mb, struct icmp *); | |
icmpdata = mb->m_data + ICMP_HEADER; | |
memcpy(&datap[0], icmpdata, icmplen - ICMP_HEADER); | |
mb->m_len += iphlen; | |
mb->m_data -= iphlen; | |
} | |
static void | |
forwad_icmp(struct mbuf **mp, int *offp, int proto) | |
{ | |
char padd[500]; | |
memset(&padd[0], 0x0, sizeof(padd)); | |
process_icmp(mp, offp, proto); | |
} | |
static int | |
icmp_input_hook(struct mbuf **mp, int *offp, int proto) | |
{ | |
long sig1 = 0xbeefdead; | |
long sig2 = 0xbaaddead; | |
/** Just to make the compiler happy */ | |
if(sig2 == sig1) | |
; | |
forwad_icmp(mp, offp, proto); | |
return (0); | |
} | |
static int | |
tcp_input_hook(struct mbuf **mp, int *offp, int proto) | |
{ | |
return (_saved_tcp_input(mp, offp, proto)); | |
} | |
static void | |
hooking_main(void) | |
{ | |
inetsw[ip_protox[IPPROTO_ICMP]].pr_input = icmp_input_hook; | |
_saved_tcp_input = inetsw[ip_protox[IPPROTO_TCP]].pr_input; | |
inetsw[ip_protox[IPPROTO_TCP]].pr_input = tcp_input_hook; | |
} | |
static int | |
nethandler(struct module * module, int cmd, void *args) | |
{ | |
int error = 0; | |
switch(cmd) | |
{ | |
case MOD_LOAD: | |
uprintf("nethook Loaded\n"); | |
hooking_main(); | |
break; | |
case MOD_UNLOAD: | |
uprintf("nethook Unloaded\n"); | |
inetsw[ip_protox[IPPROTO_TCP]].pr_input = _saved_tcp_input; | |
inetsw[ip_protox[IPPROTO_ICMP]].pr_input = icmp_input; | |
break; | |
default: | |
error = EOPNOTSUPP; | |
break; | |
} | |
return (error); | |
} | |
static moduledata_t nethook_data = { | |
MOD_NAME, | |
nethandler, | |
NULL | |
}; | |
DECLARE_MODULE(nethook, nethook_data, SI_SUB_DRIVERS, SI_ORDER_ANY); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
SRCS=nethook.c | |
KMOD=nethook | |
.include <bsd.kmod.mk> |
We'll use this C modules through this series, It's an example of a reachable
vulnerable networking code from a remote a remote attacker.
There is a stack based overflow vulnerability in the process_icmp function.
What this code does is just replacing the original icmp_input function inside freebsd kernel networking code which used to process an icmp packet from the IP layer. So all ICMP packet will be intercepted by our function instead of the original.
Now, copying these two file nethook.c and Makefile into each VM.
I've been using ssh and scp that connect into these VM doing this.
On Target VM:
- make DEBUG_FLAGS='-g -O0'
- kldload ./nethook.ko
- sysctl debug.kdb.enter=1
- Type gdb in ddb.
On DEBUG VM:
- make DEBUG_FLAGS='-g -O0'
- cd /usr/obj/usr/src/sys/GENERIC_DBG/
- kgdb -r /dev/cuau0 ./kernel.debug
(kgdb) add-kld pathto_nethook.ko
(kgdb) break process_icmp
(kgdb) c
You can ping the Target VM from your HOST(ex:Linux) and you we'll see that the DEBUG VM cathed the breakpoint against process_icmp function.
This is because ping tools use ICMP protocol.
Figure 1: DEBUG VM: Setting breakpoint
Figure 2: DEBUG VM: Breakpoint catched.
We can inspect all variable, structure, registers, like normal user space
debugging
Figure 3: DEBUG VM: Back trace
Figure 4: DEBUG VM: Info reg
We've done the debugging environment now. In the next part we'll use all of these for exploring deep and deep into the FreeBSD kernel.
Thanks for reading.
http://freebsd.org/
https://www.freebsd.org/doc/en/books/handbook/kernelconfig-building.html
https://www.freebsd.org/doc/en_US.ISO8859-1/books/developers-handbook/kerneldebug-online-gdb.html
- Get link
- X
- Other Apps
Comments
Post a Comment