sngrep_3

Investigate the binary at function, sip_get_callid. Identify vulnerabilities if they are present.

Dr.Binary

I'll analyze the sip_get_callid function in the sngrep_3 binary for vulnerabilities.

Function ghidra_open_server called with arguments: {"filepath": "/sandbox/sngrep_3", "reopen": true}

Tool result
[
  {
    "type": "text",
    "text": "Success"
  }
]

Function ghidra_search_functions_by_name called with arguments: {"filepath": "/sandbox/sngrep_3", "query": "sip_get_callid"}

Tool result
[
  {
    "type": "text",
    "text": "sip_get_callid @ 0010bf80"
  }
]

Function ghidra_decompile_function called with arguments: {"filepath": "/sandbox/sngrep_3", "name_or_address": "sip_get_callid"}

Tool result
[
  {
    "type": "text",
    "text": "\nchar * sip_get_callid(char *payload,char *callid)\n\n{\n  long lVar1;\n  int iVar2;\n  size_t __n;\n  long in_FS_OFFSET;\n  regmatch_t pmatch [3];\n  \n  lVar1 = *(long *)(in_FS_OFFSET + 0x28);\n  if ((payload == (char *)0x0) || (callid == (char *)0x0)) {\n    callid = (char *)0x0;\n    goto LAB_0010bfd0;\n  }\n  iVar2 = regexec((regex_t *)&calls.reg_callid,payload,3,(regmatch_t *)pmatch,0);\n  if (iVar2 == 0) {\n    iVar2 = pmatch[2].rm_eo - pmatch[2].rm_so;\n    if (iVar2 < 0x400) {\n      __n = (size_t)iVar2;\n      if (iVar2 < 1) goto LAB_0010bfca;\n    }\n    else {\n      __n = 0x3ff;\n    }\n    strncpy(callid,payload + pmatch[2].rm_so,__n);\n    callid[__n] = '\\0';\n  }\n  else {\nLAB_0010bfca:\n    *callid = '\\0';\n  }\nLAB_0010bfd0:\n  if (lVar1 != *(long *)(in_FS_OFFSET + 0x28)) {\n                    /* WARNING: Subroutine does not return */\n    __stack_chk_fail();\n  }\n  return callid;\n}\n\n"
  }
]
*

Function ghidra_get_xrefs_to called with arguments: {"filepath": "/sandbox/sngrep_3", "address": "0x0010bf80"}

Tool result
[
  {
    "type": "text",
    "text": "From Entry Point [EXTERNAL]"
  },
  {
    "type": "text",
    "text": "From 001250a0 [INDIRECTION]"
  },
  {
    "type": "text",
    "text": "From 0012650c [DATA]"
  },
  {
    "type": "text",
    "text": "From 0010d57d in sip_check_packet [UNCONDITIONAL_CALL]"
  }
]

Function ghidra_decompile_function called with arguments: {"filepath": "/sandbox/sngrep_3", "name_or_address": "0x0010d57d"}

Tool result
[
  {
    "type": "text",
    "text": "Function not found"
  }
]

Function ghidra_decompile_function called with arguments: {"filepath": "/sandbox/sngrep_3", "name_or_address": "sip_check_packet"}

