Vulnerability: s2s/out.c in jabberd2 2.2.16 and earlier does not verify that a request was made for an XMPP Server Dialback response, which allows remote XMPP servers to spoof domains via a (1) Verify Response or (2) Authorization Response.
Vulnerability ID: CVE-2012-3525
CWE: CWE-20
Severity score: 4.9
Project: https://github.com/Jabberd2/jabberd2
Published: 2012-08-25
File: s2s/out.c
Commit message: Fixed possibility of Unsolicited Dialback Attacks
Commit author: Tomasz Sterna

Vulnerable version (before fix):
 static void _out_result(conn_t out, nad_t nad) {     rkeylen = strlen(rkey);      /* key is valid */     if(nad_find_attr(nad, 0, -1, "type", "valid") >= 0) {         log_write(out->s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] outgoing route '%s' is now valid%s%s", out->fd->fd, out->ip, out->port, rkey, (out->s->flags & SX_SSL_WRAPPER) ? ", TLS negotiated" : "", out->s->compressed ? ", ZLIB compression enabled" : "");          xhash_put(out->states, pstrdup(xhash_pool(out->states), rkey), (void *) conn_VALID);    /* !!! small leak here */ static void _out_verify(conn_t out, nad_t nad) {     rkey = s2s_route_key(NULL, to->domain, from->domain);      attr = nad_find_attr(nad, 0, -1, "type", "valid");     if(attr >= 0) {         xhash_put(in->states, pstrdup(xhash_pool(in->states), rkey), (void *) conn_VALID);         log_write(in->s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] incoming route '%s' is now valid%s%s", in->fd->fd, in->ip, in->port, rkey, (in->s->flags & SX_SSL_WRAPPER) ? ", TLS negotiated" : "", in->s->compressed ? ", ZLIB compression enabled" : "");         valid = 1;

Fixed version (after fix):
 static void _out_result(conn_t out, nad_t nad) {     rkeylen = strlen(rkey);      /* key is valid */     if(nad_find_attr(nad, 0, -1, "type", "valid") >= 0 && xhash_get(out->states, rkey) == (void*) conn_INPROGRESS) {         log_write(out->s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] outgoing route '%s' is now valid%s%s", out->fd->fd, out->ip, out->port, rkey, (out->s->flags & SX_SSL_WRAPPER) ? ", TLS negotiated" : "", out->s->compressed ? ", ZLIB compression enabled" : "");          xhash_put(out->states, pstrdup(xhash_pool(out->states), rkey), (void *) conn_VALID);    /* !!! small leak here */ static void _out_verify(conn_t out, nad_t nad) {     rkey = s2s_route_key(NULL, to->domain, from->domain);      attr = nad_find_attr(nad, 0, -1, "type", "valid");     if(attr >= 0 && xhash_get(in->states, rkey) == (void*) conn_INPROGRESS) {         xhash_put(in->states, pstrdup(xhash_pool(in->states), rkey), (void *) conn_VALID);         log_write(in->s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] incoming route '%s' is now valid%s%s", in->fd->fd, in->ip, in->port, rkey, (in->s->flags & SX_SSL_WRAPPER) ? ", TLS negotiated" : "", in->s->compressed ? ", ZLIB compression enabled" : "");         valid = 1;

Patch:
patch: @@ -1661,7 +1661,7 @@ static void _out_result(conn_t out, nad_t nad) {
     rkeylen = strlen(rkey);
 
     /* key is valid */
-    if(nad_find_attr(nad, 0, -1, "type", "valid") >= 0) {
+    if(nad_find_attr(nad, 0, -1, "type", "valid") >= 0 && xhash_get(out->states, rkey) == (void*) conn_INPROGRESS) {
         log_write(out->s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] outgoing route '%s' is now valid%s%s", out->fd->fd, out->ip, out->port, rkey, (out->s->flags & SX_SSL_WRAPPER) ? ", TLS negotiated" : "", out->s->compressed ? ", ZLIB compression enabled" : "");
 
         xhash_put(out->states, pstrdup(xhash_pool(out->states), rkey), (void *) conn_VALID);    /* !!! small leak here */
@@ -1749,7 +1749,7 @@ static void _out_verify(conn_t out, nad_t nad) {
     rkey = s2s_route_key(NULL, to->domain, from->domain);
 
     attr = nad_find_attr(nad, 0, -1, "type", "valid");
-    if(attr >= 0) {
+    if(attr >= 0 && xhash_get(in->states, rkey) == (void*) conn_INPROGRESS) {
         xhash_put(in->states, pstrdup(xhash_pool(in->states), rkey), (void *) conn_VALID);
         log_write(in->s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] incoming route '%s' is now valid%s%s", in->fd->fd, in->ip, in->port, rkey, (in->s->flags & SX_SSL_WRAPPER) ? ", TLS negotiated" : "", in->s->compressed ? ", ZLIB compression enabled" : "");
         valid = 1;
path: s2s/out.c