Forum Discussion

jhanington_1353's avatar
jhanington_1353
Icon for Nimbostratus rankNimbostratus
May 28, 2014

Request feedback on my STMP iRule

Long story short, I have been seeing a bunch of brute force SMTP auth attacks on our exchange server. They managed to get a valid username of one of our users so now they are trying a bunch of commonly used passwords to try to break in. After 25 tries, the account gets locked out and the legitimate user cannot read his email until I unlock his account. I noticed that the EHLO command is always the same (EHLO ABC123-PC) so I made an iRule using this the SMTP proxy here but added a couple lines so that if the EHLO message shows up then the connection is dropped.

I think this might be overkill for what I want to do but I want the community to weigh in and critique the iRule. My main concern is how much of the BigIP 1600's resources will this take to run?

when CLIENT_ACCEPTED {
    set chelo ""
    set cfrom ""
    set crcpt ""    
    TCP::respond "220\r\n"
    log local0. "client accepted"
    TCP::collect
}

when CLIENT_DATA {

    set cdata [TCP::payload]
    if { [ string length $cdata ] <= 0 } {
        return
    }
    if { not ( $cdata contains "\r\n" ) } {
        log local0. "get <$cdata> so far"
        return
    }
    if { $cdata starts_with "EHLO ABC123-pc" }{

        reject
    }
    if { $cdata starts_with "HELO" } {
        set chelo [TCP::payload]
        log local0. "get helo <$cdata>"
        TCP::respond "250 OK\r\n"
        TCP::payload replace 0 [string length $chelo] ""
        return
    }
    if { $cdata starts_with "MAIL FROM:" } {
        set cfrom [TCP::payload]
        log local0. "get from <$cfrom>"
        TCP::respond "250 OK\r\n"
        TCP::payload replace 0 [string length $cfrom] ""
        return
    }
    if { $cdata starts_with "RCPT TO:" } {
        set crcpt "$crcpt[TCP::payload]"
        log local0. "get rcpt <$crcpt>"
        TCP::respond "250 OK\r\n"
        TCP::payload replace 0 [string length [TCP::payload]] ""
        return
    }
    if { $cdata starts_with "DATA" } {
        log local0. "get data <$cdata>"
        TCP::payload replace 0 0 $chelo$cfrom$crcpt
    }
    log local0. "payload [TCP::payload]"
    TCP::release
    TCP::collect
}

when SERVER_CONNECTED {
    log "server connected"
    TCP::collect
}

when SERVER_DATA {
    set sdata [TCP::payload]

    if { $sdata starts_with "220" } {
        log local0. "get data <$sdata>"
        TCP::payload replace 0 [string length $sdata] ""
        return
    }
    if { $sdata contains "\r\n354 " } {
        log local0. "get data <$sdata>"
        TCP::payload replace 0 [string length $sdata] "354\r\n"
    }
    if { [ string length $sdata ] <= 0 } {
        return
    }
    log local0. "payload <[TCP::payload]>"
    TCP::release
    TCP::collect
}
when CLIENT_CLOSED {
    log local0. "client closed"
}
  • Arie's avatar
    Arie
    Icon for Altostratus rankAltostratus

    Unfortunately I don't have time right now to look at the iRule itself, but I may be able to help you answer the question on how much of a load it would put on the LTM. Are you familiar with the "timing"-command? The iRule-editor has an easy way to look at the values.

     

  • JG's avatar
    JG
    Icon for Cumulonimbus rankCumulonimbus

    But the client can change the string in the initiation string that is supposed to be its domain name anytime it wants, since you effectively have an open relay.

     

    I have been working on an irule that will enforce validation of the domain name in the client initiation string. But I have not yet been able to find a suitable environment to test it properly, or at all at the moment. I will share it once I have tested it to my satisfaction.