
On Tue, Aug 21, 2018 at 9:06 PM Kobi Shmueli <kobi@dal.net> wrote:
Hi all, Due to the recent flood attacks we're having, I was thinking about adding two more IRCd(+Services) features to help us:
Is there something unique about what is happening in the flood events that prevents perpetrators working around delay timers and message-specific rules? Many of these such as Join_Connect_Time would surely have a large negative impact on legitimate users and "normal operation" greatly while active. I'm sure we could look at features of Text messages besides "Is it CTCP or not?" and "Is it Notice or not?" --- I would assume if CTCPs and Norices are blocked; the abusers don't stop flooding attacks: they just pivot to a different kind of disruptive message; Probably something dense in control characters ---- detectable If a dynamic message classification scheme could be implemented. Are those creating the flood attacks using registered nicknames? Perhaps some extensions above +r to "Increase the threshold of identification" As in extended User Flags as in SVSXUF <username> :REGISTERED:<Timestamp of nick registration> SVSXCF <channel> EXEMPT_REGISTERED_BEFORE:<N> <- Exempt nicknames identified/registered before the given Timestamp or identified to a nick registered for a given number of days SVSXUF <username> :IDENTIFIED_2FA <- User Logged into NickServ in a manner requiring Two-Factor Authentication such as OATH-TOTP or E-mailed one time password, suggesting this is not a stolen nick account SVSXCF <channel> EXEMPT_IDENTIFIED_2FA It seems like having the extended channel flags is an improvement over re-using simple cmodes, but still inadequately expressive, so far as enabling channel managers to easily adapt quickly as abusers adapt, without further Ircd changes every time abusers change their behavior. Ideally there would be a mechanism to create parseable rules with test conditions such as pattern matches boolean logic, arithmetic, relational expressions, bitwise tests, and boolean combinations on tests for any attribute that Ircd or Services knows related to the Sending user/their relationship to channels. To form Join/Message conditions or.. * Have a custom "Ad-Hoc challenge" or "Captcha" prompt start coming up for users joining a "Channel Under Attack" or "Controlled user Join Mode" * Chanops can set a timestamp XYZ the Attack began defaulting to now and "Timeout" (number of seconds/mins/hours to apply) * Open join condition: Logical expression users joining can meet to skip Join Control: such as Nickserv users registered 24 hours before attack started at XYZ timestamp or connected to IRC before XYZ - <delta>. * Some form of Challenge/Custom CAPTCHA definition such as: Channel X option challenge_header :Please be advised, you need to answer the following challenge to join this channel: Channel X option challenge_prescript :var a = Math.round(Math.random()*5); var b = Math.round(Math.random()*5) Channel X option challenge_prompt : response.add("What is " + a.toString() + " plus " + b.toString() + " ?") Channel X option challenge_answer : challenge.addAnswer("My answer is " + (a+b).toString()) Channel X option challenge_footer :To complete the challenge, within 1 minute: please type /join ${channel.name} :My answer is <ANSWER> * Controlled join condition: Extra conditions required if controlled join in effect - user joining Ok flagged as "Joined while `controlled`'", * Message condition: Extra conditions required to send message to channel Channel X option message_condition :user_channel.controlled_join_flag() || user_channel.joined_timestamp < XYZ || user_channel.is_voice() * Message content condition: Extra conditions for channel Textual content, unless speaker is +v or +o Channel X option message_condition text_condition message.type != NOTICE || message.match(/^\1/) --- Perhaps all floods of significant volume have some element of client automation involved, and I would suggest steps with first implementing a "Uniform network policy on IRC bots": That is, a short page on technical requirements and restrictions that users running bots for legitimate reasons on the network should be required to read fully comply with regardless of what server a user connects to, and include complete prohibition of undeclared (non-IrcOp) user scripts working in a fully automated fashion: requiring all Allowed (legitimate) types of bots to "Self-Declare" themself as bots. Require by rule Bots which automatically send any automatic messages, respond to any remote control commands, or automatically Join/Part any channel for any reason to declare themselves: By sending an On-Connect command such as :<nick> :I_AM_A_BOT, Registering a single nickname with NickServ, and also applying a SET ISBOT on command. Once a user's session declares itself as bot: they need to be services-recognized (+r) Or INVITED before JOINing to Any channel, then they need to be voiced (+v) or chanopped (+o) to speak in any channel or show members a QUIT or PART message -- To dissuade flooders using this. (This implies all declared bots require channel management approval), And finally all the PRIVMSG or NOTICE commands from a declared bot should be to a channel, services, a user joined to the bot's approved channels, or to a user who has placed bot on a server-side /notify list or sent the bot a PRIVMSG within past 10 minutes.
From then on, you can look at trying to classify and block Undeclared Bots of any kind, while allowing simple "Legitimate channel bots" to function :
* Undeclared bots that send more than X PRIVMSG/NOTICE commands to different recipients in a short amount of time could trigger a monitoring event. * Could add to extended channel flags an "UNDERATTACK:<TIMESTAMP> <TIMEOUT_SECONDS>" to allow a resource to be temporarily marked as KNOWN being hit by something right now. After <Timeout_Seconds> or when manually cancelled, the condition is over. The UNDERATTACK Signal flag could be provided to channel Founders, SOPs, and (At founder discretion) AOPs, for channels meeting some size threshold or other qualification, with the cautionary note that this may generate abuse alerts, and channel management only allowed to raise mitigation signals after a flood attack was observed by at least 2 different IRC users or repetitive flooding with apparently-immediate evasion of a ban. * Channels could have different Modes/Modelocks, JOIN/Message/Etc control conditions in effect depending on whether an UNDERATTACK extended flag is currently In effect or Not. * Users not declared as bots that send a PRIVMSG/NOTICE command to A channel or user currently 'under attack', especially multiple messages or in <20 seconds of connecting could trigger a monitoring event --- The severity of monitoring event could be affected by comparing connection timestamps to the timestamp that Flag was put in effect on a given channel. ---- Possibly have each IRC server to maintain a "Reputation Score" for each local client, that is recalculated as the connection progresses from New connection through connection registration ; (NICK, USER, Identify, Join, etc), based on the user connection as time proceeds, OR after that user triggers "Monitoring events" which cause additional Observations of interest called "Features" to become attached to that local user's client connection in ircd, For example: It's hard for a human to send a message within seconds of connecting or identifying to services or doing something else --- sending a message within the first 10 seconds strongly suggests automatic action. *Thus have: a system of statistical classifiers that determine a Weight and a Probability for each feature for calculating that Score whether connection is a likely Malicious Bot/Flooder or a Human based on the accumulated series of features that have so far attached to the user connection. * Services should be able to centrally distribute the classification rules and have ways of affecting User session score to record the "KNOWN BAD". * A high enough confidence level that user is an Evil bot or sent spam, such as Score <= 2%, or services forced their score to 0: might be used to Automatically and silently: Disable a local user connection's access to IRC commands -- the server could pretend all commands succeed by supplying fake data or data previously seen by the client while quietly removing client from all channels and moving all user connections from that IP address to a tarpitting daemon to hold the client resources or force Buffering on the client until the malicious client exhausts its connection resources. Provide channel commands to filter unknowns and potential Bots/floodscripts, such as: MINUSERREP = 30% Score < 30% : Not allowed to JOIN or Message the channel. CHALLENGE_LOWER = 30%, CHALLENGE_UPPER = 70% Users joining with reputation Score >= 30% and <= 70%: "Must answer the programmable channel-specific 'challenge question' to show you are human to Join or Continue speaking on this channel" Possible service commands: SVSUSERREPUTATION <nickname> APPLY :[{<CLEAR|+|-><feature_name> ....}] SVSUSERREPUTATION <nickname> (GET|SET) :[{<EXACT|+|-><fixed score adjustment percentage> ....}] - SVSUSERCLASSIFIER ADDFEATURE <feature_name> [("" | BUILTIN | <automatic recognition pattern>)] # Add terminal user feature for example ADDFEATURE UMODE_PLUSR BUILTIN ADDFEATURE REGISTERED_30 :services_applied REGISTERED_30 ADDFEATURE a529269fb1459 :user.host pcre:/^.*\@aol\.com$/i SVSUSERCLASSIFIER (SET|DEL) <feature_name> [~]<token1> [~]<token2> <weight> <probability percentage> # Add feature to program # A Non-terminal named <feature_name> is added to the classifier # <token1> and <token2> are the names of two other Features that may be terminal or non-terminal # <weight> and <probability> are the values calculated according to any chosen training algorithm # These correspond to the weight and probability of the user being legitimate, # when the connection contains these two features. # # If the token is prefixed by "~" - This is the negation operator that indicates # the absence of a feature. # # services would choose for Scoring the user connections SVSUSERCLASSIFIER (RESET|DISABLE|ENABLE) # Clear classification program, or Enable after services has submitted a valid program - SVSTEXTCLASSIFIER (ADDTOKEN|DELTOKEN) <terminal_feature_name> :<pattern recognition rule> SVSTEXTCLASSIFIER (SET|DEL) <feature_name> [~]<token1> [~]<token2> <weight> <probability percentage> SVSTEXTCLASSIFIER (RESET|DISABLE|ENABLE) # Clear classifier program, or Enable after program fully sent -------------------- Services might get to say something like "User's nickname registered for more than 30 days?" then SVSUSERREPUTATION foobar :APPLY +Registered_30 But the user did something strange on login.... they sent the same ID command twice: SVSUSERREPUTATION foobar :APPLY +Registered_30 +MultipleIdentify_2 Foobar's server replies to APPLY with :<server> REPUTATIONNOW Foobar <Score> The SCORE is calculated according to the Features currently attached to Foobar based on the classification table that was loaded onto the server that Foobar is connected to. Or perhaps services saw realname is "Xyz abc", and the incident responders handling a recent situation looked at the data and worked out that all the baddies had this feature. SVSUSERREPUTATION foobar :APPLY +Registered_30 +RealnameContainsXyz * They need a way to program this classification rule Up on services, and for services to look at a large set of samples of historic data traces on Legitimate and the known Non-legitimate connections that will Have versus Not have this pcre:/^Xyz/i in the Realname field feature, in order to appropriately assign the Weight and Probability values to Score connections in the future based on this feature. Example Starting Score: 0.50 (50% = Unknown, 0% = Bot/Flooder/Spammer, 100% = Human) Within 20,60,90 seconds of connecting, build a table of commands to be assigned features if they show up significantly on Good or Bad clients. UnknownIRCCommand_20Seconds, Notice_InFirst20Seconds, PRIVMSG_InFirst20Seconds If 100% of the clients that sent a PRIVMSG in 20 seconds of connecting are spammer, then you have Table entry: Feature Weight PercentageLegitimateUsers PRIVMSG_InFirst20Seconds, <To be determined> 0% For PRIVMSG/Notice/Part commands... use an Additional Separate classification system a "Text classifier" by the same principle consolidate the spamminess of a PRIVMSG/NOTICE into its own feature for User Evil bot Versus Good human classification. For NOTICE/PRIVMSG analysis Build a large corpus from known LEGITIMATE versus Attack messages that channels have received and consider using Pairs of Notable features to further score the characteristics of the text within PRIVMSG or NOTICE content : * To assign each PRIVMSG/NOTICE content a "Spam/flood" score indicating whether is likely a legitimate message or contains mostly features in common with spam. The features are Words, Patterns, or (Recursively) other Features found in Past message text, and the Ratio of Good/Legitimate to Bad messages that contained that pair of features. Example classification tables: SCORE = For features found, the sum of: ( Probability * Weight ) divided by Sum of the Weights of all found features With SCORE=0% meaning classifier is certain the text is Evil; 100% meaning certain the text itself is not spam, and 50% = we have no idea. A manually generated features list might look something like this: It's up to the human or machine trainer involved to decide what combaintions of feature pairs have significant enough weight to list. Example FEATURE_PAIRS TABLE TOKEN NAME FEATURE1 FEATURE2 WEIGHT PROBABILITY CTCP_AND_URL IS_CTCP CONTAINS_URL 20 10% ~CTCP_AND_URL IS_CTCP CONTAINS_URL xx yyyyy <--- "~" denotes the Absence of the CTCP_AND_URL feature CTCP_AND_NOCOLOR IS_CTCP NOCOLOR 3 38% COLOR_AND_URL CONTAINS_URL COLOR_2 15 0% BLAH CTCP_AND_NOCOLOR CTRL_6 30 0% TERMINAL FEATURES (TOKENS) NO_CONTROL_CHARS = ~ pcre:/[:cntrl:]/ ALPHABETIC_ONLY = pcre:/^[:alpha:]+$/ ALPHANUMERIC_ONLY = pcre:/^[:alnum:]+$/ IS_CTCP = pcre:/^\1/ ( Text starts with Ctrl-A ) HELLO = pcre:/\<hello\>/i ALL_LOWERCASE = pcre:/^[a-z]+$/ ALL_CAPS = caps_percentage() == 100 HEAVY_CAPS = caps_percentage() > 10 MOSTLY_CAPS = caps_percentage() > 50 SHORT_MESSAGE = length() < 40 LONG_MESSAGE = length() > 80 VERY_LONG_MESSAGE = length() > 160 CONTAINS_URL = pcre:/\W:\/\/.*\..*/" NOCOLOR = charcount(\3)=0 BOLD_2 = charcount(\2)=4 COLOR_2 = charcount(\3) = 4 CTRL_6 = pcre:/(.*[:ctrl:].*){6,}/ :services.dal.net SVSTEXTCLASSIFIER RESET :services.dal.net SVSTEXTCLASSIFIER ADDTOKEN CONTAINS_URL :pcre:/\W:\/\/.*\..*/" :services.dal.net SVSTEXTCLASSIFIER ADDTOKEN COLOR_2 :charcount(\3)=4 :services.dal.net SVSTEXTCLASSIFIER SET CONTAINS_URL COLOR_2 15 0 ..... Updating calculation of score from list of Features present: Evaluation: The classification table only has pairs of two features. A message has a feature if either the Feature is defined as: 1. A Terminal feature and the message satisfies the Terminal rule or condition. 2. A Pair of features named in the Classification table, and for both features in the pair, the message has both features. 3. A negated feature prefixed by [~], and the message has the feature of not containing the feature to the right of the negation. pseudocode function ScoreMessage(message : string, table : classification_table) begin score = 0.0 total_weight = 0 Foreach fp : feature_pair (f1,f2) in table.entries If Has_the_Feature (message, f1) && Has_the_Feature (message, f2) Then If fp.probability >= 0 && fp.probability <= 100 && fp.weight > 0 && fp.weight <= 1000 score += (fp.probability - 50) * fp.weight total_weight += fp.weight end end if end for score = (50.0 + score) / total_weight return score end -- -JH