Latest revision |
Your text |
Line 1: |
Line 1: |
− | {{mirc title|mSL Injection}} | + | {{DISPLAYTITLE:mSL Injection - mIRC}} |
− | '''mSL injection''' (mIRC Scripting Language injection) is a code injection technique that exploits mIRC's ability to dynamically evaluate code on the run. With mSLs powerful commands and identifiers, the result of a code injection attack can be disastrous. It is important that you understand what to look for when working with vulnerable commands. | + | {{mIRC Guide}} |
| + | {{Preknow|This article is designed to educate people about what mSL injections are, how they happen, and how to prevent them. One should not misuse the information to gain unauthorized access or to execute malicious code, it is provided to make the innocent users aware of the threats they are exposed to when using some of the less understood commands available to mIRC. We will not be held responsible for any damage done.}} |
| + | |
| + | '''mSL injection''' is a code injection technique that exploits mIRC's ability to dynamically evaluate code on the run. With mSLs powerful commands and identifiers, the result of a code injection attack can be disastrous. It is important that you understand what to look for when working with vulnerable commands. |
| | | |
| This tutorial will try to summarize for you what commands are problematic, how to detect it, and how to fix it. | | This tutorial will try to summarize for you what commands are problematic, how to detect it, and how to fix it. |
Line 16: |
Line 19: |
| echo -a $me | | echo -a $me |
| </syntaxhighlight> | | </syntaxhighlight> |
− | Here {{mIRC|$me}} is evaluated, then -a is passed as the first parameter and the value of {{mIRC|$me}} is passed as the second parameter to the /echo command. | + | Here $me is evaluated, then -a is passed as the first parameter and the value of $me is passed as the second parameter to the /echo command. |
| | | |
| == Nested command == | | == Nested command == |
Line 27: |
Line 30: |
| * /scon | | * /scon |
| * /scid | | * /scid |
− | * /dde
| |
| | | |
| === The /timer command === | | === The /timer command === |
Line 37: |
Line 39: |
| //.timer 1 1 echo -a $day | | //.timer 1 1 echo -a $day |
| </syntaxhighlight> | | </syntaxhighlight> |
− | Which will execute "echo -a <value of {{mIRC|$day}}>" one time, after waiting 1 second. | + | Which will execute "echo -a <value of $day>" one time, after waiting 1 second. |
| | | |
− | What happens here is that the parameters passed to the /timer command are evaluated once as we saw, so {{mIRC|$day}} gets evaluated once, producing the current day. | + | What happens here is that the parameters passed to the /timer command are evaluated once as we saw, so $day gets evaluated once, producing the current day. |
| | | |
− | The timer will register that its associated command to be executed when the delay has passed is "echo -a <{{mIRC|$day}}'s value>" | + | The timer will register that its associated command to be executed when the delay has passed is "echo -a <$day's value>" |
| | | |
− | When the timer fires, its command (a new command) is executed and therefore all of its parameters are, once again, evaluated one time. In this example there is no problem and we can't see the difference because {{mIRC|$day}} can only return a day of the week. If {{mIRC|$day}} is monday, evaluating the plain text monday will always produce monday. | + | When the timer fires, its command (a new command) is executed and therefore all of its parameters are, once again, evaluated one time. In this example there is no problem and we can't see the difference because $day can only return a day of the week. If $day is monday, evaluating the plain text monday will always produce monday. |
| | | |
| But what if we didn't have $day? what if we had something like $2? Let's consider a more useful example, an innocent reminder script: | | But what if we didn't have $day? what if we had something like $2? Let's consider a more useful example, an innocent reminder script: |
Line 62: |
Line 64: |
| Indeed, /timer evaluated the parameter once: $2 is evaluated to 18000 and $3- to "jill's birthday tomorrow!" | | Indeed, /timer evaluated the parameter once: $2 is evaluated to 18000 and $3- to "jill's birthday tomorrow!" |
| | | |
− | The associated command of the timer is correctly <code>notice Mike [Reminder] jill's birthday tomorrow! (Set 18000 seconds ago)</code>, when the timer fires, the /notice command will see its parameters evaluated once, but there is nothing to evaluate in this case. | + | The associated command of the timer is correctly "notice Mike [Reminder] jill's birthday tomorrow! (Set 18000 seconds ago)", when the timer fires, the /notice command will see its parameters evaluated once, but there is nothing to evaluate in this case. |
| | | |
− | Although this script might seem simple, let's take a look at what happens when someone provides incorrect or even malicious input as in this case: | + | Although this script might seem simple, let's that a look at what happens when someone provides incorrect or even malicious input as in this case, input: |
| | | |
| <pre><Mike> !reminder 0 . | ns drop nick | quit hacked! | | <pre><Mike> !reminder 0 . | ns drop nick | quit hacked! |
Line 72: |
Line 74: |
| This is an msl injection attack. Let's take a deeper look into what has happened: | | This is an msl injection attack. Let's take a deeper look into what has happened: |
| | | |
− | As we know, /timer evaluated the parameter once; $2 is evaluated to <code>0</code> and $3- is evaluated to <code>. | ns drop nick | quit hacked!</code> | + | As we know, /timer evaluated the parameter once $2 is evaluated to 0 and $3- is evaluated to ". | ns drop nick | quit hacked!" |
| | | |
− | So now, the associated command of the timer becomes <code>.notice Mike [Reminder] . | ns drop nick | quit hacked!</code> and you might be recognizing the pipe character, used to separate commands, which mIRC will interpret as such, resulting in /ns drop nick and /quit hacked! being executed. | + | So now, the associated command of the timer becomes "notice Mike [Reminder] . | ns drop nick | quit hacked! | noop" and you might be recognizing the pipe character, used to seperate commands, which mIRC will interpret as such, resulting in /ns drop nick and /quit hacked! being executed. |
| | | |
| Clearly, you can see how the timer command can be extremely dangerous. The unfortunate part is that there is no clean way of solving this problem. The only way to prevent this from happening is to encode the problematic parameters so that when they get evaluated, they produce something which needs one more evaluation to produce the correct value. We usually do that by encoding the parameters using based64 encoding. Below is an alias to perform this: | | Clearly, you can see how the timer command can be extremely dangerous. The unfortunate part is that there is no clean way of solving this problem. The only way to prevent this from happening is to encode the problematic parameters so that when they get evaluated, they produce something which needs one more evaluation to produce the correct value. We usually do that by encoding the parameters using based64 encoding. Below is an alias to perform this: |
Line 97: |
Line 99: |
| And Mike now can't do anything harmful. | | And Mike now can't do anything harmful. |
| | | |
− | /timer will evaluate the parameter as we know but this time, $safe($3-) where $3- is <code>. | ns drop nick | quit hacked!</code> is evaluated to <code>{{mIRC|$decode}}( LiB8IG5zIGRyb3AgbmljayB8IHF1aXQgaGFja2VkIQ== ,m)</code> and $safe($2) to <code>{{mIRC|$decode}}( MTgwMDA= ,m)</code>. | + | /timer will evaluate the parameter as we know but this time, $safe($3-) where $3- is ". | ns drop nick | quit hacked!" is evaluated to "$decode( LiB8IG5zIGRyb3AgbmljayB8IHF1aXQgaGFja2VkIQ== ,m)" and $safe($2) to "$decode( MTgwMDA= ,m)". |
| | | |
− | The command associated with the timer now becomes <code>{{mIRC|/notice}} Mike [Reminder] {{mIRC|$decode}}( LiB8IG5zIGRyb3AgbmljayB8IHF1aXQgaGFja2VkIQ== ,m) (Set {{mIRC|$decode}}( MTgwMDA= ,m) seconds ago)</code> and those {{mIRC|$decode}}, when evaluated once by {{mIRC|/notice}}, will produce the correct result (the original input of Mike). | + | The command associated with the timer nows becomes "/notice Mike [Reminder] $decode( LiB8IG5zIGRyb3AgbmljayB8IHF1aXQgaGFja2VkIQ== ,m) (Set $decode( MTgwMDA= ,m) seconds ago)" and those $decode, when evaluated once by /notice, will produce the correct result (the original input of Mike). |
| | | |
− | Now you don't need to do that for any {{mIRC|/timer}} command of course, only when the parameter is unknown at the time you are writing the script, such as $2 and $3- here. | + | Now you don't need to do that for any /timer command of course, only when the parameter is unknown at the time you are writing the script, such as $2 and $3- here. |
− | | |
− | '''Note''': Since mIRC 7.44, an $unsafe identifier has been added which behaves just like $safe (the name was changed to unsafe to avoid misleading new users), delaying the execution of one level.
| |
| | | |
| ===== $chan/# ===== | | ===== $chan/# ===== |
| | | |
− | You may think {{mIRC|$chan}} can't be evaluated in an malicious way but that's not true, if the {{mIRC|$chan}} (also #) identifier is unknown, you should encode it as well. | + | You may think $chan can't be evaluated in an malicious way but that's not true, if the $chan (also #) identifier is unknown, you should encode it as well. |
| | | |
| The reason for this is mIRC allows prefixing an identifier with the pound sign to make mIRC prefixes (if needed) the evaluated string by the pound symbol. For example: | | The reason for this is mIRC allows prefixing an identifier with the pound sign to make mIRC prefixes (if needed) the evaluated string by the pound symbol. For example: |
Line 117: |
Line 117: |
| <syntaxhighlight lang="mirc">#A #B</syntaxhighlight> | | <syntaxhighlight lang="mirc">#A #B</syntaxhighlight> |
| | | |
− | So what does that have to do with {{mIRC|$chan}} and timers? Everything! | + | So what does that have to do with $chan and timers? Everything! |
| | | |
| Consider the following bot's code: | | Consider the following bot's code: |
Line 141: |
Line 141: |
| -Bot- Hello Mike, Welcome to foo_bar_42</pre> | | -Bot- Hello Mike, Welcome to foo_bar_42</pre> |
| | | |
− | Because {{mIRC|$chan}} (or #) was not escaped, it was evaluated. Mike was able to evaluate the $bot_pass alias and get the bot's password. | + | Because $chan (or #) was not escaped, it was evaluated. Mike was able to evaluate the $bot_pass alias and get the bot's password. |
| | | |
− | You might want to watch out for {{mIRC|$nick}} as well, some servers allow nicknames to have the '$' character. | + | You might want to watch out for $nick as well, some servers allow nicknames to have the '$' character. |
| | | |
| === /scon and /scid === | | === /scon and /scid === |
− | Both of these commands were created to evaluate/execute code on a given connection. Just like the {{mIRC|/timer}} command, any unknown content must be escaped somehow. | + | Both of these commands were created to evaluate/execute code on a given connection. Just like the /timer command, any unknown content must be escaped somehow. |
| | | |
− | Though, unlike {{mIRC|/timer}}, the {{mIRC|/scid}} and {{mIRC|/scon}} are so that when their associated command triggers, they are able to evaluate local variables (but they can't evaluate local identifier like $1-), which makes the escaping easier, you can use the $safe method, but you can simply just use a local variable, consider this less practical example: | + | Though, unlike /timer, the /scid and /scon are so that when their associated command triggers, they are able to evaluate local variables (but they can't evaluate local identifier like $1-), which makes the escaping easier, you can use the $safe method, but you can simply just use a local variable, consider this less practical example: |
| | | |
| <syntaxhighlight lang="mirc">on *:text:!global *:#:{ | | <syntaxhighlight lang="mirc">on *:text:!global *:#:{ |
Line 154: |
Line 154: |
| }</syntaxhighlight> | | }</syntaxhighlight> |
| | | |
− | The script is designed to do a global amsg (i.e. perform an {{mIRC|/amsg}} on every active connection). Just like the timer command, $1- will be evaluated again in the specified connection when the associated command of {{mIRC|/scon}} triggers (/amsg [AMSG] $1-), which means any user code will become part of your bot's code. | + | The script is designed to do a global amsg (i.e. perform an /amsg on every active connection). Just like the timer command, $1- will be evaluated again in the specified connection when the associated /amsg command triggers, which means any user code will become part of your bot's code. |
| | | |
| * $safe solution: | | * $safe solution: |
Line 166: |
Line 166: |
| <syntaxhighlight lang="mirc">on *:text:!global *:#:{ | | <syntaxhighlight lang="mirc">on *:text:!global *:#:{ |
| var %a $1- | | var %a $1- |
− | scon -at1 amsg [AMSG] % $+ a | + | scon -at1 amsg [AMSG] % $+ %a |
| }</syntaxhighlight> | | }</syntaxhighlight> |
| | | |
− | The associated command becomes <code>amsg [AMSG] %a</code> and %a is evaluated correctly to produce the user's message. | + | The associated command becomes "amsg [AMSG] %a" and %a is evaluated correctly to produce the user's message. |
− | | |
− | '''Note''': /scid and /scon can be used to change the current connection only, in this case you can just execute the command normally after, does not work for /scon -a for example.
| |
− | | |
− | === /dde ===
| |
− | | |
− | /dde has the same issue and the same solution as /timer, just use $safe on the problematic parameters.
| |
| | | |
| == /flash == | | == /flash == |
| | | |
− | Though /flash is the only command doing it for now, more command might do this in the future. {{mIRC|/flash}} does not take a new command as one of its parameter but it can take a text as an optional parameter, to be used automatically later, that text will be evaluated once by {{mIRC|/flash}}, and mIRC will also evaluate the text parameter once when applying the flash: | + | Though /flash is the only command doing it for now, more command might do this in the future. /flash does not take a new command as one of its parameter but it can take a text as an optional parameter, to be used automatically later, that text will be evaluated once by /flash, and mIRC will also evaluate the text parameter once when applying the flash: |
− | | |
− | <syntaxhighlight lang="mirc">on *:text:!testflash:#:/flash $ $+ me</syntaxhighlight>
| |
| | | |
− | So $ $+ me evaluates to "{{mIRC|$me}}" by {{mIRC|/flash}}, and $me will be evaluated to your nickname (that text appears in mIRC's titlebar).
| + | <syntaxhighlight lang="mirc">on *:text:!testflash:#:/flash $ $+ $me</syntaxhighlight> |
| | | |
− | The $safe solution must be used there.
| + | So $ $+ me is evaluate to "$me" by /flash, and $me will be evaluated to your nickname (that text appears in mIRC's titlebar). |
| | | |
| = Injection via $identifiers = | | = Injection via $identifiers = |
| | | |
| == $readini() and $read() == | | == $readini() and $read() == |
− | If you have visited #mSL on swiftirc, and you had some code that used {{mIRC|$read|$read()}} or {{mIRC|$readini|$readini()}} without the n switch you would most likely had people yelling at you to always use it. But why? The reason is: | + | If you have visited #mSL on swiftirc, and you had some code that used $read() or $readini() without the n switch you would most likely had people yelling at you to always use it. But why? The reason is: |
| | | |
| '''By default BOTH $read() and $readini() treat the text in the file as code!''' | | '''By default BOTH $read() and $readini() treat the text in the file as code!''' |
Line 222: |
Line 214: |
| * Bot (~Bot@isp.example.com) Quit (Quit: hacked!)</pre> | | * Bot (~Bot@isp.example.com) Quit (Quit: hacked!)</pre> |
| | | |
− | In this example Mike used the fact that {{mIRC|$findfile|$findfile()}} can execute a command when it finds a matching file. It should be clear how dangerous this can be. | + | In this example Mike used the fact that $findfile() can execute a command when it finds a matching file. It should be clear how dangerous this can be. |
| | | |
| So how do we fix it? Using the '''n''' option! | | So how do we fix it? Using the '''n''' option! |
Line 241: |
Line 233: |
| msg $chan [[ $+ $nick $+ ] $v1 | | msg $chan [[ $+ $nick $+ ] $v1 |
| } | | } |
− | }</syntaxhighlight>
| |
− |
| |
− | == $submenu ==
| |
− |
| |
− | The value returned by the alias called by $submenu is evaluated a second time, again, $safe and similar methods are your friend:
| |
− |
| |
− | <syntaxhighlight lang="mirc">menu menubar {
| |
− | double evaluation
| |
− | .$submenu($testsm($1))
| |
− | }
| |
− | alias testsm {
| |
− | if ($1 == 1) return item : echo -ag > $!!me
| |
| }</syntaxhighlight> | | }</syntaxhighlight> |
| | | |
| == $calc() == | | == $calc() == |
− | ALL unknown (in advance) input to {{mIRC|$calc}} should be validated. $calc has its own special evaluation routine, it possesses the ability to double evaluate variables and identifier if their value returns a %variable. Consider the following code: | + | ALL input to $calc should be validated. Since $calc has its own special evaluation routine, it possesses the ability to evaluate variables from within text. Consider the following code: |
| | | |
| <syntaxhighlight lang="mirc">//var %x = 12345 | tokenize 32 % $+ x | echo -a $1 = $calc($1)</syntaxhighlight> | | <syntaxhighlight lang="mirc">//var %x = 12345 | tokenize 32 % $+ x | echo -a $1 = $calc($1)</syntaxhighlight> |
Line 264: |
Line 244: |
| %x = 12345 | | %x = 12345 |
| | | |
− | '''Surprise!''' We bet you did not expect that to happen. (This is actually a side effect of {{mIRC|$calc}} being able to evaluate variables inside parenthesis or immediately after an operator without a space.) | + | '''Surprise!''' We bet you did not expect that to happen. (This is actually a side effect of $calc being able to evaluate variables inside parenthesis or immediately after an operator without a space.) |
| | | |
| Now let's take a look at a more practical example: | | Now let's take a look at a more practical example: |
Line 291: |
Line 271: |
| | | |
| It's important to note that EVEN if %password was set to "1234rosebud". The $calc() will return "1234", which is not the whole password but it's a big chunk of it. | | It's important to note that EVEN if %password was set to "1234rosebud". The $calc() will return "1234", which is not the whole password but it's a big chunk of it. |
− |
| |
− | A simple way to prevent this from happening with such a script is to restrict the usage to input which do not contain identifiers and %variables:
| |
− |
| |
− | <syntaxhighlight lang="mirc">
| |
− | on *:text:!calc *:#:{
| |
− | if (!$regex($2-,/\$\S+|%\S+/)) {
| |
− | msg $nick [Calc] $2- = $calc($2-)
| |
− | }
| |
− | }</syntaxhighlight>
| |
− |
| |
− | == $decode ==
| |
− |
| |
− | This is not really an exploit, but is a way for someone to disguise their malicious command. It can't be executed except by someone taking advantage of the $iif() bug below, or else as part of a script. When a /command is typed in a channel editbox, it will not let anything be executed if it's a command which begins with a % or a $, but that behavior does not extend to remote scripts.
| |
− |
| |
− | <syntaxhighlight lang="mirc">
| |
− | //var %cmd echo | [ %cmd ] 4 -a hello world
| |
− | </syntaxhighlight>
| |
− |
| |
− | Pasting the above command into an editbox echoes 'hello world' to the active window in red text. However it won't work if the square braces are removed, because the command beginning with % halts the editbox command, but doesn't halt the same thing in a remote script.
| |
− |
| |
− | Something similar can be done with $decode, but it only works if $decode(string) is placed somewhere which allows its contents to be evaluated/executed, which includes the $iif bug, placing into a timer's command line, inside square braces, etc. Below shows how the decode string is created, but the echo command is NOT executed by $decode, but by the fact that the decoded string is placed into the timer's command string. If the "timer 1 1" had not been there, this would have executed the echo command if it were inside a remote script, but would not have executed in the editbox simply because the editbox doesn't execute commands beginning with % or $.
| |
− |
| |
− | <syntaxhighlight lang="mirc">
| |
− | //var -s %a $remove($encode(echo 4 -a hello world,m),=) | timer 1 1 $decode(ZWNobyA0IC1hIGhlbGxvIHdvcmxk,m)
| |
− | </syntaxhighlight>
| |
− |
| |
− | == $findfile $finddir $hfind $dllcall etc ==
| |
− |
| |
− | This category relates to identifiers who have a 'command parm' or a 'callback alias' where a malicious command could be placed. It's harder for $hfind and $dllcall to be exploited, because they require knowing the name of an existing hashtable or the pathname to a dll file. However, there's always at least 1 filename in the $mircdir folder, so the following /noop command can be used to execute the encoded echo command contained in $findfile's command parm. Again, the $decode command is not executing the command, it's just disguising the command that has been placed into a location which executes code placed there. The following 3 commands are doing the exact same thing, with the only difference being that $decode is hiding what the payload command actually is.
| |
− |
| |
− | <syntaxhighlight lang="mirc">
| |
− | //noop $findfile(.,*,1, $decode(ZWNobyA0IC1hIGhlbGxvIHdvcmxk,m) )
| |
− | //noop $findfile(.,*,1, $+(echo 4 -a hello world) )
| |
− | //noop $findfile(.,*,1, echo 4 -a hello world )
| |
− | </syntaxhighlight>
| |
| | | |
| = Injection via Bugs = | | = Injection via Bugs = |
Line 331: |
Line 276: |
| | | |
| == $iif( (cond) /cmd, true, false ) == | | == $iif( (cond) /cmd, true, false ) == |
− | Due to the way mIRC handles {{mIRC|$iif|$iif()}} statements, by wrapping a condition in parens and then appending a command, mIRC will execute/eval the command/identifier. | + | Due to the way mIRC handles $iif() statements, by wrapping a condition in parens and then appending a command or identifier BEFORE the comma, mIRC will execute/eval the command/identifier. |
| | | |
| <syntaxhighlight lang="mirc">//echo -a $iif( (1) echo -a See what I mean, truthy, falsey)</syntaxhighlight> | | <syntaxhighlight lang="mirc">//echo -a $iif( (1) echo -a See what I mean, truthy, falsey)</syntaxhighlight> |
| | | |
− | The above will echo "See what I mean {{mIRC|/return|/!return 1}}", and neither the truthy or falsey statements are returned nor is the outter echo statement executed. | + | The above will echo "See what I mean /!return 1", and neither the truthy or falsey statements are returned nor is the outter echo statement executed. |
− | This is happening because internally, {{mIRC|$iif}} is calling the /if construct in the following way: | + | This is happening because internally, $iif is calling the /if construct in the following way: |
| <syntaxhighlight lang="mirc"> //if (condition) !return 1 | !return 0</syntaxhighlight> | | <syntaxhighlight lang="mirc"> //if (condition) !return 1 | !return 0</syntaxhighlight> |
| which gives: | | which gives: |
| <syntaxhighlight lang="mirc"> //if ( (1) echo -a See what I mean) !return 1 | !return 0</syntaxhighlight> | | <syntaxhighlight lang="mirc"> //if ( (1) echo -a See what I mean) !return 1 | !return 0</syntaxhighlight> |
− | And the quirk is there, this syntax actually executes the echo command. | + | And the quirk is there, this syntax actually executes the command. |
| | | |
| The abuse of this is limited as the user of mIRC would either have to code the malformed $iif() statement or be tricked into issuing it from something such as the editbox. Be careful! | | The abuse of this is limited as the user of mIRC would either have to code the malformed $iif() statement or be tricked into issuing it from something such as the editbox. Be careful! |
| | | |
− | = Injection via mIRC configuration =
| + | [[Category: mIRC]] |
− | | |
− | You should inspect your mIRC settings for certain things which can be used to exploit you. If you check these things, you can help defend against some exploits which depend on a combination of factors, where just severing 1 link in the chain prevents the exploit.<br>
| |
− | | |
− | First, check the Options menu of your Alt+R scripts editor. It's a good idea set a few options here which can prevent problems.
| |
− | | |
− | # Identifier warning
| |
− | | |
− | This halts a script when an invalid identifier name is used, rather than evaluating the identifier as $null. The error warning can alert you to a script error which can cause it to not do as you expect.
| |
− | | |
− | <syntaxhighlight lang="mirc">
| |
− | alias identwarntest {
| |
− | $nosuchidentifier echo -a hello world
| |
− | }
| |
− | </syntaxhighlight>
| |
− | | |
− | If you do not have identifier warning, and the above identifier is the mis-typing of an identifier which was supposed to return either "echo -a" or "notice $nick" or "msg #channel", then without identifier warning being checked, that identifier evaluates to $null, causing the remainder of the command to be executed. If the 1st word is not a valid command, mIRC sends the command to a server in case that's a valid server command, which makes it possible to leak sensitive info in some cases. By halting the script with an identifier warning, this gives a chance to fix your script.
| |
− | | |
− | # Initialization Warning
| |
− | | |
− | This warns if the /load command or the script-editor's /file/open has loaded a script containing :START" or :LOAD: events which would execute code immediately. This still doesn't defend against scripts containing :TEXT: or other events which could be triggered *later*, and doesn't defend if /reload was used instead of /load.
| |
− | | |
− | # Monitor File Changes
| |
− | | |
− | This warns if a loaded script has changed without being changed by the scripts editor itself. Sometimes it can be caused by your editing scripts in a 3rd party editor such as notepad, but it could also be caused by a script using /write to alter itself or a different script.
| |
− | | |
− | * It's possible to have a script loaded that you don't realize.
| |
− | | |
− | <syntaxhighlight lang="mirc">
| |
− | //write $chr(160) test | .reload -rs999 $chr(160)
| |
− | </syntaxhighlight>
| |
− | | |
− | This creates a file without a filetype, where the filename itself is not visible in most fonts, then loads it as a remote script. All you see in the script editor's "view" menu is an extra-thick border at the bottom of the scripts list, and if you have too many scripts loaded, it's hiding inside the "more" list. This next command lists all the scripts you have loaded. If you see a line showing nothing between the double quotes or is something you don't recognize, you should investigate and possibly unload it.
| |
− | | |
− | <syntaxhighlight lang="mirc">
| |
− | //var %i 1 | while ($script(%i)) { echo -a %i : $qt($nopath($script(%i))) | inc %i }
| |
− | </syntaxhighlight>
| |
− | | |
− | * Restricting DCC Get filetypes.
| |
− | | |
− | You should view the contents of your downloads folder with suspicion if you don't know from whom you received the file. If you disable filetype blocking, you should do it temporarily, by using the "turn ignore back on in xx minutes" feature, which causes the 'disable' choice to revert back to the prior 'accept only' or 'ignore only' setting.<br>
| |
− | | |
− | While you can either configure Options/DCC/Ignore as 'ignore only' to specify a list of filetypes to be blocked, or as 'accept only' to specify a list of the only filetypes accepted, 'ignore only' requires updating the list as new executable filetypes need to be added. It's probably better to use 'accept only', since this allows you to manage the list of the only filetypes which are accepted. You should block all executable filetypes, without expecting to be able to inspect the download folder for suspicious items.
| |
− | | |
− | <syntaxhighlight lang="mirc">
| |
− | //var %a $chr(8238) $+ piz.!wen.oediv.ezicr.exe | echo -a write %a test
| |
− | </syntaxhighlight>
| |
− | | |
− | As you can see from the above command, this is a filename ending with .exe, which means it's an executible filetype. However, if your windows font is unicode-aware, and you use "/run ." to view the contents of your mirc folder, you'll see that this .exe file appears as if it's a .zip file. If someone created an .exe file containing the icon normally associated with .zip files, then renames it to this filename, and then uses DCC to send this file to you - it would appear as if it's a .zip file that's safe to click on to view the contents. This next event handler creates a log of the files you've received via DCC, and allows you to check later to see who sent an unknown file to you.
| |
− | | |
− | <syntaxhighlight lang="mirc">
| |
− | on *:FILERCVD:*:{
| |
− | write getlog.txt $time(yyyy.mm.dd HH:nn:ss) $network $nick $get(-1).ip $address($nick,5) $get(-1).size file: $filename
| |
− | }
| |
− | </syntaxhighlight>
| |
− | | |
− | = Injection via server command =
| |
− | | |
− | IRC servers accept strings containing $crlf $lf or $cr and will execute text following the line-ending as a 2nd server command using whatever permissions belong to your nick at that time.
| |
− | <pre>
| |
− | //msg #channel message $crlf mode #home +o Mallory
| |
− | </pre>
| |
− | When the server receives this message from mIRC, it uses the $crlf to split this into 2 commands. The first command displays the message to #channel, and the 2nd command tells the server to give @op status in channel #home to Mallory. If you do not have permissions in #home to give @ops, or if a nick Mallory is not in that channel, nothing happens. But if both are true, then you have just given op status to Mallory.
| |
− | | |
− | This method can only tell the server to execute commands recognized by the server. It does not know any mIRC-only /commands or $identifiers, and the 2nd command is executed even if the 1st command is invalid, such as #channel not existing. This means echoing such a string is no danger, because /echo will not send any string to a server, and it will not execute them either.
| |
− | | |
− | This exploit cannot be achieved by responding to an ON TEXT command, because the server cannot display a message to a channel which contains an embedded $cr and/or $lf.
| |
− | | |
− | However, this exploit can take advantage of scripts which send text to channels which can contain them. Examples could include the above examples of an evaluated command inside a $decode string, or can be accomplished by a script which messages the title/description or other content from a webpage that the attacker controls. Another method can be 'now playing' scripts which message text to channel describing information about the mp3 song that is either beginning or ending. While it's common for fields like $sound(filename.mp3).comment to contain $cr's, they generally are not displayed in channel messages. However, it's also possible for Album or Title to also contain them.
| |
− | | |
− | In addition to executing commands to give @op privileges to someone, the malicious commands could include things like making you drop your nickserv account at some ircd's. Also, they can induce you to execute commands which have a future effect, such as adding a nick to a chanserv access list, or a command to add Mallory's certificate fingerprint to your nickserv account, which would allow them to take channel actions in the future, or to login your nickserv account any time in the future, even if you change your nickserv password. While those would almost certainly trigger a confirmation message from chanserv or nickserv, those messages often go into the status window, and would often be unseen, especially if they happened while your keyboard is unattended.
| |
− | | |
− | To defend against such an exploit, any command sent to the server (not only a channel message) containing text that could come from a source which contains line-ending characters should be sanitized to remove/disable them.
| |
− | | |
− | <pre>
| |
− | $remove(string,$cr,$lf)
| |
− | </pre>
| |
− | This sanitizing would cause both strings to be combined as a single string, so if the first message is a plausible channel message, the hidden message is displayed as part of the channel message
| |
− | | |
− | However, this is not sufficient if the first server command is able to cause damage even if combined with additional text, such as when the first command is the give-them-@ops command. The better defense is to halt the server command if the string contains a $cr and/or $lf that shouldn't be there:
| |
− | | |
− | <pre>
| |
− | if ($cr isin $replace(string,$lf,$cr)) { echo -a string exploit attempt: $2 | halt }
| |
− | </pre>
| |