### Gowap's botnet stats system v5.18 ## # Noyga ### variables ### # 1j bottree timeout set bottree-timeout 86400 # 12j known-bot timeout set knownbot-timeout 777777 set bottree_file "./scripts/info.cfg" set linked_bots "" set known_bots "" set timeout_bots "" set max_botcount 0 set max_bottime [unixtime] set dcc.bold_color "\[1m" set dcc.link_color "\[1;32m" set dcc.unlink_color "\[1;31m" set dcc.stop_color "\[0m" set html.branch_color "#777799" set html.link_color "" set html.unlink_color "" set html.stop_color "" # fields: botnick uplink linktime unlinktime link-type set bottree_list "" ### list interface proc bnl:search_bot {bot} { global known_bots return [lsearch -exact [string tolower $known_bots] [string tolower $bot]] } proc bnl:search_linked_bot {bot} { global linked_bots return [lsearch -exact [string tolower $linked_bots] [string tolower $bot]] } proc bnl:read_bot {bot} { global bottree_list return [lindex $bottree_list [bnl:search_bot $bot]] } proc bnl:write_bot {bot hub linktime unlinktime link_type} { global known_bots global bottree_list set bot_index [bnl:search_bot $bot] if {$bot_index < 0} { lappend known_bots $bot lappend bottree_list [list $bot $hub $linktime $unlinktime $link_type] } else { set bottree_list [lreplace $bottree_list $bot_index $bot_index [list $bot $hub $linktime $unlinktime $link_type]] } } proc bnl:del_bot {bot} { global known_bots global bottree_list set bot_index [bnl:search_bot $bot] if {$bot_index >= 0} { set known_bots [ldelete $known_bots $bot_index] set bottree_list [ldelete $bottree_list $bot_index] } } proc bnl:list_downlinks {bot} { global bottree_list set sublist "" foreach botline $bottree_list { set rbot [lindex $botline 0] set lbot [lindex $botline 1] if {[string tolower $lbot] == [string tolower $bot]} { lappend sublist $rbot } } return $sublist } proc bnl:list_alldownlinks {bot} { global bottree_list global bottree-timeout set activelist "" set timeoutlist "" foreach botline $bottree_list { set rbot [lindex $botline 0] set lbot [lindex $botline 1] if {[string tolower $lbot] == [string tolower $bot]} { set unlink_time [lindex [bnl:read_bot $rbot] 3] if { ($unlink_time ==0) || ([expr [unixtime] - $unlink_time] < ${bottree-timeout})} { lappend activelist $rbot } else { lappend timeoutlist $rbot } } } return [list $activelist $timeoutlist] } proc bnl:list_subnet {bot} { global bottree_list set sublist [list [bnl:read_bot $bot]] foreach sbot [bnl:list_downlinks $bot] { set sublist [concat $sublist [bnl:list_subnet $sbot]] } return $sublist } ### bottree proc bnt:reset_depths {} { global bottree_depth global known_bots global timeout_bots set bottree_depth "" set timeout_bots "" foreach bot $known_bots { lappend bottree_depth [list $bot 0 0] } } proc bnt:get_depth {bot} { global bottree_depth global botnet-nick if {[string tolower $bot] == [string tolower ${botnet-nick}]} { return 0 } else { return [lindex [lindex $bottree_depth [bnl:search_bot $bot]] 1] } } proc bnt:get_depthcounts {bot} { global bottree_depth global botnet-nick if {[string tolower $bot] == [string tolower ${botnet-nick}]} { return 1 } else { return [lindex [lindex $bottree_depth [bnl:search_bot $bot]] 2] } } proc bnt:find_depths {bot} { global bottree_depth global timeout_bots set clevel [bnt:get_depth $bot] set cdepth_count [bnt:get_depthcounts $bot] set alldownlinks [bnl:list_alldownlinks $bot] set adownlinks [lindex $alldownlinks 0] set tdownlinks [lindex $alldownlinks 1] set timeout_bots [concat $timeout_bots $tdownlinks] set count [llength $adownlinks] foreach sbot $adownlinks { incr count -1 set bot_index [bnl:search_bot $sbot] set depth_count $cdepth_count lappend depth_count $count set bottree_depth [lreplace $bottree_depth $bot_index $bot_index [list $sbot [expr $clevel + 1] $depth_count]] bnt:find_depths $sbot } foreach sbot $tdownlinks { set bot_index [bnl:search_bot $sbot] set depth_count $cdepth_count lappend depth_count 0 set bottree_depth [lreplace $bottree_depth $bot_index $bot_index [list $sbot [expr $clevel + 1] $depth_count]] bnt:find_depths $sbot } } proc print_subtree {bot idx} { global botnet-nick global dcc.link_color global dcc.unlink_color global dcc.stop_color set tree_string "" set cdepth [bnt:get_depth $bot] set cdepth_count [bnt:get_depthcounts $bot] for {set sdepth 1} {$sdepth <= $cdepth} {incr sdepth} { if {[lindex $cdepth_count $sdepth] != 0} { append tree_string " |" } elseif {$sdepth == $cdepth} { append tree_string " `" } else { append tree_string " " } } set botline [bnl:read_bot $bot] if {([lindex $botline 3] == 0) || ($bot == ${botnet-nick})} { set color ${dcc.link_color} } else { set color ${dcc.unlink_color} } putdcc $idx "${tree_string}[lindex $botline 4]${color}${bot}${dcc.stop_color}" foreach sbot [lindex [bnl:list_alldownlinks $bot] 0] { print_subtree $sbot $idx } } proc html_subtree {bot fd} { global botnet-nick global bottree-timeout global timeout_bots global html.branch_color global html.link_color global html.unlink_color global html.stop_color set tree_string "" set botline [bnl:read_bot $bot] set unlinktime [lindex $botline 3] if {$unlinktime == ""} { set unlinktime [unixtime] } set cdepth [bnt:get_depth $bot] set cdepth_count [bnt:get_depthcounts $bot] for {set sdepth 1} {$sdepth <= $cdepth} {incr sdepth} { if {[lindex $cdepth_count $sdepth] != 0} { append tree_string "|" } elseif {$sdepth == $cdepth} { append tree_string "`" } else { append tree_string "" } } if {([lindex $botline 3] == 0) || ($bot == ${botnet-nick})} { set color ${html.link_color} } else { set color ${html.unlink_color} } puts $fd "${tree_string}[lindex $botline 4]${color}${bot}${html.stop_color}" foreach sbot [lindex [bnl:list_alldownlinks $bot] 0] { html_subtree $sbot $fd } } proc print_list {ilist title cols idx} { set ilist [lsort -dictionary $ilist] set listlength [llength $ilist] putdcc $idx $title for {set botcs 0} {$botcs < $listlength} {incr botcs $cols} { putdcc $idx "[lrange $ilist $botcs [expr $botcs - 1 + $cols]]" } } proc html_list {ilist title cols fd} { set ilist [lsort -dictionary $ilist] set listlength [llength $ilist] puts $fd "" puts $fd "" for {set botcs 0} {$botcs < $listlength} {incr botcs $cols} { set col_string "" for {set boti $botcs} {$boti < [expr $botcs + $cols]} {incr boti} { append col_string "" } puts $fd "$col_string" } puts $fd "
$title[lindex $ilist $boti]
" } proc print_tree {idx} { global botnet-nick global known_bots global linked_bots global timeout_bots global max_botcount global max_bottime global dcc.bold_color global dcc.link_color global dcc.unlink_color global dcc.stop_color bnt:reset_depths bnt:find_depths ${botnet-nick} print_subtree ${botnet-nick} $idx putdcc $idx "${dcc.bold_color}[llength $known_bots] bot(s) connu(s)${dcc.stop_color}" putdcc $idx "[llength $linked_bots] bot(s) ${dcc.link_color}linké(s)${dcc.stop_color} (max: $max_botcount bots le [fr_date $max_bottime])" putdcc $idx "[expr [llength $known_bots] - [llength $linked_bots]] bot(s) ${dcc.unlink_color}non linké(s)${dcc.stop_color} dont [llength $timeout_bots] non représentés " if {[llength $timeout_bots] > 0} { print_list $timeout_bots "Autres bots non linkés depuis plus d'un jour" 9 $idx } } proc html_tree {file} { global timezone global botnet-nick global known_bots global linked_bots global timeout_bots global max_botcount global max_bottime global knownbot-timeout global html.link_color global html.unlink_color global html.stop_color set fd [open $file "w"] bnt:reset_depths puts $fd "" puts $fd "" puts $fd " Le botnet vu de ${botnet-nick}" puts $fd " " puts $fd " " puts $fd " " puts $fd "" puts $fd "" puts $fd "Le botnet vu de ${botnet-nick} le [fr_date [unixtime]]" bnt:find_depths ${botnet-nick} puts $fd "

