CVE-2008-1897 (C, published 2008-04-23T16:05Z)
Description: value: The IAX2 channel driver (chan_iax2) in Asterisk Open Source 1.0.x, 1.2.x before 1.2.28, and 1.4.x before 1.4.19.1; Business Edition A.x.x, B.x.x before B.2.5.2, and C.x.x before C.1.8.1; AsteriskNOW before 1.0.3; Appliance Developer Kit 0.x.x; and s800i before 1.1.0.3, when configured to allow unauthenticated calls, does not verify that an ACK response contains a call number matching the server's reply to a NEW message, which allows remote attackers to cause a denial of service (traffic amplification) via a spoofed ACK response that does not complete a 3-way handshake.  NOTE: this issue exists because of an incomplete fix for CVE-2008-1923.
Severity: MEDIUM (CVSS v3 base score: )
Weakness: CWE-287 \u2014 Improper Authentication
When an actor claims to have a given identity, the product does not prove or insufficiently proves that the claim is correct.
Repository: https://github.com/xrg/asterisk-xrg
Files changed:
channels/chan_iax2.c
Commit message: When we receive a full frame that is supposed to contain our call number,
ensure that it has the correct one.
(closes issue #10078)
(AST-2008-006)


Vulnerable code:
static int match(struct sockaddr_in *sin, unsigned short callno, unsigned short dcallno, struct chan_iax2_pvt *cur)
		if ((cur->peercallno == callno) ||
			((dcallno == cur->callno) && !cur->peercallno)) {
static int __find_callno(unsigned short callno, unsigned short dcallno, struct sockaddr_in *sin, int new, int sockfd, int return_locked)
				if (match(sin, callno, dcallno, iaxs[x])) {
				if (match(sin, callno, dcallno, iaxs[x])) {
		gettimeofday(&now, NULL);
		for (x=1;x<TRUNK_CALL_START;x++) {
			if (!iaxs[x] && ((now.tv_sec - lastused[x].tv_sec) > MIN_REUSE_TIME)) break;
		if (x >= TRUNK_CALL_START) {
static int find_callno(unsigned short callno, unsigned short dcallno, struct sockaddr_in *sin, int new, int sockfd) {
	return __find_callno(callno, dcallno, sin, new, sockfd, 0);
static int find_callno_locked(unsigned short callno, unsigned short dcallno, struct sockaddr_in *sin, int new, int sockfd) {
	return __find_callno(callno, dcallno, sin, new, sockfd, 1);
		fr->callno = find_callno(ntohs(vh->callno) & ~0x8000, dcallno, &sin, new, fd);
				fr->callno = find_callno_locked(callno & ~IAX_FLAG_FULL, 0, &sin, NEW_PREVENT, fd);
		fr->callno = find_callno(ntohs(mh->callno) & ~IAX_FLAG_FULL, dcallno, &sin, new, fd);
		reg->callno = find_callno_locked(0, 0, &reg->addr, NEW_FORCE, defaultsockfd);
	callno = find_callno_locked(0, 0, &sin, NEW_FORCE, cai.sockfd);
	peer->callno = find_callno(0, 0, &peer->addr, NEW_FORCE, peer->sockfd);
	callno = find_callno_locked(0, 0, &sin, NEW_FORCE, cai.sockfd);
	callno = find_callno_locked(0, 0, &sin, NEW_FORCE, cai.sockfd);

Fixed code:
static int match(struct sockaddr_in *sin, unsigned short callno, unsigned short dcallno, struct chan_iax2_pvt *cur, int full_frame)
		if ( (cur->peercallno == 0 || cur->peercallno == callno) &&
			 (full_frame ? dcallno == cur->callno : 1) ) {
static int __find_callno(unsigned short callno, unsigned short dcallno, struct sockaddr_in *sin, int new, int sockfd, int return_locked, int full_frame)
				if (match(sin, callno, dcallno, iaxs[x], full_frame)) {
				if (match(sin, callno, dcallno, iaxs[x], full_frame)) {
		int start, found = 0;


		now = ast_tvnow();
		start = 1 + (ast_random() % (TRUNK_CALL_START - 1));
		for (x = start; 1; x++) {
			if (x == TRUNK_CALL_START) {
				x = 0;
				continue;
			}

			if (!iaxs[x] && ((now.tv_sec - lastused[x].tv_sec) > MIN_REUSE_TIME)) {
				found = 1;
				break;
			}
			
			if (x == start - 1) {
				break;
			}
		if (x == start - 1 && !found) {
static int find_callno(unsigned short callno, unsigned short dcallno, struct sockaddr_in *sin, int new, int sockfd, int full_frame) {
	return __find_callno(callno, dcallno, sin, new, sockfd, 0, full_frame);
static int find_callno_locked(unsigned short callno, unsigned short dcallno, struct sockaddr_in *sin, int new, int sockfd, int full_frame) {
	return __find_callno(callno, dcallno, sin, new, sockfd, 1, full_frame);
		fr->callno = find_callno(ntohs(vh->callno) & ~0x8000, dcallno, &sin, new, fd, 0);
				fr->callno = find_callno_locked(callno & ~IAX_FLAG_FULL, 0, &sin, NEW_PREVENT, fd, 0);
		fr->callno = find_callno(ntohs(mh->callno) & ~IAX_FLAG_FULL, dcallno, &sin, new, fd, ntohs(mh->callno) & IAX_FLAG_FULL);
		reg->callno = find_callno_locked(0, 0, &reg->addr, NEW_FORCE, defaultsockfd, 0);
	callno = find_callno_locked(0, 0, &sin, NEW_FORCE, cai.sockfd, 0);
	peer->callno = find_callno(0, 0, &peer->addr, NEW_FORCE, peer->sockfd, 0);
	callno = find_callno_locked(0, 0, &sin, NEW_FORCE, cai.sockfd, 0);
	callno = find_callno_locked(0, 0, &sin, NEW_FORCE, cai.sockfd, 0);