/* * main dissector function for an etch message */ static void dissect_etch_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { /* We've a full PDU: 8 bytes + pdu_packetlen bytes */ emem_strbuf_t *colInfo = NULL; if (pinfo->cinfo || tree) { colInfo = get_column_info(tvb); /* get current symbol */ } if (pinfo->cinfo) { col_set_str(pinfo->cinfo, COL_PROTOCOL, "ETCH"); gbl_pdu_counter++; /* Switch to another frame? => Clear column */ if (pinfo->fd->num != gbl_old_frame_num) { col_clear(pinfo->cinfo, COL_INFO); gbl_pdu_counter = 0; } gbl_old_frame_num = pinfo->fd->num; col_set_writable(pinfo->cinfo, TRUE); col_append_fstr(pinfo->cinfo, COL_INFO, "%s ", colInfo->str); } if (tree) { /* we are being asked for details */ unsigned int offset; proto_item *ti; proto_tree *etch_tree; ti = proto_tree_add_protocol_format(tree, proto_etch, tvb, 0, -1, "ETCH Protocol: %s", colInfo->str); offset = 9; etch_tree = proto_item_add_subtree(ti, ett_etch); proto_tree_add_item(etch_tree, hf_etch_sig, tvb, 0, 4, ENC_BIG_ENDIAN); proto_tree_add_item(etch_tree, hf_etch_length, tvb, 4, 4, ENC_BIG_ENDIAN); proto_tree_add_item(etch_tree, hf_etch_version, tvb, 8, 1, ENC_NA); read_struct(&offset, tvb, etch_tree, 0); } }
// This is the raw NTDS command function. When the remote user // sends a command request for extapi_ntds_parse, this function fires. // It calls the setup routines for our Jet Instance, attaches the isntance // to the NTDS.dit database the user specified, and creates our channel. // The user interacts with the NTDS database through that channel from that point on. DWORD ntds_parse(Remote *remote, Packet *packet) { Packet *response = packet_create_response(packet); DWORD res = ERROR_SUCCESS; struct jetState *ntdsState = calloc(1,sizeof(struct jetState)); PCHAR filePath = packet_get_tlv_value_string(packet, TLV_TYPE_NTDS_PATH); // Check if the File exists if (0xffffffff == GetFileAttributes(filePath)) { res = 2; goto out; } strncpy_s(ntdsState->ntdsPath, 255, filePath, 254); // Attempt to get the SysKey from the Registry unsigned char sysKey[17]; if (!get_syskey(sysKey)) { res = GetLastError(); goto out; } JET_ERR startupStatus = engine_startup(ntdsState); if (startupStatus != JET_errSuccess) { res = startupStatus; goto out; } // Start a Session in the Jet Instance JET_ERR sessionStatus = JetBeginSession(ntdsState->jetEngine, &ntdsState->jetSession, NULL, NULL); if (sessionStatus != JET_errSuccess) { JetTerm(ntdsState->jetEngine); res = sessionStatus; goto out; } JET_ERR openStatus = open_database(ntdsState); if (openStatus != JET_errSuccess) { JetEndSession(ntdsState->jetSession, (JET_GRBIT)NULL); JetTerm(ntdsState->jetEngine); res = openStatus; goto out; } JET_ERR tableStatus = JetOpenTable(ntdsState->jetSession, ntdsState->jetDatabase, "datatable", NULL, 0, JET_bitTableReadOnly | JET_bitTableSequential, &ntdsState->jetTable); if (tableStatus != JET_errSuccess) { engine_shutdown(ntdsState); res = tableStatus; goto out; } // Create the structure for holding all of the Column Definitions we need struct ntdsColumns *accountColumns = calloc(1, sizeof(struct ntdsColumns)); JET_ERR columnStatus = get_column_info(ntdsState, accountColumns); if (columnStatus != JET_errSuccess) { engine_shutdown(ntdsState); free(accountColumns); res = columnStatus; goto out; } JET_ERR pekStatus; struct encryptedPEK *pekEncrypted = calloc(1,sizeof(struct encryptedPEK)); struct decryptedPEK *pekDecrypted = calloc(1,sizeof(struct decryptedPEK)); // Get and Decrypt the Password Encryption Key (PEK) pekStatus = get_PEK(ntdsState, accountColumns, pekEncrypted); if (pekStatus != JET_errSuccess) { res = pekStatus; free(accountColumns); free(pekEncrypted); free(pekDecrypted); engine_shutdown(ntdsState); goto out; } if (!decrypt_PEK(sysKey, pekEncrypted, pekDecrypted)) { res = GetLastError(); free(accountColumns); free(pekEncrypted); free(pekDecrypted); engine_shutdown(ntdsState); goto out; } // Set our Cursor on the first User record JET_ERR cursorStatus = find_first(ntdsState); if (cursorStatus != JET_errSuccess) { res = cursorStatus; free(accountColumns); free(pekEncrypted); free(pekDecrypted); engine_shutdown(ntdsState); goto out; } cursorStatus = next_user(ntdsState, accountColumns); if (cursorStatus != JET_errSuccess) { res = cursorStatus; free(accountColumns); free(pekEncrypted); free(pekDecrypted); engine_shutdown(ntdsState); goto out; } // If we made it this far, it's time to set up our channel PoolChannelOps chops; Channel *newChannel; memset(&chops, 0, sizeof(chops)); NTDSContext *ctx; // Allocate storage for the NTDS context if (!(ctx = calloc(1, sizeof(NTDSContext)))) { res = ERROR_NOT_ENOUGH_MEMORY; free(accountColumns); free(pekEncrypted); free(pekDecrypted); engine_shutdown(ntdsState); goto out; } ctx->accountColumns = accountColumns; ctx->ntdsState = ntdsState; ctx->pekDecrypted = pekDecrypted; // Initialize the pool operation handlers chops.native.context = ctx; chops.native.close = ntds_channel_close; chops.read = ntds_channel_read; if (!(newChannel = channel_create_pool(0, CHANNEL_FLAG_SYNCHRONOUS | CHANNEL_FLAG_COMPRESS, &chops))) { res = ERROR_NOT_ENOUGH_MEMORY; free(accountColumns); free(pekEncrypted); free(pekDecrypted); engine_shutdown(ntdsState); goto out; } channel_set_type(newChannel, "ntds"); packet_add_tlv_uint(response, TLV_TYPE_CHANNEL_ID, channel_get_id(newChannel)); out: packet_transmit_response(res, remote, response); return ERROR_SUCCESS; }
/* describe table, if c is not NULL cur->cols and cur->ncols is also set */ int describe_table(PGresult * res, dbTable ** table, cursor * c) { int i, ncols, kcols; int pgtype, gpgtype; char *fname; int sqltype, fsize, precision, scale; dbColumn *column; G_debug(3, "describe_table()"); ncols = PQnfields(res); /* Count columns of known type */ kcols = 0; for (i = 0; i < ncols; i++) { get_column_info(res, i, &pgtype, &gpgtype, &sqltype, &fsize); if (sqltype == DB_SQL_TYPE_UNKNOWN) continue; kcols++; /* known types */ } G_debug(3, "kcols = %d", kcols); if (!(*table = db_alloc_table(kcols))) { return DB_FAILED; } if (c) { c->ncols = kcols; c->cols = (int *)G_malloc(kcols * sizeof(int)); } /* set the table name */ /* TODO */ db_set_table_name(*table, ""); /* set the table description */ db_set_table_description(*table, ""); /* TODO */ /* db_set_table_delete_priv_granted (*table); db_set_table_insert_priv_granted (*table); db_set_table_delete_priv_not_granted (*table); db_set_table_insert_priv_not_granted (*table); */ kcols = 0; for (i = 0; i < ncols; i++) { fname = PQfname(res, i); get_column_info(res, i, &pgtype, &gpgtype, &sqltype, &fsize); G_debug(3, "col: %s, kcols %d, pgtype : %d, gpgtype : %d, sqltype %d, fsize : %d", fname, kcols, pgtype, gpgtype, sqltype, fsize); /* PG types defined in globals.h (and pg_type.h) */ if (sqltype == DB_SQL_TYPE_UNKNOWN) { if (gpgtype == PG_TYPE_POSTGIS_GEOM) { G_warning(_("PostgreSQL driver: PostGIS column '%s', type 'geometry' " "will not be converted"), fname); continue; } else { /* Warn, ignore and continue */ G_warning(_("PostgreSQL driver: column '%s', type %d is not supported"), fname, pgtype); continue; } } if (gpgtype == PG_TYPE_INT8) G_warning(_("column '%s' : type int8 (bigint) is stored as integer (4 bytes) " "some data may be damaged"), fname); if (gpgtype == PG_TYPE_VARCHAR && fsize < 0) { G_warning(_("column '%s' : type character varying is stored as varchar(250) " "some data may be lost"), fname); fsize = 250; } if (gpgtype == PG_TYPE_BOOL) G_warning(_("column '%s' : type bool (boolean) is stored as char(1), values: 0 (false), " "1 (true)"), fname); column = db_get_table_column(*table, kcols); db_set_column_name(column, fname); db_set_column_length(column, fsize); db_set_column_host_type(column, gpgtype); db_set_column_sqltype(column, sqltype); /* TODO */ precision = 0; scale = 0; /* db_set_column_precision (column, precision); db_set_column_scale (column, scale); */ /* TODO */ db_set_column_null_allowed(column); db_set_column_has_undefined_default_value(column); db_unset_column_use_default_value(column); /* TODO */ /* db_set_column_select_priv_granted (column); db_set_column_update_priv_granted (column); db_set_column_update_priv_not_granted (column); */ if (c) { c->cols[kcols] = i; } kcols++; } return DB_OK; }