[llength $known_bots] bot(s) connu(s)
" puts $fd "${html.link_color}[llength $linked_bots] bot(s) linké(s)${html.stop_color} (max: $max_botcount bots le [fr_date $max_bottime])
" puts $fd "${html.unlink_color}[expr [llength $known_bots] - [llength $linked_bots]] bot(s) non linké(s)${html.stop_color} dont [llength $timeout_bots] non représentés
" puts $fd "" html_subtree ${botnet-nick} $fd puts $fd "
" if {[llength $timeout_bots] > 0} { puts $fd "

" html_list $timeout_bots "Autres bots non linkés depuis plus d'un jour" 10 $fd } puts $fd "

Mise à jour toutes les 5 minutes
" puts $fd "

Durée de mémorisation des bots: [hr_time ${knownbot-timeout}]" puts $fd "

botstats.tcl © Noyga, 2001
" puts $fd "" puts $fd "" flush $fd close $fd } ### file interface proc bnf:store_tree {file} { global max_botcount global max_bottime global bottree_list set fd [open $file "w"] puts $fd [list $max_botcount $max_bottime] foreach botline $bottree_list { puts $fd $botline } flush $fd close $fd } proc bnf:read_tree {file} { global max_botcount global max_bottime global bottree_list global known_bots set fd [open $file "r"] set known_bots "" set bottree_list "" set maxline [gets $fd] set max_botcount [lindex $maxline 0] set max_bottime [lindex $maxline 1] while {![eof $fd]} { set botline [gets $fd] if {$botline != ""} { lappend known_bots [lindex $botline 0] lappend bottree_list $botline } } close $fd } ### botnet interface proc bnn:get_bot {bot} { set botprop "" foreach botline [botlist] { set lbot [lindex $botline 0] if {[string tolower $lbot] == [string tolower $bot]} { return $botline } } return "" } proc bnn:list_downlinks {bot} { set sublist "" foreach botline [botlist] { set rbot [lindex $botline 0] set lbot [lindex $botline 1] if {[string tolower $lbot] == [string tolower $bot]} { set sublist [linsert $sublist end $rbot] } } return $sublist } ### expire old bots proc expire_old_bots {} { global known_bots global bottree_list global knownbot-timeout set botcount [llength $known_bots] for {set botindex 0} {$botindex < $botcount} {incr botindex} { set unlinktime [lindex [lindex $bottree_list $botindex] 3] if {$unlinktime != 0} { if {[expr [unixtime] - $unlinktime] > ${knownbot-timeout}} { putlog "obsolete bot: erasing [lindex $known_bots $botindex]" set known_bots [ldelete $known_bots $botindex] set bottree_list [ldelete $bottree_list $botindex] incr botcount -1 incr botindex -1 } } } } ### init procs proc init:fix_linked_bots {} { foreach bot [bots] { set nbotline [bnn:get_bot $bot] if {[bnl:search_bot $bot] < 0} { bnl:write_bot $bot [lindex $nbotline 1] [unixtime] 0 [lindex $nbotline 3] putlog "Added $bot in my bottree (new bot)" } else { set lbotline [bnl:read_bot $bot] bnl:write_bot $bot [lindex $nbotline 1] [lindex $lbotline 2] [lindex $lbotline 3] [lindex $nbotline 3] } } } proc init:fix_subtree {bot} { global uptime foreach sbot [bnl:list_downlinks $bot] { set botline [bnl:read_bot $sbot] if {[islinked $sbot] == 1} { if {[lindex $botline 3] > 0} { set linktime $uptime putlog "fix: Added $sbot in my bottree" } else { set linktime [lindex $botline 2] } bnl:write_bot $sbot [lindex $botline 1] $linktime 0 [lindex $botline 4] } else { set unlinktime [lindex $botline 3] if {$unlinktime == 0} { set unlinktime $uptime putlog "fix: Deleted $sbot from my bottree" } bnl:write_bot $sbot [lindex $botline 1] [lindex $botline 2] $unlinktime [lindex $botline 4] } init:fix_subtree $sbot } } ### binds procs proc link:addbots {bot hub} { global linked_bots global max_botcount global max_bottime if {[bnl:search_linked_bot $bot] < 0} { lappend linked_bots $bot set botcount [llength $linked_bots] if {$botcount > $max_botcount} { set max_botcount $botcount set max_bottime [unixtime] } bnl:write_bot $bot $hub [unixtime] 0 [lindex [bnn:get_bot $bot] 3] #putlog "Added $bot (from $hub) in my bottree" foreach sbot [bnn:list_downlinks $bot] { link:addbots $sbot $bot } } else { putlog "WARNING: loop detected when adding $bot from $hub in my bottree" unlink $bot "loop detected" } } proc disc:expirebots {bot} { global linked_bots if {[bnl:search_linked_bot $bot] < 0} { putlog "WARNING: $bot wasn't linked" } else { if {[bnl:search_bot $bot] < 0} { putlog "WARNING: $bot was linked, but unknown to me" } else { set linked_bots [ldelete $linked_bots [bnl:search_linked_bot $bot]] set botinfo [bnl:read_bot $bot] bnl:write_bot $bot [lindex $botinfo 1] [lindex $botinfo 2] [unixtime] [lindex $botinfo 4] foreach sbot [bnn:list_downlinks $bot] { disc:expirebots $sbot } #putlog "Deleted $bot from my bottree" } } } proc bupd:updatebot {bot share} { if {[bnl:search_linked_bot $bot] < 0} { putlog "WARNING: $bot wasn't linked" } else { if {[bnl:search_bot $bot] < 0} { putlog "WARNING: $bot was linked, but unknown to me" } else { set botinfo [bnl:read_bot $bot] bnl:write_bot $bot [lindex $botinfo 1] [lindex $botinfo 2] [lindex $botinfo 3] $share #putlog "updated $bot : status $share" } } } proc time:pub {min hour day month year} { global bottree_url dccbroadcast "Bonjour je génère une page de visualisation du botnet sur $bottree_url" } proc time:store_tree {min hour day month year} { global bottree_file putlog "Writing bottree file..." bnf:store_tree $bottree_file } proc time:html_bigjob {min hour day month year} { global html_output global html_dest global ftp_server global ftp_login global ftp_passwd putlog "generating HTML file..." html_tree $html_output putlog "Transfering the file to the http server..." ftpsend $ftp_server $ftp_login $ftp_passwd $html_output $html_dest putlog "Launched in the background." } proc time:store_tree {min hour day month year} { global bottree_file putlog "Writing bottree file..." bnf:store_tree $bottree_file } proc time:expire_bots {min hour day month year} { global bottree_file putlog "Checking for old bots..." expire_old_bots } proc time:paranoid_resync {min hour day month year} { global bottree_file putlog "Paranoïa: resyncing..." botstats_reset } proc evnt:store_tree {type} { global bottree_file putlog "Writing bottree file..." bnf:store_tree $bottree_file } proc dcc:store_tree {handle idx args} { global bottree_file set file [lindex [join $args] 0] if {$file == ""} { set file $bottree_file } putlog "Writing bottree file..." bnf:store_tree $file return 1 } proc dcc:read_tree {handle idx args} { global bottree_file set file [lindex [join $args] 0] if {$file == ""} { set file $bottree_file } bnf:read_tree $file return 1 } proc dcc:xbottree {handle idx args} { global botnet-nick print_tree $idx return 1 } proc dcc:hbottree {handle idx args} { global botnet-nick set file [lindex [join $args] 0] if {$file == ""} { putdcc $idx "Usage: hbottree " return 0 } html_tree $file return 1 } ### init ... proc botstats_reset {} { global bottree_file global linked_bots global botnet-nick bnf:read_tree $bottree_file set linked_bots [bots] expire_old_bots init:fix_linked_bots init:fix_subtree ${botnet-nick} bnt:reset_depths } botstats_reset ### binds bind link - * link:addbots bind disc - * disc:expirebots bind bupd - * bupd:updatebot bind dcc n|- store_tree dcc:store_tree bind dcc n|- read_tree dcc:read_tree bind dcc -|- xbottree dcc:xbottree bind dcc n|- hbottree dcc:hbottree bind time - "36 * * * *" time:store_tree bind time - "37 17 * * *" time:expire_bots bind time - "33 15 ?1 * *" time:paranoid_resync bind time - "?2 * * * *" time:html_bigjob bind time - "?7 * * * *" time:html_bigjob bind time - "19 ?0 * * *" time:pub bind evnt - prerehash evnt:store_tree bind evnt - prerestart evnt:store_tree putlog "Système de statistiques prêt"