diff options
author | Stefan Metzmacher <metze@samba.org> | 2021-08-05 11:26:16 +0200 |
---|---|---|
committer | Jule Anger <janger@samba.org> | 2021-11-08 10:52:13 +0100 |
commit | 5337dc5eaeb7abba3aeb73cc6ef0471ffc9e7bc8 (patch) | |
tree | 2d8e142eeda991a6c1443292bda53ab7f9773b2b | |
parent | ec1ea05e8f1dcca14ed7a92a0645da9ff73f33d3 (diff) | |
download | samba-5337dc5eaeb7abba3aeb73cc6ef0471ffc9e7bc8.tar.gz |
CVE-2021-3738 s4:torture/drsuapi: DsBindAssocGroup* tests
This adds a reproducer for an invalid memory access, when
using the context handle from DsBind across multiple connections
within an association group.
BUG: https://bugzilla.samba.org/show_bug.cgi?id=14468
Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
-rw-r--r-- | selftest/knownfail.d/drsuapi.DsBindAssocGroupWS | 1 | ||||
-rw-r--r-- | source4/torture/rpc/drsuapi.c | 172 |
2 files changed, 173 insertions, 0 deletions
diff --git a/selftest/knownfail.d/drsuapi.DsBindAssocGroupWS b/selftest/knownfail.d/drsuapi.DsBindAssocGroupWS new file mode 100644 index 00000000000..9af5a904fdd --- /dev/null +++ b/selftest/knownfail.d/drsuapi.DsBindAssocGroupWS @@ -0,0 +1 @@ +^samba4.rpc.drsuapi.*drsuapi.DsBindAssocGroupWS diff --git a/source4/torture/rpc/drsuapi.c b/source4/torture/rpc/drsuapi.c index 3e8105af07b..1cd8f77db9c 100644 --- a/source4/torture/rpc/drsuapi.c +++ b/source4/torture/rpc/drsuapi.c @@ -25,6 +25,7 @@ #include "lib/cmdline/popt_common.h" #include "librpc/gen_ndr/ndr_drsuapi_c.h" #include "torture/rpc/torture_rpc.h" +#include "libcli/security/dom_sid.h" #include "param/param.h" #define TEST_MACHINE_NAME "torturetest" @@ -845,6 +846,173 @@ static bool torture_drsuapi_tcase_teardown(struct torture_context *tctx, void *d return ret; } +static bool __test_DsBind_assoc_group(struct torture_context *tctx, + const char *testname, + struct DsPrivate *priv, + struct cli_credentials *creds) +{ + NTSTATUS status; + const char *err_msg; + struct drsuapi_DsCrackNames r; + union drsuapi_DsNameRequest req; + uint32_t level_out; + union drsuapi_DsNameCtr ctr; + struct drsuapi_DsNameString names[1]; + const char *dom_sid = NULL; + struct dcerpc_pipe *p1 = NULL; + struct dcerpc_pipe *p2 = NULL; + TALLOC_CTX *mem_ctx = priv; + struct dcerpc_binding *binding = NULL; + struct policy_handle ds_bind_handle = { .handle_type = 0, }; + + torture_comment(tctx, "%s: starting...\n", testname); + + torture_assert_ntstatus_ok(tctx, + torture_rpc_binding(tctx, &binding), + "torture_rpc_binding"); + + torture_assert_ntstatus_ok(tctx, + dcerpc_pipe_connect_b(tctx, + &p1, + binding, + &ndr_table_drsuapi, + creds, + tctx->ev, + tctx->lp_ctx), + "connect p1"); + + torture_assert_ntstatus_ok(tctx, + dcerpc_pipe_connect_b(tctx, + &p2, + p1->binding, + &ndr_table_drsuapi, + creds, + tctx->ev, + tctx->lp_ctx), + "connect p2"); + + torture_assert(tctx, test_DsBind(p1, tctx, &ds_bind_handle, NULL), "DsBind"); + + ZERO_STRUCT(r); + r.in.bind_handle = &ds_bind_handle; + r.in.level = 1; + r.in.req = &req; + r.in.req->req1.codepage = 1252; /* german */ + r.in.req->req1.language = 0x00000407; /* german */ + r.in.req->req1.count = 1; + r.in.req->req1.names = names; + r.in.req->req1.format_flags = DRSUAPI_DS_NAME_FLAG_NO_FLAGS; + + r.in.req->req1.format_offered = DRSUAPI_DS_NAME_FORMAT_SID_OR_SID_HISTORY; + r.in.req->req1.format_desired = DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT; + + r.out.level_out = &level_out; + r.out.ctr = &ctr; + + dom_sid = dom_sid_string(mem_ctx, torture_join_sid(priv->join)); + + names[0].str = dom_sid; + + torture_comment(tctx, "Testing DsCrackNames on p1 with name '%s'" + " offered format: %d desired format:%d\n", + names[0].str, + r.in.req->req1.format_offered, + r.in.req->req1.format_desired); + status = dcerpc_drsuapi_DsCrackNames_r(p1->binding_handle, mem_ctx, &r); + if (!NT_STATUS_IS_OK(status)) { + const char *errstr = nt_errstr(status); + err_msg = talloc_asprintf(mem_ctx, "dcerpc_drsuapi_DsCrackNames failed - %s", errstr); + torture_fail(tctx, err_msg); + } else if (!W_ERROR_IS_OK(r.out.result)) { + err_msg = talloc_asprintf(mem_ctx, "DsCrackNames failed - %s", win_errstr(r.out.result)); + torture_fail(tctx, err_msg); + } else if (r.out.ctr->ctr1->array[0].status != DRSUAPI_DS_NAME_STATUS_OK) { + err_msg = talloc_asprintf(mem_ctx, "DsCrackNames failed on name - %d", + r.out.ctr->ctr1->array[0].status); + torture_fail(tctx, err_msg); + } + + torture_comment(tctx, "Testing DsCrackNames on p2 with name '%s'" + " offered format: %d desired format:%d\n", + names[0].str, + r.in.req->req1.format_offered, + r.in.req->req1.format_desired); + status = dcerpc_drsuapi_DsCrackNames_r(p2->binding_handle, mem_ctx, &r); + if (!NT_STATUS_IS_OK(status)) { + const char *errstr = nt_errstr(status); + err_msg = talloc_asprintf(mem_ctx, "dcerpc_drsuapi_DsCrackNames failed - %s", errstr); + torture_fail(tctx, err_msg); + } else if (!W_ERROR_IS_OK(r.out.result)) { + err_msg = talloc_asprintf(mem_ctx, "DsCrackNames failed - %s", win_errstr(r.out.result)); + torture_fail(tctx, err_msg); + } else if (r.out.ctr->ctr1->array[0].status != DRSUAPI_DS_NAME_STATUS_OK) { + err_msg = talloc_asprintf(mem_ctx, "DsCrackNames failed on name - %d", + r.out.ctr->ctr1->array[0].status); + torture_fail(tctx, err_msg); + } + + TALLOC_FREE(p1); + + torture_comment(tctx, "Testing DsCrackNames on p2 (with p1 closed) with name '%s'" + " offered format: %d desired format:%d\n", + names[0].str, + r.in.req->req1.format_offered, + r.in.req->req1.format_desired); + status = dcerpc_drsuapi_DsCrackNames_r(p2->binding_handle, mem_ctx, &r); + if (!NT_STATUS_IS_OK(status)) { + const char *errstr = nt_errstr(status); + err_msg = talloc_asprintf(mem_ctx, "dcerpc_drsuapi_DsCrackNames failed - %s", errstr); + torture_fail(tctx, err_msg); + } else if (!W_ERROR_IS_OK(r.out.result)) { + err_msg = talloc_asprintf(mem_ctx, "DsCrackNames failed - %s", win_errstr(r.out.result)); + torture_fail(tctx, err_msg); + } else if (r.out.ctr->ctr1->array[0].status != DRSUAPI_DS_NAME_STATUS_OK) { + err_msg = talloc_asprintf(mem_ctx, "DsCrackNames failed on name - %d", + r.out.ctr->ctr1->array[0].status); + torture_fail(tctx, err_msg); + } + + torture_comment(tctx, "%s: ... finished\n", testname); + return true; +} + +static bool test_DsBindAssocGroupAdmin(struct torture_context *tctx, + struct DsPrivate *priv, + struct cli_credentials *creds) +{ + return __test_DsBind_assoc_group(tctx, __func__, priv, + priv->admin_credentials); +} + +static bool test_DsBindAssocGroupDC(struct torture_context *tctx, + struct DsPrivate *priv, + struct cli_credentials *creds) +{ + return __test_DsBind_assoc_group(tctx, __func__, priv, + priv->dc_credentials); +} + +static bool test_DsBindAssocGroupWS(struct torture_context *tctx, + struct DsPrivate *priv, + struct cli_credentials *creds) +{ + struct test_join *wks_join = NULL; + struct cli_credentials *wks_credentials = NULL; + int rnd = rand() % 1000; + char *wks_name = talloc_asprintf(tctx, "WKS%s%d", TEST_MACHINE_NAME, rnd); + bool ret; + + torture_comment(tctx, "%s: About to join workstation with name %s\n", + __func__, wks_name); + wks_join = torture_join_domain(tctx, wks_name, ACB_WSTRUST, + &wks_credentials); + torture_assert(tctx, wks_join, "Failed to join as WORKSTATION"); + ret = __test_DsBind_assoc_group(tctx, __func__, priv, + wks_credentials); + torture_leave_domain(tctx, wks_join); + return ret; +} + /** * DRSUAPI test case implementation */ @@ -874,4 +1042,8 @@ void torture_rpc_drsuapi_tcase(struct torture_suite *suite) torture_tcase_add_simple_test(tcase, "DsReplicaUpdateRefs", (run_func)test_DsReplicaUpdateRefs); torture_tcase_add_simple_test(tcase, "DsGetNCChanges", (run_func)test_DsGetNCChanges); + + torture_tcase_add_simple_test(tcase, "DsBindAssocGroupAdmin", (run_func)test_DsBindAssocGroupAdmin); + torture_tcase_add_simple_test(tcase, "DsBindAssocGroupDC", (run_func)test_DsBindAssocGroupDC); + torture_tcase_add_simple_test(tcase, "DsBindAssocGroupWS", (run_func)test_DsBindAssocGroupWS); } |