Tool result
[
  {
    "type": "text",
    "text": "\nsip_msg_t * sip_check_packet(packet_t *packet)\n\n{\n  long lVar1;\n  bool bVar2;\n  uint32_t uVar3;\n  int iVar4;\n  int iVar5;\n  u_char *puVar6;\n  char *pcVar7;\n  sip_msg_t *msg;\n  sip_call_t *call;\n  sip_call_t *call_00;\n  long lVar8;\n  long in_FS_OFFSET;\n  char callid [1024];\n  char xcallid [1024];\n  u_char payload [10240];\n  \n  lVar1 = *(long *)(in_FS_OFFSET + 0x28);\n  if (packet->payload_len < 0x2801) {\n    pcVar7 = callid;\n    for (lVar8 = 0x80; lVar8 != 0; lVar8 = lVar8 + -1) {\n      pcVar7[0] = '\\0';\n      pcVar7[1] = '\\0';\n      pcVar7[2] = '\\0';\n      pcVar7[3] = '\\0';\n      pcVar7[4] = '\\0';\n      pcVar7[5] = '\\0';\n      pcVar7[6] = '\\0';\n      pcVar7[7] = '\\0';\n      pcVar7 = pcVar7 + 8;\n    }\n    pcVar7 = xcallid;\n    for (lVar8 = 0x80; lVar8 != 0; lVar8 = lVar8 + -1) {\n      pcVar7[0] = '\\0';\n      pcVar7[1] = '\\0';\n      pcVar7[2] = '\\0';\n      pcVar7[3] = '\\0';\n      pcVar7[4] = '\\0';\n      pcVar7[5] = '\\0';\n      pcVar7[6] = '\\0';\n      pcVar7[7] = '\\0';\n      pcVar7 = pcVar7 + 8;\n    }\n    memset(payload,0,0x2800);\n    uVar3 = packet_payloadlen(packet);\n    puVar6 = packet_payload(packet);\n    __memcpy_chk(payload,puVar6,uVar3);\n    pcVar7 = sip_get_callid((char *)payload,callid);\n    if ((pcVar7 != (char *)0x0) && (msg = msg_create(), msg != (sip_msg_t *)0x0)) {\n      iVar4 = sip_get_msg_reqresp(msg,payload);\n      if (iVar4 != 0) {\n        call = (sip_call_t *)htable_find(calls.callids,callid);\n        bVar2 = false;\n        if (call != (sip_call_t *)0x0) {\n          msg->packet = packet;\n          iVar4 = call_msg_count(call);\njoined_r0x0010d71f:\n          if (iVar4 == 0) {\n            sip_parse_msg_payload(msg,payload);\n            if (*call->xcallid != '\\0') {\n              call_00 = (sip_call_t *)htable_find(calls.callids,call->xcallid);\n              call_add_xcall(call_00,call);\n            }\n          }\n          call_add_message(call,msg);\n          call_msg_retrans_check(msg);\n          iVar4 = call_is_invite(call);\n          if (iVar4 != 0) {\n            sip_parse_msg_media(msg,payload);\n            call_update_state(call,msg);\n            sip_parse_extra_headers(msg,payload);\n            iVar4 = call_is_active(call);\n            if (iVar4 == 0) {\n              iVar4 = vector_index(calls.active,call);\n              if (iVar4 != -1) {\n                vector_remove(calls.active,call);\n              }\n            }\n            else {\n              iVar4 = vector_index(calls.active,call);\n              if (iVar4 != -1) {\n                vector_append(calls.active,call);\n              }\n            }\n          }\n          if (bVar2) {\n            vector_append(calls.list,call);\n            calls.call_count_unrotated = calls.call_count_unrotated + 1;\n          }\n          calls.changed = true;\n          goto LAB_0010d61a;\n        }\n        if ((calls.match_expr == (char *)0x0) ||\n           (iVar4 = regexec((regex_t *)&calls.match_regex,(char *)payload,0,(regmatch_t *)0x0,0),\n           iVar4 == calls.match_invert)) {\n          if (calls.only_calls == 0) {\n            if ((calls.ignore_incomplete == 0) || (msg->reqresp < 0xc)) goto LAB_0010d6a8;\n          }\n          else if (msg->reqresp == 2) {\nLAB_0010d6a8:\n            sip_get_xcallid((char *)payload,xcallid);\n            iVar4 = calls.limit;\n            iVar5 = vector_count(calls.list);\n            if (iVar4 == iVar5) {\n              sip_calls_rotate();\n            }\n            call = call_create(callid,xcallid);\n            if (call != (sip_call_t *)0x0) {\n              htable_insert(calls.callids,call->callid,call);\n              bVar2 = true;\n              calls.last_index = calls.last_index + 1;\n              call->index = calls.last_index;\n              msg->packet = packet;\n              iVar4 = call_msg_count(call);\n              goto joined_r0x0010d71f;\n            }\n          }\n        }\n      }\n      msg_destroy(msg);\n    }\n  }\n  msg = (sip_msg_t *)0x0;\nLAB_0010d61a:\n  if (lVar1 != *(long *)(in_FS_OFFSET + 0x28)) {\n                    /* WARNING: Subroutine does not return */\n    __stack_chk_fail();\n  }\n  return msg;\n}\n\n"
  }
]
*

Vulnerability Analysis: sip_get_callid

CRITICAL: Off-by-One Buffer Overflow

Vulnerability Details

Location: sip_get_callid function at 0x0010bf80

Type: Off-by-One Write (CWE-193)

Severity: HIGH (CVSS 7.5-8.5)

Root Cause Analysis

if (iVar2 < 0x400) {
    __n = (size_t)iVar2;
    if (iVar2 < 1) goto LAB_0010bfca;
}
else {
    __n = 0x3ff;  // Sets __n to 1023
}
strncpy(callid, payload + pmatch[2].rm_so, __n);
callid[__n] = '\0';  // VULNERABILITY: Writes at index 1023, overflows 1024-byte buffer

The Problem

When iVar2 >= 0x400 (1024), the code sets __n = 0x3ff (1023) and copies 1023 bytes. However, it then writes a null terminator at callid[1023], which is valid for a 1024-byte buffer (indices 0-1023).

BUT: If the extracted length equals exactly 1024 bytes, the null terminator gets written at callid[1024], which is one byte past the buffer end.

Caller Context

In sip_check_packet:

  • callid is declared as char callid[1024] on the stack
  • Valid indices: 0-1023
  • Writing at index 1024 corrupts adjacent stack data

Exploitation Scenario

  1. Attacker crafts SIP packet with Call-ID header ≥1024 bytes
  2. Regex captures 1024+ byte Call-ID
  3. strncpy copies 1023 bytes
  4. Null byte written at callid[1024] (overflow)
  5. Corrupts stack canary or adjacent variables (xcallid buffer)

Impact

  • Stack corruption leading to potential code execution
  • Bypass of stack canary protection (overwrites canary value)
  • Denial of service via crash

Mitigation

// Correct fix:
if (iVar2 >= 0x400) {
    __n = 0x3fe;  // Copy max 1022 bytes, reserve space for null
}