Tcl
Contents |
Introduction
Tcl is a dynamic language. Initially it was designed as an embedded language that other applications can use for configuration or scripting capabilities. Later it grew into a much more complex language, even offering building standalone (one-file) executables with all the scripts included.
Tcl has a very simple and consistent syntax. A script consists of one or more commands, where each command is separated by semi-colon or newline character. Each command consists of one or more words, separated by white spaces. Words can also be grouped using symbols like quotes or curly brackets.
Let's consider the following code:
set message "Hello, John" puts $message
In this case, the script consists of two commands. The first command sets variable message to Hello, John. The second command prints out contents of message variable. Commands are separated by newline character or semi-colon.
In Tcl, words within a command might be grouped by using either {} or "". First one works without substitution whereas the other one substitutes variables and commands.
For example:
set message "John"
puts "Hello, $message."
puts {Hello, $message.}
The actual output would contain first line as Hello, John. whereas the second line would read Hello, $message..
Tcl also allows using output from a different command as a word or part of a word. For example:
set how [string repeat "very " 10] puts "I love Tcl $how much!" puts "I love Tcl [string repeat "very " 10]much!"
The output would be I love Tcl very very very very very very very very very very much! for both puts invocations.
Taken from [1] by the author of the original page and is put here with his permission.
Expr and double evaluation
One of the specifics of Tcl language is how math is done in it. For example in order to do 1+1, you need to run
set result [expr {1+1}]
This is the correct form. Some people abbreviate it to
set result [expr 1+1]
But the problem with that is that it gets double-evaluated. First of all, it runs slower. Second of all when using variables, it allows injecting code and for stuff such as bots, it is a dangerous issue.
For the sake of this example let's assume that we're writing a computer game that will allow user to enter a number of people to hire and will do some calculations based on that.
Let's assume our code looks like this:
proc hire {proffesion amount} {
global state economy
if {![info exists state($proffesion)]} {
return -code error -errorcode "NOOCCUPATION" "invalid proffesion name"
}
if {$amount > $state(peasents)} {
return -code error -errorcode "NOPEOPLE" "not enough peasents"
}
set cost [expr $amount * $economy(${proffesion}hirecost)]
if {$cost > $state(gold)} {
return -code error -errorcode "NOGOLD" "not enough gold"
}
set state(gold) [expr $state(gold)-$cost]
set state($proffesion) [expr $state($proffesion)+$amount]
set state(peasents) [expr $state(peasents)-$amount]
}
So, taking a global value the code will do some calculations based on the amount of people to hire to a profession. And it will deduct some gold since you need to pay for training these people.
Things seem to look fine, except for the fact that expr commands do not have their arguments wrapped in curly braces ({ and }).
When running the code, Tcl will first substitute $amount and then pass that to expr, which will also do evaluation of the parameter. Let's assume a malicious user somehow sets the amount to:
[set amount {[set amount 50; format %d 10]}; format %d 0]
At this point, when substituting amount, such text will be passed to expr command, which will then evaluate the code in square brackets. The code will replace the actual value of amount variable and return certain values - 0 the first time, 10 the second time and 50 the third time.
While the code needed to know the variable name and the order of calculations done, the effect is quite interesting - the gold deducted is 0, the number of peasants subtracted is 10 while the number of professionals gained is 50. For me, that's a nice field for cheating, especially if the game would be client-server based and the server would not do proper type checking.
For those of you familiar with PHP and SQL, consider it a bit similar to SQL injection, but actually being Tcl injection - you can inject either malicious code or different results by passing properly prepared statement.
Taken from [2] by the author of the original page and is put here with his permission.
Eggdrop
Eggdrop is a very popular bot written in C and using Tcl for scripting. Even though some things are a bit specific to eggdrop, all of Tcl's syntax is actually the same and using majority of Tcl features (XML, SQLite, scheduling, emails, web server etc) can be used within eggdrop with no or slight modifications.
Resources
- http://wiki.tcl.tk/ - wiki for Tcl/Tk users
- http://www.eggheads.org/ - homepage of Eggdrop
- http://www.tclscript.com/ - Scripts for eggdrop users