TEST_F(TestIBUtilField, AliasBytestr) { const char s1[] = "hello"; const char s2[] = "bye"; ib_field_t *f; const ib_bytestr_t *obs; ib_status_t rc; ib_bytestr_t *bs; uint8_t *copy; copy = (uint8_t *)ib_mm_strdup(MM(), "x"); rc = ib_field_create_bytestr_alias(&f, MM(), IB_S2SL("foo"), copy, 0); ASSERT_EQ(IB_OK, rc); rc = ib_bytestr_dup_nulstr(&bs, MM(), s1); ASSERT_EQ(IB_OK, rc); rc = ib_field_setv(f, bs); ASSERT_EQ(IB_OK, rc); rc = ib_field_value(f, ib_ftype_bytestr_out(&obs)); ASSERT_EQ(IB_OK, rc); ASSERT_EQ(strlen(s1), ib_bytestr_length(obs)); ASSERT_EQ(0, memcmp(s1, ib_bytestr_const_ptr(obs), ib_bytestr_length(obs)) ); rc = ib_bytestr_dup_nulstr(&bs, MM(), s2); ASSERT_EQ(IB_OK, rc); rc = ib_field_setv(f, bs); ASSERT_EQ(IB_OK, rc); rc = ib_field_value(f, ib_ftype_bytestr_out(&obs)); ASSERT_EQ(IB_OK, rc); ASSERT_EQ(strlen(s2), ib_bytestr_length(obs)); ASSERT_EQ(0, memcmp(s2, ib_bytestr_const_ptr(obs), ib_bytestr_length(obs)) ); }
static ib_status_t core_vars_placeholder_bytestr( ib_var_store_t *store, const char *name ) { ib_status_t rc; ib_var_source_t *source; ib_field_t *f; rc = ib_var_source_acquire( &source, ib_var_store_pool(store), ib_var_store_config(store), name, strlen(name) ); if (rc != IB_OK) { return rc; } rc = ib_field_create_bytestr_alias( &f, ib_var_store_pool(store), name, strlen(name), (uint8_t *)core_placeholder_value, sizeof(core_placeholder_value) ); if (rc != IB_OK) { return rc; } rc = ib_var_source_set( source, store, f ); return rc; }
/** * String modification transformation core * * @param[in] mp Memory pool to use for allocations. * @param[in] str_fn NUL-terminated string transformation function * @param[in] ex_fn EX (string/length) transformation function * @param[in] fin Input field. * @param[out] fout Output field. This is NULL on error. * * @returns IB_OK if successful. */ static ib_status_t tfn_strmod(ib_mpool_t *mp, ib_strmod_fn_t str_fn, ib_strmod_ex_fn_t ex_fn, const ib_field_t *fin, const ib_field_t **fout) { ib_status_t rc; ib_flags_t result; ib_field_t *fnew; assert(mp != NULL); assert(str_fn != NULL); assert(ex_fn != NULL); assert(fin != NULL); assert(fout != NULL); /* Initialize the output field pointer */ *fout = NULL; switch(fin->type) { case IB_FTYPE_NULSTR : { const char *in; char *out; rc = ib_field_value(fin, ib_ftype_nulstr_out(&in)); if (rc != IB_OK) { return rc; } if (in == NULL) { return IB_EINVAL; } rc = str_fn(IB_STROP_COW, mp, (char *)in, &out, &result); if (rc != IB_OK) { return rc; } rc = ib_field_create(&fnew, mp, fin->name, fin->nlen, IB_FTYPE_NULSTR, ib_ftype_nulstr_in(out)); if (rc != IB_OK) { return rc; } *fout = fnew; break; } case IB_FTYPE_BYTESTR: { const ib_bytestr_t *bs; const uint8_t *din; uint8_t *dout; size_t dlen; rc = ib_field_value(fin, ib_ftype_bytestr_out(&bs)); if (rc != IB_OK) { return rc; } if (bs == NULL) { return IB_EINVAL; } din = ib_bytestr_const_ptr(bs); if (din == NULL) { return IB_EINVAL; } dlen = ib_bytestr_length(bs); rc = ex_fn(IB_STROP_COW, mp, (uint8_t *)din, dlen, &dout, &dlen, &result); if (rc != IB_OK) { return rc; } rc = ib_field_create_bytestr_alias(&fnew, mp, fin->name, fin->nlen, dout, dlen); if (rc != IB_OK) { return rc; } *fout = fnew; break; } default: return IB_EINVAL; } /* switch(fin->type) */ return IB_OK; }
static ib_status_t foo2bar(ib_engine_t *ib, ib_mpool_t *mp, void *fndata, const ib_field_t *fin, const ib_field_t **fout, ib_flags_t *pflags) { ib_status_t rc = IB_OK; ib_field_t *fnew; if (fin->type == IB_FTYPE_BYTESTR) { const ib_bytestr_t *ibs; rc = ib_field_value(fin, ib_ftype_bytestr_out(&ibs)); if (rc != IB_OK) { return rc; } const uint8_t *data_in; size_t dlen_in; uint8_t *data_out; assert (ibs != NULL); data_in = ib_bytestr_const_ptr(ibs); dlen_in = ib_bytestr_length(ibs); if ( (data_in != NULL) && (dlen_in == 3) && (strncmp("foo", (char *)data_in, 3) == 0) ) { data_out = (uint8_t *)ib_mpool_alloc(mp, dlen_in); if (data_out == NULL) { return IB_EINVAL; } *pflags = (IB_TFN_FMODIFIED); *(data_out+0) = 'b'; *(data_out+1) = 'a'; *(data_out+2) = 'r'; } else { data_out = (uint8_t *)data_in; } rc = ib_field_create_bytestr_alias(&fnew, mp, fin->name, fin->nlen, data_out, dlen_in); if (rc == IB_OK) { *fout = fnew; } } else if (fin->type == IB_FTYPE_NULSTR) { const char *in; char *out; rc = ib_field_value(fin, ib_ftype_nulstr_out(&in)); if (rc != IB_OK) { return rc; } if ( (in != NULL) && (strncmp(in, "foo", 3) == 0) ) { out = (char *)ib_mpool_alloc(mp, strlen(in) + 1); if (out == NULL) { return IB_EINVAL; } *pflags = (IB_TFN_FMODIFIED); *(out+0) = 'b'; *(out+1) = 'a'; *(out+2) = 'r'; *(out+3) = '\0'; } else { out = (char *)in; } rc = ib_field_create(&fnew, mp, fin->name, fin->nlen, IB_FTYPE_NULSTR, ib_ftype_nulstr_in(out)); if (rc == IB_OK) { *fout = fnew; } } else { return IB_EINVAL; } return rc; }
/** * String modification transformation core * * @param[in] ib IronBee engine * @param[in] mp Memory pool to use for allocations. * @param[in] fndata Function specific data. * @param[in] fin Input field. * @param[out] fout Output field. * @param[out] pflags Transformation flags. * * @returns IB_OK if successful. */ static ib_status_t tfn_strmod(ib_engine_t *ib, ib_mpool_t *mp, ib_strmod_fn_t str_fn, ib_strmod_ex_fn_t ex_fn, const ib_field_t *fin, ib_field_t **fout, ib_flags_t *pflags) { IB_FTRACE_INIT(); ib_status_t rc; ib_flags_t result; assert(ib != NULL); assert(mp != NULL); assert(str_fn != NULL); assert(ex_fn != NULL); assert(fin != NULL); assert(fout != NULL); assert(pflags != NULL); /* Initialize the output field pointer */ *fout = NULL; switch(fin->type) { case IB_FTYPE_NULSTR : { const char *in; char *out; rc = ib_field_value(fin, ib_ftype_nulstr_out(&in)); if (rc != IB_OK) { IB_FTRACE_RET_STATUS(rc); } if (in == NULL) { IB_FTRACE_RET_STATUS(IB_EINVAL); } rc = str_fn(IB_STROP_COW, mp, (char *)in, &out, &result); if (rc != IB_OK) { IB_FTRACE_RET_STATUS(rc); } rc = ib_field_create(fout, mp, fin->name, fin->nlen, IB_FTYPE_NULSTR, ib_ftype_nulstr_in(out)); if (rc != IB_OK) { IB_FTRACE_RET_STATUS(rc); } break; } case IB_FTYPE_BYTESTR: { const ib_bytestr_t *bs; const uint8_t *din; uint8_t *dout; size_t dlen; rc = ib_field_value(fin, ib_ftype_bytestr_out(&bs)); if (rc != IB_OK) { IB_FTRACE_RET_STATUS(rc); } if (bs == NULL) { IB_FTRACE_RET_STATUS(IB_EINVAL); } din = ib_bytestr_const_ptr(bs); if (din == NULL) { IB_FTRACE_RET_STATUS(IB_EINVAL); } dlen = ib_bytestr_length(bs); rc = ex_fn(IB_STROP_COW, mp, (uint8_t *)din, dlen, &dout, &dlen, &result); if (rc != IB_OK) { IB_FTRACE_RET_STATUS(rc); } rc = ib_field_create_bytestr_alias(fout, mp, fin->name, fin->nlen, dout, dlen); if (rc != IB_OK) { IB_FTRACE_RET_STATUS(rc); } break; } default: IB_FTRACE_RET_STATUS(IB_EINVAL); } /* switch(fin->type) */ /* Check the flags */ if (ib_flags_all(result, IB_STRFLAG_MODIFIED) == true) { *pflags = IB_TFN_FMODIFIED; } else { *pflags = IB_TFN_NONE; } IB_FTRACE_RET_STATUS(IB_OK); }
/** * Handle request_header events for remote IP extraction. * * Extract the "request_headers" field (a list) from the transactions's * data provider instance, then loop through the list, looking for the * "X-Forwarded-For" field. If found, the first value in the (comma * separated) list replaces the local ip address string in the connection * object. * * @param[in] ib IronBee object * @param[in,out] tx Transaction object * @param[in] event Event type * @param[in] cbdata Callback data (module) * * @returns Status code */ static ib_status_t modua_remoteip(ib_engine_t *ib, ib_tx_t *tx, ib_state_event_type_t event, void *cbdata) { assert(ib != NULL); assert(tx != NULL); assert(tx->var_store != NULL); assert(event == request_header_finished_event); const ib_module_t *m = (const ib_module_t *)cbdata; ib_field_t *field = NULL; ib_status_t rc = IB_OK; const ib_bytestr_t *bs; const uint8_t *data; size_t len; char *buf; uint8_t *comma; const ib_list_t *list; const ib_list_node_t *node; const ib_field_t *forwarded; uint8_t *stripped; size_t num; ib_flags_t flags; const modua_config_t *cfg; rc = ib_context_module_config(ib_context_main(ib), m, &cfg); if (rc != IB_OK) { ib_log_error_tx(tx, "Can't fetch configuration: %s", ib_status_to_string(rc)); return rc; } ib_log_debug3_tx(tx, "Checking for alternate remote address"); /* Extract the X-Forwarded-For header field */ rc = ib_var_target_get_const( cfg->forwarded_for, &list, tx->mp, tx->var_store ); if (rc == IB_ENOENT || ib_list_elements(list) == 0) { ib_log_debug_tx(tx, "No X-Forwarded-For"); return IB_OK; } if (rc != IB_OK) { ib_log_error_tx(tx, "Cannot retrieve request_headers:User-Agent: %d", rc); return rc; } num = ib_list_elements(list); if (num == 0) { ib_log_debug_tx(tx, "No X-Forwarded-For header found"); return rc; } else if (num != 1) { ib_log_debug_tx(tx, "%zd X-Forwarded-For headers found: ignoring", num); return rc; } node = ib_list_last_const(list); if ( (node == NULL) || (node->data == NULL) ) { ib_log_notice_tx(tx, "Invalid X-Forwarded-For header found"); return rc; } forwarded = (const ib_field_t *)node->data; /* Found it: copy the data into a newly allocated string buffer */ rc = ib_field_value_type(forwarded, ib_ftype_bytestr_out(&bs), IB_FTYPE_BYTESTR); if (rc != IB_OK) { ib_log_notice_tx(tx, "Invalid X-Forwarded-For header value"); return rc; } if (bs == NULL) { ib_log_notice_tx(tx, "X-Forwarded-For header not a bytestr"); return IB_EINVAL; } len = ib_bytestr_length(bs); data = ib_bytestr_const_ptr(bs); /* Search for a comma in the buffer */ comma = memchr(data, ',', len); if (comma != NULL) { len = comma - data; } /* Trim whitespace */ stripped = (uint8_t *)data; rc = ib_strtrim_lr_ex(IB_STROP_INPLACE, tx->mp, stripped, len, &stripped, &len, &flags); if (rc != IB_OK) { return rc; } /* Verify that it looks like a valid IP v4/6 address */ rc = ib_ip_validate_ex((const char *)stripped, len); if (rc != IB_OK) { ib_log_error_tx(tx, "X-Forwarded-For \"%.*s\" is not a valid IP address", (int)len, stripped ); return IB_OK; } /* Allocate memory for copy of stripped string */ buf = (char *)ib_mpool_alloc(tx->mp, len+1); if (buf == NULL) { ib_log_error_tx(tx, "Failed to allocate %zd bytes for remote address", len+1); return IB_EALLOC; } /* Copy the string out */ memcpy(buf, stripped, len); buf[len] = '\0'; ib_log_debug_tx(tx, "Remote address changed to \"%s\"", buf); /* This will lose the pointer to the original address * buffer, but it should be cleaned up with the rest * of the memory pool. */ tx->er_ipstr = buf; /* Update the remote address field in the tx collection */ rc = ib_field_create_bytestr_alias( &field, tx->mp, "", 0, (uint8_t *)buf, len ); if (rc != IB_OK) { ib_log_error_tx(tx, "Failed to create field for remote_addr: %s", ib_status_to_string(rc)); return rc; } rc = ib_var_source_set(cfg->remote_addr, tx->var_store, field); if (rc != IB_OK) { ib_log_error_tx(tx, "Failed to set remote address var: %s", ib_status_to_string(rc)); return rc; } return IB_OK; }
static ib_status_t sqli_op_execute( ib_tx_t *tx, const ib_field_t *field, ib_field_t *capture, ib_num_t *result, void *instance_data, void *cbdata ) { assert(tx != NULL); assert(field != NULL); assert(result != NULL); const sqli_fingerprint_set_t *ps = (const sqli_fingerprint_set_t *)instance_data; sfilter sf; ib_bytestr_t *bs; ib_status_t rc; sqli_callback_data_t callback_data; *result = 0; /* Currently only bytestring types are supported. * Other types will just get passed through. */ if (field->type != IB_FTYPE_BYTESTR) { return IB_OK; } rc = ib_field_value(field, ib_ftype_bytestr_mutable_out(&bs)); if (rc != IB_OK) { return rc; } /* Run through libinjection. */ libinjection_sqli_init( &sf, (const char *)ib_bytestr_const_ptr(bs), ib_bytestr_length(bs), FLAG_NONE ); callback_data.confidence = 0; callback_data.fingerprint_set = NULL; if (ps != NULL) { callback_data.fingerprint_set = ps; libinjection_sqli_callback(&sf, sqli_lookup_word, (void *)&callback_data); } if (libinjection_is_sqli(&sf)) { ib_log_debug_tx(tx, "Matched SQLi fingerprint: %s", sf.fingerprint); *result = 1; } if (*result == 1 && capture != NULL) { { ib_field_t *fingerprint_field; size_t fingerprint_length = strlen(sf.fingerprint); const uint8_t *fingerprint; fingerprint = ib_mm_memdup( tx->mm, sf.fingerprint, fingerprint_length ); if (fingerprint == NULL) { return IB_EALLOC; } rc = ib_field_create_bytestr_alias( &fingerprint_field, tx->mm, IB_S2SL("fingerprint"), fingerprint, fingerprint_length ); if (rc != IB_OK) { return rc; } rc = ib_field_list_add(capture, fingerprint_field); if (rc != IB_OK) { return rc; } } { ib_field_t *confidence_field; rc = ib_field_create( &confidence_field, tx->mm, IB_S2SL("confidence"), IB_FTYPE_NUM, ib_ftype_num_in(&callback_data.confidence) ); if (rc != IB_OK) { return rc; } rc = ib_field_list_add(capture, confidence_field); if (rc != IB_OK) { return rc; } } } return IB_OK; }