rendered paste body### Gowap's botnet stats system v5.18
##
# Noyga <Benoit.Timbert@free.fr>
### 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 "<font color =\"#00FF00\">"
set html.unlink_color "<font color =\"#FF0000\">"
set html.stop_color "</font>"
# 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 "</td><td></td><td bgcolor=\"${html.branch_color}\"><font color=\"${html.branch_color}\">|</font>"
} elseif {$sdepth == $cdepth} {
append tree_string "</td><td></td><td bgcolor=\"${html.branch_color}\"><font color=\"${html.branch_color}\">`</font>"
} else {
append tree_string "</td><td></td><td>"
}
}
if {([lindex $botline 3] == 0) || ($bot == ${botnet-nick})} {
set color ${html.link_color}
} else {
set color ${html.unlink_color}
}
puts $fd "<tr><td>${tree_string}</td><td bgcolor=\"#070744\">[lindex $botline 4]${color}${bot}${html.stop_color}</td></tr>"
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 "<table border=2 cellspacing=1 cellpadding=1>"
puts $fd "<th colspan=$cols>$title</th>"
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 "<td>[lindex $ilist $boti]</td>"
}
puts $fd "<tr>$col_string</tr>"
}
puts $fd "</table>"
}
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 "<html>"
puts $fd "<head>"
puts $fd " <title>Le botnet vu de ${botnet-nick}</title>"
puts $fd " <meta http-equiv=\"Expires\" content=\"[ctime [expr [unixtime] + 333]] $timezone\">"
puts $fd " <meta http-equiv=\"Refresh\" content=\"999\">"
puts $fd " <meta generator=\"botstats.tcl by Noyga\">"
puts $fd "</head>"
puts $fd "<body bgcolor=\"black\" text=\"white\" link=\"yellow\" vlink=\"orange\" alink=\"red\">"
puts $fd "Le botnet vu de <b>${botnet-nick}</b> le [fr_date [unixtime]]"
bnt:find_depths ${botnet-nick}
puts $fd "<p><b>[llength $known_bots] bot(s) connu(s)</b><br>"
puts $fd "<b>${html.link_color}[llength $linked_bots] bot(s) linké(s)${html.stop_color}</b> (max: $max_botcount bots le [fr_date $max_bottime])<br>"
puts $fd "<b>${html.unlink_color}[expr [llength $known_bots] - [llength $linked_bots]] bot(s) non linké(s)${html.stop_color}</b> dont [llength $timeout_bots] non représentés<br>"
puts $fd "<table border=0 cellspacing=0 cellpadding=0>"
html_subtree ${botnet-nick} $fd
puts $fd "</table>"
if {[llength $timeout_bots] > 0} {
puts $fd "<p>"
html_list $timeout_bots "Autres bots non linkés depuis plus d'un jour" 10 $fd
}
puts $fd "<p>Mise à jour toutes les 5 minutes<br>"
puts $fd "<p>Durée de mémorisation des bots: [hr_time ${knownbot-timeout}]"
puts $fd "<p><center><a href=\"http://bluebloup.free.fr/eggdrop/botstats.tcl\">botstats.tcl</a> © <a href=\"mailto:Benoit.Timbert@free.fr\">Noyga</a>, 2001</center>"
puts $fd "</body>"
puts $fd "</html>"
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 <file>"
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"