CVE-2020-8815 (C#, published 2020-02-12T15:15Z)
Description: value: Improper connection handling in the base connection handler in IKTeam BearFTP before v0.3.1 allows a remote attacker to achieve denial of service via a Slowloris approach by sending a large volume of small packets.
Severity: MEDIUM (CVSS v3 base score: 7.5)
Weakness: CWE-20 \u2014 Improper Input Validation
The product receives input or data, but it does
        not validate or incorrectly validates that the input has the
        properties that are required to process the data safely and
        correctly.
Repository: https://github.com/kolya5544/BearFTP
Files changed:
BearFTP/Config.cs
BearFTP/Program.cs
BearFTP/Resources/ConfigFile.txt
BearFTP/example_config/config.json
CHANGELOG.txt
Commit message: Implemented maxthreads, added another entry to TODO


Vulnerable code:
        public static string _VERSION = "v0.3.1 BETA";
                            perip.AutoFlush = true;
                            
                            } else
                       
                    new Thread(new ThreadStart(() =>
                        Thread.CurrentThread.IsBackground = true;
                        bool triggered = false;
                        bool trigger2 = false;
                        Client c = new Client("null", "null", "null");
                        string username = "";
                        string password = "";
                        string directory = "/";
                        bool Authed = false;
                        bool passive = false;
                        int error = MaxErrors;
                        
                        //AbuseDBIP.com API
                        bool hacking = false;
                        bool bruteforce = false;
                        bool webapp = false;
                        string comment = "";
                        bool banned = false;
                        
                        
                        try
                        {
                            Thread.Sleep(100);
                            Log("Connected - " + hostname, "in", true, hostname, perip);
                            LogWrite("220 " + Banner.Replace("%host%", Hostname) + "\r\n", sw, hostname, perip);
                            while (client.Connected)
                                
                                string answ = sr.ReadLine(); //Who'd think this ACTUALLY works. BUT: It's doesnt work on Linux? (Needs testing)
                                //Tested on Ubuntu 16.04 client and 18.04 server. Seems to work!
                         
                                string upperfix = answ.Split(' ')[0].ToUpper();
                                answ.Replace(answ.Split(' ')[0], upperfix); //Fixing the lowercase commands an easy way

                                //Command processing.
                                if (answ.Length >= 3) //We dont want dummies to spam/DDoS.
                                {
                                    Log(answ, "in", true, hostname, perip);
                                }
                                if (answ.StartsWith("CONNECT") || answ.StartsWith("GET http"))
                                    if (Ban)
                                    {
                                        var aaa = new Ban();
                                        aaa.hostname = hostname;
                                        aaa.time = BanLength;
                                        bans.Add(aaa);
                                        client.Close();
                                    }
                                    var a = ReportAsync(hostname, "[" + DateTime.Now.ToString("MM/dd/yyyy HH:mm:ss") + "] " + "System scanning (Proxy judging) using CONNECT or GET requests", false, false, true, true, false);
                                    a.Start();
                                }
                                if (answ.Length > 128)
                                {
                                    client.Close();
                                }
                                if (answ.StartsWith("OPTS"))
                                {
                                    LogWrite("200 Encoding successfully changed!\r\n", sw, hostname, perip);
                                }
                                else if (answ.StartsWith("USER") && username.Length < 3 && !Authed)
                                {
                                    string temp = answ.Substring(5).Trim();
                                    Regex r = new Regex("^[a-zA-Z0-9]*$");
                                    if (r.IsMatch(temp) && temp.Length < 32 && temp.Length > 1 && (temp != "anonymous" || AllowAnonymous))
                                    {
                                        username = temp;
                                        LogWrite("331 This user is protected with password\r\n", sw, hostname, perip);
                                    else
                                        LogWrite("530 Wrong username or/and password.\r\n", sw, hostname, perip);
                                        if (temp.Length > 128)
                                }
                                else if (answ.StartsWith("PASS") && password.Length < 3 && !Authed)
                                {
                                    string temp = answ.Substring(5).Trim();
                                    if (temp.Length < 32 && temp.Length > 1)
                                        password = temp;
                                        if (password == "IEUser@" && PunishScans)
                                            if (Ban)
                                            {
                                                var aaa = new Ban();
                                                aaa.hostname = hostname;
                                                aaa.time = BanLength;
                                                bans.Add(aaa);
                                                client.Close();
                                            }
                                            var a = ReportAsync(hostname, "[" + DateTime.Now.ToString("MM/dd/yyyy HH:mm:ss") + "] " + "System scanning (port scanning) using NMAP", false, false, false, true, false);
                                            a.Start();


                                        LogWrite("230 Successful login.\r\n", sw, hostname, perip);
                                        ns.ReadTimeout = 60000;
                                        Authed = true;
                                        c = new Client(username, password, hostname);

                                        connected.Add(c);
                                    }
                                    else
                                    {
                                        LogWrite("530 Wrong username or/and password.\r\n", sw, hostname, perip);
                                        if (temp.Length > 128)
                                            client.Close();
                                }
                                else if (answ.Trim() == "SYST")
                                {
                                    LogWrite("215 UNIX Type: L8\r\n", sw, hostname, perip);
                                }
                                else if (answ.Trim() == "FEAT")
                                {
                                    LogWrite("502 Command unavailable.\r\n", sw, hostname, perip);
                                }
                                else if (answ.Trim() == "PWD")
                                {
                                    LogWrite("257 \"" + directory + "\" is the current working directory\r\n", sw, hostname, perip);
                                }
                                else if (answ.Trim() == "PORT")
                                {
                                    LogWrite("502 Command unavailable.\r\n", sw, hostname, perip);
                                }
                                else if (answ.Trim().StartsWith("TYPE"))
                                {
                                    LogWrite("200 OK!\r\n", sw, hostname, perip);
                                }
                                else if (answ.Trim().StartsWith("STOR") && Authed)
                                {
                                    Thread.Sleep(2000);
                                    if (passives.ContainsKey(c))
                                        Connectivity connn;
                                        passives.TryGetValue(c, out connn);
                                        if (connn.tcp.Connected)
                                            Thread.Sleep(1000);
                                            LogWrite("150 Ok to send data.\r\n", sw, hostname, perip);
                                            Thread.Sleep(100);
                                            List<byte> filess = new List<byte>();
                                            var bytess = default(byte[]);
                                            using (var memstream = new MemoryStream())
                                                var buffer = new byte[512];
                                                var bytesRead = default(int);
                                                while ((bytesRead = connn.sr.BaseStream.Read(buffer, 0, buffer.Length)) > 0)
                                                    memstream.Write(buffer, 0, bytesRead);
                                                bytess = memstream.ToArray();
                                            }
                                            System.IO.File.WriteAllBytes("dumps/dump_i" + rnd.Next(1, 2000000000).ToString() + ".txt", bytess);
                                            Thread.Sleep(200);
                                            LogWrite("226 Transfer complete!\r\n", sw, hostname, perip);
                                            if (Ban)
                                            {
                                                var aaa = new Ban();
                                                aaa.hostname = hostname;
                                                aaa.time = BanLength;
                                                bans.Add(aaa);
                                                client.Close();
                                            }
                                            var a = ReportAsync(hostname, "[" + DateTime.Now.ToString("MM/dd/yyyy HH:mm:ss") + "] " + "Unauthorized system access using FTP", true, false, false, false, false);
                                            a.Start();
                                            client.Close();
                                            c.Connected = false;
                                }
                                else if (answ.StartsWith("RETR") && Authed)
                                {
                                    Thread.Sleep(2000);
                                    string filename = answ.Substring(5).Trim().Replace("/", "");
                                    File aaaa = null;
                                    foreach (File aa in files)
                                        if (aa.name == filename)
                                            aaaa = aa;
                                    if (passives.ContainsKey(c) && aaaa != null)
                                        Connectivity connn;
                                        passives.TryGetValue(c, out connn);
                                        if (connn.tcp.Connected)
                                            Thread.Sleep(1000);
                                            LogWrite("150 Ok to send data.\r\n", sw, hostname, perip);
                                            Thread.Sleep(100);
                                            //       byte[] file = aaaa.content;
                                            //Encoding.ASCII.GetChars(file);
                                            //      connn.sw.Write(chars, 0, file.Length);
                                            //      connn.tcp.Close();
                                            SendFile(aaaa, connn.sw);
                                            connn.tcp.Close();
                                            Thread.Sleep(200);
                                            LogWrite("226 Transfer complete!\r\n", sw, hostname, perip);

                                            if (Ban)
                                                var aaa = new Ban();
                                                aaa.hostname = hostname;
                                                aaa.time = BanLength;
                                                bans.Add(aaa);
                                                client.Close();
                                            var a = ReportAsync(hostname, "[" + DateTime.Now.ToString("MM/dd/yyyy HH:mm:ss") + "] " + "Unauthorized system access using FTP", true, false, false, false, false);
                                            a.Start();
                                        else
                                            client.Close();
                                            c.Connected = false;
                                    }
                                }
                                else if (answ.Trim() == "PASV" && Authed)
                                {
                                    if (Authed && !passive)
                                    {
                                        LogWrite("227 Entering Passive Mode " + PasvInit(PortPasv, Hostname) + "\r\n", sw, hostname, perip);
                                        c.passive = true;
                                }
                                else if (answ.Trim().StartsWith("SIZE") && Authed)
                                {
                                    string filename = answ.Substring(5).Trim().Replace("/", "");
                                    File aaaa = null;
                                    foreach (File aa in files)
                                        if (aa.name == filename)
                                            aaaa = aa;
                                    if (aaaa != null)
                                        LogWrite("213 " + aaaa.size.ToString(), sw, hostname, perip);
                                }
                                else if (answ.Trim().StartsWith("LIST") && Authed)
                                {
                                    Thread.Sleep(1500);
                                    if (passives.ContainsKey(c))
                                        Connectivity connn;
                                        passives.TryGetValue(c, out connn);
                                        if (connn.tcp.Connected)
                                            string Builder = "";
                                            Builder += "drwxrwxrwx 5 root root 12288 Dec  1 16:51 .\r\n";
                                            Builder += "drwxrwxrwx 5 root root 12288 Dec  1 16:51 ..\r\n";
                                            int length = 5;
                                            foreach (File file in files)
                                                if (file.size.ToString().Length > length)
                                                    length = file.size.ToString().Length;
                                            foreach (File file in files)
                                                Builder += file.chmod;
                                                Builder += " " + rnd.Next(1, 9) + " ";
                                                Builder += "root root ";
                                                Builder += new string(' ', length - file.size.ToString().Length) + file.size.ToString();
                                                Builder += " " + file.creation;
                                                Builder += " " + file.name + "\r\n";
                                            LogWrite("150 Here comes the directory listing.\r\n", sw, hostname, perip);
                                            Thread.Sleep(100);
                                            connn.sw.Write(Builder);
                                            connn.tcp.Close();
                                            Thread.Sleep(100);
                                            LogWrite("226 Directory send OK\r\n", sw, hostname, perip);

                                        }
                                        else
                                        {
                                            client.Close();
                                            c.Connected = false;
                                }
                                else if (answ.StartsWith("CWD"))
                                {
                                    LogWrite("200 OK!\r\n", sw, hostname, perip);
                                }
                                else if (answ.StartsWith("CPFR"))
                                {
                                    //Fun part: tricking random exploiters. Very "hackers"
                                    triggered = true; //First level trigger
                                    LogWrite("350 Need more information.\r\n", sw, hostname, perip);
                                }
                                else if (answ.Trim().StartsWith("CPTO") && triggered)
                                {
                                    LogWrite("250 Need more information.\r\n", sw, hostname, perip);
                                }
                                else if (answ.Trim().StartsWith("AUTH"))
                                {
                                    LogWrite("502 Please use plain FTP.\r\n", sw, hostname, perip); // We dont want them to use security.
                                }
                                else if (Authed && username == "admin" && md5(password) == "")
                                {
                                    //Todo: admin cmds
                                }
                                else if (answ.Trim().StartsWith("CLNT"))
                                {
                                    LogWrite("200 OK!\r\n", sw, hostname, perip);
                                }
                                else if (Authed && answ.Trim().StartsWith("NOOP"))
                                {
                                    LogWrite("200 OK!\r\n", sw, hostname, perip);
                                } else if (Authed && answ.Trim().StartsWith("REST"))
                                {
                                    LogWrite("502 There is no such command.\r\n", sw, hostname, perip);
                                }
                                else
                                {
                                    if (answ.Length >= 3)
                                        error--;
                                        if (error <= 0)
                                            client.Close();
                                        }
                                }
                                if (answ.Contains("php") && triggered)
                                {
                                    trigger2 = true; //Second level trigger
                                }
                                if (trigger2)
                                {
                                    LogWrite("110 Illegal activity was detected.\r\n", sw, hostname, perip);
                                    LogWrite("110 Please, log off now.\r\n", sw, hostname, perip);
                                    if (Ban)
                                        var aaa = new Ban();
                                        aaa.hostname = hostname;
                                        aaa.time = BanLength;
                                        bans.Add(aaa);
                                        client.Close();
                                    var a = ReportAsync(hostname, "[" + DateTime.Now.ToString("MM/dd/yyyy HH:mm:ss") + "] " + "RCE Attempt at 21 port using ProFTPd exploit", true, false, false, false, false);
                                    a.Start();

                        }
                        catch (Exception e)
                        {
                            client.Close();
                            c.Connected = false;
                        }
                        Active.SetConnections(hostname, actives, Active.GetConnections(hostname, actives) - 1);
                        if (PerIPLogs)
                        {
                            try
                                perips.Remove(perip);
                                perip.Close();
                            } catch
                    )).Start();
                    Thread user = new Thread(new ThreadStart(() =>
                        Thread.CurrentThread.IsBackground = true;
                        Client c = new Client("1", "2", "3");
                        
                        try
                        {
                            bool ispresent = false;
                            foreach (Client cl in connected)
                                if (cl.hostname == hostname && cl.Connected)
                                    c = cl;
                                    ispresent = true;
                            }
                            if (!ispresent)
                            {
                                client.Close();
                            }
                            else
                            {
                                Connectivity ca = new Connectivity();
                                ca.sr = sr;
                                ca.sw = sw;
                                ca.tcp = client;
                                passives.Add(c, ca);
                                for (int i = 0; client.Connected; i++)
                                {
                                    Thread.Sleep(1000);
                                    if (i >= 120)
                                        client.Close();
                                        passives.Remove(c);
                                client.Close();
                                passives.Remove(c);
                        }
                        catch (Exception e)
                        {
                            if (!e.Message.StartsWith("An item"))
                                client.Close();
                                passives.Remove(c);
                        Active.SetConnections(hostname, pasv_actives, Active.GetConnections(hostname, pasv_actives) - 1);
                    }
                    ));
                    user.Start();
- Local command handler to edit config on-the-fly (see COMMANDS.md)

Fixed code:
        public int MaxThreads = 50;
                MaxThreads = json.MaxThreads;
        public int MaxThreads { get; set; }
        public static int MaxThreads = 50;
        //Count of dynamic threads currently used by a server
        public static int thread_amount = 0;

        public static string _VERSION = "v0.4.0 BETA";
                                perip.AutoFlush = true;

                            }
                            else

                    if (thread_amount <= MaxThreads)
                        thread_amount++;
                        new Thread(new ThreadStart(() =>
                        {
                            Thread.CurrentThread.IsBackground = true;
                            bool triggered = false;
                            bool trigger2 = false;
                            Client c = new Client("null", "null", "null");
                            string username = "";
                            string password = "";
                            string directory = "/";
                            bool Authed = false;
                            bool passive = false;
                            int error = MaxErrors;
                            //AbuseDBIP.com API
                            bool hacking = false;
                            bool bruteforce = false;
                            bool webapp = false;
                            string comment = "";
                            bool banned = false;


                            try
                                Log("Connected - " + hostname, "in", true, hostname, perip);
                                LogWrite("220 " + Banner.Replace("%host%", Hostname) + "\r\n", sw, hostname, perip);

                                while (client.Connected)
                                    Thread.Sleep(100);
                                    string answ = sr.ReadLine(); //Who'd think this ACTUALLY works. BUT: It's doesnt work on Linux? (Needs testing)
                                                                 //Tested on Ubuntu 16.04 client and 18.04 server. Seems to work!
                                    string upperfix = answ.Split(' ')[0].ToUpper();
                                    answ.Replace(answ.Split(' ')[0], upperfix); //Fixing the lowercase commands an easy way
                                    //Command processing.
                                    if (answ.Length >= 3) //We dont want dummies to spam/DDoS.
                                    {
                                        Log(answ, "in", true, hostname, perip);
                                    if (answ.StartsWith("CONNECT") || answ.StartsWith("GET http"))
                                        if (Ban)
                                            var aaa = new Ban();
                                            aaa.hostname = hostname;
                                            aaa.time = BanLength;
                                            bans.Add(aaa);
                                        var a = ReportAsync(hostname, "[" + DateTime.Now.ToString("MM/dd/yyyy HH:mm:ss") + "] " + "System scanning (Proxy judging) using CONNECT or GET requests", false, false, true, true, false);
                                        a.Start();


                                    if (answ.Length > 128)
                                    {
                                        client.Close();
                                    }
                                    if (answ.StartsWith("OPTS"))
                                    {
                                        LogWrite("200 Encoding successfully changed!\r\n", sw, hostname, perip);
                                    }
                                    else if (answ.StartsWith("USER") && username.Length < 3 && !Authed)
                                        string temp = answ.Substring(5).Trim();
                                        Regex r = new Regex("^[a-zA-Z0-9]*$");
                                        if (r.IsMatch(temp) && temp.Length < 32 && temp.Length > 1 && (temp != "anonymous" || AllowAnonymous))
                                            username = temp;
                                            LogWrite("331 This user is protected with password\r\n", sw, hostname, perip);
                                        else
                                            LogWrite("530 Wrong username or/and password.\r\n", sw, hostname, perip);
                                            if (temp.Length > 128)
                                            {
                                                client.Close();
                                            }
                                    else if (answ.StartsWith("PASS") && password.Length < 3 && !Authed)
                                        string temp = answ.Substring(5).Trim();
                                        if (temp.Length < 32 && temp.Length > 1)
                                            password = temp;
                                            if (password == "IEUser@" && PunishScans)
                                                if (Ban)
                                                {
                                                    var aaa = new Ban();
                                                    aaa.hostname = hostname;
                                                    aaa.time = BanLength;
                                                    bans.Add(aaa);
                                                    client.Close();
                                                }
                                                var a = ReportAsync(hostname, "[" + DateTime.Now.ToString("MM/dd/yyyy HH:mm:ss") + "] " + "System scanning (port scanning) using NMAP", false, false, false, true, false);
                                                a.Start();
                                            }
                                            LogWrite("230 Successful login.\r\n", sw, hostname, perip);
                                            ns.ReadTimeout = 60000;
                                            Authed = true;
                                            c = new Client(username, password, hostname);

                                            connected.Add(c);
                                            LogWrite("530 Wrong username or/and password.\r\n", sw, hostname, perip);
                                            if (temp.Length > 128)
                                            {
                                                client.Close();
                                            }
                                    else if (answ.Trim() == "SYST")
                                    {
                                        LogWrite("215 UNIX Type: L8\r\n", sw, hostname, perip);
                                    }
                                    else if (answ.Trim() == "FEAT")
                                    {
                                        LogWrite("502 Command unavailable.\r\n", sw, hostname, perip);
                                    }
                                    else if (answ.Trim() == "PWD")
                                        LogWrite("257 \"" + directory + "\" is the current working directory\r\n", sw, hostname, perip);
                                    }
                                    else if (answ.Trim() == "PORT")
                                    {
                                        LogWrite("502 Command unavailable.\r\n", sw, hostname, perip);
                                    }
                                    else if (answ.Trim().StartsWith("TYPE"))
                                    {
                                        LogWrite("200 OK!\r\n", sw, hostname, perip);
                                    }
                                    else if (answ.Trim().StartsWith("STOR") && Authed)
                                    {
                                        Thread.Sleep(2000);
                                        if (passives.ContainsKey(c))
                                            Connectivity connn;
                                            passives.TryGetValue(c, out connn);
                                            if (connn.tcp.Connected)
                                            {
                                                Thread.Sleep(1000);
                                                LogWrite("150 Ok to send data.\r\n", sw, hostname, perip);
                                                Thread.Sleep(100);
                                                List<byte> filess = new List<byte>();
                                                var bytess = default(byte[]);
                                                using (var memstream = new MemoryStream())
                                                {
                                                    var buffer = new byte[512];
                                                    var bytesRead = default(int);
                                                    while ((bytesRead = connn.sr.BaseStream.Read(buffer, 0, buffer.Length)) > 0)
                                                        memstream.Write(buffer, 0, bytesRead);
                                                    bytess = memstream.ToArray();
                                                }
                                                System.IO.File.WriteAllBytes("dumps/dump_i" + rnd.Next(1, 2000000000).ToString() + ".txt", bytess);
                                                Thread.Sleep(200);
                                                LogWrite("226 Transfer complete!\r\n", sw, hostname, perip);

                                                if (Ban)
                                                {
                                                    var aaa = new Ban();
                                                    aaa.hostname = hostname;
                                                    aaa.time = BanLength;
                                                    bans.Add(aaa);
                                                    client.Close();
                                                }
                                                var a = ReportAsync(hostname, "[" + DateTime.Now.ToString("MM/dd/yyyy HH:mm:ss") + "] " + "Unauthorized system access using FTP", true, false, false, false, false);
                                                a.Start();


                                            }
                                            else
                                            {
                                                client.Close();
                                                c.Connected = false;
                                            }
                                    else if (answ.StartsWith("RETR") && Authed)
                                        Thread.Sleep(2000);
                                        string filename = answ.Substring(5).Trim().Replace("/", "");
                                        File aaaa = null;
                                        foreach (File aa in files)
                                            if (aa.name == filename)
                                                aaaa = aa;
                                        if (passives.ContainsKey(c) && aaaa != null)
                                            Connectivity connn;
                                            passives.TryGetValue(c, out connn);
                                            if (connn.tcp.Connected)
                                            {
                                                Thread.Sleep(1000);
                                                LogWrite("150 Ok to send data.\r\n", sw, hostname, perip);
                                                Thread.Sleep(100);
                                                //       byte[] file = aaaa.content;
                                                //Encoding.ASCII.GetChars(file);
                                                //      connn.sw.Write(chars, 0, file.Length);
                                                //      connn.tcp.Close();
                                                SendFile(aaaa, connn.sw);
                                                connn.tcp.Close();
                                                Thread.Sleep(200);
                                                LogWrite("226 Transfer complete!\r\n", sw, hostname, perip);

                                                if (Ban)
                                                {
                                                    var aaa = new Ban();
                                                    aaa.hostname = hostname;
                                                    aaa.time = BanLength;
                                                    bans.Add(aaa);
                                                    client.Close();
                                                }
                                                var a = ReportAsync(hostname, "[" + DateTime.Now.ToString("MM/dd/yyyy HH:mm:ss") + "] " + "Unauthorized system access using FTP", true, false, false, false, false);
                                                a.Start();
                                            }
                                            else
                                            {
                                                client.Close();
                                                c.Connected = false;
                                            }
                                    else if (answ.Trim() == "PASV" && Authed)
                                        if (Authed && !passive)
                                            LogWrite("227 Entering Passive Mode " + PasvInit(PortPasv, Hostname) + "\r\n", sw, hostname, perip);
                                            c.passive = true;
                                    else if (answ.Trim().StartsWith("SIZE") && Authed)
                                        string filename = answ.Substring(5).Trim().Replace("/", "");
                                        File aaaa = null;
                                        foreach (File aa in files)
                                        {
                                            if (aa.name == filename)
                                            {
                                                aaaa = aa;
                                            }
                                        }
                                        if (aaaa != null)
                                        {
                                            LogWrite("213 " + aaaa.size.ToString(), sw, hostname, perip);
                                        }
                                    else if (answ.Trim().StartsWith("LIST") && Authed)
                                        Thread.Sleep(1500);
                                        if (passives.ContainsKey(c))
                                            Connectivity connn;
                                            passives.TryGetValue(c, out connn);
                                            if (connn.tcp.Connected)
                                                string Builder = "";
                                                Builder += "drwxrwxrwx 5 root root 12288 Dec  1 16:51 .\r\n";
                                                Builder += "drwxrwxrwx 5 root root 12288 Dec  1 16:51 ..\r\n";
                                                int length = 5;
                                                foreach (File file in files)
                                                {
                                                    if (file.size.ToString().Length > length)
                                                    {
                                                        length = file.size.ToString().Length;
                                                    }
                                                }
                                                foreach (File file in files)
                                                    Builder += file.chmod;
                                                    Builder += " " + rnd.Next(1, 9) + " ";
                                                    Builder += "root root ";
                                                    Builder += new string(' ', length - file.size.ToString().Length) + file.size.ToString();
                                                    Builder += " " + file.creation;
                                                    Builder += " " + file.name + "\r\n";
                                                LogWrite("150 Here comes the directory listing.\r\n", sw, hostname, perip);
                                                Thread.Sleep(100);
                                                connn.sw.Write(Builder);
                                                connn.tcp.Close();
                                                Thread.Sleep(100);
                                                LogWrite("226 Directory send OK\r\n", sw, hostname, perip);

                                            else
                                                client.Close();
                                                c.Connected = false;
                                    else if (answ.StartsWith("CWD"))
                                    {
                                        LogWrite("200 OK!\r\n", sw, hostname, perip);
                                    }
                                    else if (answ.StartsWith("CPFR"))
                                    {
                                        //Fun part: tricking random exploiters. Very "hackers"
                                        triggered = true; //First level trigger
                                        LogWrite("350 Need more information.\r\n", sw, hostname, perip);
                                    }
                                    else if (answ.Trim().StartsWith("CPTO") && triggered)
                                    {
                                        LogWrite("250 Need more information.\r\n", sw, hostname, perip);
                                    }
                                    else if (answ.Trim().StartsWith("AUTH"))
                                    {
                                        LogWrite("502 Please use plain FTP.\r\n", sw, hostname, perip); // We dont want them to use security.
                                    }
                                    else if (Authed && username == "admin" && md5(password) == "")
                                        //Todo: admin cmds
                                    }
                                    else if (answ.Trim().StartsWith("CLNT"))
                                    {
                                        LogWrite("200 OK!\r\n", sw, hostname, perip);
                                    }
                                    else if (Authed && answ.Trim().StartsWith("NOOP"))
                                    {
                                        LogWrite("200 OK!\r\n", sw, hostname, perip);
                                    }
                                    else if (Authed && answ.Trim().StartsWith("REST"))
                                    {
                                        LogWrite("502 There is no such command.\r\n", sw, hostname, perip);
                                    }
                                    else
                                    {
                                        if (answ.Length >= 3)
                                            error--;
                                            if (error <= 0)
                                            {
                                                client.Close();
                                            }
                                        }
                                    if (answ.Contains("php") && triggered)
                                        trigger2 = true; //Second level trigger
                                    if (trigger2)
                                    {
                                        LogWrite("110 Illegal activity was detected.\r\n", sw, hostname, perip);
                                        LogWrite("110 Please, log off now.\r\n", sw, hostname, perip);
                                        if (Ban)
                                        {
                                            var aaa = new Ban();
                                            aaa.hostname = hostname;
                                            aaa.time = BanLength;
                                            bans.Add(aaa);
                                            client.Close();
                                        }
                                        var a = ReportAsync(hostname, "[" + DateTime.Now.ToString("MM/dd/yyyy HH:mm:ss") + "] " + "RCE Attempt at 21 port using ProFTPd exploit", true, false, false, false, false);
                                        a.Start();
                                    }

                            catch (Exception e)
                                client.Close();
                                c.Connected = false;
                            }
                            Active.SetConnections(hostname, actives, Active.GetConnections(hostname, actives) - 1);
                            if (PerIPLogs)
                                try
                                {
                                    perips.Remove(perip);
                                    perip.Close();
                                }
                                catch
                                {
                                }
                            thread_amount--;
                        )).Start();
                    }
                    else
                    {
                        Console.WriteLine("-> ALL FREE THREADS ARE CURRENTLY BUSY! <-");
                        client.Close();
                    if (thread_amount <= MaxThreads)
                        thread_amount++;
                        Thread user = new Thread(new ThreadStart(() =>
                        {
                            Thread.CurrentThread.IsBackground = true;
                            Client c = new Client("1", "2", "3");

                            try
                                bool ispresent = false;
                                foreach (Client cl in connected)
                                    if (cl.hostname == hostname && cl.Connected)
                                    {
                                        c = cl;
                                        ispresent = true;
                                    }
                                if (!ispresent)
                                {
                                    client.Close();
                                }
                                else
                                {
                                    Connectivity ca = new Connectivity();
                                    ca.sr = sr;
                                    ca.sw = sw;
                                    ca.tcp = client;
                                    passives.Add(c, ca);
                                    for (int i = 0; client.Connected; i++)
                                        Thread.Sleep(1000);
                                        if (i >= 120)
                                        {
                                            client.Close();
                                            passives.Remove(c);
                                        }
                                    client.Close();
                                    passives.Remove(c);
                            catch (Exception e)
                                if (!e.Message.StartsWith("An item"))
                                {
                                    client.Close();
                                    passives.Remove(c);
                                }
                            Active.SetConnections(hostname, pasv_actives, Active.GetConnections(hostname, pasv_actives) - 1);
                            thread_amount--;
                        ));
                        user.Start();
                    }
  "MaxThreads": 50,
  "MaxThreads": 30,
- Local command handler to edit config on-the-fly (see COMMANDS.md)
- Config option for disabling outputting to console